|
#############################################################################
##
#W ctadmin.g GAP character table library Thomas Breuer
#W Ute Schiffer
##
## This file contains the data of the {\GAP} character table library that is
## not automatically produced from the library files.
##
#############################################################################
##
TBLNAME:= Concatenation( List( PKGNAME,
x -> Concatenation( x, "ctbllib/data/;" ) ) );
#############################################################################
##
#F Immutable( <obj> )
#F MakeImmutable( <obj> )
#F MakeReadOnlyGlobal( <obj> )
#F TestPackageAvailability( ... )
#F IsPosInt( <n> )
#V TOM_TBL_INFO
#F ListWithIdenticalEntries( <len>, <entry> )
#F BindGlobal
#F ValueGlobal
##
## These are used in `ctprimar.tbl' but not available in {\GAP}~3.4.
##
if not IsBound( IsEmpty ) then
IsEmpty:= list -> ( list = [] );
fi;
if not IsBound( Immutable ) then
Immutable:= x -> x;
fi;
if not IsBound( MakeImmutable ) then
MakeImmutable:= Ignore;
fi;
if not IsBound( MakeReadOnlyGlobal ) then
MakeReadOnlyGlobal:= Ignore;
fi;
if not IsBound( TestPackageAvailability ) then
TestPackageAvailability:= function( arg ) return true; end;
fi;
if not IsBound( IsPackageMarkedForLoading ) then
IsPackageMarkedForLoading:= function( arg ) return true; end;
fi;
if not IsBound( IsPosInt ) then
IsPosInt:= ( n -> IsInt( n ) and 0 < n );
fi;
if not IsBound( TOM_TBL_INFO ) then
TOM_TBL_INFO:= [];
fi;
if not IsBound( ListWithIdenticalEntries ) then
ListWithIdenticalEntries:= function( len, entry )
return List( [ 1 .. len ], i -> entry );
end;
fi;
if not IsBound( DuplicateFreeList ) then
DuplicateFreeList:= function( list )
local l, i;
l:= [];
for i in list do
if not i in l then
Add( l, i );
fi;
od;
return l;
end;
fi;
if not IsBound( BindGlobal ) then
BindGlobal:= function( varname, value )
if varname = "LIBLIST" then
LIBLIST:= value;
elif varname = "TOM_TBL_INFO" then
TOM_TBL_INFO:= value;
else
Error( "BindGlobal is not fully available in GAP 3" );
fi;
end;
fi;
ConstructIndexTwoSubdirectProduct:= 0;
ConstructSubdirect:= 0;
ConstructPermuted:= 0;
ConstructAdjusted:= 0;
ConstructFactor:= 0;
ConstructWreathSymmetric:= 0;
if not IsBound( ValueGlobal ) then
ValueGlobal:= function( varname )
local constr, pos;
constr:= [ "ConstructMGA", ConstructMixed,
"ConstructMixed", ConstructMixed,
"ConstructProj", ConstructProj,
"ConstructDirectProduct", ConstructDirectProduct,
"ConstructSubdirect", ConstructSubdirect,
"ConstructIndexTwoSubdirectProduct",
ConstructIndexTwoSubdirectProduct,
"ConstructWreathSymmetric", ConstructWreathSymmetric,
"ConstructIsoclinic", ConstructIsoclinic,
"ConstructV4G", ConstructV4G,
"ConstructGS3", ConstructGS3,
"ConstructPermuted", ConstructPermuted,
"ConstructAdjusted", ConstructAdjusted,
"ConstructFactor", ConstructFactor,
"ConstructClifford", ConstructClifford ];
pos:= Position( constr, varname );
if pos <> false then
return constr[ pos+1 ];
else
Error( "ValueGlobal is not fully available in GAP 3" );
fi;
end;
fi;
#############################################################################
##
#V CharTableDoubleCoverAlternating
#V CharTableDoubleCoverSymmetric
##
## These are used in `data/ctgeneri.tbl' but are not available in {\GAP}~3.
##
CharTableDoubleCoverAlternating := rec();
CharTableDoubleCoverSymmetric := rec();
#############################################################################
##
#F Conductor( <obj> )
##
## This is used in `data/ctgeneri.tbl'.
##
Conductor:= NofCyc;
#############################################################################
##
#V GAP_4_SPECIALS
##
## list of pairs whose first entries are the `identifier' values
## of tables whose `construction' component would require {\GAP}~4 features,
## and the second entries are the corresponding functions that do the same
## in {\GAP}~3.
##
GAP_4_SPECIALS := [
[ "2.(2xF4(2)).2", function( tbl )
local pi, irr, i, outer1, outer2, chi, j, adjustch, adjustcl, z;
pi:= (2,3)(6,7)(10,11)(14,15)(18,19)(22,23)(28,29)(32,33)(40,41)(44,45)
(48,49)(58,59)(62,63)(66,67)(70,71)(74,75)(78,79)(82,83)(86,87)(90,91)
(96,97)(100,101)(110,111)(114,115)(118,119)(122,123)(126,127)(132,133)
(136,137)(140,141)(144,145)(150,151)(158,159)(162,163)(166,167)(170,
171)(174,175)(182,183)(186,187)(190,191)(196,197)(200,201)(204,205)
(208,209)(212,213)(228,229)(234,235)(246,247)(254,255)(258,259)(264,
265)(268,269)(272,273)(276,277)(280,281)(284,285)(288,289)(292,293)
(296,297)(300,301);
ConstructDirectProduct( tbl, [["2.F4(2).2"],["Cyclic",2]], pi, () );
Unbind( tbl.orders );
Unbind( tbl.fusions[ Length( tbl.fusions ) ] );
Unbind( tbl.fusions[ Length( tbl.fusions ) ] );
irr:= tbl.irreducibles;
for i in [ 1 .. Length( irr ) ] do
irr[i]:= ShallowCopy( irr[i] );
od;
outer1:= [215..302];
outer2:= [3,4,7,8,11,12,15,16,19,20,23,24,26,29,30,33,34,36,38,41,42,45,46,
49,50,52,54,56,59,60,63,64,67,68,71,72,75,76,79,80,83,84,87,88,91,92,94,97,
98,101,102,104,106,108,111,112,115,116,119,120,123,124,127,128,130,133,134,
137,138,141,142,145,146,148,151,152,154,156,159,160,163,164,167,168,171,172,
175,176,178,180,183,184,187,188,191,192,194,197,198,201,202,205,206,209,210,
213,214,216,218,220,222,224,226,229,230,232,235,236,238,240,242,244,247,248,
250,252,255,256,259,260,262,265,266,269,270,273,274,277,278,281,282,285,286,
289,290,293,294,297,298,301,302];
i:= E(4);
for chi in irr do
if chi[1] = chi[2] then
if chi[1] <> chi[2] or chi[1] <> chi[3] then
for j in outer1 do
chi[j]:= i * chi[j];
od;
fi;
else
for j in outer2 do
chi[j]:= i * chi[j];
od;
fi;
od;
adjustch:= [183,184,185,186,191,192,193,194,195,196,197,198,199,200,201,202,
209,210,211,212,217,218,219,220,223,224,225,226,237,238,239,240,265,266,267,
268,271,272,273,274,275,276,277,278,287,288,289,290,291,292,293,294,295,296,
297,298,299,300,301,302];
adjustcl:=[227,228,229,230,233,234,235,236,245,246,247,248,253,254,255,256,
257,258,259,260,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,
278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,
297,298,299,300,301,302];
z:= E(8);
for chi in irr{ adjustch{ [ 1, 3 .. 59 ] } } do
for j in adjustcl do
chi[j]:= z * chi[j];
od;
od;
z:= E(8)^3;
for chi in irr{ adjustch{ [ 2, 4 .. 60 ] } } do
for j in adjustcl do
chi[j]:= z * chi[j];
od;
od;
end ],
[ "C9Y3.3^5.U4(2)", function( tbl )
local e, e8, e2, e7, chi, i;
ConstructDirectProduct( tbl, [["Cyclic",3],["3.3^5.U4(2)"]] );
Unbind( tbl.orders );
Unbind( tbl.fusions[ Length( tbl.fusions ) ] );
Unbind( tbl.fusions[ Length( tbl.fusions ) ] );
for i in [ 1 .. Length( tbl.irreducibles ) ] do
tbl.irreducibles[i]:= ShallowCopy( tbl.irreducibles[i] );
od;
e:= E(9);
e8:= E(9)^8;
e2:= E(9)^2;
e7:= E(9)^7;
for chi in tbl.irreducibles do
if chi[2] = chi[1] * E(3) then
for i in [ 86 .. 170 ] do
chi[i]:= chi[i] * e8;
od;
for i in [ 171 .. 255 ] do
chi[i]:= chi[i] * e7;
od;
elif chi[2] = chi[1] * E(3)^2 then
for i in [ 86 .. 170 ] do
chi[i]:= chi[i] * e;
od;
for i in [ 171 .. 255 ] do
chi[i]:= chi[i] * e2;
od;
fi;
od;
end ],
[ "Isoclinic(3.U3(8)x3)", function( tbl )
local dp, aux;
dp:= CharTableDirectProduct( CharTable( "3.U3(8)" ),
CharTable( "Cyclic", 9 ) );
aux:= CharTableFactorGroup( dp, [ 1, 16, 22 ] );
tbl.centralizers:= aux.centralizers;
tbl.powermap:= aux.powermap;
tbl.irreducibles:= aux.irreducibles;
end ],
[ "Isoclinic(U3(8).3_3x3)", function( tbl )
local dp, aux;
dp:= CharTableDirectProduct( CharTable( "U3(8).3_3" ),
CharTable( "Cyclic", 9 ) );
aux:= CharTableNormalSubgroup( dp, Concatenation( [ 1, 4 .. 124 ],
[128,131,134,138,141,144,146,149,152,156,159,162,164,167,170,174,
177,180,182,185,188,192,195,198,200,203,206,210,213,216,218,221,
224,228,231,234,236,239,242,246,249,252] ) );
tbl.centralizers:= aux.centralizers;
tbl.powermap:= aux.powermap;
tbl.irreducibles:= aux.irreducibles;
end ],
];
#############################################################################
##
#F IrreducibleCharactersOfIsoclinicGroup( <irr>, <center>, <outer>, <xpos> )
##
IrreducibleCharactersOfIsoclinicGroup:= function( irr, center, outer, xpos )
local nonfaith, faith, irreds, root1, chi, values, root2;
# Adjust faithful characters in outer classes.
nonfaith:= [];
faith:= [];
irreds:= [];
root1:= E(4);
if Length( center ) = 1 then
# The central subgroup has order two.
for chi in irr do
values:= chi;
if values[ center[1] ] = values[1] then
Add( nonfaith, values );
else
values:= ShallowCopy( values );
values{ outer }:= root1 * values{ outer };
Add( faith, values );
fi;
Add( irreds, values );
od;
else
# The central subgroup has order four.
root2:= E(8);
for chi in irr do
values:= chi;
if ForAll( center, i -> values[i] = values[1] ) then
Add( nonfaith, values );
else
values:= ShallowCopy( values );
if ForAny( center, i -> values[i] = values[1] ) then
values{ outer }:= root1 * values{ outer };
elif values[ xpos ] / values[1] = root1 then
values{ outer }:= root2 * values{ outer };
else
# If B is the matrix for g in G, the matrix for gz in H
# depends on the character value of z^2 = x;
# we have to choose the same square root for the whole character,
# so the two possibilities differ just by the ordering of the two
# extensions which we get.
values{ outer }:= root2^-1 * values{ outer };
fi;
Add( faith, values );
fi;
Add( irreds, values );
od;
fi;
return rec( all:= irreds, nonfaith:= nonfaith, faith:= faith );
end;
#############################################################################
##
#F CharTableIsoclinic( <tbl> )
#F CharTableIsoclinic( <tbl>, <classes_of_normal_subgroup> )
#F CharTableIsoclinic( <tbl>, <nsg>, <center> )
##
## for table of groups $2.G.2$, the character table of the isoclinic group
## (see ATLAS, Chapter 6, Section 7)
##
CharTableIsoclinic;
CharTableIsoclinic := function( arg )
local i, # 'E(4)'
j, # loop variable
chi, # one character
orders,
class,
map,
tbl, # input table
linear, # linear characters of 'tbl'
isoclinic, # the isoclinic table, result
center, # nontrivial class(es) contained in the center
nsg, # index 2 subgroup
outer, # classes outside the index 2 subgroup
images,
factorfusion,
reg, # restriction to regular classes
half, kernel, xpos, irreds, invfusion, k, ypos, old;
# check the argument
if not ( Length( arg ) in [ 1 .. 3 ] and IsCharTable( arg[1] ) )
or ( Length( arg ) = 2 and not IsList( arg[2] ) ) then
Error( "usage: CharTableIsoclinic( tbl[, classes_of_nsg] )");
fi;
# get the ordinary table if necessary
if IsBound( arg[1].ordinary ) then
tbl:= arg[1].ordinary;
else
tbl:= arg[1];
fi;
if not IsBound( tbl.powermap ) then
tbl.powermap:= [];
fi;
# compute the isoclinic table of the ordinary table
# Get the classes of the normal subgroup of index 2.
if Length( arg ) = 1 then
nsg:= false;
center:= false;
elif Length( arg ) = 2 then
# The 2nd argument describes the normal subgroup of index 2
# or the centre.
if IsList( arg[2] ) and Sum( tbl.classes{ arg[2] } ) = tbl.size / 2 then
nsg:= arg[2];
center:= false;
else
nsg:= false;
center:= arg[2];
fi;
else
nsg:= arg[2];
center:= arg[3];
if IsInt( center ) then
center:= [ center ];
fi;
fi;
# Check `nsg'.
if nsg = false then
# Identify the unique normal subgroup of index 2.
half:= tbl.size / 2;
linear:= Filtered( tbl.irreducibles, x -> x[1] = 1 );
kernel:= Filtered( List( linear, KernelChar ),
ker -> Sum( tbl.classes{ ker } ) = half );
elif IsList( nsg ) and Sum( tbl.classes{ nsg } ) = tbl.size / 2 then
kernel:= [ nsg ];
else
Error( "normal subgroup described by <nsg> must have index 2" );
fi;
# Check `center'.
if center = false then
# Get the unique central subgroup of order 2 in the normal subgroup.
center:= Filtered( [ 1 .. Length( tbl.classes ) ],
i -> tbl.classes[i] = 1 and tbl.orders[i] = 2
and ForAny( kernel, n -> i in n ) );
if Length( center ) <> 1 then
Error( "central subgroup of order 2 not uniquely determined,\n",
"use CharacterTableIsoclinic( <tbl>, <classes>, <center> )" );
fi;
elif IsPosInt( center ) then
center:= [ center ];
else
center:= Difference( center, [ 1 ] );
fi;
# If there is more than one index 2 subgroup
# and if there is a unique central subgroup $Z$ of order 2 or 4
# then consider only those index 2 subgroups containing $Z$.
if 1 < Length( kernel ) then
kernel:= Filtered( kernel, ker -> IsSubset( ker, center ) );
fi;
if Length( kernel ) <> 1 then
Error( "normal subgroup of index 2 not uniquely determined,\n",
"use CharacterTableIsoclinic( <tbl>, <classes_of_nsg> )" );
fi;
nsg:= kernel[1];
if not IsSubset( nsg, center ) then
Error( "<center> must lie in <nsg>" );
elif ForAny( center, i -> tbl.classes[i] <> 1 ) then
Error( "<center> must be a list of positions of central classes" );
elif Length( center ) = 1 then
xpos:= center[1];
if tbl.orders[ xpos ] <> 2 then
Error( "<center> must list the classes of a central subgroup" );
fi;
elif Length( center ) = 3 and ForAny( center, i -> tbl.orders[i] = 4 ) then
xpos:= First( center, i -> tbl.orders[i] = 4 );
else
Error( "the central subgroup must have order 2 or 4" );
fi;
# classes outside the normal subgroup
outer:= Difference( [ 1 .. Length( tbl.classes ) ], nsg );
# Adjust faithful characters in outer classes.
irreds:= IrreducibleCharactersOfIsoclinicGroup( tbl.irreducibles, center,
outer, xpos );
# make the record of the isoclinic table
isoclinic:= rec(
identifier := Concatenation( "Isoclinic(",
tbl.identifier, ")" ),
size := tbl.size,
centralizers := Copy( tbl.centralizers ),
classes := Copy( tbl.classes ),
orders := Copy( tbl.orders ),
fusions := [],
fusionsource := [],
powermap := Copy( tbl.powermap ),
irreducibles := irreds.all,
operations := CharTableOps );
isoclinic.order:= isoclinic.size;
isoclinic.name:= isoclinic.identifier;
# get the fusion map onto the factor group modulo the center
factorfusion:= CollapsedMat( irreds.nonfaith, [] ).fusion;
invfusion:= InverseMap( factorfusion );
# adjust the power maps
for j in [ 1 .. Length( isoclinic.powermap ) ] do
if IsBound( isoclinic.powermap[j] ) then
map:= isoclinic.powermap[j];
# For $p \bmod |z| = 1$, the map remains unchanged,
# since $g^p = h$ implies $(gz)^p = hz^p = hz$ then.
# So we have to deal with the cases $p = 2$ and $p$ congruent
# to the other odd positive integers up to $|z| - 1$.
k:= j mod ( 2 * Length( center ) + 2 );
if j = 2 then
ypos:= xpos;
elif k <> 1 then
ypos:= Powmap( tbl.powermap, (k-1)/2, xpos );
fi;
if k <> 1 then
for class in outer do
old:= map[ class ];
images:= invfusion[ factorfusion[ old ] ];
if IsList( images ) then
if Length( center ) = 1 then
# The image is ``the other'' class.
images:= Difference( images, [ old ] );
else
# It can happen that the class powers to itself.
# Use the character values for the decision.
images:= Filtered( images,
x -> ForAll( irreds.faith,
chi -> chi[ old ] = 0 or
chi[x] / chi[ old ] = chi[ ypos ] / chi[1] ) );
fi;
map[ class ]:= images[1];
if j = 2 then
isoclinic.orders[ class ]:= 2 * tbl.orders[ images[1] ];
fi;
fi;
od;
fi;
fi;
od;
# if we want the isoclinic table of a Brauer table then
# transfer the normal subgroup information to the regular classes,
# and adjust the irreducibles
if tbl <> arg[1] then
reg:= CharTableRegular( isoclinic, arg[1].prime );
factorfusion:= GetFusionMap( reg, isoclinic );
reg.irreducibles:= Copy( arg[1].irreducibles );
center:= Position( factorfusion, center );
outer:= Filtered( [ 1 .. Length( reg.centralizers ) ],
x -> factorfusion[x] in outer );
for chi in Filtered( reg.irreducibles,
x -> x[ center ] <> x[1] ) do
for class in outer do
chi[ class ]:= i * chi[ class ];
od;
od;
isoclinic:= reg;
fi;
# adjust the table name
isoclinic.identifier:= Concatenation( "Isoclinic(",
arg[1].identifier, ")" );
# return the result
return isoclinic;
end;
#############################################################################
##
#V LIBTABLE
##
LIBTABLE:= rec(
TABLEFILENAME := "",
LOADSTATUS := rec(),
clmelab := [],
clmexsp := [] );
#############################################################################
##
#F GALOIS( <chars>, <list> )
#F TENSOR( <chars>, <list> )
##
## are global variables used to store the library tables in compressed form.
##
## The entry '[GALOIS,[<i>,<j>]]' in the 'irreducibles' or 'projectives'
## component of a library table means the <j>-th Galois conjugate of
## the <i>-th character.
##
## The entry '[TENSOR,[<i>,<j>]]' in the 'irreducibles' or 'projectives'
## component of a library table means the tensor product of the <i>-th
## and the <j>-th character.
##
#F EvalChars( <chars> )
##
## replaces all entries of the form '[<func>,<list>]' in the list <chars>
## by the result '<func>( <chars>, <list> )'.
##
GALOIS := function( chars, li )
return List( chars[ li[1] ], x -> GaloisCyc( x, li[2] ) );
end;
TENSOR := function( chars, list )
local i, chi, psi, result;
chi:= chars[ list[1] ];
psi:= chars[ list[2] ];
result:= [];
for i in [ 1 .. Length( chi ) ] do result[i]:= chi[i] * psi[i]; od;
return result;
end;
EvalChars := function( chars )
local i;
for i in [ 1 .. Length( chars ) ] do
if IsFunc( chars[i][1] ) then
chars[i]:= chars[i][1]( chars, chars[i][2] );
fi;
od;
end;
#############################################################################
##
#F MBT( <arg> )
##
## The library format of Brauer tables is a call to the function
## 'MBT', with the following arguments.
##
## 1. identifier of the table
## 2. field characteristic
## 3. text (list of lines)
## 4. block
## 5. defect
## 6. basic set
## 7. Brauer tree information
## 8. inverses of decomposition matrices restricted to basic sets
## 9. blocks of proper factor groups
## 10. list of generators for the group of table automorphisms
## 11. 2nd indicator (in characteristic 2 only)
## 12. (optional) record with additional components
##
MBT := function( arg )
local i, record;
record:= rec(
text := arg[ 3],
prime := arg[ 2],
block := arg[ 4],
defect := arg[ 5],
basicset := arg[ 6],
brauertree := arg[ 7],
decinv := arg[ 8],
factorblocks := arg[ 9],
automorphisms := arg[10],
indicator := arg[11]
);
for i in RecFields( record ) do
if record.(i) = 0 then
Unbind( record.(i) );
fi;
od;
if Length( arg ) = 12 then
for i in RecFields( arg[12] ) do
record.(i):= arg[12].(i);
od;
fi;
LIBTABLE.( LIBTABLE.TABLEFILENAME ).(
Concatenation( arg[1], "mod", String( arg[2] ) ) ):= record;
end;
#############################################################################
##
#F MOT( <arg> )
##
## The library format of ordinary character tables is a call to the function
## 'MOT', with the following arguments.
##
## 1. identifier of the table
## 2. text (list of lines)
## 3. list of centralizer orders
## 4. list of power maps
## 5. list of irreducibles
## 6. list of generators for the group of table automorphisms
## 7. (optional) construction of the table
##
## Each fusion is added by 'ALF', any other component of the table must be
## added individually via 'ARC( <identifier>, <compname>, <compval> )'.
##
## 'MOT' constructs a (preliminary) table record, and puts it into the
## component 'LIBTABLE.TABLEFILENAME' of 'LIBTABLE'.
## The 'fusionsource' and 'projections' are dealt with when the table is
## constructed by 'CharTableLibrary'.
## Admissible names are notified by 'ALN( <name>, <othernames> )'.
##
MOT := function( arg )
local record, i;
# Construct the table record.
record:= rec(
text := arg[2],
centralizers := arg[3],
powermap := arg[4],
fusions := [],
irreducibles := arg[5],
automorphisms := arg[6]
);
for i in RecFields( record ) do
if record.(i) = 0 then
Unbind( record.(i) );
fi;
od;
if IsBound( arg[7] ) then
record.construction:= arg[7];
fi;
# Store the table record.
LIBTABLE.( LIBTABLE.TABLEFILENAME ).( arg[1] ):= record;
#Print( "stored for ", arg[1], " in ", LIBTABLE.TABLEFILENAME, "\n" );
end;
#############################################################################
##
#F LowercaseString( <string> ) . . . string consisting of lower case letters
##
LowercaseString := function( str )
local alp, ALP, result, i, pos;
alp:= "abcdefghijklmnopqrstuvwxyz";
ALP:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
result:= "";
for i in str do
pos:= Position( ALP, i );
if pos = false then
Add( result, i );
else
Add( result, alp[ pos ] );
fi;
od;
return result;
end;
#############################################################################
##
#F NotifyCharTableName( <firstname>, <newnames> )
##
## notifies the new names in the list <newnames> for the library table with
## first name <firstname>, if there is no other table yet for that some of
## these names are admissible.
##
NotifyCharTableName := function( firstname, newnames )
local lower,
pos,
pos2,
name,
j;
if not ( IsString( firstname )
and IsList( newnames ) and ForAll( newnames, IsString ) ) then
Error( "<firstname> and entries in list <newnames> must be strings" );
fi;
if ForAny( [ 1 .. Length( firstname ) - 2 ],
x -> firstname{ [ x .. x+2 ] } = "mod" ) then
Error( "Brauer tables must not have explicitly given 'othernames'" );
fi;
pos:= Position( LIBLIST.firstnames, firstname );
if pos = false then
Error( "no GAP library table with first name '", firstname, "'" );
fi;
lower:= List( newnames, LowercaseString );
if ForAny( lower, x -> x in LIBLIST.allnames ) then
Error( "<newnames> must contain only new names" );
fi;
Append( LIBLIST.allnames, lower );
Append( LIBLIST.position, List( lower, x -> pos ) );
SortParallel( LIBLIST.allnames, LIBLIST.position );
end;
#############################################################################
##
#F NotifyCharTable( <firstname>, <filename>, <othernames> )
##
## notifies a new ordinary table to the library.
## This table has 'identifier' component <firstname>,
## it is contained in the file with name <filename>, and
## it is known to have also the names contained in the list <othernames>.
##
## 'NotifyCharTable' modifies the global variable 'LIBLIST' after having
## checked that there is no other table yet with admissible name equal to
## <firstname> or contained in <othernames>.
##
NotifyCharTable := function( firstname, filename, othernames )
local len, pos;
if not ( IsString( firstname ) and IsString( filename )
and IsList( othernames ) ) then
Error( "<firstname>, <filename> must be strings, ",
"<othernames> must be a list" );
fi;
if LowercaseString( firstname ) in LIBLIST.allnames then
Error( "'", firstname, "' is already a valid name" );
fi;
Add( LIBLIST.firstnames, firstname );
if not filename in LIBLIST.files then
Add( LIBLIST.files, filename );
fi;
len:= Length( LIBLIST.firstnames );
LIBLIST.filenames[ len ]:= Position( LIBLIST.files, filename );
LIBLIST.fusionsource[ len ]:= [];
NotifyCharTableName( firstname, [ firstname ] );
NotifyCharTableName( firstname, othernames );
# Allow natural names.
#T !!
end;
#############################################################################
##
#F LibInfoCharTable( <tblname> )
##
## is a record with components 'firstName' and 'fileName', the former being
## the 'identifier' component of the library table for that <tblname> is an
## admissible name, and the latter being the name of the file in that the
## table is stored;
## if no such table exists in the {\GAP} library then 'false' is returned.
##
## If <tblname> contains the substring "mod" it is regarded as name of a
## Brauer table, the first name is computed from that of the corresponding
## ordinary table (which must exist) also if the library does not contain
## the Brauer table.
##
LibInfoCharTable := function( tblname )
local i, ordinfo, obj, pos;
# Is 'tblname' the name of a Brauer table, i.e., has it the structure
# '<ordname>mod<prime>' ?
# If so, return '<firstordname>mod<prime>' where
# '<firstordname> = LibInfoCharTable( <ordname> ).firstName'.
tblname:= LowercaseString( tblname );
for i in [ 1 .. Length( tblname ) - 2 ] do
if tblname{ [ i .. i+2 ] } = "mod" then
ordinfo:= LibInfoCharTable( tblname{ [ 1 .. i-1 ] } );
if ordinfo <> false then
Append( ordinfo.firstName, tblname{ [ i .. Length( tblname ) ] } );
ordinfo.fileName[3]:= 'b';
fi;
return ordinfo;
fi;
od;
# The name might belong to an ordinary table.
pos:= PositionSorted( LIBLIST.allnames, tblname );
if Length( LIBLIST.allnames ) < pos or
LIBLIST.allnames[ pos ] <> tblname then
pos:= false;
fi;
if pos <> false then
pos:= LIBLIST.position[ pos ];
if pos <> false then
return rec( firstName := Copy( LIBLIST.firstnames[ pos ] ),
fileName := Copy( LIBLIST.files[
LIBLIST.filenames[ pos ] ] ) );
fi;
return false;
fi;
# The name might belong to a generic table.
if tblname in LIBLIST.GENERIC.allnames then
return rec( firstName := LIBLIST.GENERIC.firstnames[
Position( LIBLIST.GENERIC.allnames, tblname ) ],
fileName := "ctgeneri" );
fi;
return false;
end;
#############################################################################
##
#F FirstNameCharTable( <tblname> )
#F FileNameCharTable( <tblname> )
##
FirstNameCharTable := function( name )
name:= LibInfoCharTable( name );
if name <> false then
name:= name.firstName;
fi;
return name;
end;
FileNameCharTable := function( name )
name:= LibInfoCharTable( name );
if name <> false then
name:= name.fileName;
fi;
return name;
end;
#############################################################################
##
#F ALN( <name>, <names> ) . . . . . . . . . . . . . add library table names
##
ALN := NotifyCharTableName;
#############################################################################
##
#F ALF( <from>, <to>, <map> ) . . . . . . . . . . add library table fusions
#F ALF( <from>, <to>, <map>, <text> )
##
ALF := function( arg )
local pos;
if ALN <> Ignore then
# A file is read that does not belong to the official library.
# Check that the names are valid.
pos:= Position( LIBLIST.firstnames, arg[2] );
if not arg[1] in RecFields( LIBTABLE.( LIBTABLE.TABLEFILENAME ) ) then
Error( "source '", arg[1], "' is not stored in 'LIBTABLE.",
LIBTABLE.TABLEFILENAME, "'" );
elif pos = false then
Error( "destination '", arg[2], "' is not a valid first name" );
fi;
# Check whether there was already such a fusion.
if arg[1] in LIBLIST.fusionsource[ pos ] then
Error( "there is already a fusion from '",
arg[1], "' to '", arg[2], "'" );
fi;
# Store the fusion source.
Add( LIBLIST.fusionsource[ pos ], arg[1] );
fi;
if Length( arg ) = 4 then
Add( LIBTABLE.( LIBTABLE.TABLEFILENAME ).( arg[1] ).fusions,
rec( name:= arg[2], map:= arg[3],
text:= Concatenation( arg[4] ) ) );
else
Add( LIBTABLE.( LIBTABLE.TABLEFILENAME ).( arg[1] ).fusions,
rec( name:= arg[2], map:= arg[3] ) );
fi;
end;
#############################################################################
##
#F ACM( <spec>, <dim>, <val> ) . . . . . . . . . . . . . add Clifford matrix
##
## <spec> is one of "elab", "exsp".
## <dim> is the dimension of the Clifford matrix,
## <val> is the Clifford matrix itself.
##
ACM := function( spec, dim, val )
spec:= LIBTABLE.( Concatenation( "clm", spec ) );
if not IsBound( spec[ dim ] ) then
spec[ dim ]:= [];
fi;
Add( spec[ dim ], val );
end;
#############################################################################
##
#F ARC( <name>, <comp>, <val> ) . . . . . . . add component of library table
##
ARC := function( name, comp, val )
local r;
if comp = "CAS" then
for r in val do
if IsBound( r.text ) and not IsString( r.text ) then
r.text:= Concatenation( r.text );
fi;
od;
fi;
LIBTABLE.( LIBTABLE.TABLEFILENAME ).( name ).( comp ):= val;
end;
#############################################################################
##
#F ConstructMixed( <tbl>, <subname>, <factname>, <plan>, <perm> )
##
## <tbl> is the table of a group $m.G.a$,
## <subname> is the name of a subgroup $m.G$ which is a cyclic central
## extension of the (not necessarily simple) group $G$,
## <factname> is the name of the factor group $G.a$ of <tbl> where the
## outer automorphisms $a$ (a group of prime order) acts nontrivially on
## the central $m$.
## Then the faithful characters of <tbl> are induced characters of $m.G$.
##
## <plan> is a list of lists, each containing the numbers of characters of
## $m.G$ that form an orbit under the action of $a$
## (so the induction of characters is simulated).
## <perm> is the permutation that must be applied to the list of characters
## that is obtained on appending the faithful characters to the
## inflated characters of the factor group.
##
## Examples of tables where this is used to compress the library files are
## the tables of $3.F_{3+}.2$ (subgroup $3.F_{3+}$, factor group $F_{3+}.2$)
## and $6.Fi_{22}.2$ (subgroup $6.Fi_{22}$, factor group $2.Fi_{22}.2$).
##
ConstructMixed := function( tbl, sub, fact, plan, perm )
local factfus, # factor fusion from 'tbl' to 'fact'
subfus, # subgroup fusion from 'sub' to 'tbl'
proj, # projection map of 'subfus'
irreds, # list of irreducibles
zero, # list of zeros to be appended to the characters
irr, newirr, entry, sum, chi, i;
fact := CharTable( fact );
sub := CharTable( sub );
factfus := GetFusionMap( tbl, fact );
subfus := GetFusionMap( sub, tbl );
proj := ProjectionMap( subfus );
irreds := List( fact.irreducibles, x -> x{ factfus } );
zero := [ 1 .. Length( factfus ) ] * 0;
irr := sub.irreducibles;
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.irreducibles:= Permuted( irreds, perm );
end;
#############################################################################
##
#F ConstructProj( <tbl>, <irrinfo> )
##
## constructs irreducibles for projective tables from projectives of
## a factor group table.
##
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.centralizers );
factor:= CharTable( irrinfo[1][1] );
fus:= GetFusionMap( tbl, factor );
mult:= tbl.centralizers[1] / factor.centralizers[1];
irreds:= List( factor.irreducibles, x -> 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( factor.projectives, x -> x.name = name );
faith:= List( proj.chars, y -> y{ fus } );
proj:= Copy( proj.map );
if name = tbl.identifier then
factfus:= [ 1 .. Length( tbl.centralizers ) ];
else
factfus:= First( tbl.fusions, x -> x.name = name ).map;
fi;
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, dependent on the value of 'd'\:
Adjust:= [];
for i in [ 1 .. d-1 ] do
Adjust[i]:= Filtered( [ 1 .. Length( factfus ) ],
x -> adjust[ factfus[x] ] = factfus[x] - i );
od;
# 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 ) ];
for i in [ 1 .. nccl ] do
if chi[i] = omegasquare then
Add( foll, i );
else
Add( prox, i );
fi;
od;
elif Length( linear ) = 3 then # out = 4
prox:= [];
foll:= [];
chi:= irreds[2];
for i in [ 1 .. nccl ] do
if chi[i] = -I then Add( foll, i ); else Add( prox, i ); fi;
od;
else
prox:= [ 1 .. nccl ];
foll:= [];
fi;
if d = 2 then
# special case without Galois partners
for chi in faith do
for i in Adjust[1] do chi[i]:= - chi[i]; od;
Add( irreds, chi );
for lin in linear do
ext:= List( [ 1 .. nccl ], x -> lin[x] * chi[x] );
if not ext in irreds then Add( irreds, ext ); fi;
od;
od;
elif d = 12 then
# special case with three Galois partners and 'lin = []'
vals:= [ E(12)^7, - omegasquare, - I, E(3), E(12)^11, -1,
-E(12)^7, omegasquare, I, -E(3), -E(12)^11 ];
for j in [ 1 .. Length( faith ) ] do
chi:= faith[j];
for i in [ 1 .. 11 ] do
chi{ Adjust[i] }:= vals[i] * chi{ Adjust[i] };
od;
Add( irreds, chi );
for i in partner[j] do
Add( irreds, List( chi, x -> GaloisCyc( x, i ) ) );
od;
od;
else
if d = 3 then
Adjust{ [ 1, 2 ] }:= [ Union( Intersection( Adjust[1], prox ),
Intersection( Adjust[2], foll ) ),
Union( Intersection( Adjust[2], prox ),
Intersection( Adjust[1], foll ) ) ];
vals:= [ E(3), E(3)^2 ];
elif d = 4 then
Adjust{ [ 1, 3 ] }:= [ Union( Intersection( Adjust[1], prox ),
Intersection( Adjust[3], foll ) ),
Union( Intersection( Adjust[3], prox ),
Intersection( Adjust[1], foll ) ) ];
vals:= [ I, -1, -I ];
elif d = 6 then
vals:= [ -E(3), omegasquare, -1, E(3), - omegasquare ];
fi;
for j in [ 1 .. Length( faith ) ] do
chi:= faith[j];
for i in [ 1 .. d-1 ] do
chi{ Adjust[i] }:= vals[i] * chi{ Adjust[i] };
od;
Add( irreds, chi );
for lin in linear do
ext:= List( [ 1 .. nccl ], x -> lin[x] * chi[x] );
if not ext in irreds then Add( irreds, ext ); fi;
od;
chi:= List( chi, x -> GaloisCyc( x, partner[j] ) );
Add( irreds, chi );
for lin in linear do
ext:= List( [ 1 .. nccl ], x -> lin[x] * chi[x] );
if not ext in irreds then Add( irreds, ext ); fi;
od;
od;
fi;
od;
tbl.irreducibles:= irreds;
end;
#############################################################################
##
#F ConstructDirectProduct( <tbl>, <factors> )
#F ConstructDirectProduct( <tbl>, <factors>, <permclasses>, <permchars> )
##
## special case of a 'construction' call for a library table <tbl>\:
##
## constructs a direct product of the tables described in the list
## <factors>, stores all those of its record components in <tbl>
## that are not yet bound in <tbl>.
## The 'fusions' component of <tbl> will be enlarged by the fusions of the
## direct product (factor fusions).
##
## If the optional arguments <permclasses>, <permchars> are given then
## classes and characters of the result are sorted accordingly.
##
ConstructDirectProduct := function( arg )
local tbl, factors, t, i, fld;
tbl:= arg[1];
factors:= arg[2];
t:= CharTableLibrary( factors[1] );
for i in [ 2 .. Length( factors ) ] do
t:= CharTableDirectProduct( t, CharTableLibrary( factors[i] ) );
od;
if 2 < Length( arg ) then
SortClassesCharTable( t, arg[3] );
SortCharactersCharTable( t, arg[4] );
Unbind( t.permutation );
fi;
for fld in Difference( RecFields( t ), RecFields( tbl ) ) do
tbl.( fld ):= t.( fld );
od;
if 1 < Length( factors ) then
Append( tbl.fusions, t.fusions );
fi;
end;
#############################################################################
##
#F ConstructIsoclinic( <tbl>, <factors>[, <nsg>[, <centre>]]
#F [, <permclasses>, <permchars>] )
##
ConstructIsoclinic := function( arg )
local tbl, factors, t, i, args, perms, fld;
tbl:= arg[1];
factors:= arg[2];
t:= CharTableLibrary( factors[1] );
for i in [ 2 .. Length( factors ) ] do
t:= CharTableDirectProduct( t, CharTableLibrary( factors[i] ) );
od;
args:= Filtered( arg, x -> not IsPerm( x ) );
if Length( args ) = 2 then
t:= CharTableIsoclinic( t );
elif Length( args ) = 3 then
t:= CharTableIsoclinic( t, args[3] );
elif Length( args ) = 4 then
t:= CharTableIsoclinic( t, args[3], args[4] );
else
Error( "invalid arguments <arg>" );
fi;
perms:= Filtered( arg, IsPerm );
if Length( perms ) = 2 then
SortClassesCharTable( t, perms[1] );
SortCharactersCharTable( t, perms[2] );
fi;
for fld in RecFields( t ) do
if not IsBound( tbl.( fld ) ) then
tbl.( fld ):= t.( fld );
fi;
od;
end;
#############################################################################
##
#F ConstructV4G( <tbl>, <facttbl>, <aut> )
##
## Let <tbl> be the character table of a group of type $2^2.G$
## where an outer automorphism of order 3 permutes the three involutions
## in the central $2^2$.
## Let <aut> be the permutation of classes of <tbl> induced by that
## automorphism, and <facttbl> the name of the character table
## of the factor group $2.G$.
## Then 'ConstructV4G' constructs the irreducible characters of <tbl> from
## that information.
##
ConstructV4G := function( arg )
local tbl, facttbls, aut, ker, fus, i, chars;
tbl:= arg[1];
if Length( arg ) = 2 then
facttbls:= arg[2];
else
facttbls:= [ arg[2] ];
aut:= arg[3];
fi;
fus:= List( facttbls, x -> First( tbl.fusions,
fus -> fus.name = x ).map );
facttbls:= List( facttbls, CharTable );
tbl.irreducibles:= List( facttbls[1].irreducibles, x -> x{ fus[1] } );
if Length( arg ) = 2 then
for i in [ 2 .. Length( facttbls ) ] do
Append( tbl.irreducibles, Filtered( List( facttbls[i].irreducibles,
x -> x{ fus[i] } ),
x -> not x in tbl.irreducibles ) );
od;
else
ker:= KernelChar( fus[1] );
ker:= Difference( OnTuples( ker, aut ), ker )[1];
chars:= List( Filtered( tbl.irreducibles, x -> x[1] <> x[ ker ] ),
x -> Permuted( x, aut ) );
Append( tbl.irreducibles, chars );
Append( tbl.irreducibles, List( chars, x -> Permuted( x, aut ) ) );
fi;
end;
#############################################################################
##
#F ConstructGS3( <tbls3>, <tbl2>, <tbl3>, <ind2>, <ind3>, <ext>, <perm> )
##
## constructs the irreducibles of a table <tbls3> of type $G.S_3$ from the
## tables <tbl2> and <tbl3> of $G.2$ and $G.3$, respectively.
## <ind2> is a list of numbers denoting irreducibles of <tbl2>.
## <ind3> is a list of pairs, each denoting irreducibles of <tbl3>.
## <ext> is a list of pairs, each denoting one irreducible of <tbl2>
## and one of <tbl3>.
## <perm> is a permutation that must be applied to the irreducibles.
##
ConstructGS3 := function( tbls3, tbl2, tbl3, ind2, ind3, ext, perm )
local fus2, # fusion map 'tbl2' in 'tbls3'
fus3, # fusion map 'tbl3' in 'tbls3'
proj2, # projection $G.S3$ to $G.2$
pos, # position in 'proj2'
proj2i, # inner part of projection $G.S3$ to $G.2$
proj2o, # outer part of projection $G.S3$ to $G.2$
proj3, # projection $G.S3$ to $G.3$
zeroon2, # zeros for part of $G.2 \setminus G$ in $G.S_3$
irr, # irreducible characters of 'tbls3'
i, # loop over 'ind2'
pair, # loop over 'ind3' and 'ext'
chi, # character
chii, # inner part of character
chio; # outer part of character
tbl2:= CharTable( tbl2 );
tbl3:= CharTable( tbl3 );
fus2:= GetFusionMap( tbl2, tbls3 );
fus3:= GetFusionMap( tbl3, tbls3 );
proj2:= ProjectionMap( fus2 );
pos:= First( [ 1 .. Length( proj2 ) ], x -> not IsBound( proj2[x] ) );
proj2i:= proj2{ [ 1 .. pos-1 ] };
pos:= First( [ pos .. Length( proj2 ) ], x -> IsBound( proj2[x] ) );
proj2o:= proj2{ [ pos .. Length( proj2 ) ] };
proj3:= ProjectionMap( fus3 );
zeroon2:= Difference( [ 1 .. Length( tbls3.centralizers ) ], fus3 ) * 0;
irr:= [];
# Induce the characters given by 'ind2' from 'tbl2'.
Append( irr, Induced( tbl2, tbls3, tbl2.irreducibles{ ind2 } ) );
# Induce the characters given by 'ind3' from 'tbl3'.
for pair in ind3 do
chi:= Sum( pair, x -> tbl3.irreducibles[x] );
Add( irr, Concatenation( chi{ proj3 }, zeroon2 ) );
od;
# Put the extensions from 'tbl' together.
for pair in ext do
chii:= tbl3.irreducibles[ pair[1] ]{ proj3 };
chio:= tbl2.irreducibles[ pair[2] ]{ proj2o };
Add( irr, Concatenation( chii, chio ) );
Add( irr, Concatenation( chii, -chio ) );
od;
# Permute the characters with 'perm'.
irr:= Permuted( irr, perm );
# Store the irreducibles.
tbls3.irreducibles:= irr;
end;
#############################################################################
##
#F ConstructPermuted( <tbl>, <libnam>[, <prmclasses>, <prmchars>] )
##
## The library table <tbl> is completed with help of the library table with
## name <libnam>, whose classes and characters must be permuted by the
## permutations <prmclasses> and <prmchars>, respectively.
##
ConstructPermuted := function( arg )
local tbl, t, fld, automorphisms, irredinfo, classtext, fusions,
projectives;
tbl:= arg[1];
t := CharTableLibrary( arg[2] );
for fld in RecFields( t ) do
if not IsBound( tbl.( fld ) ) then
tbl.(fld) := t.(fld);
fi;
od;
if IsBound( tbl.automorphisms ) then
automorphisms:= tbl.automorphisms;
Unbind( tbl.automorphisms );
fi;
if IsBound( tbl.irredinfo ) then
irredinfo:= tbl.irredinfo;
Unbind( tbl.irredinfo );
fi;
if IsBound( tbl.classtext ) then
classtext:= tbl.classtext;
Unbind( tbl.classtext );
fi;
if IsBound( tbl.fusions ) then
fusions:= tbl.fusions;
tbl.fusions:= [];
fi;
if IsBound( tbl.projectives ) then
projectives:= tbl.projectives;
Unbind( tbl.projectives );
fi;
if 2 < Length( arg ) then
SortClassesCharTable( tbl, arg[3] );
fi;
if 3 < Length( arg ) then
SortCharactersCharTable( tbl, arg[4] );
fi;
Unbind( tbl.permutation );
if IsBound( automorphisms ) then
tbl.automorphisms:= automorphisms;
fi;
if IsBound( irredinfo ) then
tbl.irredinfo:= irredinfo;
fi;
if IsBound( classtext ) then
tbl.classtext:= classtext;
fi;
if IsBound( fusions ) then
tbl.fusions:= fusions;
fi;
if IsBound( projectives ) then
tbl.projectives:= projectives;
fi;
end;
#############################################################################
##
#F ConstructAdjusted( <tbl>, <libnam>, <pairs>
#F [, <permclasses>, <permchars>] )
##
ConstructAdjusted:= function( arg )
local tbl, t, pair;
tbl:= arg[1];
# Get the permuted library table.
t:= CharTableLibrary( arg[2] );
if 3 < Length( arg ) and arg[4] <> () then
SortClassesCharTable( t, arg[4] );
fi;
if 4 < Length( arg ) and arg[5] <> () then
SortCharactersCharTable( t, arg[5] );
fi;
# Set the components that shall be adjusted.
for pair in arg[3] do
if pair[1] = "ComputedPowerMaps" then
tbl.powermaps:= pair[2];
else
Error( "transfer of component `", pair[1],
"' is not yet supported by `ConstructAdjusted'" );
fi;
od;
# Transfer not adjusted defining components.
if not IsBound( tbl.centralizers ) then
tbl.centralizers:= t.centralizers;
fi;
if not IsBound( tbl.powerpaps ) then
tbl.powermap:= t.powermap;
fi;
if not IsBound( tbl.irreducibles ) then
tbl.irreducibles:= t.irreducibles;
fi;
end;
#############################################################################
##
#F ConstructFactor( <tbl>, <libnam>, <kernel> )
##
## The library table <tbl> is completed with help of the library table with
## name <libnam>, whose classes and characters must be permuted by the
## permutations <prmclasses> and <prmchars>, respectively.
##
ConstructFactor := function( tbl, libnam, kernel )
local t, fld;
t:= CharTableFactorGroup( CharTableLibrary( libnam ), kernel );
for fld in RecFields( t ) do
if not IsBound( tbl.( fld ) ) then
tbl.(fld) := t.(fld);
fi;
od;
end;
#############################################################################
##
#F ConstructSubdirect( <tbl>, <factors>, <choice> )
##
## The library table <tbl> is completed with help of the table got from
## taking the direct product of the tables with names in the list <factors>,
## and then taking the table consisting of the classes in the list <choice>.
##
ConstructSubdirect := function( tbl, factors, choice )
local t, i, fld;
t:= CharTableLibrary( factors[1] );
for i in [ 2 .. Length( factors ) ] do
t:= CharTableDirectProduct( t, CharTableLibrary( factors[i] ) );
od;
t:= CharTableNormalSubgroup( t, choice );
for fld in RecFields( t ) do
if not IsBound( tbl.( fld ) ) then
tbl.( fld ):= t.( fld );
fi;
od;
end;
#############################################################################
##
#F IrreducibleCharactersOfIndexTwoSubdirectProduct( <irrH1xH2>, <irrG1xG2>,
#F <H1xH2fusG>, <GfusG1xG2> )
##
## We do not want to use the table head of the subdirect product because
## this function is also called by `ConstructIndexTwoSubdirectProduct',
## and there just a record is available from which the table is computed
## later.
##
IrreducibleCharactersOfIndexTwoSubdirectProduct:=
function( irrH1xH2, irrG1xG2, H1xH2fusG, GfusG1xG2 )
local H1xH2fusG1xG2, restpos, i, rest, pos, irr, zero, proj1, perm,
proj2, chi, ind, j;
H1xH2fusG1xG2:= CompositionMaps( GfusG1xG2, H1xH2fusG );
# Compute which irreducibles of H1xH2 extend to G1xG2.
restpos:= List( irrH1xH2, x -> [] );
for i in [ 1 .. Length( irrG1xG2 ) ] do
rest:= irrG1xG2[i]{ H1xH2fusG1xG2 };
pos:= Position( irrH1xH2, rest );
if pos <> false then
Add( restpos[ pos ], i );
fi;
od;
irr:= [];
zero:= 0 * GfusG1xG2;
proj1:= ProjectionMap( H1xH2fusG );
perm:= Product( List( Filtered( InverseMap( H1xH2fusG ), IsList ),
l -> ( l[1], l[2] ) ) );
if perm = 1 then
perm:= ();
fi;
proj2:= [];
for i in [ 1 .. Length( proj1 ) ] do
if IsBound( proj1[i] ) then
proj2[i]:= proj1[i]^perm;
fi;
od;
for i in [ 1 .. Length( irrH1xH2 ) ] do
if not IsEmpty( restpos[i] ) then
# The i-th irreducible of H1xH2 extends to G1xG2.
# Restrict these extensions to G.
Append( irr, DuplicateFreeList( List( irrG1xG2{ restpos[i] },
chi -> chi{ GfusG1xG2 } ) ) );
else
# The i-th irreducible character of H1xH2 has inertia subgroup one of
# H1xG2 or G1xH2, so it induces irreducibly to G.
# Compute the induced character (without using the table head).
chi:= irrH1xH2[i];
# The curly bracket operator works only for dense sublists.
# ind:= ShallowCopy( zero ) + chi{ proj1 } + chi{ proj2 };
ind:= ShallowCopy( zero );
for j in [ 1 .. Length( proj1 ) ] do
if IsBound( proj1[j] ) then
ind[j]:= ind[j] + chi[ proj1[j] ];
fi;
od;
for j in [ 1 .. Length( proj2 ) ] do
if IsBound( proj2[j] ) then
ind[j]:= ind[j] + chi[ proj2[j] ];
fi;
od;
if not ind in irr then
Add( irr, ind );
fi;
fi;
od;
return irr;
end;
#############################################################################
##
#F ClassFusionsForIndexTwoSubdirectProduct( <tblH1>, <tblG1>, <tblH2>,
#F <tblG2> )
##
## It is assumed that all tables are either ordinary tables or Brauer tables
## for the same characteristic.
##
## Note that the components `GfusG1xG2', `Gclasses', `Gorders' refer only to
## the classes inside the normal subgroup `<tblH1> * <tblH2>'.
##
ClassFusionsForIndexTwoSubdirectProduct:= 0;
ClassFusionsForIndexTwoSubdirectProduct:=
function( tblH1, tblG1, tblH2, tblG2 )
local p, H1classes, H2classes, H1orders, H2orders, H1fusG1, H2fusG2,
inv1, inv2, ncclH2, ncclG2, H1xH2fusG, GfusG1xG2,
Gclasses, Gorders, i1, i2, posG1xG2, len, pos,
ordH1, ordG1, ordH2, ordG2, info, modGfusordG, modfus2,
modG1xG2fusordG1xG2, modH1xH2fusordH1xH2;
if IsBound( tblH1.prime ) then
p:= tblH1.prime;
else
p:= 0;
fi;
if p = 0 then
H1classes:= tblH1.classes;
H2classes:= tblH2.classes;
H1orders:= tblH1.orders;
H2orders:= tblH2.orders;
H1fusG1:= GetFusionMap( tblH1, tblG1 );
if H1fusG1 = false then
H1fusG1:= RepresentativesFusions( tblH1,
SubgroupFusions( tblH1, tblG1 ), tblG1 );
if Length( H1fusG1 ) <> 1 then
Error( "fusion <tblH1> to <tblG1> is not determined" );
fi;
fi;
H2fusG2:= GetFusionMap( tblH2, tblG2 );
if H2fusG2 = false then
H2fusG2:= RepresentativesFusions( tblH2,
SubgroupFusions( tblH2, tblG2 ), tblG2 );
if Length( H2fusG2 ) <> 1 then
Error( "fusion <tblH2> to <tblG2> is not determined" );
fi;
fi;
inv1:= InverseMap( H1fusG1 );
inv2:= InverseMap( H2fusG2 );
ncclH2:= Length( H2classes );
ncclG2:= Length( tblG2.classes );
H1xH2fusG:= [];
GfusG1xG2:= [];
Gclasses:= [];
Gorders:= [];
for i1 in [ 1 .. Length( inv1 ) ] do
if IsBound( inv1[ i1 ] ) then
for i2 in [ 1 .. Length( inv2 ) ] do
if IsBound( inv2[ i2 ] ) then
posG1xG2:= ( i1 - 1 ) * ncclG2 + i2;
if IsInt( inv1[ i1 ] ) then
if IsInt( inv2[ i2 ] ) then
# no fusion
len:= Length( GfusG1xG2 ) + 1;
H1xH2fusG[ ( inv1[ i1 ] - 1 ) * ncclH2 + inv2[ i2 ] ]:= len;
GfusG1xG2[ len ]:= posG1xG2;
Gclasses[ len ]:= H1classes[ inv1[ i1 ] ]
* H2classes[ inv2[ i2 ] ];
Gorders[ len ]:= LcmInt( H1orders[ inv1[ i1 ] ],
H2orders[ inv2[ i2 ] ] );
else
# fusion from H2 to G2
len:= Length( GfusG1xG2 ) + 1;
for pos in inv2[ i2 ] do
H1xH2fusG[ ( inv1[ i1 ] - 1 ) * ncclH2 + pos ]:= len;
od;
GfusG1xG2[ len ]:= posG1xG2;
Gclasses[ len ]:= 2 * H1classes[ inv1[ i1 ] ]
* H2classes[ inv2[ i2 ][1] ];
Gorders[ len ]:= LcmInt( H1orders[ inv1[ i1 ] ],
H2orders[ inv2[ i2 ][1] ] );
fi;
elif IsInt( inv2[ i2 ] ) then
# fusion from H1 to G1
len:= Length( GfusG1xG2 ) + 1;
for pos in inv1[ i1 ] do
H1xH2fusG[ ( pos - 1 ) * ncclH2 + inv2[ i2 ] ]:= len;
od;
GfusG1xG2[ len ]:= posG1xG2;
Gclasses[ len ]:= 2 * H1classes[ inv1[ i1 ][1] ]
* H2classes[ inv2[ i2 ] ];
Gorders[ len ]:= LcmInt( H1orders[ inv1[ i1 ][1] ],
H2orders[ inv2[ i2 ] ] );
else
# fusion in both factors (get two classes)
len:= Length( GfusG1xG2 ) + 1;
H1xH2fusG[ ( inv1[ i1 ][1]-1 ) * ncclH2 + inv2[i2][1] ]:= len;
H1xH2fusG[ ( inv1[ i1 ][2]-1 ) * ncclH2 + inv2[i2][2] ]:= len;
GfusG1xG2[ len ]:= posG1xG2;
Gclasses[ len ]:= 2 * H1classes[ inv1[ i1 ][1] ]
* H2classes[ inv2[ i2 ][1] ];
Gorders[ len ]:= LcmInt( H1orders[ inv1[ i1 ][1] ],
H2orders[ inv2[ i2 ][1] ] );
H1xH2fusG[ ( inv1[i1][1]-1 ) * ncclH2 + inv2[i2][2] ]:= len + 1;
H1xH2fusG[ ( inv1[i1][2]-1 ) * ncclH2 + inv2[i2][1] ]:= len + 1;
GfusG1xG2[ len + 1 ]:= posG1xG2;
Gclasses[ len + 1 ]:= Gclasses[ len ];
Gorders[ len + 1 ]:= Gorders[ len ];
fi;
fi;
od;
fi;
od;
else
ordH1:= tblH1.ordinary;
ordG1:= tblG1.ordinary;
ordH2:= tblH2.ordinary;
ordG2:= tblG2.ordinary;
# Compute the maps for the underlying ordinary tables.
info:= ClassFusionsForIndexTwoSubdirectProduct( ordH1, ordG1,
ordH2, ordG2 );
# Compute the embeddings of `p'-regular classes of G, H1xH2, G1xG2,
# without actually constructing these tables.
modGfusordG:= Filtered( [ 1 .. Length( info.Gorders ) ],
i -> info.Gorders[i] mod p <> 0 );
modfus2:= GetFusionMap( tblG2, ordG2 );
modG1xG2fusordG1xG2:= Concatenation(
List( GetFusionMap( tblG1, ordG1 ),
i -> modfus2 + ( i - 1 ) * Length( ordG2.classes ) ) );
modfus2:= GetFusionMap( tblH2, ordH2 );
modH1xH2fusordH1xH2:= Concatenation(
List( GetFusionMap( tblH1, ordH1 ),
i -> modfus2 + ( i - 1 ) * Length( ordH2.classes ) ) );
# Compute the maps for the Brauer tables.
H1xH2fusG:= CompositionMaps( InverseMap( modGfusordG ),
CompositionMaps( info.H1xH2fusG, modH1xH2fusordH1xH2 ) );
GfusG1xG2:= CompositionMaps( InverseMap( modG1xG2fusordG1xG2 ),
CompositionMaps( info.GfusG1xG2, modGfusordG ) );
Gclasses:= info.Gclasses{ modGfusordG };
Gorders:= info.Gorders{ modGfusordG };
fi;
return rec( H1xH2fusG:= H1xH2fusG,
GfusG1xG2:= GfusG1xG2,
Gclasses:= Gclasses,
Gorders:= Gorders
);
end;
#############################################################################
##
#F ConstructIndexTwoSubdirectProduct( <tbl>, <tblH1>, <tblG1>, <tblH2>,
#F <tblG2>, <outerfus>, <permclasses>, <permchars> )
##
ConstructIndexTwoSubdirectProduct:= function( tbl, tblH1, tblG1, tblH2, tblG2,
outerfus, permclasses, permchars )
local info, irreds;
tblH1:= CharTable( tblH1 );
tblG1:= CharTable( tblG1 );
tblH2:= CharTable( tblH2 );
tblG2:= CharTable( tblG2 );
info:= ClassFusionsForIndexTwoSubdirectProduct(
tblH1, tblG1, tblH2, tblG2 );
irreds:= IrreducibleCharactersOfIndexTwoSubdirectProduct(
KroneckerProduct( tblH1.irreducibles, tblH2.irreducibles ),
KroneckerProduct( tblG1.irreducibles, tblG2.irreducibles ),
info.H1xH2fusG, Concatenation( info.GfusG1xG2, outerfus ) );
tbl.irreducibles:= Permuted(
List( irreds, chi -> Permuted( chi, permclasses ) ),
permchars );
end;
#############################################################################
##
#F ConstructWreathSymmetric( <tbl>, <subname>, <n>
#F [, <permclasses>, <permchars>] )
##
ConstructWreathSymmetric:= function( arg )
local tbl, sub, t, fld;
tbl:= arg[1];
sub:= CharTableLibrary( arg[2] );
t:= CharTableWreathSymmetric( sub, arg[3] );
if 3 < Length( arg ) then
SortClassesCharTable( t, arg[4] );
SortCharactersCharTable( t, arg[5] );
if not IsBound( tbl.permutation ) then
# Do *not* inherit the permutation from the construction!
tbl.permutation:= ();
fi;
fi;
for fld in Difference( RecFields( t ), RecFields( tbl ) ) do
tbl.( fld ):= t.( fld );
od;
end;
#############################################################################
##
#F UnpackedCll( <cll> )
##
## is a record with the components 'mat', 'inertiagrps', 'fusionclasses',
## and perhaps 'libname'.
## These are the only components used in the construction of library
## character tables encoded by Clifford matrices.
##
## The meaning of <cll> is the same as in 'CllToClf'.
##
UnpackedCll := function( cll )
local l, clmlist, # library list of the possible matrices
clf, # Clifford matrix record, result
pi; # permutation to sort library matrices
# Initialize the Clifford matrix record.
clf:= rec(
inertiagrps := cll[1],
fusionclasses := cll[2]
);
if Length( cll[2] ) = 1 then
clf.mat:= [ [ 1 ] ];
elif Length( cll[3] ) = 2 then
# is already unpacked, for example dimension 2
clf.mat:= cll[3];
else
# Fetch the matrix from the library.
cll:= cll[3];
clf.libname:= cll;
l:= cll[2];
clmlist:= LibraryTables( Concatenation( "clm", cll[1] ) );
if clmlist = false or not IsBound( clmlist[l] ) then
Error( "sorry, component <mat> not found in the library" );
fi;
clf.mat:= Copy( clmlist[l][ cll[3] ] );
# Sort the rows and columns of the Clifford matrix
# w.r.t. the explicitly given permutations.
if IsBound( cll[4] ) then
clf.mat:= Permuted( clf.mat, cll[4] );
fi;
if IsBound( cll[5] ) then
pi:= cll[5];
clf.mat:= List( clf.mat, x -> Permuted( x, pi ) );
fi;
fi;
return clf;
end;
#############################################################################
##
#F CllToClf( <tbl>, <cll> )
##
## is a Clifford matrix for the table <tbl>.
## It is constructed from the list <cll> that contains
## the following entries.
## 1. list of indices of inertia factors
## 2. list of classes fusing in the factor group
## 3. identification of the matrix,
## either unbound (then the matrix has dimension <= 2)
## or a list containing
## a. string '"elab"' or '"exsp"'
## b. size of the Clifford matrix
## c. index in the library file
## d. (optional) necessary permutation of columns
## or a list containing
## a. the Clifford matrix itself and
## b. the column weights.
## 4. (case '"exsp"') a list with items of record 'splitinfos':
## a. classindex
## b. p
## c. numclasses
## d. root
##
CllToClf := function( tbl, cll )
local Ti, #
factor, # character table of the factor group G/N
i, nr,
dim, # dimension of the matrix
clf, # expanded record
pos,
map;
Ti:= tbl.cliffordTable.Ti;
factor:= Ti.tables[1];
--> --------------------
--> maximum size reached
--> --------------------
[ Verzeichnis aufwärts0.61unsichere Verbindung
Übersetzung europäischer Sprachen durch Browser
]
|