|
#############################################################################
##
#W construc.gi GAP 4 package CTblLib Thomas Breuer
##
## 1. Character Tables of Groups of Structure $M.G.A$
## 2. Character Tables of Groups of Structure $G.S_3$
## 3. Character Tables of Groups of Structure $G.2^2$
## 4. Character Tables of Groups of Structure $2^2.G$
## 5. Character Tables of Subdirect Products of Index Two
## 6. Brauer Tables of Extensions by $p$-regular Automorphisms
## 7. Construction Functions used in the Character Table Library
## 8. Character Tables of Coprime Central Extensions
## 9. Miscellaneous
##
#############################################################################
##
## 1. Character Tables of Groups of Structure $M.G.A$
##
#############################################################################
##
#F IrreducibleCharactersOfTypeMGA( <tblMG>, <tblGA>, <Mclasses>, <MGAfusGA>,
#F <orbs>, <a> )
##
## <Mclasses> is assumed to be the set of classes in <tblMG> that are mapped
## to the identity in the factor group $G$
## that is a normal subgroup of <tblGA>.
## Note that the table of $G$ is not needed at all in the construction,
## only the quotient $|G.a| / |G|$ seems to be a necessary parameter.
##
BindGlobal( "IrreducibleCharactersOfTypeMGA",
function( tblMG, tblGA, Mclasses, MGAfusGA, orbs, a )
local irr, p, m, ordtbl, zero, chi, ind, i;
irr:= List( Irr( tblGA ), chi -> CompositionMaps( chi, MGAfusGA ) );
p:= UnderlyingCharacteristic( tblMG );
m:= Sum( SizesConjugacyClasses( tblMG ){ Mclasses }, 0 );
if p <> 0 then
# Consider the ordinary tables, and divide the group orders by the
# orders of the `p'-cores.
# Note that we may construct the 3-modular table of $6.A_6.2_1$ from
# the table of its derived subgroup and the table of one of the factor
# groups $3.A_6.2_1$ or $A_6.2_1$.
ordtbl:= OrdinaryCharacterTable( tblMG );
m:= m * Sum( SizesConjugacyClasses( ordtbl ){
ClassPositionsOfPCore( ordtbl, p ) }, 0 );
ordtbl:= OrdinaryCharacterTable( tblGA );
m:= m / Sum( SizesConjugacyClasses( ordtbl ){
ClassPositionsOfPCore( ordtbl, p ) }, 0 );
fi;
zero:= Zero( MGAfusGA );
for chi in Irr( tblMG ) do
if not IsSubset( ClassPositionsOfKernel( chi ), Mclasses ) then
ind:= ShallowCopy( zero );
for i in [ 1 .. Length( orbs ) ] do
if IsBound( orbs[i] ) then
ind[i]:= Sum( chi{ orbs[i] }, 0 ) * ( a / Length( orbs[i] ) );
fi;
od;
if not ind in irr then
Add( irr, ind );
fi;
fi;
od;
return irr;
end );
#############################################################################
##
#F PossibleCharacterTablesOfTypeMGA( <tblMG>, <tblG>, <tblGA>, <orbs>,
#F <identifier> )
##
InstallGlobalFunction( PossibleCharacterTablesOfTypeMGA,
function( tblMG, tblG, tblGA, orbs, identifier )
local MGfusG, # factor fusion map from `tblMG' onto `tblG'
GfusGA, # subgroup fusion map from `tblG' into `tblGA'
tblMGA, # record for the desired table
MGfusMGA, # subgroup fusion map from `tblMG' into `tblMGA'
factouter, # positions of classes of `tblGA' outside `tblG'
MGAfusGA, # factor fusion map from `tblMGA' onto `tblGA'
inner, # inner classes of `tblMGA'
outer, # outer classes of `tblMGA'
nccl, # class number of `tblMG'
classes, # class lengths of `tblMG'
i, # loop variable
primes, # prime divisors of the order of `tblMGA'
invMGAfusGA, # inverse of `MGAfusGA'
p, # loop variable
GAmapp, # `p'-th power map of `tblGA'
orders, # element orders of `tblMGA'
suborders, # element orders of `tblMG'
outerorders, # outer part of the orders
gcd, # g.c.d. of the orders of `M' and `A'
matautos, # matrix automorphisms of the irred. of `tblMGA'
tblrecord, # record of `tblMGA' (power maps perhaps ambiguous)
info, # list of possible tables
newinfo, # list of possible tables for the next step
pair, # loop variable
pow, # one possible power map
newmatautos, # automorphisms respecting one more power map
newtblMGA, # intermediate table with one more unique power map
oldfus;
# Check the arguments.
if not ForAll( [ tblMG, tblG, tblGA ], IsOrdinaryTable ) then
Error( "<tblG>, <tblMG>, <tblGA> must be ordinary character tables" );
fi;
# Fetch the stored fusions.
MGfusG:= GetFusionMap( tblMG, tblG );
GfusGA:= GetFusionMap( tblG, tblGA );
if MGfusG = fail or GfusGA = fail then
Error( "fusions <tblMG> -> <tblG>, <tblG> -> <tblGA> must be stored" );
fi;
# Initialize the table record `tblMGA' of $m.G.a$.
tblMGA:= rec( UnderlyingCharacteristic := 0,
Identifier := identifier,
Size := Size( tblMG ) * Size( tblGA ) / Size( tblG ),
ComputedPowerMaps := [] );
# The class fusion of `tblMG' into `tblMGA' is given by `orbs'.
MGfusMGA:= InverseMap( orbs );
# Determine the outer classes of `tblGA'.
factouter:= Difference( [ 1 .. NrConjugacyClasses( tblGA ) ], GfusGA );
# Compute the fusion of `tblMGA' onto `tblGA'.
MGAfusGA:= CompositionMaps( GfusGA, CompositionMaps( MGfusG, orbs ) );
Append( MGAfusGA, factouter );
# Distinguish inner and outer classes of `tblMGA'.
inner:= [ 1 .. Maximum( MGfusMGA ) ];
outer:= [ Maximum( MGfusMGA ) + 1 .. Length( MGAfusGA ) ];
nccl:= Length( inner ) + Length( outer );
# Compute the class lengths of `tblMGA'.
tblMGA.SizesConjugacyClasses:= Concatenation( Zero( inner ),
( Size( tblMG ) / Size( tblG ) )
* SizesConjugacyClasses( tblGA ){ factouter } );
classes:= SizesConjugacyClasses( tblMG );
for i in inner do
tblMGA.SizesConjugacyClasses[i]:= Sum( classes{ orbs[i] } );
od;
# Compute the centralizer orders of `tblMGA'.
tblMGA.SizesCentralizers:= List( tblMGA.SizesConjugacyClasses,
x -> tblMGA.Size / x );
# Compute the irreducible characters of `tblMGA'.
tblMGA.Irr:= IrreducibleCharactersOfTypeMGA( tblMG, tblGA,
ClassPositionsOfKernel( MGfusG ), MGAfusGA, orbs,
Size( tblGA ) / Size( tblG ) );
# Compute approximations for power maps of `tblMGA'.
# (All $p$-th power maps for $p$ coprime to $|A|$ are uniquely
# determined this way, since inner and outer part are kept separately.)
#T We know more:
#T If |A| is a prime and does not divide |M| then the action is
#T semiregular; we have a unique fixed point for any element in N
#T that has a p-th root outside N.
primes:= PrimeDivisors( tblMGA.Size );
invMGAfusGA:= InverseMap( MGAfusGA );
for p in primes do
# inner part: Transfer the map from `tblMG' to `tblMGA'.
tblMGA.ComputedPowerMaps[p]:= CompositionMaps( MGfusMGA,
CompositionMaps( PowerMap( tblMG, p ), orbs ) );
# outer part: Use the map of `tblGA' for an approximation.
GAmapp:= PowerMap( tblGA, p );
for i in outer do
tblMGA.ComputedPowerMaps[p][i]:=
invMGAfusGA[ GAmapp[ MGAfusGA[i] ] ];
od;
od;
# Enter the element orders.
# (If $|A|$ and $|M|$ are coprime then the orders of outer elements
# are uniquely determined; otherwise there may be ambiguities.)
orders:= [];
suborders:= OrdersClassRepresentatives( tblMG );
for i in [ 1 .. Length( MGfusMGA ) ] do
orders[ MGfusMGA[i] ]:= suborders[i];
od;
outerorders:= OrdersClassRepresentatives( tblGA ){ factouter };
gcd:= Gcd( Size( tblMG ), Size( tblGA ) ) / Size( tblG );
if gcd <> 1 then
gcd:= DivisorsInt( gcd );
outerorders:= List( outerorders, x -> gcd * x );
fi;
tblMGA.OrdersClassRepresentatives:= Concatenation( orders, outerorders );
# Compute the automorphisms of the matrix of characters.
if gcd = 1 then
matautos:= [ tblMGA.SizesCentralizers,
tblMGA.OrdersClassRepresentatives ];
else
matautos:= [ tblMGA.SizesCentralizers ];
fi;
matautos:= MatrixAutomorphisms( tblMGA.Irr, matautos,
GroupByGenerators( [], () ) );
# Convert the record to a character table object.
# (Keep a record for the case that we need copies later.)
tblrecord:= ShallowCopy( tblMGA );
Unbind( tblrecord.ComputedPowerMaps );
ConvertToCharacterTableNC( tblMGA );
# Test and improve the (perhaps ambiguous) power maps
# (and update the automorphisms if necessary) using characters.
# Whenever several $p$-th power maps are possible then we branch,
# so we end up with a list of possible character tables.
info:= [ [ tblMGA, matautos ] ];
for p in primes do
newinfo:= [];
for pair in info do
tblMGA:= pair[1];
matautos:= pair[2];
pow:= ComputedPowerMaps( tblMGA )[p];
pow:= PossiblePowerMaps( tblMGA, p, rec( powermap:= pow ) );
if not IsEmpty( pow ) then
# Consider representatives up to matrix automorphisms.
for pow in RepresentativesPowerMaps( pow, matautos ) do
newmatautos:= SubgroupProperty( matautos,
perm -> ForAll( [ 1 .. nccl ],
i -> pow[ i^perm ] = pow[i]^perm ),
TrivialSubgroup( matautos ),
TrivialSubgroup( matautos ) );
newtblMGA:= ConvertToLibraryCharacterTableNC(
ShallowCopy( tblrecord ) );
SetComputedPowerMaps( newtblMGA,
StructuralCopy( ComputedPowerMaps( tblMGA ) ) );
ComputedPowerMaps( newtblMGA )[p]:= pow;
Add( newinfo, [ newtblMGA, newmatautos ] );
od;
fi;
od;
# Hand over the list for the next step.
info:= newinfo;
od;
# Here we have the final list of tables.
for pair in info do
tblMGA:= pair[1];
SetAutomorphismsOfTable( tblMGA, pair[2] );
StoreFusion( tblMGA, MGAfusGA, tblGA );
oldfus:= ShallowCopy( ComputedClassFusions( tblMG ) );
StoreFusion( tblMG, MGfusMGA, tblMGA );
SetConstructionInfoCharacterTable( tblMGA,
ConstructMGAInfo( tblMGA, tblMG, tblGA ) );
if Length( oldfus ) < Length( ComputedClassFusions( tblMG ) ) then
Unbind( ComputedClassFusions( tblMG )[
Length( ComputedClassFusions( tblMG ) ) ] );
fi;
SetInfoText( tblMGA,
"constructed using `PossibleCharacterTablesOfTypeMGA'" );
# Store the unique element orders if necessary.
if gcd <> 1 then
ResetFilterObj( tblMGA, HasOrdersClassRepresentatives );
SetOrdersClassRepresentatives( tblMGA,
ElementOrdersPowerMap( ComputedPowerMaps( tblMGA ) ) );
fi;
od;
# Return the result list.
return List( info, pair -> rec( table := pair[1],
MGfusMGA := MGfusMGA ) );
end );
#############################################################################
##
#F BrauerTableOfTypeMGA( <modtblMG>, <modtblGA>, <ordtblMGA> )
##
InstallGlobalFunction( BrauerTableOfTypeMGA,
function( modtblMG, modtblGA, ordtblMGA )
local p, modtblMGA, MGfusMGA, MGAfusGA, orbs, i, kernel;
# Fetch the underlying characteristic, and check the arguments.
p:= UnderlyingCharacteristic( modtblMG );
if UnderlyingCharacteristic( modtblGA ) <> p then
Info( InfoCharacterTable, 1,
"BrauerTableOfTypeMGA: UnderlyingCharacteristic values differ\n",
"#I for <modtblMG>, <modtblGA>" );
return fail;
elif not IsOrdinaryTable( ordtblMGA ) then
Info( InfoCharacterTable, 1,
"BrauerTableOfTypeMGA: <ordtblMGA> must be the ordinary table\n",
"#I of M.G.A" );
return fail;
fi;
# We cannot assume that the ordinary table of `tblMGA' has the same
# ordering of classes as is guaranteed for the table to be constructed.
# (Consider the case of $M.G = 3.U.3$ and $G.A = U.6$, where the
# outer classes of $U.2$ precede the outer classes of $U.3$.)
modtblMGA:= CharacterTableRegular( ordtblMGA, p );
# Compute the restriction of the action to the `p'-regular classes.
MGfusMGA:= GetFusionMap( modtblMG, modtblMGA );
if MGfusMGA = fail then
Info( InfoCharacterTable, 1,
"BrauerTableOfTypeMGA: the class fusion\n",
"#I OrdinaryCharacterTable( <modtblMG> ) -> <ordtblMGA> ",
"must be stored" );
return fail;
fi;
# Compute the irreducibles.
MGAfusGA:= GetFusionMap( modtblMGA, modtblGA );
orbs:= InverseMap( MGfusMGA );
for i in [ 1 .. Length( orbs ) ] do
if IsBound( orbs[i] ) and IsInt( orbs[i] ) then
orbs[i]:= [ orbs[i] ];
fi;
od;
kernel:= Filtered( [ 1 .. NrConjugacyClasses( modtblMG ) ],
i -> MGAfusGA[ MGfusMGA[i] ] = 1 );
SetIrr( modtblMGA, List( IrreducibleCharactersOfTypeMGA( modtblMG,
modtblGA, kernel, MGAfusGA, orbs,
Size( ordtblMGA ) / Size( modtblMG ) ),
x -> Character( modtblMGA, x ) ) );
SetInfoText( modtblMGA, "constructed using `BrauerTableOfTypeMGA'" );
# Return the result.
return rec( table:= modtblMGA, MGfusMGA:= MGfusMGA );
end );
#############################################################################
##
#F PossibleActionsForTypeMGA( <tblMG>, <tblG>, <tblGA> )
##
InstallGlobalFunction( PossibleActionsForTypeMGA,
function( tblMG, tblG, tblGA )
local tfustA,
Mtfust,
ker,
index,
inner,
i,
elms,
cenMG,
cenG,
inv,
factorbits,
img,
newelms,
chars;
# Check that the function is applicable.
tfustA:= GetFusionMap( tblG, tblGA );
if tfustA = fail then
Error( "class fusion <tblG> -> <tblGA> must be stored on <tblG>" );
fi;
Mtfust:= GetFusionMap( tblMG, tblG );
if Mtfust = fail then
Error( "class fusion <tblMG> -> <tblG> must be stored on <tblMG>" );
fi;
index:= Size( tblGA ) / Size( tblG );
if not IsPrimeInt( index ) then
inner:= Set( tfustA );
for i in PrimeDivisors( index ) do
if ForAll( PowerMap( tblGA, index / i ), j -> j in inner ) then
Error( "factor of <tblGA> by <tblG> must be cyclic" );
fi;
od;
fi;
# The automorphism must have order equal to the order of $A$.
# We need to consider only one generator for each cyclic group of
# the right order.
elms:= Filtered( Elements( AutomorphismsOfTable( tblMG ) ),
#T better avoid computing all elements
x -> Order( x ) = index );
elms:= Set( List( elms, SmallestGeneratorPerm ) );
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) of order ", index );
# The automorphism respects the fusion of classes of $G$ into $G.A$.
inv:= InverseMap( Mtfust );
for i in [ 1 .. Length( inv ) ] do
if IsInt( inv[i] ) then
inv[i]:= [ inv[i] ];
fi;
od;
factorbits:= Filtered( InverseMap( tfustA ), IsList );
for i in [ 1 .. Length( inv ) ] do
img:= First( factorbits, orb -> i in orb );
if img = fail then
img:= inv[i];
newelms:= Filtered( elms, x -> OnSets( img, x ) = img );
else
img:= Union( inv{ Difference( img, [ i ] ) } );
newelms:= Filtered( elms, x -> IsSubset( img, OnSets( inv[i], x ) ) );
fi;
if newelms <> elms then
elms:= newelms;
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) mapping ",i," compatibly" );
fi;
od;
# The automorphism must act semiregularly on those characters of $M.G$
# that are not characters of $G$.
# (Think of the case that the centres of $G$ and $M.G$ have orders
# $2$ and $6$, respectively, and $A$ is of order $2$.)
ker:= ClassPositionsOfKernel( Mtfust );
chars:= Filtered( Irr( tblMG ),
chi -> not IsSubset( ClassPositionsOfKernel( chi ), ker ) );
elms:= Filtered( elms,
x -> Set( OrbitLengths( Group(x), chars, Permuted ) )
= [ index ] );
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) acting semiregularly" );
# Form the orbits on the class positions.
elms:= Set( List( elms, x -> Set( List( Orbits( Group(x),
[ 1 .. NrConjugacyClasses( tblMG ) ] ), Set ) ) ) );
# Return the result.
return elms;
end );
#############################################################################
##
#F ConstructMGA( <tbl>, <subname>, <factname>, <plan>, <perm> )
##
InstallGlobalFunction( ConstructMGA,
function( tbl, subname, factname, plan, perm )
local factfus, subfus, proj, irreds, zero, irr, newirr, entry, sum, chi,
i;
factfus := First( tbl.ComputedClassFusions,
fus -> fus.name = factname ).map;
factname := CharacterTableFromLibrary( factname );
subname := CharacterTableFromLibrary( subname );
subfus := First( ComputedClassFusions( subname ),
fus -> fus.name = tbl.Identifier ).map;
proj := ProjectionMap( subfus );
irreds := List( Irr( factname ),
x -> ValuesOfClassFunction( x ){ factfus } );
zero:= [ 1 .. Length( factfus ) ] * 0;
irr:= Irr( subname );
newirr:= [];
for entry in plan do
# Note that `proj' need not be dense.
sum:= Sum( irr{ entry } );
chi:= ShallowCopy( zero );
for i in [ 1 .. Length( chi ) ] do
if IsBound( proj[i] ) then
chi[i]:= sum[ proj[i] ];
fi;
od;
Add( newirr, chi );
od;
Append( irreds, newirr );
tbl.Irr:= Permuted( irreds, perm );
end );
#############################################################################
##
## 2. Character Tables of Groups of Structure $G.S_3$
##
#############################################################################
##
#F IrreducibleCharactersOfTypeGS3( <tbl>, <tblC>, <tblK>, <aut>,
#F <tblfustblC>, <tblfustblK>, <tblCfustblKC>, <tblKfustblKC>, <outerC> )
##
BindGlobal( "IrreducibleCharactersOfTypeGS3",
function( tbl, tblC, tblK, aut, tblfustblC, tblfustblK, tblCfustblKC,
tblKfustblKC, outerC )
local irreducibles, # list of irreducible characters, result
zero, # zero vector on the classes of `tblC' \ `tbl'
irrtbl, # irreducible of `tbl'
irrtblC, # irreducible of `tblC'
irrtblK, # irreducible of `tblK'
done, # Boolean list, `true' for all processed characters
outerKC, # position of classes outside `tblK'
k, # order of the factor `tblK / tbl'
c, # order of the factor `tblC / tbl'
p, # characteristic of `tbl'
r, # ramification index
i, # loop over the irreducibles of `tblK'
chi, # currently processed character of `tblK'
img, # image of `chi' under `aut'
rest, # restriction of `chi' to `tbl' (via `tblfustblK')
e, # current ramification
const, # irreducible constituents of `rest'
ext, # extensions of an extendible constituent to `tblC'
chitilde, # one extension
irr, # one irreducible character
j, # loop over the classes of `tblK'
sum; # an induced character
# Initializations.
irreducibles:= [];
zero:= 0 * outerC;
irrtbl:= Irr( tbl );
irrtblC:= Irr( tblC );
irrtblK:= Irr( tblK );
done:= BlistList( [ 1 .. Length( irrtblK ) ], [] );
outerKC:= tblCfustblKC{ outerC };
k:= Size( tblK ) / Size( tbl );
c:= Size( tblC ) / Size( tbl );
p:= UnderlyingCharacteristic( tbl );
r:= RootInt( k );
if r^2 <> k then
r:= 1;
fi;
# Loop over the irreducibles of `tblK'.
for i in [ 1 .. Length( irrtblK ) ] do
if not done[i] then
done[i]:= true;
chi:= irrtblK[i];
img:= Permuted( chi, aut );
if img = chi then
# `chi' extends.
rest:= chi{ tblfustblK };
e:= 1;
if rest in irrtbl then
# `rest' is invariant in `tblKC', so we take the values
# of its extensions to `tblC' on the outer classes.
const:= [ rest ];
elif r <> 1 and rest / r in irrtbl then
# `rest' is a multiple of an irreducible character of `tbl'.
const:= [ rest / r ];
e:= r;
else
# `rest' is a sum of `k' irreducibles of `tbl';
# exactly one of them is fixed under the action of `tblC',
# so we take the values of the extensions of this constituent
# on the outer classes.
const:= Filtered( irrtbl,
x -> x[1] = rest[1] / k and
Induced( tbl, tblK, [ x ], tblfustblK )[1] = chi );
Assert( 1, Length( const ) = k,
"Strange number of constituents.\n" );
fi;
ext:= Filtered( irrtblC, x -> x[1] = const[1][1]
and x{ tblfustblC } in const );
Assert( 1, ( p = c and Length( ext ) = 1 ) or
( p <> c and Length( ext ) = c ),
"Extendible constituent is not unique.\n" );
# We can handle only a few cases where $e \neq 1$:
if e <> 1 and e = c - 1 then
# If $e = |C|-1$ then sum up all except one extension.
ext:= List( ext, x -> Sum( ext ) - x );
elif e <> 1 and e = c + 1 then
# If $e = |C|+1$ then sum up all plus one extension.
ext:= List( ext, x -> Sum( ext ) + x );
elif e <> 1 then
Error( "cannot handle a case where <e> > 1" );
fi;
for chitilde in ext do
irr:= [];
for j in [ 1 .. Length( tblKfustblKC ) ] do
irr[ tblKfustblKC[j] ]:= chi[j];
od;
irr{ outerKC }:= chitilde{ outerC };
Add( irreducibles, irr );
od;
else
# `chi' induces irreducibly.
irr:= [];
done[ Position( irrtblK, img ) ]:= true;
sum:= chi + img;
for j in [ 3 .. c ] do
img:= Permuted( img, aut );
done[ Position( irrtblK, img ) ]:= true;
sum:= sum + img;
od;
for j in [ 1 .. Length( tblKfustblKC ) ] do
irr[ tblKfustblKC[j] ]:= sum[j];
od;
irr{ outerKC }:= zero;
Add( irreducibles, irr );
fi;
fi;
od;
# Return the result.
Assert( 1, Length( irreducibles ) = Length( irreducibles[1] ),
Concatenation( "Not all irreducibles found (have ",
String( Length( irreducibles ) ), " of ",
String( Length( irreducibles[1] ) ), ")\n" ) );
return irreducibles;
end );
#############################################################################
##
#F CharacterTableOfTypeGS3( <tbl>, <tblC>, <tblK>, <aut>, <identifier> )
#F CharacterTableOfTypeGS3( <modtbl>, <modtblC>, <modtblK>, <ordtblKC>,
#F <identifier> )
##
InstallGlobalFunction( CharacterTableOfTypeGS3,
function( tbl, tblC, tblK, aut, identifier )
local p, # prime integer
tblfustblC, # class fusion from `tbl' into `tblC'
tblfustblK, # class fusion from `tbl' into `tblK'
tblKfustblKC, # class fusion from `tblK' into the desired table
tblCfustblKC, # class fusion from `tblC' into the desired table
outer, # positions of the classes of `tblC' \ `tbl'
i,
tblKC,
classes,
subclasses,
k,
orders,
suborders,
powermap,
pow,
oldfusC,
oldfusK;
# Fetch the underlying characteristic, and check the arguments.
p:= UnderlyingCharacteristic( tbl );
if UnderlyingCharacteristic( tblC ) <> p
or UnderlyingCharacteristic( tblK ) <> p then
Error( "UnderlyingCharacteristic values differ for <tbl>, <tblC>, ",
"<tblK>" );
elif 0 < p and not IsOrdinaryTable( aut ) then
Error( "enter the ordinary table of G.KC as the fourth argument" );
elif 0 = p and not IsPerm( aut ) then
Error( "enter a permutation as the fourth argument" );
fi;
# Fetch the stored fusions from `tbl'.
tblfustblC:= GetFusionMap( tbl, tblC );
tblfustblK:= GetFusionMap( tbl, tblK );
if tblfustblC = fail or tblfustblK = fail then
Error( "fusions <tbl> -> <tblC>, <tbl> -> <tblK> must be stored" );
fi;
outer:= Difference( [ 1 .. NrConjugacyClasses( tblC ) ], tblfustblC );
if 0 < p then
# We assume that the ordinary table of `tblKC' (given as the argument
# `aut') has the same ordering of classes as is guaranteed for the
# table to be constructed.
tblKC:= CharacterTableRegular( aut, p );
# Compute the restriction of the action to the `p'-regular classes.
tblKfustblKC:= GetFusionMap( tblK, tblKC );
if tblKfustblKC = fail then
Error( "fusion <tblK> -> <tblKC> must be stored" );
fi;
aut:= Product( List( Filtered( InverseMap( tblKfustblKC ), IsList ),
x -> MappingPermListList( x,
Concatenation( x{ [ 2 .. Length(x) ] },
[ x[1] ] ) ) ),
() );
# Fetch fusions for the result.
tblKfustblKC:= GetFusionMap( tblK, tblKC );
tblCfustblKC:= GetFusionMap( tblC, tblKC );
else
# Compute the needed fusions into `tblKC'.
tblKfustblKC:= InverseMap( Set( Orbits( Group( aut ),
[ 1 .. NrConjugacyClasses( tblK ) ] ) ) );
tblCfustblKC:= CompositionMaps( tblKfustblKC,
CompositionMaps( tblfustblK, InverseMap( tblfustblC ) ) );
tblCfustblKC{ outer }:= [ 1 .. Length( outer ) ]
+ Maximum( tblKfustblKC );
# Initialize the record for the character table `tblKC'.
tblKC:= rec( UnderlyingCharacteristic := 0,
Identifier := identifier,
Size := Size( tblK ) * Size( tblC ) / Size( tbl ) );
# Compute class lengths and centralizer orders.
classes:= ListWithIdenticalEntries( Maximum( tblCfustblKC ), 0 );
subclasses:= SizesConjugacyClasses( tblK );
for i in [ 1 .. Length( subclasses) ] do
classes[ tblKfustblKC[i] ]:= classes[ tblKfustblKC[i] ]
+ subclasses[i];
od;
subclasses:= SizesConjugacyClasses( tblC );
k:= Size( tblK ) / Size( tbl );
for i in outer do
classes[ tblCfustblKC[i] ]:= classes[ tblCfustblKC[i] ]
+ k * subclasses[i];
od;
tblKC.SizesConjugacyClasses:= classes;
tblKC.SizesCentralizers:= List( classes, x -> tblKC.Size / x );
# Compute element orders.
orders:= [];
suborders:= OrdersClassRepresentatives( tblK );
for i in [ 1 .. Length( tblKfustblKC ) ] do
orders[ tblKfustblKC[i] ]:= suborders[i];
od;
suborders:= OrdersClassRepresentatives( tblC );
for i in outer do
orders[ tblCfustblKC[i] ]:= suborders[i];
od;
tblKC.OrdersClassRepresentatives:= orders;
# Convert the record to a table object.
ConvertToLibraryCharacterTableNC( tblKC );
# Put the power maps together.
powermap:= ComputedPowerMaps( tblKC );
for p in PrimeDivisors( Size( tblKC ) ) do
pow:= InitPowerMap( tblKC, p );
TransferDiagram( PowerMap( tblC, p ), tblCfustblKC, pow );
TransferDiagram( PowerMap( tblK, p ), tblKfustblKC, pow );
powermap[p]:= pow;
Assert( 1, ForAll( pow, IsInt ),
Concatenation( Ordinal( p ),
" power map not uniquely determined" ) );
od;
fi;
# Compute the irreducibles.
SetIrr( tblKC,
List( IrreducibleCharactersOfTypeGS3( tbl, tblC, tblK, aut,
tblfustblC, tblfustblK, tblCfustblKC, tblKfustblKC,
outer ),
chi -> Character( tblKC, chi ) ) );
if IsOrdinaryTable( tblKC ) then
oldfusC:= ShallowCopy( ComputedClassFusions( tblC ) );
StoreFusion( tblC, tblCfustblKC, tblKC );
oldfusK:= ShallowCopy( ComputedClassFusions( tblK ) );
StoreFusion( tblK, tblKfustblKC, tblKC );
SetConstructionInfoCharacterTable( tblKC,
ConstructGS3Info( tblC, tblK, tblKC ).list );
if Length( oldfusC ) < Length( ComputedClassFusions( tblC ) ) then
Unbind( ComputedClassFusions( tblC )[
Length( ComputedClassFusions( tblC ) ) ] );
fi;
if Length( oldfusK ) < Length( ComputedClassFusions( tblK ) ) then
Unbind( ComputedClassFusions( tblK )[
Length( ComputedClassFusions( tblK ) ) ] );
fi;
fi;
SetInfoText( tblKC, "constructed using `CharacterTableOfTypeGS3'" );
# Return the result.
return rec( table := tblKC,
tblCfustblKC := tblCfustblKC,
tblKfustblKC := tblKfustblKC );
end );
#############################################################################
##
#F PossibleActionsForTypeGS3( <tbl>, <tblC>, <tbl3> )
##
#T Do we need a function that computes also compatible fusions if necessary?
#T (The condition is that the orbits on the classes of <tbl> describe an
#T action of S_3.)
##
InstallGlobalFunction( PossibleActionsForTypeGS3, function( tbl, tblC, tblK )
local tfustC, tfustK, c, elms, inner, linK, i, vals, c1, c2, newelms,
inv, orbs, orb;
# Check that the function is applicable.
tfustC:= GetFusionMap( tbl, tblC );
if tfustC = fail then
Error( "class fusion <tbl> -> <tblC> must be stored on <tbl>" );
fi;
tfustK:= GetFusionMap( tbl, tblK );
if tfustK = fail then
Error( "class fusion <tbl> -> <tblK> must be stored on <tbl>" );
fi;
# The automorphism must have order `c'.
c:= Size( tblC ) / Size( tbl );
elms:= Filtered( Elements( AutomorphismsOfTable( tblK ) ),
#T better avoid computing all elements
x -> Order( x ) = c );
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) of order ", c );
if Length( elms ) <= 1 then
return elms;
fi;
# The automorphism must permute the outer cosets of `tblK'.
inner:= Set( tfustK );
linK:= Filtered( Irr( tblK ),
chi -> IsSubset( ClassPositionsOfKernel( chi ), inner ) );
linK:= Difference( linK, [ TrivialCharacter( tblK ) ] );
elms:= Filtered( elms, x -> Permuted( linK[1], x ) = linK[2] );
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) permuting the cosets" );
if Length( elms ) <= 1 then
return elms;
fi;
# The automorphism respects the fusion of classes of `tbl' into `tblC'.
for i in InverseMap( tfustC ) do
if IsList( i ) then
vals:= SortedList( tfustK{ i } );
c1:= vals[1];
c2:= vals[2];
if c1 <> c2 then
RemoveSet( vals, c1 );
newelms:= Filtered( elms, x -> c1^x in vals );
if newelms <> elms then
elms:= newelms;
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) fusing ", c1, " and ",
c2 );
if Length( elms ) <= 1 then
return elms;
fi;
fi;
fi;
fi;
od;
# Two inner classes that are not fused in `tblC'
# cannot be conjugate in `tKC'.
# (Note that the centralizer order in `tblC' is `c' times larger than
# in `tbl', and this extra factor does not occur in the centralizer
# order in `tblK'.)
inv:= InverseMap( tfustK );
orbs:= Union( List( elms, i -> Filtered( Orbits( Group( i ), inner ),
orb -> Length( orb ) = c ) ) );
orbs:= Filtered( orbs,
x -> ( ForAll( inv{ x }, IsInt )
and Number( Set( tfustC{ inv{ x } } ) ) > 1 )
or ( ForAll( inv{ x }, IsList )
and ForAny( inv[ x[1] ],
y -> SizesCentralizers( tbl )[y]
< SizesCentralizers( tblC )[ tfustC[y] ] ) ) );
for orb in orbs do
c1:= orb[1];
c2:= orb[2];
newelms:= Filtered( elms, x -> c1^x <> c2 );
if newelms <> elms then
elms:= newelms;
Info( InfoCharacterTable, 1,
Length( elms ),
" automorphism(s) not fusing ", c1, " and ", c2 );
if Length( elms ) <= 1 then
return elms;
fi;
fi;
od;
# Return the result.
return elms;
end );
#############################################################################
##
## 3. Character Tables of Groups of Structure $G.2^2$
##
#############################################################################
##
#F PossibleActionsForTypeGV4( <tblG>, <tblsG2> )
##
InstallGlobalFunction( PossibleActionsForTypeGV4,
function( tblG, tblsG2 )
local tfust2, perms, actonG, fixedinG, i, j, k, inv, stabs, elms,
domains, triples, elm, comp, nccl, filt2, filt3;
# Check that the function is applicable.
tfust2:= List( tblsG2, t2 -> GetFusionMap( tblG, t2 ) );
if fail in tfust2 then
Error( "class fusions <tblG> -> <tblsG2> must be stored on <tblG>" );
elif ForAny( tblsG2, t2 -> Size( t2 ) <> 2 * Size( tblG ) ) then
Error( "<tblG> must have index 2 in all tables in <tblsG2>" );
fi;
# For computing compatible actions on the tables in `tblsG2',
# we rearrange these tables such that the fusions are sorted.
# In particular, the classes of <tblG> shall come first.
perms:= [];
actonG:= [];
fixedinG:= [];
for i in [ 1 .. 3 ] do
perms[i]:= [];
j:= 1;
for k in [ 1 .. Length( tfust2[i] ) ] do
if not IsBound( perms[i][ tfust2[i][k] ] ) then
perms[i][ tfust2[i][k] ]:= j;
j:= j+1;
fi;
od;
for k in [ 1 .. NrConjugacyClasses( tblsG2[i] ) ] do
if not IsBound( perms[i][k] ) then
perms[i][k]:= j;
j:= j+1;
fi;
od;
perms[i]:= PermList( perms[i] );
tfust2[i]:= OnTuples( tfust2[i], perms[i] );
inv:= InverseMap( tfust2[i] );
actonG[i]:= Product( List( Filtered( inv, IsList ),
x -> (x[1], x[2]) ),
() );
fixedinG[i]:= Filtered( inv, IsInt );
od;
# Check that the three fusions are compatible in the sense that
# the product of the three permutations induced on the classes of
# <tblG> is the identity.
if not IsOne( Product( actonG ) ) then
Info( InfoCharacterTable, 1,
"the three subgroup fusions are not compatible" );
return [];
fi;
# The automorphisms must have order at most 2.
fixedinG:= Intersection( fixedinG );
stabs:= [];
for i in [ 1 .. 3 ] do
stabs[i]:= Stabilizer( AutomorphismsOfTable( tblsG2[i] ),
OnTuples( tfust2[i]{ fixedinG }, perms[i]^-1 ), OnTuples );
od;
elms:= List( stabs, H -> Filtered( H, x -> Order( x ) <= 2 ) );
Info( InfoCharacterTable, 1,
Product( List( elms, Length ) ),
" triple(s) of automorphisms of order <= 2" );
# Two classes of $G$ that are not conjugate in any $G.2_i$
# are not conjugate in $G.2^2$.
# (By the compatibility, we need to test nonconjugacy only in $G.2_1$.)
elms[1]:= Filtered( elms[1],
x -> ForAll( tfust2[1]{ fixedinG },
p -> p^( x^perms[1] ) = p ) );
Info( InfoCharacterTable, 1,
Product( List( elms, Length ) ),
" triple(s) of automorphisms respecting inner classes" );
# The automorphisms must act compatibly on `tblG', and
# they must result in the same number of classes for $G.2^2$.
# (Note that the class number corresponds to the number of cycles.)
domains:= List( tblsG2, t -> [ 1 .. NrConjugacyClasses( t ) ] );
triples:= [];
for elm in elms[1] do
comp:= CompositionMaps( InverseMap(
OrbitsPerms( [ elm^perms[1] ], domains[1] ) ), tfust2[1] );
nccl:= 2 * NrConjugacyClasses( tblsG2[1] )
- 3 * NrMovedPointsPerm( elm ) / 2;
filt2:= Filtered( elms[2], x -> comp = CompositionMaps(
InverseMap( OrbitsPerms( [ x^perms[2] ], domains[2] ) ),
tfust2[2] )
and nccl = 2 * NrConjugacyClasses( tblsG2[2] )
- 3 * NrMovedPointsPerm( x ) / 2 );
filt3:= Filtered( elms[3], x -> comp = CompositionMaps(
InverseMap( OrbitsPerms( [ x^perms[3] ], domains[3] ) ),
tfust2[3] )
and nccl = 2 * NrConjugacyClasses( tblsG2[3] )
- 3 * NrMovedPointsPerm( x ) / 2 );
Append( triples, Cartesian( [ elm ], filt2, filt3 ) );
od;
Info( InfoCharacterTable, 1,
Length( triples ),
" triple(s) of automorphisms acting compatibly" );
# Return the result.
return triples;
end );
#############################################################################
##
#F PossibleCharacterTablesOfTypeGV4( <tblG>, <tblsG2>, <acts>, <identifier>
#F [, <tblGfustblsG2>] )
#F PossibleCharacterTablesOfTypeGV4( <modtblG>, <modtblsG2>, <ordtblGV4>
#F [, <ordtblsG2fusordtblG4>] )
##
InstallGlobalFunction( PossibleCharacterTablesOfTypeGV4,
function( arg )
local tblG, tblsG2, ordtblGV4, GfusG2, acts, identifier, char, tblGV4,
G2fusGV4, classes, cosets, G2fusGV4outer, i, k, tblfusordtbl, rest,
defectzero, intrest, G2fusGV4inner, ncclinner, tblrec,
subclasses, orders, suborders, map, powermap, p, pow, irr, ind,
indirr, triv, done, bad, num2, ext, numinv, poss1, poss2, chi,
intmat1, intmat2, todo, minus, nexttodo, poss, j, modrest;
# Get and check the arguments.
if Length( arg ) = 3 and
IsBrauerTable( arg[1] ) and IsList( arg[2] )
and IsOrdinaryTable( arg[3] ) then
tblG := arg[1];
tblsG2 := arg[2];
ordtblGV4 := arg[3];
GfusG2 := List( tblsG2, t -> GetFusionMap( tblG, t ) );
elif Length( arg ) = 4 and
IsBrauerTable( arg[1] ) and IsList( arg[2] )
and IsOrdinaryTable( arg[3] ) and IsList( arg[4] ) then
tblG := arg[1];
tblsG2 := arg[2];
ordtblGV4 := arg[3];
GfusG2 := List( tblsG2, t -> GetFusionMap( tblG, t ) );
G2fusGV4 := arg[4];
elif Length( arg ) = 4 and
IsOrdinaryTable( arg[1] ) and IsList( arg[2] ) and IsList( arg[3] )
and IsString( arg[4] ) then
tblG := arg[1];
tblsG2 := arg[2];
acts := arg[3];
identifier := arg[4];
GfusG2 := List( tblsG2, t -> GetFusionMap( tblG, t ) );
elif Length( arg ) = 5 and
IsCharacterTable( arg[1] ) and IsList( arg[2] ) and IsList( arg[3] )
and IsString( arg[4] ) and IsList( arg[5] ) then
tblG := arg[1];
tblsG2 := arg[2];
acts := arg[3];
identifier := arg[4];
GfusG2 := arg[5];
else
Error( "usage: PossibleCharacterTablesOfTypeGV4( <tlbG>, <tblsG2>, ",
"<acts>, <identifier>[, <fusions>] ) or\n",
"PossibleCharacterTablesOfTypeGV4( <modtblG>, <modtblsG2>, ",
"<ordtblGV4>[, <fusions>] )" );
fi;
if fail in GfusG2 then
Error( "the class fusions <tblG> -> <tblsG2> must be stored" );
fi;
# Fetch the underlying characteristic.
char:= UnderlyingCharacteristic( tblG );
if 0 < char then
# We assume that the ordinary table of `tblGV4' (given as an argument)
# has the same ordering of classes as is guaranteed for the
# table to be constructed.
tblGV4:= CharacterTableRegular( ordtblGV4, char );
if not IsBound( G2fusGV4 ) then
# Fetch the three fusions if they were not entered.
G2fusGV4:= List( tblsG2, t -> GetFusionMap( t, tblGV4 ) );
if fail in G2fusGV4 then
Error( "fusions <tblsG2> -> <tblGV4> must be stored" );
fi;
else
# Transfer the given fusions to the Brauer tables.
G2fusGV4:= List( [ 1 .. 3 ],
i -> CompositionMaps(
InverseMap( GetFusionMap( tblGV4, ordtblGV4 ) ),
CompositionMaps( G2fusGV4[i],
GetFusionMap( tblsG2[i],
OrdinaryCharacterTable( tblsG2[i] ) ) ) ) );
fi;
acts:= List( G2fusGV4,
map -> Product( List( Filtered( InverseMap( map ), IsList ),
pair -> ( pair[1], pair[2] ) ), () ) );
classes:= ShallowCopy( SizesConjugacyClasses( tblGV4 ) );
cosets:= Intersection( G2fusGV4 );
cosets:= List( G2fusGV4, map -> Difference( map, cosets ) );
G2fusGV4outer:= List( G2fusGV4, ShallowCopy );
for i in [ 1 .. 3 ] do
for k in GfusG2[i] do
Unbind( G2fusGV4outer[i][k] );
od;
od;
# We will use that defect zero characters must occur.
tblfusordtbl:= GetFusionMap( tblGV4, ordtblGV4 );
rest:= List( Irr( ordtblGV4 ), x -> x{ tblfusordtbl } );
defectzero:= Filtered( rest, x -> Size( tblGV4 ) / x[1] mod char <> 0 );
intrest:= IntegralizedMat( rest );
else
if not ( Length( acts ) = 3 and ForAll( acts, IsPerm ) ) then
Error( "<acts> must contain three permutations" );
fi;
# Construct the three fusions into $G.2^2$, via the three embeddings.
# The classes of $G$ come first in each map; note that we must choose
# the classes of $G$ compatibly in all three maps.
G2fusGV4inner:= [];
G2fusGV4inner[1]:= InverseMap( Set( Orbits( Group( acts[1] ),
Set( GfusG2[1] ) ) ) );
G2fusGV4inner[2]:= CompositionMaps( G2fusGV4inner[1],
CompositionMaps( GfusG2[1], InverseMap( GfusG2[2] ) ) );
G2fusGV4inner[3]:= CompositionMaps( G2fusGV4inner[1],
CompositionMaps( GfusG2[1], InverseMap( GfusG2[3] ) ) );
ncclinner:= Maximum( G2fusGV4inner[1] );
G2fusGV4outer:= [];
G2fusGV4outer[1]:= InverseMap( Set( Orbits( Group( acts[1] ),
Difference( [ 1 .. NrConjugacyClasses( tblsG2[1] ) ],
Set( GfusG2[1] ) ) ) ) ) + ncclinner;
G2fusGV4outer[2]:= InverseMap( Set( Orbits( Group( acts[2] ),
Difference( [ 1 .. NrConjugacyClasses( tblsG2[2] ) ],
Set( GfusG2[2] ) ) ) ) ) + Maximum( G2fusGV4outer[1] );
G2fusGV4outer[3]:= InverseMap( Set( Orbits( Group( acts[3] ),
Difference( [ 1 .. NrConjugacyClasses( tblsG2[3] ) ],
Set( GfusG2[3] ) ) ) ) ) + Maximum( G2fusGV4outer[2] );
cosets:= List( G2fusGV4outer, Set );
# Compute class lengths, centralizer orders, and element orders.
G2fusGV4:= G2fusGV4inner + G2fusGV4outer;
classes:= ListWithIdenticalEntries( Maximum( G2fusGV4[3] ), 0 );
subclasses:= SizesConjugacyClasses( tblsG2[1] );
orders:= [];
suborders:= OrdersClassRepresentatives( tblsG2[1] );
for i in [ 1 .. Length( G2fusGV4inner[1] ) ] do
if IsBound( G2fusGV4inner[1][i] ) then
classes[ G2fusGV4inner[1][i] ]:= classes[ G2fusGV4inner[1][i] ]
+ subclasses[i];
orders[ G2fusGV4inner[1][i] ]:= suborders[i];
fi;
od;
for k in [ 1 .. 3 ] do
subclasses:= SizesConjugacyClasses( tblsG2[k] );
suborders:= OrdersClassRepresentatives( tblsG2[k] );
map:= G2fusGV4outer[k];
for i in [ 1 .. Length( map ) ] do
if IsBound( map[i] ) then
classes[ map[i] ]:= classes[ map[i] ] + subclasses[i];
orders[ map[i] ]:= suborders[i];
fi;
od;
od;
# Initialize the record for the character table `tblGV4'.
tblrec:= rec( UnderlyingCharacteristic := 0,
Identifier := identifier,
Size := 4 * Size( tblG ),
SizesConjugacyClasses := Immutable( classes ),
OrdersClassRepresentatives := orders );
tblrec.SizesCentralizers:= List( classes, x -> tblrec.Size / x );
# Convert the record to a table object.
tblGV4:= ConvertToCharacterTableNC( ShallowCopy( tblrec ) );
# Put the power maps together.
powermap:= ComputedPowerMaps( tblGV4 );
for p in PrimeDivisors( Size( tblGV4 ) ) do
pow:= InitPowerMap( tblGV4, p );
for k in [ 1 .. 3 ] do
TransferDiagram( PowerMap( tblsG2[k], p ), G2fusGV4[k], pow );
od;
powermap[p]:= pow;
Assert( 1, ForAll( pow, IsInt ),
Concatenation( Ordinal( p ),
" power map not uniquely determined" ) );
od;
tblrec.ComputedPowerMaps:= ComputedPowerMaps( tblGV4 );
fi;
# Compute the irreducibles, starting from the irreducibles of $G$.
# First we compute the known extensions of the trivial character,
# then add the characters which are induced from some table in `tblsG2',
# then try to determine the extensions of the remaining characters.
irr:= List( Irr( tblG ), ValuesOfClassFunction );
ind:= List( [ 1 .. 3 ],
i -> InducedClassFunctionsByFusionMap( tblG, tblsG2[i], irr,
GfusG2[i] ) );
indirr:= List( [ 1 .. NrConjugacyClasses( tblG ) ],
k -> List( [ 1 .. 3 ],
i -> ind[i][k] in Irr( tblsG2[i] ) ) );
irr:= [];
triv:= Position( Irr( tblG ), TrivialCharacter( tblG ) );
if char = 2 then
irr[ triv ]:= [ 0 * classes + 1 ];
else
irr[ triv ]:= List( [ 1 .. 4 ], i -> 0 * classes + 1 );
irr[ triv ][3]{ cosets[1] }:= 0 * cosets[1] - 1;
irr[ triv ][4]{ cosets[1] }:= 0 * cosets[1] - 1;
irr[ triv ][2]{ cosets[2] }:= 0 * cosets[2] - 1;
irr[ triv ][4]{ cosets[2] }:= 0 * cosets[2] - 1;
irr[ triv ][2]{ cosets[3] }:= 0 * cosets[3] - 1;
irr[ triv ][3]{ cosets[3] }:= 0 * cosets[3] - 1;
fi;
done:= [ triv ];
bad:= [];
for i in [ 1 .. NrConjugacyClasses( tblG ) ] do
if not i in done then
num2:= Number( indirr[i], x -> x = false );
if num2 = 2 then
# This cannot happen, so the actions must be wrong.
Info( InfoCharacterTable, 1,
"PossibleCharacterTablesOfTypeGV4: contradiction, ",
"imposs. inertia subgroup" );
return [];
elif num2 = 0 then
# The character has inertia subgroup $G$.
irr[i]:= Induced( tblsG2[1], tblGV4, [ ind[1][i] ], G2fusGV4[1] );
AddSet( done, i );
AddSet( done, Position( ind[1], ind[1][i], i ) );
AddSet( done, Position( ind[2], ind[2][i], i ) );
AddSet( done, Position( ind[3], ind[3][i], i ) );
elif num2 = 1 then
# The character has inertia subgroup one of the $G.2_k$.
k:= Position( indirr[i], false );
ext:= Filtered( Irr( tblsG2[k] ),
x -> x{ GfusG2[k] } = Irr( tblG )[i] );
irr[i]:= Induced( tblsG2[k], tblGV4, ext, G2fusGV4[k] );
k:= ( ( k+1 ) mod 3 ) + 1;
AddSet( done, i );
AddSet( done, Position( ind[k], ind[k][i], i ) );
else
# The character has inertia subgroup $G.2^2$.
ext:= List( [ 1 .. 3 ], j -> Filtered( Irr( tblsG2[j] ),
x -> x{ GfusG2[j] } = Irr( tblG )[i] ) );
numinv:= Number( [ 1 .. 3 ],
x -> Permuted( ext[x][1], acts[x] ) = ext[x][1] );
ext:= ext[1];
if numinv in [ 1, 2 ] then
Info( InfoCharacterTable, 1,
"PossibleCharacterTablesOfTypeGV4: contradiction, ",
"impossible inertia subgroup" );
return [];
elif Permuted( ext[1], acts[1] ) <> ext[1] then
# The character induces from any of the $G.2_i$.
irr[i]:= Induced( tblsG2[1], tblGV4, ext{[1]}, G2fusGV4[1] );
AddSet( done, i );
else
# In characteristic $2$, we get a unique extension.
# Otherwise the character extends $4$-fold,
# and we have two possibilities for combining the different
# extensions to the tables in `tblsG2'.
ext:= List( ext, chi -> CompositionMaps( chi,
InverseMap( G2fusGV4[1] ) ) );
if char = 2 then
irr[i]:= ext;
AddSet( done, i );
else
poss1:= [ ShallowCopy( ext[1] ),
ShallowCopy( ext[1] ),
ShallowCopy( ext[2] ),
ShallowCopy( ext[2] ) ];
ext:= Filtered( Irr( tblsG2[2] ),
x -> x{ GfusG2[2] } = Irr( tblG )[i] );
for k in [ 1 .. Length( G2fusGV4outer[2] ) ] do
if IsBound( G2fusGV4outer[2][k] ) then
poss1{ [ 1 .. 4 ] }[ G2fusGV4outer[2][k] ]:=
ext[1][k] * [ 1, -1, 1, -1 ];
fi;
od;
ext:= Filtered( Irr( tblsG2[3] ),
x -> x{ GfusG2[3] } = Irr( tblG )[i] );
for k in [ 1 .. Length( G2fusGV4outer[3] ) ] do
if IsBound( G2fusGV4outer[3][k] ) then
poss1{ [ 1 .. 4 ] }[ G2fusGV4outer[3][k] ]:=
ext[1][k] * [ 1, -1, -1, 1 ];
fi;
od;
poss2:= List( poss1, ShallowCopy );
for chi in poss2 do
chi{ cosets[3] }:= - chi{ cosets[3] };
od;
if 0 < char and Size( tblGV4 ) / ext[1][1] mod char <> 0 then
if ForAll( poss1, x -> x in defectzero ) then
irr[i]:= poss1;
elif ForAll( poss2, x -> x in defectzero ) then
irr[i]:= poss2;
else
Error( "inconsistency involving defect zero characters" );
fi;
AddSet( done, i );
elif 0 < char then
# Check whether the possibilities are in the Z-span of the
# restricted ordinary characters.
intmat1:= IntegralizedMat( [ poss1[1] ],
intrest.inforec ).mat[1];
intmat2:= IntegralizedMat( [ poss2[1] ],
intrest.inforec ).mat[1];
if intmat1 = fail or
SolutionIntMat( intrest.mat, intmat1 ) = fail then
if intmat2 = fail or
SolutionIntMat( intrest.mat, intmat2 ) = fail then
# No combination of Brauer characters fits.
return [];
fi;
irr[i]:= poss2;
AddSet( done, i );
elif intmat2 = fail or
SolutionIntMat( intrest.mat, intmat2 ) = fail then
irr[i]:= poss1;
AddSet( done, i );
else
irr[i]:= [ poss1, poss2 ];
fi;
else
irr[i]:= [ poss1, poss2 ];
fi;
fi;
fi;
fi;
fi;
od;
# Deal with the extension case.
todo:= Difference( [ 1 .. NrConjugacyClasses( tblG ) ], done );
if char = 0 then
# For each set of four extensions of one character,
# check the scalar products with the characters $\chi^{2-}$,
# for all known irreducible (nonlinear) characters $\chi$.
pow:= ComputedPowerMaps( tblGV4 )[2];
minus:= Set( List( Union( Filtered( irr,
x -> x[1] <> 1 and
NestingDepthA( x ) = 2 ) ),
chi -> MinusCharacter( chi, pow, 2 ) ) );
nexttodo:= todo;
repeat
todo:= ShallowCopy( nexttodo );
for i in todo do
# Try to exclude one of the two possibilities via scalar products.
poss1:= NonnegIntScalarProducts( tblGV4, minus, irr[i][1][1] );
poss2:= NonnegIntScalarProducts( tblGV4, minus, irr[i][2][1] );
if not poss1 and not poss2 then
# Something must be wrong, for example the given actions.
Info( InfoCharacterTable, 1,
"PossibleCharacterTablesOfTypeGV4: contradiction, ",
"incompat. scalar products" );
return [];
elif poss1 and not poss2 then
irr[i]:= irr[i][1];
UniteSet( minus,
Set( List( irr[i], chi -> MinusCharacter( chi, pow, 2 ) ) ) );
RemoveSet( nexttodo, i );
elif poss2 and not poss1 then
irr[i]:= irr[i][2];
UniteSet( minus,
Set( List( irr[i], chi -> MinusCharacter( chi, pow, 2 ) ) ) );
RemoveSet( nexttodo, i );
fi;
od;
until todo = nexttodo;
# Form all combinations of extensions that are still possible.
poss:= [ irr ];
for i in todo do
poss:= Concatenation( [ List( poss, ShallowCopy ),
List( poss, ShallowCopy ) ] );
for j in [ 1 .. Length( poss ) / 2 ] do
poss[j][i]:= irr[i][1];
od;
for j in [ Length( poss ) / 2 + 1 .. Length( poss ) ] do
poss[j][i]:= irr[i][2];
od;
od;
for i in [ 1 .. Length( poss ) ] do
# Check that the irreducibles are closed under multiplication
# with linear characters,
# and that the power maps are admissible.
# Note that `PossiblePowerMaps' is not sufficient here,
# we check whether all symmetrizations decompose.
# An example where this excludes a candidate table is
# `2.U4(3).(2^2)_{133}'.
# Note that for large primes, constructing the symmetrizations
# is not feasible.
# An example where this happens is the table of `S4(9).2^2',
# the group order is divisible by 41.
tblGV4:= ConvertToCharacterTableNC( ShallowCopy( tblrec ) );
SetIrr( tblGV4, List( Concatenation( Compacted( poss[i] ) ),
chi -> Character( tblGV4, chi ) ) );
if ForAll( Irr( tblGV4 ), x -> ForAll( LinearCharacters( tblGV4 ),
y -> y * x in Irr( tblGV4 ) ) )
and ForAll( PrimeDivisors( Size( tblGV4 ) ),
p -> p > 20 or
ForAll( Symmetrizations( tblGV4, Irr( tblGV4 ), p ),
x -> NonnegIntScalarProducts( tblGV4,
Irr( tblGV4 ), x ) ) ) then
SetInfoText( tblGV4,
"constructed using `PossibleCharacterTablesOfTypeGV4'" );
AutomorphismsOfTable( tblGV4 );
poss[i]:= rec( table:= tblGV4, G2fusGV4:= G2fusGV4 );
else
Unbind( poss[i] );
fi;
od;
poss:= Compacted( poss );
else
# `char'-modular case:
# Form all combinations.
#T improve: consider blockwise, and perhaps for increasing degree
poss:= [ irr ];
for i in todo do
poss:= Concatenation( [ List( poss, ShallowCopy ),
List( poss, ShallowCopy ) ] );
for j in [ 1 .. Length( poss ) / 2 ] do
poss[j][i]:= poss[j][i][1];
od;
for j in [ Length( poss ) / 2 + 1 .. Length( poss ) ] do
poss[j][i]:= poss[j][i][2];
od;
od;
# Check each combination.
for i in [ 1 .. Length( poss ) ] do
# Test the decomposability of ordinary irreducibles.
poss[i]:= Concatenation( Compacted( poss[i] ) );
if fail in Decomposition( poss[i], rest, "nonnegative" ) then
Unbind( poss[i] );
else
# Test the decomposability of the restrictions
# to the subgroups of index two.
for j in [ 1 .. 3 ] do
modrest:= List( poss[i], x -> x{ G2fusGV4[j] } );
if fail in Decomposition( Irr( tblsG2[j] ), modrest,
"nonnegative" ) then
Unbind( poss[i] );
break;
fi;
od;
fi;
od;
poss:= Compacted( poss );
for i in [ 1 .. Length( poss ) ] do
tblGV4:= CharacterTableRegular( ordtblGV4, char );
SetIrr( tblGV4, List( poss[i],
chi -> Character( tblGV4, chi ) ) );
SetInfoText( tblGV4,
"constructed using `PossibleCharacterTablesOfTypeGV4'" );
AutomorphismsOfTable( tblGV4 );
poss[i]:= rec( table:= tblGV4, G2fusGV4:= G2fusGV4 );
od;
fi;
return poss;
end );
#############################################################################
##
#F PossibleActionsForTypeGA( <tblG>, <tblGA> )
##
InstallGlobalFunction( PossibleActionsForTypeGA,
function( tblG, tblGA )
local tfustA, A, elms, i, newelms;
# Check that the function is applicable.
tfustA:= GetFusionMap( tblG, tblGA );
if tfustA = fail then
Error( "class fusion <tblG> -> <tblGA> must be stored on <tblG>" );
fi;
# The automorphism must have order dividing `A'.
A:= Size( tblGA ) / Size( tblG );
elms:= Filtered( Elements( AutomorphismsOfTable( tblG ) ),
#T better avoid computing all elements
x -> A mod Order( x ) = 0 );
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) of order dividing ", A );
if Length( elms ) <= 1 then
return elms;
fi;
# The automorphism respects the fusion of classes of `tblG' into `tblGA'.
for i in InverseMap( tfustA ) do
if IsList( i ) then
newelms:= Filtered( elms, x -> OnSets( i, x ) = i and
OnPoints( i[1], x ) <> i[1] );
else
newelms:= Filtered( elms, x -> OnPoints( i, x ) = i );
fi;
if newelms <> elms then
elms:= newelms;
Info( InfoCharacterTable, 1,
Length( elms ), " automorphism(s) acting on ", i );
if Length( elms ) <= 1 then
return elms;
fi;
fi;
od;
# Return the result.
return elms;
end );
#############################################################################
##
#F ConstructMGAInfo( <tblmGa>, <tblmG>, <tblGa> )
##
InstallGlobalFunction( ConstructMGAInfo, function( tblmGa, tblmG, tblGa )
local factfus, subfus, kernel, nccl, irr, plan, chi, rest, nonfaith,
proj, zero, faithful, entry, sum, i, perm;
factfus:= GetFusionMap( tblmGa, tblGa );
subfus:= GetFusionMap( tblmG, tblmGa );
if factfus = fail or subfus = fail then
Error( "fusions <tblmG> -> <tblmGa> -> <tblGa> must be stored" );
fi;
kernel:= ClassPositionsOfKernel( factfus );
nccl:= NrConjugacyClasses( tblmG );
irr:= Irr( tblmG );
plan:= [];
for chi in Irr( tblmGa ) do
if not IsSubset( ClassPositionsOfKernel( chi ), kernel ) then
rest:= chi{ subfus };
Add( plan, Filtered( [ 1 .. nccl ],
i -> ScalarProduct( tblmG, rest, irr[i] ) <> 0 ) );
fi;
od;
nonfaith:= List( Irr( tblGa ), chi -> chi{ factfus } );
proj:= ProjectionMap( subfus );
zero:= [ 1 .. NrConjugacyClasses( tblmGa ) ] * 0;
faithful:= [];
for entry in plan do
# Note that `proj' need not be dense.
sum:= Sum( irr{ entry } );
chi:= ShallowCopy( zero );
for i in [ 1 .. Length( chi ) ] do
if IsBound( proj[i] ) then
chi[i]:= sum[ proj[i] ];
fi;
od;
Add( faithful, chi );
od;
perm:= Sortex( Concatenation( nonfaith, faithful ) ) /
Sortex( ShallowCopy( Irr( tblmGa ) ) );
return [ "ConstructMGA",
Identifier( tblmG ), Identifier( tblGa ), plan, perm ];
end );
#############################################################################
##
#F ConstructProj( <tbl>, <irrinfo> )
#F ConstructProjInfo( <tbl>, <kernel> )
##
InstallGlobalFunction( ConstructProj, function( tbl, irrinfo )
local i, j, factor, fus, mult, irreds, linear, omegasquare, I,
d, name, factfus, proj, adjust, Adjust,
ext, lin, chi, faith, nccl, partner, divs, prox, foll,
vals;
nccl:= Length( tbl.SizesCentralizers );
factor:= CharacterTableFromLibrary( irrinfo[1][1] );
fus:= First( tbl.ComputedClassFusions,
fus -> fus.name = irrinfo[1][1] ).map;
mult:= tbl.SizesCentralizers[1] / Size( factor );
irreds:= List( Irr( factor ), x -> ValuesOfClassFunction( x ){ fus } );
linear:= Filtered( irreds, x -> x[1] = 1 );
linear:= Filtered( linear, x -> ForAny( x, y -> y <> 1 ) );
# some roots of unity
omegasquare:= E(3)^2;
I:= E(4);
# Loop over the divisors of `mult' (a divisor of 12).
# Note the succession for `mult = 12'!
if mult <> 12 then
divs:= Difference( DivisorsInt( mult ), [ 1 ] );
else
divs:= [ 2, 4, 3, 6, 12 ];
fi;
for d in divs do
# Construct the faithful irreducibles for an extension by `d'.
# For that, we split and adjust the portion of characters (stored
# on the small table `factor') as if we would create this extension,
# and then we blow up these characters to the whole table.
name:= irrinfo[d][1];
partner:= irrinfo[d][2];
proj:= First( ProjectivesInfo( factor ), x -> x.name = name );
faith:= List( proj.chars, y -> y{ fus } );
if name = tbl.Identifier then
factfus:= [ 1 .. Length( tbl.SizesCentralizers ) ];
else
factfus:= First( tbl.ComputedClassFusions, x -> x.name = name ).map;
fi;
adjust:= First( tbl.ComputedClassFusions,
r -> r.name = Identifier( factor ) ).map;
proj:= ProjectionMap( CompositionMaps( adjust,
InverseMap( factfus ) ) );
Add( proj, Length( factfus ) + 1 ); # for termination of loop
adjust:= [];
for i in [ 1 .. Length( proj ) - 1 ] do
for j in [ proj[i] .. proj[i+1]-1 ] do
adjust[ j ]:= proj[i];
od;
od;
# Now we have to multiply the values on certain classes `j' with
# roots of unity, depending on the value of `d':
#T Note that we do not have the factor fusion from d.G to G available,
#T since the only tables we have are those of mult.G and G,
#T together with the projective characters for the various intermediate
#T tables!
#T -> wait: in the sit. m.G -->> d.G -->> G,
#T we know the fusions m.G -->> d.G and m.G -->> G and thus can
#T compute d.G -->> G as a composition!
Adjust:= [];
for i in [ 1 .. d-1 ] do
Adjust[i]:= Filtered( [ 1 .. Length( factfus ) ],
x -> adjust[ factfus[x] ] = factfus[x] - i );
od;
#T this means to adjust also in many zero columns;
#T if d = 6 and a class has only 2 or 3 preimages, the second preimage class
#T need not be adjusted for the faithful characters ...
# d = 2: classes in `Adjust[1]' multiply with `-1'
# d = 3: classes in `Adjust[x]' multiply
# with `E(3)^x' for the proxy cohort,
# with `E(3)^(2*x)' for the follower cohort
# d = 4: classes in `Adjust[x]' multiply
# with `E(4)^x' for the proxy cohort,
# with `(-E(4))^x' for the follower cohort,
# d = 6: classes in `Adjust[x]' multiply with `(-E(3))^x'
# d = 12: classes in `Adjust[x]' multiply with `(E(12)^7)^x'
#
# (*Note* that follower cohorts of classes never occur in projective
# ATLAS tables ... )
# Determine proxy classes and follower classes:
if Length( linear ) in [ 2, 5 ] then # out in [ 3, 6 ]
prox:= [];
foll:= [];
chi:= irreds[ Length( linear ) ];
--> --------------------
--> maximum size reached
--> --------------------
[ zur Elbe Produktseite wechseln0.53Quellennavigators
Analyse erneut starten
]
|