|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Thomas Breuer, Götz Pfeiffer.
##
## Copyright of GAP belongs to its developers, whose names are too numerous
## to list here. Please refer to the COPYRIGHT file for details.
##
## SPDX-License-Identifier: GPL-2.0-or-later
##
## This file contains the implementations corresponding to the declarations
## in `ctbl.gd'.
##
## 1. Some Remarks about Character Theory in GAP
## 2. Character Table Categories
## 3. The Interface between Character Tables and Groups
## 4. Operators for Character Tables
## 5. Attributes and Properties for Groups as well as for Character Tables
## 6. Attributes and Properties only for Character Tables
## x. Operations Concerning Blocks
## 7. Other Operations for Character Tables
## 8. Creating Character Tables
## 9. Printing Character Tables
## 10. Constructing Character Tables from Others
## 11. Sorted Character Tables
## 12. Storing Normal Subgroup Information
## 13. Auxiliary Stuff
##
#############################################################################
##
## 1. Some Remarks about Character Theory in GAP
##
#############################################################################
##
## 2. Character Table Categories
##
#############################################################################
##
## 3. The Interface between Character Tables and Groups
##
#############################################################################
##
#F CharacterTableWithStoredGroup( <G>, <tbl>[, <arec>] )
#F CharacterTableWithStoredGroup( <G>, <tbl>, <bijection> )
##
InstallGlobalFunction( CharacterTableWithStoredGroup, function( arg )
local G, tbl, arec, ccl, compat, new, i;
# Get and check the arguments.
if Length( arg ) = 2 and IsGroup( arg[1] )
and IsOrdinaryTable( arg[2] ) then
arec:= rec();
elif Length( arg ) = 3 and IsGroup( arg[1] )
and IsOrdinaryTable( arg[2] )
and ( IsRecord( arg[3] ) or IsList(arg[3]) ) then
arec:= arg[3];
else
Error( "usage: CharacterTableWithStoredGroup(<G>,<tbl>[,<arec>])" );
fi;
G := arg[1];
tbl := arg[2];
if HasOrdinaryCharacterTable( G ) then
Error( "<G> has already a character table" );
fi;
ccl:= ConjugacyClasses( G );
#T How to exploit the known character table
#T if the conjugacy classes of <G> are not yet computed?
if IsList( arec ) then
compat:= arec;
else
compat:= CompatibleConjugacyClasses( G, ccl, tbl, arec );
fi;
if not IsList( compat ) then
return fail;
fi;
# Permute the classes if necessary.
if compat <> [ 1 .. Length( compat ) ] then
ccl:= ccl{ compat };
fi;
# Create a copy of the table.
new:= ConvertToLibraryCharacterTableNC(
rec( UnderlyingCharacteristic := 0 ) );
# Set the supported attribute values.
# We may assume that the subobjects of mutable attribute values
# are already immutable.
for i in [ 3, 6 .. Length( SupportedCharacterTableInfo ) ] do
if Tester( SupportedCharacterTableInfo[ i-2 ] )( tbl )
and SupportedCharacterTableInfo[ i-1 ] <> "Irr" then
Setter( SupportedCharacterTableInfo[ i-2 ] )( new,
SupportedCharacterTableInfo[ i-2 ]( tbl ) );
fi;
od;
# Set the irreducibles.
SetIrr( new, List( Irr( tbl ),
chi -> Character( new, ValuesOfClassFunction( chi ) ) ) );
# The identification is unique, store attribute values.
SetUnderlyingGroup( new, G );
SetConjugacyClasses( new, ccl );
SetIdentificationOfConjugacyClasses( new, compat );
SetOrdinaryCharacterTable( G, new );
return new;
end );
#############################################################################
##
#M CompatibleConjugacyClasses( <G>, <ccl>, <tbl>[, <arec>] )
##
InstallMethod( CompatibleConjugacyClasses,
"three argument version, call `CompatibleConjugacyClassesDefault'",
[ IsGroup, IsList, IsOrdinaryTable ],
function( G, ccl, tbl )
return CompatibleConjugacyClassesDefault( G, ccl, tbl, rec() );
end );
InstallMethod( CompatibleConjugacyClasses,
"four argument version, call `CompatibleConjugacyClassesDefault'",
[ IsGroup, IsList, IsOrdinaryTable, IsRecord ],
CompatibleConjugacyClassesDefault );
#############################################################################
##
#M CompatibleConjugacyClasses( <tbl>[, <arec>] )
##
InstallMethod( CompatibleConjugacyClasses,
"one argument version, call `CompatibleConjugacyClassesDefault'",
[ IsOrdinaryTable ],
function( tbl )
return CompatibleConjugacyClassesDefault( false, false, tbl, rec() );
end );
InstallMethod( CompatibleConjugacyClasses,
"two argument version, call `CompatibleConjugacyClassesDefault'",
[ IsOrdinaryTable, IsRecord ],
function( tbl, arec )
return CompatibleConjugacyClassesDefault( false, false, tbl, arec );
end );
#############################################################################
##
#F CompatibleConjugacyClassesDefault( <G>, <ccl>, <tbl>, <arec> )
#F CompatibleConjugacyClassesDefault( false, false, <tbl>, <arec> )
##
InstallGlobalFunction( CompatibleConjugacyClassesDefault,
function( G, ccl, tbl, arec )
local natchar, # natural character (if known)
nccl, # no. of conjugacy classes of `G'
pi1, # the partition of positions in `tbl'
pi2, # the partition of positions in `ccl'
bijection, # partial bijection currently known
refine, # function that does the refinement
tbl_orders, # element orders of classes in `tbl'
reps, # representatives of the classes in `ccl'
fun1, fun2, # functions returning invariants
tbl_classes, # class lengths in `tbl'
degree, # degree of the natural character
derpos, # positions of classes in the derived subgroup
primes, # primedivisors of the group order
powerclass,
powerclasses,
result, # return value
usesymm, # local function to use table automorphisms
usepowers, # local function to use power maps
usegalois, # local function to use Galois conjugation
sums, # list of lengths of entries in `equpos'
i,
j,
symm, # group of symmetries that is still available
ords,
p;
if IsBound( arec.natchar ) then
natchar:= arec.natchar;
fi;
nccl:= NrConjugacyClasses( tbl );
if ccl <> false and Length( ccl ) <> nccl then
return fail;
fi;
# We set up two partitions `pi1' of the column positions in `tbl'
# and `pi2' of the positions in `ccl'
# such that the $i$-th entries correspond to each other.
# These partitions are successively refined
# until either the bijection is found or no more criteria are available.
# Uniquely identified classes are removed from `pi1' and `pi2',
# and inserted in `bijection'.
if IsBound( arec.bijection ) then
bijection:= ShallowCopy( arec.bijection );
pi1:= [ Filtered( [ 1 .. nccl ], i -> not IsBound( bijection[i] ) ) ];
pi2:= [ Difference( [ 1 .. nccl ], bijection ) ];
else
bijection:= [];
pi1:= [ [ 1 .. nccl ] ];
pi2:= [ [ 1 .. nccl ] ];
fi;
# the function that does the refinement,
# the return value `false' means that the bijection is still ambiguous,
# `true' means that either the bijection is unique or an inconsistency
# was detected (in the former case, `result' holds the bijection,
# in the latter case, `result' is `fail')
refine:= function( fun1, fun2, range )
local newpi1, newpi2,
i, j,
val1, val2,
set,
new1, new2;
if G = false then
fun2:= fun1;
fi;
for i in range do
newpi1:= [];
newpi2:= [];
val1:= List( pi1[i], fun1 );
set:= Set( val1 );
if Length( set ) = 1 then
new1:= [ pi1[i] ];
new2:= [ pi2[i] ];
else
val2:= List( pi2[i], fun2 );
if set <> Set( val2 ) then
Info( InfoCharacterTable, 2,
"<G> and <tbl> do not fit together" );
result:= fail;
return true;
fi;
new1:= List( set, x -> [] );
new2:= List( set, x -> [] );
for j in [ 1 .. Length( val1 ) ] do
Add( new1[ Position( set, val1[j] ) ], pi1[i][j] );
Add( new2[ Position( set, val2[j] ) ], pi2[i][j] );
od;
fi;
for j in [ 1 .. Length( set ) ] do
if Length( new1[j] ) <> Length( new2[j] ) then
Info( InfoCharacterTable, 2,
"<G> and <tbl> do not fit together" );
result:= fail;
return true;
fi;
if Length( new1[j] ) = 1 then
bijection[ new1[j][1] ]:= new2[j][1];
else
Add( newpi1, new1[j] );
Add( newpi2, new2[j] );
fi;
od;
Append( pi1, newpi1 );
Append( pi2, newpi2 );
Unbind( pi1[i] );
Unbind( pi2[i] );
od;
pi1:= Compacted( pi1 );
pi2:= Compacted( pi2 );
if IsEmpty( pi1 ) then
Info( InfoCharacterTable, 2, "unique identification" );
if G = false then
result:= [];
else
result:= bijection;
fi;
return true;
else
return false;
fi;
end;
# Use element orders.
Info( InfoCharacterTable, 2,
"using element orders to identify classes" );
tbl_orders:= OrdersClassRepresentatives( tbl );
if G <> false then
reps:= List( ccl, Representative );
fi;
fun1:= ( i -> tbl_orders[i] );
fun2:= ( i -> Order( reps[i] ) );
if refine( fun1, fun2, [ 1 .. Length( pi1 ) ] ) then
return result;
fi;
# Use class lengths.
Info( InfoCharacterTable, 2,
"using class lengths to identify classes" );
tbl_classes:= SizesConjugacyClasses( tbl );
fun1:= ( i -> tbl_classes[i] );
fun2:= ( i -> Size( ccl[i] ) );
if refine( fun1, fun2, [ 1 .. Length( pi1 ) ] ) then
return result;
fi;
# Distinguish classes in the derived subgroup from others.
derpos:= ClassPositionsOfDerivedSubgroup( tbl );
if Length( derpos ) <> nccl then
Info( InfoCharacterTable, 2,
"using derived subgroup to identify classes" );
fun1:= ( i -> i in derpos );
fun2:= ( i -> reps[i] in DerivedSubgroup( G ) );
if refine( fun1, fun2, [ 1 .. Length( pi1 ) ] ) then
return result;
fi;
fi;
# Use the natural character if it is prescribed.
if IsBound( natchar ) then
Info( InfoCharacterTable, 2,
"using natural character to identify classes" );
degree:= natchar[1];
fun1:= ( i -> natchar[i] );
if IsPermGroup( G ) then
fun2:= ( i -> degree - NrMovedPoints( reps[i] ) );
elif IsMatrixGroup( G ) then
fun2:= ( i -> TraceMat( reps[i] ) );
elif G <> false then
Info( InfoCharacterTable, 2,
"<G> is no perm. or matrix group, ignore natural character" );
fun1:= ReturnTrue;
fun2:= ReturnTrue;
fi;
if refine( fun1, fun2, [ 1 .. Length( pi1 ) ] ) then
return result;
fi;
fi;
# Use power maps.
primes:= PrimeDivisors( Size( tbl ) );
# store power maps of the group, in order to identify the class
# of the power only once.
powerclasses:= [];
powerclass:= function( i, p, choice )
if not IsBound( powerclasses[p] ) then
powerclasses[p]:= [];
fi;
if not IsBound( powerclasses[p][i] ) then
powerclasses[p][i]:= First( choice, j -> reps[i]^p in ccl[j] );
fi;
return powerclasses[p][i];
end;
usepowers:= function( p )
local pmap, i, img1, pos, j, img2, choice, no, copypi1, k, fun1, fun2;
Info( InfoCharacterTable, 2, " (p = ", p, ")" );
pmap:= PowerMap( tbl, p );
# First consider classes whose image under the bijection is known
# but for whose `p'-th power the image is not yet known.
for i in [ 1 .. Length( bijection ) ] do
img1:= pmap[i];
if IsBound( bijection[i] ) and not IsBound( bijection[ img1 ] ) then
pos:= 0;
for j in [ 1 .. Length( pi1 ) ] do
if img1 in pi1[j] then
pos:= j;
break;
fi;
od;
if G = false then
img2:= img1;
else
img2:= powerclass( bijection[i], p, pi2[ pos ] );
if img2 = fail then
result:= fail;
return true;
fi;
fi;
bijection[ img1 ]:= img2;
RemoveSet( pi1[ pos ], img1 );
RemoveSet( pi2[ pos ], img2 );
if Length( pi1[ pos ] ) = 1 then
bijection[ pi1[ pos ][1] ]:= pi2[ pos ][1];
Unbind( pi1[ pos ] );
Unbind( pi2[ pos ] );
if IsEmpty( pi1 ) then
Info( InfoCharacterTable, 2, "unique identification" );
if G = false then
result:= [];
else
result:= bijection;
fi;
return true;
fi;
pi1:= Compacted( pi1 );
pi2:= Compacted( pi2 );
fi;
fi;
od;
# Next consider each set of nonidentified classes
# together with its `p'-th powers.
copypi1:= ShallowCopy( pi1 );
for i in [ 1 .. Length( copypi1 ) ] do
choice:= [];
no:= 0;
for j in Set( pmap{ copypi1[i] } ) do
if IsBound( bijection[j] ) then
AddSet( choice, bijection[j] );
no:= no + 1;
else
pos:= 0;
for k in [ 1 .. Length( pi1 ) ] do
if j in pi1[k] then
pos:= k;
break;
fi;
od;
if not IsSubset( choice, pi2[ pos ] ) then
no:= no + 1;
UniteSet( choice, pi2[ pos ] );
fi;
fi;
od;
if 1 < no then
fun1:= function( j )
local img;
img:= pmap[j];
if IsBound( bijection[ img ] ) then
return AdditiveInverse( bijection[ img ] );
else
return First( [ 1 .. Length( pi1 ) ], k -> img in pi1[k] );
fi;
end;
fun2:= function( j )
local img;
img:= powerclass( j, p, choice );
if img in bijection then
return AdditiveInverse( img );
else
return First( [ 1 .. Length( pi2 ) ], k -> img in pi2[k] );
fi;
end;
if refine( fun1, fun2, [ Position( pi1, copypi1[i] ) ] ) then
return true;
fi;
fi;
od;
return false;
end;
# Use symmetries of the table.
# (There may be asymmetries because of the prescribed character,
# so we start with the partition stabilizer of `pi1'.)
symm:= AutomorphismsOfTable( tbl );
if IsBound( natchar ) then
for i in pi1 do
symm:= Stabilizer( symm, i, OnSets );
od;
fi;
# Sort `pi1' and `pi2' according to decreasing element order.
# (catch automorphisms for long orbits, hope for powers
# if ambiguities remain)
ords:= List( pi1, x -> - tbl_orders[ x[1] ] );
ords:= Sortex( ords );
pi1:= Permuted( pi1, ords );
pi2:= Permuted( pi2, ords );
# If all points in a part of `pi1' are in the same orbit
# under table automorphism,
# we may separate one point from the others.
usesymm:= function()
local i, tuple;
for i in [ 1 .. Length( pi1 ) ] do
if not IsTrivial( symm ) then
tuple:= pi1[i];
if 1 < Length( tuple )
and tuple = Set( Orbit( symm, tuple[1], OnPoints ) ) then
Info( InfoCharacterTable, 2,
"found useful table automorphism" );
symm:= Stabilizer( symm, tuple[1] );
bijection[ tuple[1] ]:= pi2[i][1];
RemoveSet( pi1[i], pi1[i][1] );
RemoveSet( pi2[i], pi2[i][1] );
if Length( pi1[i] ) = 1 then
bijection[ pi1[i][1] ]:= pi2[i][1];
Unbind( pi1[i] );
Unbind( pi2[i] );
fi;
fi;
fi;
od;
if IsEmpty( pi1 ) then
Info( InfoCharacterTable, 2, "unique identification" );
if G = false then
result:= [];
else
result:= bijection;
fi;
return true;
fi;
pi1:= Compacted( pi1 );
pi2:= Compacted( pi2 );
return false;
end;
# Use Galois conjugacy of classes.
usegalois:= function()
local galoisfams, copypi1, i, list, fam, id, im, res, pos, fun1, fun2;
galoisfams:= GaloisMat( TransposedMat( Irr( tbl ) ) ).galoisfams;
galoisfams:= List( Filtered( galoisfams, IsList ), x -> x[1] );
copypi1:= ShallowCopy( pi1 );
for i in [ 1 .. Length( copypi1 ) ] do
list:= copypi1[i];
fam:= First( galoisfams, x -> IsSubset( x, list ) );
if fam <> fail then
id:= First( fam, j -> IsBound( bijection[j] ) );
if id <> fail then
Info( InfoCharacterTable, 2,
"found useful Galois automorphism" );
im:= bijection[ id ];
res:= PrimeResidues( tbl_orders[ id ] );
RemoveSet( res, 1 );
pos:= Position( pi1, copypi1[i] );
fun1:= ( j -> First( res, k -> PowerMap( tbl, k, id ) = j ) );
fun2:= ( j -> First( res,
k -> powerclass( im, k, pi2[ pos ] ) = j ) );
if refine( fun1, fun2, [ pos ] ) then
return true;
fi;
fi;
fi;
od;
return false;
end;
repeat
sums:= List( pi1, Length );
Info( InfoCharacterTable, 2,
"trying power maps to identify classes" );
for p in primes do
if usepowers( p ) then
return result;
fi;
od;
if usesymm() then
return result;
fi;
if usegalois() then
return result;
fi;
until sums = List( pi1, Length );
# no identification yet ...
Info( InfoCharacterTable, 2,
"not identified classes: ", pi1 );
if G = false then
return pi1;
else
return fail;
fi;
end );
#############################################################################
##
## 4. Operators for Character Tables
##
#############################################################################
##
#M \mod( <ordtbl>, <p> ) . . . . . . . . . . . . . . . . . <p>-modular table
##
InstallMethod( \mod,
"for ord. char. table, and pos. integer (call `BrauerTable')",
[ IsOrdinaryTable, IsPosInt ],
BrauerTable );
#############################################################################
##
#M \*( <tbl1>, <tbl2> ) . . . . . . . . . . . . . direct product of tables
##
InstallOtherMethod( \*,
"for two nearly character tables (call `CharacterTableDirectProduct')",
[ IsNearlyCharacterTable, IsNearlyCharacterTable ],
CharacterTableDirectProduct );
#############################################################################
##
#M \/( <tbl>, <list> ) . . . . . . . . . character table of a factor group
##
InstallOtherMethod( \/,
"for char. table, and positions list (call `CharacterTableFactorGroup')",
[ IsNearlyCharacterTable, IsList and IsCyclotomicCollection ],
CharacterTableFactorGroup );
#############################################################################
##
## 5. Attributes and Properties for Groups as well as for Character Tables
##
#############################################################################
##
#M CharacterDegrees( <G> ) . . . . . . . . . . . . . . . . . . . for a group
#M CharacterDegrees( <G>, <zero> ) . . . . . . . . . . for a group and zero
##
## - The two-argument version with second argument zero
## delegates to the one-argument version.
##
## - The two-argument version with second argument a positive integer <p>
## has one method that
## - calls the one-argument version if <p> does not divide the group order,
## - calls 'CharacterDegreesAbelian' if the group is abelian,
## - uses stored irreducibles of the Brauer character table in question,
## - calls 'CharacterDegreesConlon' if the group is solvable,
## - and delegates to the Brauer character table in question otherwise
## (which may result in an error if the degrees cannot be computed).
##
## - The one-argument version has at least the following methods,
## listed according to decreasing rank:
## - system getter,
## - applicable to 'IsGroup and IsAbelian',
## - applicable to 'IsGroup and HasIrr',
## - applicable to 'IsGroup and HasOrdinaryCharacterTable'
## (call 'TryNextMethod()' if the table does not store irreducibles),
## - applicable to 'IsGroup and IsHandledByNiceMonomorphism'
## (gets installed via 'AttributeMethodByNiceMonomorphism'),
## - applicable to 'IsGroup and MayBeHandledByNiceMonomorphism'
## (gets installed via 'AttributeMethodByNiceMonomorphism'),
## - applicable to 'IsGroup'
## (this method decides about the algorithm to be used).
##
InstallMethod( CharacterDegrees,
"for a group, and zero (call the one-argument version)",
[ IsGroup, IsZeroCyc ],
{ G, zero } -> List( CharacterDegrees( G ), ShallowCopy ) );
BindGlobal( "CharacterDegreesAbelian", function( G, p )
G:= Size( G );
if p <> 0 then
while G mod p = 0 do
G:= G / p;
od;
fi;
return [ [ 1, G ] ];
end );
InstallMethod( CharacterDegrees,
"for an abelian group",
[ IsGroup and IsAbelian ],
{} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method
G -> CharacterDegreesAbelian( G, 0 ) );
InstallMethod( CharacterDegrees,
"for a group with known Irr value",
[ IsGroup and HasIrr ],
{} -> RankFilter( IsHandledByNiceMonomorphism ) + 1, # override nice mon. method
G -> Collected( List( Irr( G ), DegreeOfCharacter ) ) );
InstallMethod( CharacterDegrees,
"for a group with known OrdinaryCharacterTable value",
[ IsGroup and HasOrdinaryCharacterTable ],
{} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method
function( G )
G:= OrdinaryCharacterTable( G );
if not HasIrr( G ) then
TryNextMethod();
fi;
return Collected( List( Irr( G ), DegreeOfCharacter ) );
end );
InstallMethod( CharacterDegrees,
"for a group",
[ IsGroup ],
function( G )
# We assume that the 'Irr' value is not known,
# otherwise a method with higher rank would have been successful.
if IsAbelian( G ) then
return CharacterDegreesAbelian( G, 0 );
elif IsSupersolvableGroup( G ) then
return CharacterDegreesBaumClausen( G );
elif IsSolvableGroup( G ) then
return CharacterDegreesConlon( G, 0 );
else
# We have no better methods.
return Collected( List( Irr( G ), DegreeOfCharacter ) );
fi;
end );
#############################################################################
##
#M CharacterDegrees( <G>, <p> ) . . . . . . . . . . . . . . . for prime <p>
##
InstallMethod( CharacterDegrees,
"for a group, and positive integer",
[ IsGroup, IsPosInt ],
function( G, p )
local tbl, modtbl;
Assert( 1, IsPrimeInt( p ) );
if Size( G ) mod p <> 0 then
return List( CharacterDegrees( G ), ShallowCopy );
elif IsAbelian( G ) then
return CharacterDegreesAbelian( G, p );
elif HasOrdinaryCharacterTable( G ) then
# Perhaps the 'p'-modular irreducibles are stored.
tbl:= CharacterTable( G );
if IsBound( ComputedBrauerTables( tbl )[p] ) then
modtbl:= ComputedBrauerTables( tbl )[p];
if HasIrr( modtbl ) then
return List( CharacterDegrees( modtbl ), ShallowCopy );
fi;
fi;
fi;
if IsSolvableGroup( G ) then
return CharacterDegreesConlon( G, p );
else
# Perhaps we cannot compute the result.
return List( CharacterDegrees( CharacterTable( G, p ) ), ShallowCopy );
fi;
end );
#############################################################################
##
#M CharacterDegrees( <tbl> ) . . . . . . . . . . . . . for a character table
##
## If the table knows its group and the irreducibles are not yet stored then
## we try to avoid the computation of the irreducibles and therefore
## delegate to the group.
## Otherwise we use the irreducibles.
##
InstallMethod( CharacterDegrees,
"for a character table",
[ IsCharacterTable ],
function( tbl )
if HasUnderlyingGroup( tbl ) and not HasIrr( tbl ) then
return CharacterDegrees( UnderlyingGroup( tbl ),
UnderlyingCharacteristic( tbl ) );
else
return Collected( List( Irr( tbl ), DegreeOfCharacter ) );
fi;
end );
#############################################################################
##
#M CharacterDegrees( <G> ) . . . . . for group handled via nice monomorphism
##
AttributeMethodByNiceMonomorphism( CharacterDegrees, [ IsGroup ] );
#############################################################################
##
#F CommutatorLength( <tbl> ) . . . . . . . . . . . . . for a character table
##
InstallMethod( CommutatorLength,
"for a character table",
[ IsCharacterTable ],
function( tbl )
local nccl,
irr,
derived,
commut,
other,
n,
G_n,
new,
i;
# Compute the classes that form the derived subgroup of $G$.
irr:= Irr( tbl );
nccl:= Length( irr );
derived:= Intersection( List( LinearCharacters( tbl ),
ClassPositionsOfKernel ) );
commut:= Filtered( [ 1 .. nccl ],
i -> Sum( irr, chi -> chi[i] / chi[1] ) <> 0 );
other:= Difference( derived, commut );
# Loop.
n:= 1;
G_n:= derived;
while not IsEmpty( other ) do
new:= [];
for i in other do
if ForAny( derived, j -> ForAny( G_n,
k -> ClassMultiplicationCoefficient( tbl, j, k, i ) <> 0 ) ) then
Add( new, i );
fi;
od;
n:= n+1;
UniteSet( G_n, new );
SubtractSet( other, new );
od;
return n;
end );
#############################################################################
##
#M CommutatorLength( <G> ) . . . . . . . . . . . . . . . . . . for a group
##
InstallMethod( CommutatorLength,
"for a group",
[ IsGroup ],
G -> CommutatorLength( CharacterTable( G ) ) );
#############################################################################
##
#M Irr( <G> ) . . . . . . . . . . . . . . . . . . . . . . . . . for a group
##
## Delegate to the two-argument version.
##
InstallMethod( Irr,
"for a group (call the two-argument version)",
[ IsGroup ],
G -> Irr( G, 0 ) );
#############################################################################
##
#M Irr( <G>, <0> ) . . . . . . . . . . . . . . . . . for a group and zero
##
## We compute the character table of <G> if it is not yet stored
## (which must be done anyhow), and then check whether the table already
## knows its irreducibles.
## This method is successful if the method for computing the table (head)
## automatically computes also the irreducibles.
##
InstallMethod( Irr,
"partial method for a group, and zero",
[ IsGroup, IsZeroCyc ], SUM_FLAGS,
function( G, zero )
local tbl;
tbl:= OrdinaryCharacterTable( G );
if HasIrr( tbl ) then
return Irr( tbl );
else
TryNextMethod();
fi;
end );
#############################################################################
##
#M Irr( <G>, <p> ) . . . . . . . . . . . . . . . . for a group and a prime
##
InstallMethod( Irr,
"for a group, and a prime",
[ IsGroup, IsPosInt ],
function( G, p )
return Irr( BrauerTable( G, p ) );
end );
#############################################################################
##
#M Irr( <modtbl> ) . . . . . . . . . . . . . for a <p>-solvable Brauer table
##
## Compute the modular irreducibles from the ordinary irreducibles
## using the Fong-Swan Theorem.
##
InstallMethod( Irr,
"for a <p>-solvable Brauer table (use the Fong-Swan Theorem)",
[ IsBrauerTable ],
function( modtbl )
local p, # characteristic
ordtbl, # ordinary character table
rest, # restriction of characters to `p'-regular classes
irr, # list of Brauer characters
cd, # list of ordinary character degrees
chars, # nonlinear characters distributed by degree
i, # loop variable
deg, # one character degree
pos, # position of a degree
list, # characters of one degree
dec; # decomposition of ordinary characters
# into known Brauer characters
p:= UnderlyingCharacteristic( modtbl );
ordtbl:= OrdinaryCharacterTable( modtbl );
if not IsPSolvableCharacterTable( ordtbl, p ) then
TryNextMethod();
fi;
rest:= RestrictedClassFunctions( Irr( ordtbl ), modtbl );
if Size( ordtbl ) mod p <> 0 then
# Catch a trivial case.
irr:= rest;
else
# Start with the linear characters.
# (Choose the same succession as in the ordinary table,
# in particular leave the trivial character at first position
# if this is the case for `ordtbl'.)
irr:= [];
cd:= [];
chars:= [];
for i in rest do
deg:= DegreeOfCharacter( i );
if deg = 1 then
if not i in irr then
Add( irr, i );
fi;
else
pos:= Position( cd, deg );
if pos = fail then
Add( cd, deg );
Add( chars, [ i ] );
elif not i in chars[ pos ] then
Add( chars[ pos ], i );
fi;
fi;
od;
SortParallel( cd, chars );
for list in chars do
dec:= Decomposition( irr, list, "nonnegative" );
for i in [ 1 .. Length( dec ) ] do
if dec[i] = fail then
Add( irr, list[i] );
fi;
od;
od;
fi;
# Return the irreducible Brauer characters.
return irr;
end );
#############################################################################
##
#M Irr( <ordtbl> ) . . . . . . . . for an ord. char. table with known group
##
## We must delegate this to the underlying group.
## Note that the ordering of classes for the characters in the group
## and the characters in the table may be different!
## Note that <ordtbl> may have been obtained by sorting the classes of the
## table stored as the `OrdinaryCharacterTable' value of $G$;
## In this case, the attribute `ClassPermutation' of <ordtbl> is set.
## (The `OrdinaryCharacterTable' value of $G$ itself does *not* have this.)
##
InstallMethod( Irr,
"for an ord. char. table with known group (delegate to the group)",
[ IsOrdinaryTable and HasUnderlyingGroup ],
function( ordtbl )
local irr, pi;
irr:= Irr( UnderlyingGroup( ordtbl ) );
if HasClassPermutation( ordtbl ) then
pi:= ClassPermutation( ordtbl );
irr:= List( irr, chi -> Character( ordtbl,
Permuted( ValuesOfClassFunction( chi ), pi ) ) );
fi;
return irr;
end );
#############################################################################
##
#M IBr( <modtbl> ) . . . . . . . . . . . . . . for a Brauer character table
#M IBr( <G>, <p> ) . . . . . . . . . . . . for a group, and a prime integer
##
InstallMethod( IBr,
"for a Brauer table",
[ IsBrauerTable ],
Irr );
InstallMethod( IBr,
"for a group, and a prime integer",
[ IsGroup, IsPosInt ],
function( G, p ) return Irr( G, p ); end );
#############################################################################
##
#M SetIrr( <tbl>, <list> ) . . . . . . . . . . . . . . for a character table
#M SetIrr( <G>, <list> ) . . . . . . . . . . . . . . . . . . . . for a group
##
## Provide a special setter method that sets the irreducibility flag in the
## characters.
##
InstallMethod( SetIrr,
"set the irreducibility flag",
[ IsCharacterTable, IsList ],
function( tbl, irr )
local chi;
for chi in irr do
SetIsIrreducibleCharacter( chi, true );
od;
TryNextMethod();
end );
InstallMethod( SetIrr,
"set the irreducibility flag",
[ IsGroup, IsList ],
function( G, irr )
local chi;
for chi in irr do
SetIsIrreducibleCharacter( chi, true );
od;
TryNextMethod();
end );
#############################################################################
##
#M LinearCharacters( <G> )
##
## Delegate to the two-argument version, as for `Irr'.
##
InstallMethod( LinearCharacters,
"for a group (call the two-argument version)",
[ IsGroup ],
G -> LinearCharacters( G, 0 ) );
#############################################################################
##
#M LinearCharacters( <G>, 0 )
##
InstallMethod( LinearCharacters,
"for a group, and zero",
[ IsGroup, IsZeroCyc ],
function( G, zero )
local tbl, pi, img, fus, res, chi;
if HasOrdinaryCharacterTable( G ) then
tbl:= OrdinaryCharacterTable( G );
if HasIrr( tbl ) then
return LinearCharacters( tbl );
fi;
fi;
if IsAbelian( G ) then
return Irr( G, 0 );
fi;
pi:= NaturalHomomorphismByNormalSubgroupNC( G, DerivedSubgroup( G ) );
img:= ImagesSource( pi );
SetIsAbelian( img, true );
# return RestrictedClassFunctions( CharacterTable( img ),
# Irr( img, 0 ), pi );
# We cannot use this because the source of `pi' may be not identical with `G'!
fus:= FusionConjugacyClasses( pi );
tbl:= CharacterTable( G );
res:= List( Irr( img, 0 ), x -> Character( tbl, x{ fus } ) );
for chi in res do
SetIsIrreducibleCharacter( chi, true );
od;
return res;
end );
#############################################################################
##
#M LinearCharacters( <G>, <p> )
##
InstallMethod( LinearCharacters,
"for a group, and positive integer",
[ IsGroup, IsPosInt ],
function( G, p )
local ordt, modt, res, chi;
if not IsPrimeInt( p ) then
Error( "<p> must be a prime" );
fi;
ordt:= OrdinaryCharacterTable( G );
modt:= BrauerTable( ordt, p );
res:= DuplicateFreeList(
RestrictedClassFunctions( LinearCharacters( ordt ), modt ) );
for chi in res do
SetIsIrreducibleCharacter( chi, true );
od;
return res;
end );
#############################################################################
##
#M LinearCharacters( <ordtbl> ) . . . . . . . . . . . for an ordinary table
##
InstallMethod( LinearCharacters,
"for an ordinary table",
[ IsOrdinaryTable ],
function( ordtbl )
local lin, pi, chi;
if HasIrr( ordtbl ) then
return Filtered( Irr( ordtbl ), chi -> chi[1] = 1 );
elif HasUnderlyingGroup( ordtbl ) then
lin:= LinearCharacters( UnderlyingGroup( ordtbl ) );
if HasClassPermutation( ordtbl ) then
pi:= ClassPermutation( ordtbl );
lin:= List( lin, lambda -> Character( ordtbl,
Permuted( ValuesOfClassFunction( lambda ), pi ) ) );
fi;
for chi in lin do
SetIsIrreducibleCharacter( chi, true );
od;
return lin;
else
TryNextMethod();
fi;
end );
#############################################################################
##
#M LinearCharacters( <modtbl> ) . . . . . . . . . . . . for a Brauer table
##
InstallMethod( LinearCharacters,
"for a Brauer table",
[ IsBrauerTable ],
function( modtbl )
local res, chi;
res:= DuplicateFreeList( RestrictedClassFunctions(
LinearCharacters( OrdinaryCharacterTable( modtbl ) ),
modtbl ) );
for chi in res do
SetIsIrreducibleCharacter( chi, true );
od;
return res;
end );
#############################################################################
##
#M OrdinaryCharacterTable( <G> ) . . . . . . . . . . . . . . . . for a group
#M OrdinaryCharacterTable( <modtbl> ) . . . . for a Brauer character table
##
## In the first case, we setup the table object.
## In the second case, we delegate to `OrdinaryCharacterTable' for the
## group.
##
InstallMethod( OrdinaryCharacterTable,
"for a group",
[ IsGroup ],
function( G )
local tbl, ccl, idpos, bijection;
# Make the object.
tbl:= Objectify( NewType( NearlyCharacterTablesFamily,
IsOrdinaryTable and IsAttributeStoringRep ),
rec() );
# Store the attribute values of the interface.
SetUnderlyingGroup( tbl, G );
SetUnderlyingCharacteristic( tbl, 0 );
IsFinite(G);
ccl:= ConjugacyClasses( G );
idpos:= First( [ 1 .. Length( ccl ) ],
i -> Order( Representative( ccl[i] ) ) = 1 );
if idpos = 1 then
bijection:= [ 1 .. Length( ccl ) ];
else
ccl:= Concatenation( [ ccl[ idpos ] ], ccl{ [ 1 .. idpos-1 ] },
ccl{ [ idpos+1 .. Length( ccl ) ] } );
bijection:= Concatenation( [ idpos ], [ 1 .. idpos-1 ],
[ idpos+1 .. Length( ccl ) ] );
fi;
SetConjugacyClasses( tbl, ccl );
SetIdentificationOfConjugacyClasses( tbl, bijection );
# Return the table.
return tbl;
end );
##############################################################################
##
#M AbelianInvariants( <tbl> ) . . . . . . . for an ordinary character table
##
## For all Sylow $p$ subgroups of the factor of <tbl> by the normal subgroup
## given by `ClassPositionsOfDerivedSubgroup( <tbl> )',
## compute the abelian invariants by repeated factoring by a cyclic group
## of maximal order.
##
InstallMethod( AbelianInvariants,
"for an ordinary character table",
[ IsOrdinaryTable ],
function( tbl )
local kernel, # cyclic group to be factored out
inv, # list of invariants, result
primes, # list of prime divisors of actual size
max, # list of actual maximal orders, for `primes'
pos, # list of positions of maximal orders
orders, # list of representative orders
i, # loop over classes
j; # loop over primes
# Do all computations modulo the derived subgroup.
kernel:= ClassPositionsOfDerivedSubgroup( tbl );
if 1 < Length( kernel ) then
tbl:= tbl / kernel;
fi;
#T cheaper to use only orders and power maps,
#T and to avoid computing several tables!
#T (especially avoid to compute the irreducibles of the original
#T table if they are not known!)
inv:= [];
while 1 < Size( tbl ) do
# For all prime divisors $p$ of the size,
# compute the element of maximal $p$ power order.
primes:= PrimeDivisors( Size( tbl ) );
max:= List( primes, x -> 1 );
pos:= [];
orders:= OrdersClassRepresentatives( tbl );
for i in [ 2 .. Length( orders ) ] do
if IsPrimePowerInt( orders[i] ) then
j:= 1;
while orders[i] mod primes[j] <> 0 do
j:= j+1;
od;
if orders[i] > max[j] then
max[j]:= orders[i];
pos[j]:= i;
fi;
fi;
od;
# Update the list of invariants.
Append( inv, max );
# Factor out the cyclic subgroup.
tbl:= tbl / ClassPositionsOfNormalClosure( tbl, pos );
od;
return AbelianInvariantsOfList( inv );
#T if we call this function anyhow, we can also take factors by the largest
#T cyclic subgroup of the commutator factor group!
end );
#############################################################################
##
#M Exponent( <tbl> ) . . . . . . . . . . . . for an ordinary character table
##
InstallMethod( Exponent,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> Lcm( OrdersClassRepresentatives( tbl ) ) );
#############################################################################
##
#M IsAbelian( <tbl> ) . . . . . . . . . . . for an ordinary character table
##
InstallMethod( IsAbelian,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> Size( tbl ) = NrConjugacyClasses( tbl ) );
#############################################################################
##
#M IsCyclic( <tbl> ) . . . . . . . . . . . . for an ordinary character table
##
InstallMethod( IsCyclic,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> Size( tbl ) in OrdersClassRepresentatives( tbl ) );
#############################################################################
##
#M IsElementaryAbelian( <tbl> ) . . . . . . for an ordinary character table
##
InstallMethod( IsElementaryAbelian,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> Size( tbl ) = 1 or
( IsAbelian( tbl ) and IsPrimeInt( Exponent( tbl ) ) ) );
#############################################################################
##
#M IsFinite( <tbl> ) . . . . . . . . . . . . for an ordinary character table
##
InstallMethod( IsFinite,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> IsInt( Size( tbl ) ) );
#############################################################################
##
#M IsMonomialCharacterTable( <tbl> ) . . . . for an ordinary character table
##
InstallMethod( IsMonomialCharacterTable,
"for an ordinary character table with underlying group",
[ IsOrdinaryTable and HasUnderlyingGroup ],
tbl -> IsMonomialGroup( UnderlyingGroup( tbl ) ) );
#############################################################################
##
#F CharacterTable_IsNilpotentFactor( <tbl>, <N> )
##
InstallGlobalFunction( CharacterTable_IsNilpotentFactor, function( tbl, N )
local series;
series:= CharacterTable_UpperCentralSeriesFactor( tbl, N );
return Length( Last(series) ) = NrConjugacyClasses( tbl );
end );
#############################################################################
##
#M IsNilpotentCharacterTable( <tbl> )
##
InstallMethod( IsNilpotentCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
function( tbl )
local series;
series:= ClassPositionsOfUpperCentralSeries( tbl );
return Length( Last(series) ) = NrConjugacyClasses( tbl );
end );
#############################################################################
##
#M IsPerfectCharacterTable( <tbl> ) . . . . for an ordinary character table
##
InstallMethod( IsPerfectCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> Number( Irr( tbl ), chi -> chi[1] = 1 ) = 1 );
#############################################################################
##
#M IsSimpleCharacterTable( <tbl> ) . . . . . for an ordinary character table
##
## Avoid computing all normal subgroups of abelian groups and p-groups.
##
InstallMethod( IsSimpleCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
function( tbl )
if IsAbelian( tbl ) then
return IsPrimeInt( Size( tbl ) );
else
return not IsPrimePowerInt( Size( tbl ) ) and
Length( ClassPositionsOfNormalSubgroups( tbl ) ) = 2;
fi;
end );
#############################################################################
##
#M IsAlmostSimpleCharacterTable( <tbl> ) . . for an ordinary character table
##
## <ManSection>
## <Meth Name="IsAlmostSimpleCharacterTable" Arg="tbl"/>
##
## <Description>
## Given the ordinary character table of a group <M>G</M>,
## we can check whether <M>G</M> has a unique minimal normal subgroup.
## <P/>
## The simplicity and nonabelianness of this normal subgroup can be verified
## by showing that its order occurs as the order of
## a nonabelian simple group.
## Note that any minimal normal subgroup is the direct product of
## isomorphic simple groups,
## and by a result in <Cite Key="KimmerleLyonsSandlingTeague90"/>,
## no proper power of the order of a simple group is the order of a simple
## group.
## <P/>
## A finite group is almost simple if and only if it has a unique minimal
## normal subgroup <M>N</M> with the property that <M>N</M> is nonabelian
## and simple.
## (Note that in the this case, the centralizer of <M>N</M> is trivial,
## because otherwise it would contain a minimal normal subgroup different
## from <M>N</M>; so <M>G / N</M> acts as a group of outer automorphisms on
## <M>N</M>.)
## </Description>
## </ManSection>
##
## Note that we could detect also whether a table belongs to an extension of
## a simple group of prime order by outer automorphisms.
## (These groups are not regarded as almost simple.)
## Namely, such a group has a unique minimal normal subgroup <M>N</M> of
## prime order <M>p</M>
## and all nontrivial conjugacy classes of <M>G</M> inside <M>N</M>
## have length <M>[G:N]</M>.
##
InstallMethod( IsAlmostSimpleCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
function( ordtbl )
local nsg, orbs;
nsg:= ClassPositionsOfMinimalNormalSubgroups( ordtbl );
if Length( nsg ) <> 1 then
return false;
fi;
orbs:= SizesConjugacyClasses( ordtbl ){ nsg[1] };
nsg:= Sum( orbs );
# An extension of a group of prime order by a subgroup of its
# automorphism group is *not* regarded as an almost simple group.
# (We could detect these groups from `orbs', i.e., the class lengths
# in the minimal normal subgroup.)
return ( not IsPrimeInt( nsg ) )
and IsomorphismTypeInfoFiniteSimpleGroup( nsg ) <> fail;
end );
#############################################################################
##
#M IsQuasisimpleCharacterTable( <tbl> ) . . for an ordinary character table
##
InstallMethod( IsQuasisimpleCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
ordtbl -> IsPerfectCharacterTable( ordtbl ) and
IsSimpleCharacterTable( ordtbl / ClassPositionsOfCentre( ordtbl ) ) );
#############################################################################
##
#M IsSolvableCharacterTable( <tbl> ) . . . . for an ordinary character table
##
InstallMethod( IsSolvableCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> IsPSolvableCharacterTable( tbl, 0 ) );
#############################################################################
##
#M IsSporadicSimpleCharacterTable( <tbl> ) . for an ordinary character table
##
## Note that by the classification of finite simple groups, the sporadic
## simple groups are determined by their orders.
##
InstallMethod( IsSporadicSimpleCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
function( tbl )
local info;
if IsSimpleCharacterTable( tbl ) then
info:= IsomorphismTypeInfoFiniteSimpleGroup( Size( tbl ) );
return info <> fail
and IsBound( info.series )
and info.series = "Spor";
fi;
return false;
end );
#############################################################################
##
#M IsSupersolvableCharacterTable( <tbl> ) . for an ordinary character table
##
InstallMethod( IsSupersolvableCharacterTable,
"for an ordinary character table",
[ IsOrdinaryTable ],
tbl -> Size( ClassPositionsOfSupersolvableResiduum( tbl ) ) = 1 );
#############################################################################
##
#F IsomorphismTypeInfoFiniteSimpleGroup( <tbl> )
##
## The simplicity of the group with character table <A>tbl</A> can be
## checked.
## If there is only one simple group of the given order then we are done.
## Otherwise there are exactly two possibilities,
## and we distinguish them using the same arguments as in the function for
## groups.
## Namely, the group <M>A_8</M> contains an element (of order <M>5</M>)
## whose centralizer order is <M>15</M>, whereas the group <M>L_3(4)</M>
## does not have an element with this centralizer order,
## and the groups in the two infinite series <M>O(2n+1,q)</M> and
## <M>S(2n,q)</M>, where <M>q</M> is a power of the (odd) prime <M>p</M>,
## can be distinguished by the fact that in the latter group, any
## element of order <M>p</M> in the centre of the Sylow <M>p</M>-subgroup
## has centralizer order divisible by <M>q^{{2n-2}} - 1</M>, whereas no such
## elements exist in the former group.
## (Note that <M>n</M> and <M>p</M> can be computed from the order of
## <M>O(2n+1,q)</M> or <M>S(2n,q)</M>).
##
InstallMethod( IsomorphismTypeInfoFiniteSimpleGroup,
[ "IsOrdinaryTable" ],
function( tbl )
local size, type, n, q, p, sylord, pos;
if not IsSimpleCharacterTable( tbl ) then
return fail;
fi;
size:= Size( tbl );
type:= IsomorphismTypeInfoFiniteSimpleGroup( size );
if IsRecord( type ) and not IsBound( type.series ) then
# There are two simple groups of the given order.
if size <> 20160 then
# Distinguish the two possibilities in the same way as the groups
# are distinguished by `IsomorphismTypeInfoFiniteSimpleGroup'.
n:= type.parameter[1];
q:= type.parameter[2];
p:= Factors( q )[1];
sylord:= 1;
while size mod p = 0 do
sylord:= sylord * p;
size:= size / p;
od;
pos:= First( [ 1 .. NrConjugacyClasses( tbl ) ],
i -> OrdersClassRepresentatives( tbl )[i] = p
and SizesCentralizers( tbl )[i] mod sylord = 0 );
if SizesCentralizers( tbl )[ pos ] mod (q^(2*n-2)-1) <> 0 then
type:= rec( series:= "B",
parameter:= [ n, q ],
name:= Concatenation( "B(", String(n), ",", String(q),
") ", "= O(", String(2*n+1), ",",
String(q), ")" ),
shortname:= Concatenation( "O", String( 2*n+1 ), "(",
String(q), ")" ) );
else
type:= rec( series:= "C",
parameter:= [ n, q ],
name:= Concatenation( "C(", String(n), ",", String(q),
") ", "= S(", String(2*n), ",",
String(q), ")" ),
shortname:= Concatenation( "S", String( 2*n ), "(",
String( q ), ")" ) );
fi;
elif 15 in SizesCentralizers( tbl ) then
type:= rec( series:= "A",
parameter:= 8,
name:= Concatenation( "A(8) ", "~ A(3,2) = L(4,2) ",
"~ D(3,2) = O+(6,2)" ),
shortname:= "A8" );
else
type:= rec( series:= "L",
parameter:= [ 3, 4 ],
name:= "A(2,4) = L(3,4)",
shortname:= "L3(4)" );
fi;
fi;
return type;
end );
#############################################################################
##
#M NrConjugacyClasses( <ordtbl> ) . . . . . for an ordinary character table
#M NrConjugacyClasses( <modtbl> ) . . . . . . for a Brauer character table
#M NrConjugacyClasses( <G> )
##
## We delegate from <tbl> to the underlying group in the general case.
## If we know the centralizer orders or class lengths, however, we use them.
##
## If the argument is a group, we can use the known class lengths of the
## known ordinary character table.
##
InstallMethod( NrConjugacyClasses,
"for an ordinary character table with underlying group",
[ IsOrdinaryTable and HasUnderlyingGroup ],
ordtbl -> NrConjugacyClasses( UnderlyingGroup( ordtbl ) ) );
InstallMethod( NrConjugacyClasses,
"for a Brauer character table",
[ IsBrauerTable ],
modtbl -> Length( GetFusionMap( modtbl,
OrdinaryCharacterTable( modtbl ) ) ) );
InstallMethod( NrConjugacyClasses,
"for a character table with known centralizer orders",
[ IsNearlyCharacterTable and HasSizesCentralizers ],
tbl -> Length( SizesCentralizers( tbl ) ) );
InstallMethod( NrConjugacyClasses,
"for a character table with known class lengths",
[ IsNearlyCharacterTable and HasSizesConjugacyClasses ],
tbl -> Length( SizesConjugacyClasses( tbl ) ) );
InstallMethod( NrConjugacyClasses,
"for a group with known ordinary character table",
[ IsGroup and HasOrdinaryCharacterTable ],
function( G )
local tbl;
tbl:= OrdinaryCharacterTable( G );
if HasNrConjugacyClasses( tbl ) then
return NrConjugacyClasses( tbl );
else
TryNextMethod();
fi;
end );
#############################################################################
##
#M Size( <tbl> ) . . . . . . . . . . . . . . . . . . . for a character table
#M Size( <G> )
##
## We delegate from <tbl> to the underlying group if this is stored.
## If we know the centralizer orders or class lengths, we may use them.
##
## If the argument is a group <G>, we can use the known size of the
## known ordinary character table of <G>.
##
InstallMethod( Size,
"for a character table",
[ IsNearlyCharacterTable ],
function( tbl )
if HasSizesCentralizers( tbl ) then
return SizesCentralizers( tbl )[1];
elif HasUnderlyingGroup( tbl ) and HasSize( UnderlyingGroup( tbl ) ) then
return Size( UnderlyingGroup( tbl ) );
elif HasSizesConjugacyClasses( tbl ) then
return Sum( SizesConjugacyClasses( tbl ) );
elif HasIrr( tbl ) then
return SizesCentralizers( tbl )[1];
elif HasUnderlyingGroup( tbl ) then
return Size( UnderlyingGroup( tbl ) );
else
TryNextMethod();
fi;
end );
InstallMethod( Size,
"for a group with known ordinary character table",
[ IsGroup and HasOrdinaryCharacterTable ],
function( G )
local tbl;
tbl:= OrdinaryCharacterTable( G );
if HasSize( tbl ) then
return Size( tbl );
else
TryNextMethod();
fi;
end );
#############################################################################
##
## 6. Attributes and Properties only for Character Tables
##
#############################################################################
##
#M OrdersClassRepresentatives( <ordtbl> ) . for an ordinary character table
#M OrdersClassRepresentatives( <modtbl> ) . . for a Brauer character table
##
## We delegate from <tbl> to the underlying group in the general case.
## If we know the class lengths, however, we use them.
##
InstallMethod( OrdersClassRepresentatives,
"for a Brauer character table (delegate to the ordinary table)",
[ IsBrauerTable ],
function( modtbl )
local ordtbl;
ordtbl:= OrdinaryCharacterTable( modtbl );
return OrdersClassRepresentatives( ordtbl ){ GetFusionMap( modtbl,
ordtbl ) };
end );
InstallMethod( OrdersClassRepresentatives,
"for a character table with known group",
[ IsNearlyCharacterTable and HasUnderlyingGroup ],
tbl -> List( ConjugacyClasses( tbl ),
c -> Order( Representative( c ) ) ) );
InstallMethod( OrdersClassRepresentatives,
"for a character table, use known power maps",
[ IsNearlyCharacterTable ],
function( tbl )
local pow, ord, p;
# Compute the orders as determined by the known power maps.
pow:= ComputedPowerMaps( tbl );
if IsEmpty( pow ) then
return fail;
fi;
ord:= ElementOrdersPowerMap( pow );
if ForAll( ord, IsInt ) then
return ord;
fi;
# If these maps do not suffice, compute the missing power maps
# and then try again.
for p in PrimeDivisors( Size( tbl ) ) do
PowerMap( tbl, p );
od;
ord:= ElementOrdersPowerMap( ComputedPowerMaps( tbl ) );
Assert( 2, ForAll( ord, IsInt ),
"computed power maps should determine element orders" );
return ord;
end );
#############################################################################
##
#M SizesCentralizers( <ordtbl> ) . . . . . . for an ordinary character table
#M SizesCentralizers( <modtbl> ) . . . . . . . for a Brauer character table
##
## If we know the class lengths or the irreducible characters,
## we prefer them to using a perhaps known group.
##
InstallMethod( SizesCentralizers,
"for a Brauer character table",
[ IsBrauerTable ],
function( modtbl )
local ordtbl;
ordtbl:= OrdinaryCharacterTable( modtbl );
return SizesCentralizers( ordtbl ){ GetFusionMap( modtbl, ordtbl ) };
end );
InstallMethod( SizesCentralizers,
"for a character table",
[ IsNearlyCharacterTable ],
function( tbl )
local classlengths, size;
if HasSizesConjugacyClasses( tbl ) then
classlengths:= SizesConjugacyClasses( tbl );
size:= Sum( classlengths, 0 );
return List( classlengths, s -> size / s );
elif HasIrr( tbl ) then
return Sum( List( Irr( tbl ),
x -> List( x, y -> y * ComplexConjugate( y ) ) ) );
elif HasUnderlyingGroup( tbl ) then
size:= Size( tbl );
return List( ConjugacyClasses( tbl ), c -> size / Size( c ) );
fi;
# Give up.
TryNextMethod();
end );
#############################################################################
##
#M SizesConjugacyClasses( <ordtbl> ) . . . . for an ordinary character table
#M SizesConjugacyClasses( <modtbl> ) . . . . . for a Brauer character table
##
## If we know the centralizer orders or the irreducible characters,
## we prefer them to using a perhaps known group.
##
InstallMethod( SizesConjugacyClasses,
"for a Brauer character table",
[ IsBrauerTable ],
function( modtbl )
local ordtbl;
ordtbl:= OrdinaryCharacterTable( modtbl );
return SizesConjugacyClasses( ordtbl ){ GetFusionMap( modtbl,
ordtbl ) };
end );
InstallMethod( SizesConjugacyClasses,
"for a character table ",
[ IsNearlyCharacterTable ],
function( tbl )
local centsizes, size;
if HasSizesCentralizers( tbl ) or HasIrr( tbl ) then
centsizes:= SizesCentralizers( tbl );
size:= centsizes[1];
return List( centsizes, s -> size / s );
elif HasUnderlyingGroup( tbl ) then
return List( ConjugacyClasses( tbl ), Size );
fi;
# Give up.
TryNextMethod();
end );
#############################################################################
##
#M AutomorphismsOfTable( <tbl> ) . . . . . . . . . . . for a character table
##
InstallMethod( AutomorphismsOfTable,
"for a character table",
[ IsCharacterTable ],
tbl -> TableAutomorphisms( tbl, Irr( tbl ) ) );
#############################################################################
##
#M AutomorphismsOfTable( <modtbl> ) . . . for Brauer table & good reduction
##
## The automorphisms may be stored already on the ordinary table.
##
InstallMethod( AutomorphismsOfTable,
"for a Brauer table in the case of good reduction",
[ IsBrauerTable ],
function( modtbl )
if Size( modtbl ) mod UnderlyingCharacteristic( modtbl ) = 0 then
TryNextMethod();
else
return AutomorphismsOfTable( OrdinaryCharacterTable( modtbl ) );
fi;
end );
#############################################################################
##
#M ClassNames( <tbl> ) . . . . . . . . . . class names of a character table
#M ClassNames( <tbl>, \"ATLAS\" ) . . . . . class names of a character table
##
InstallMethod( ClassNames,
[ IsNearlyCharacterTable ],
tbl -> ClassNames( tbl, "default" ) );
InstallMethod( ClassNames,
[ IsNearlyCharacterTable, IsString ],
function( tbl, string )
local i, # loop variable
alpha, # alphabet
lalpha, # length of the alphabet
number, # at position <i> the current number of
# classes of order <i>
unknown, # number of next unknown element order
names, # list of classnames, result
name, # local function returning right combination of letters
orders; # list of representative orders
if LowercaseString( string ) = "atlas" then
alpha:= [ "A","B","C","D","E","F","G","H","I","J","K","L","M",
"N","O","P","Q","R","S","T","U","V","W","X","Y","Z" ];
name:= function( n )
local m;
if n <= lalpha then
return alpha[n];
else
m:= (n-1) mod lalpha + 1;
n:= ( n - m ) / lalpha;
return Concatenation( alpha[m], String( n ) );
fi;
end;
else
alpha:= [ "a","b","c","d","e","f","g","h","i","j","k","l","m",
"n","o","p","q","r","s","t","u","v","w","x","y","z" ];
name:= function(n)
local name;
name:= "";
while 0 < n do
name:= Concatenation( alpha[ (n-1) mod lalpha + 1 ], name );
n:= QuoInt( n-1, lalpha );
od;
return name;
end;
fi;
lalpha:= Length( alpha );
names:= [];
if IsCharacterTable( tbl ) or HasOrdersClassRepresentatives( tbl ) then
# A character table can be asked for representative orders,
# also if they are not yet stored.
orders:= OrdersClassRepresentatives( tbl );
number:= [];
unknown:= 1;
for i in [ 1 .. NrConjugacyClasses( tbl ) ] do
if IsInt( orders[i] ) then
if not IsBound( number[ orders[i] ] ) then
number[ orders[i] ]:= 1;
fi;
names[i]:= Concatenation( String( orders[i] ),
name( number[ orders[i] ] ) );
number[ orders[i] ]:= number[ orders[i] ] + 1;
else
names[i]:= Concatenation( "?", name( unknown ) );
unknown:= unknown + 1;
fi;
od;
else
names[1]:= Concatenation( "1", alpha[1] );
for i in [ 2 .. NrConjugacyClasses( tbl ) ] do
names[i]:= Concatenation( "?", name( i-1 ) );
od;
fi;
# Return the list of classnames.
return names;
end );
#############################################################################
##
#M CharacterNames( <tbl> ) . . . . . . character names of a character table
##
InstallMethod( CharacterNames,
[ IsNearlyCharacterTable ],
tbl -> List( [ 1 .. NrConjugacyClasses( tbl ) ],
i -> Concatenation( "X.", String( i ) ) ) );
#############################################################################
##
#M \.( <tbl>, <name> ) . . . . . . . . . position of a class with given name
##
## If <name> is a class name of the character table <tbl> as computed by
## `ClassNames', `<tbl>.<name>' is the position of the class with this name.
##
InstallMethod( \.,
"for class names of a nearly character table",
[ IsNearlyCharacterTable, IsInt ],
function( tbl, name )
local pos;
name:= NameRNam( name );
pos:= Position( ClassNames( tbl ), name );
if pos = fail then
TryNextMethod();
else
return pos;
fi;
end );
#############################################################################
##
#F ColumnCharacterTable( <tbl>,<nr> )
##
InstallGlobalFunction(ColumnCharacterTable,function(T,n)
return Irr(T){[1..Length(Irr(T))]}[n];
end);
#############################################################################
##
#M ClassPositionsOfNormalSubgroups( <tbl> )
##
InstallMethod( ClassPositionsOfNormalSubgroups,
"for an ordinary character table",
[ IsOrdinaryTable ],
function( tbl )
local kernels, # list of kernels of irreducible characters
normal, # list of normal subgroups, result
ker1, # loop variable
ker2, # loop variable
inter; # intersection of two kernels
# Get the kernels of irreducible characters.
kernels:= Set( Irr( tbl ), ClassPositionsOfKernel );
# Form all possible intersections of the kernels.
normal:= ShallowCopy( kernels );
for ker1 in normal do
for ker2 in kernels do
inter:= Intersection( ker1, ker2 );
if not inter in normal then
Add( normal, inter );
fi;
od;
od;
# Sort the list of normal subgroups (first lexicographically,
# then --stable sort-- according to length and thus inclusion).
normal:= SSortedList( normal );
SortBy( normal, Length );
# Represent the lists as ranges if possible.
# (It is not possible to do this earlier since the representation
# as a range may get lost in the `Intersection' call.)
for ker1 in normal do
--> --------------------
--> maximum size reached
--> --------------------
[ Dauer der Verarbeitung: 0.49 Sekunden
(vorverarbeitet)
]
|