Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346############################################################################# ## #W types.g GAP 4 package AtlasRep Thomas Breuer ## #Y Copyright (C) 2001, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany ## ## This file contains implementations of the actual data types used in the ## &ATLAS; of Group Representations. ## ############################################################################# ## #V AtlasOfGroupRepresentationsInfo ## BindGlobal( "AtlasOfGroupRepresentationsInfo", rec( # user parameters remote := true, servers := [ [ "brauer.maths.qmul.ac.uk", "Atlas/" ], ], wget := "prefer IO to wget", compress := false, displayFunction := Print, accessFunctions := AtlasOfGroupRepresentationsAccessFunctionsDefault, markprivate := "*", # system parameters (filled automatically) GAPnames := [], groupnames := [], ringinfo := [], permrepinfo := rec(), characterinfo := rec(), private := [], filenames := [], TableOfContents := rec( remote := rec(), types := rec( rep := [], prg := [], cache := [] ), merged := rec() ), TOC_Cache := rec(), ) ); ############################################################################# ## #D Permutation representations ## ## <#GAPDoc Label="type:perm:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-p<A>n</A><A>id</A>B<A>m</A>.m<A>nr</A></C></Mark> ## <Item> ## a file in &MeatAxe; text file format ## containing the <A>nr</A>-th generator of a permutation representation ## on <A>n</A> points. ## An example is <C>M11G1-p11B0.m1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "rep", "perm", rec( # `<groupname>G<i>-p<n><id>B<m>.m<nr>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "p", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, "B", IsDigitChar, ".m", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], AddDescribingComponents := function( record, type ) local repid, parsed, comp, info, pos; repid:= record.identifier[2][1]; parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); record.p:= Int( parsed[5] ); record.id:= parsed[6]; repid:= repid{ [ 1 .. Position( repid, '.' ) - 1 ] }; if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ) ) then info:= AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ); if IsBound( info[1] ) then info:= info[1]; pos:= Position( info[2], repid ); if pos <> fail and info[3][ pos ] <> fail then record.charactername:= info[3][ pos ]; fi; fi; fi; if IsBound( AtlasOfGroupRepresentationsInfo.permrepinfo.( repid ) ) then repid:= AtlasOfGroupRepresentationsInfo.permrepinfo.( repid ); for comp in [ "isPrimitive", "orbits", "rankAction", "stabilizer", "transitivity", "maxnr" ] do if IsBound( repid.( comp ) ) and repid.( comp ) <> "???" then record.( comp ):= repid.( comp ); fi; od; fi; end, # `[ <i>, <n>, <id>, <m>, <filenames> ]' AddFileInfo := function( list, entry, name ) local known; if 0 < entry[5] then known:= First( list, x -> x{ [ 1 .. 4 ] } = entry{ [3, 5, 6, 8 ] } ); if known = fail then known:= entry{ [ 3, 5, 6, 8 ] }; Add( known, [] ); Add( list, known ); fi; known[5][ entry[10] ]:= name; return true; fi; return false; end, DisplayOverviewInfo := [ "#", "r", function( conditions ) # Put *all* types of representations together, in particular # assume that the functions for the other "rep" kind types are trivial! local info, no; conditions:= ShallowCopy( conditions ); conditions[1]:= conditions[1][1]; info:= CallFuncList( AllAtlasGeneratingSetInfos, conditions ); no:= Length( info ); if no = 0 then no:= ""; fi; return [ String( no ), ForAny( info, x -> not IsString( x.identifier[1] ) ) ]; end ], AccessGroupCondition := function( info, cond ) return AGR.CheckOneCondition( IsPermGroup, x -> x = true, cond ) and AGR.CheckOneCondition( IsPermGroup, cond ) and AGR.CheckOneCondition( IsMatrixGroup, x -> x = false, cond ) and AGR.CheckOneCondition( NrMovedPoints, x -> ( IsFunction( x ) and x( info.p ) = true ) or info.p = x, cond ) and AGR.CheckOneCondition( IsTransitive, x -> IsBound( info.transitivity ) and ( IsFunction( x ) and x( info.transitivity > 0 ) = true ) or ( info.transitivity > 0 ) = x, cond ) and AGR.CheckOneCondition( Transitivity, x -> IsBound( info.transitivity ) and ( IsFunction( x ) and x( info.transitivity ) = true ) or info.transitivity = x, cond ) and AGR.CheckOneCondition( IsPrimitive, x -> IsBound( info.isPrimitive ) and ( IsFunction( x ) and x( info.isPrimitive ) = true ) or info.isPrimitive = x, cond ) and AGR.CheckOneCondition( RankAction, x -> IsBound( info.rankAction ) and ( IsFunction( x ) and x( info.rankAction ) = true ) or info.rankAction = x, cond ) and AGR.CheckOneCondition( Identifier, x -> ( IsFunction( x ) and x( info.id ) = true ) or info.id = x, cond ) and IsEmpty( cond ); end, DisplayGroup := function( r ) local disp, sep; if AGR.ShowOnlyASCII() then disp:= Concatenation( "G <= Sym(", String( r.p ), r.id, ")" ); else disp:= Concatenation( "G ≤ Sym(", String( r.p ), r.id, ")" ); fi; if IsBound( r.transitivity ) then disp:= [ disp ]; if r.transitivity = 0 then # For intransitive repres., show the orbit lengths. Add( disp, Concatenation( "orbit lengths ", JoinStringsWithSeparator( List( r.orbits, String ), ", " ) ) ); sep:= ", "; elif r.transitivity = 1 then # For transitivity 1, show the rank (if known). if IsBound( r.rankAction ) and r.rankAction <> "???" then Add( disp, Concatenation( "rank ", String( r.rankAction ) ) ); sep:= ", "; fi; elif IsInt( r.transitivity ) then # For transitivity at least 2, show the transitivity. Add( disp, Concatenation( String( r.transitivity ), "-trans." ) ); sep:= ", "; else # The transitivity is not known. Add( disp, "" ); sep:= ""; fi; if 0 < r.transitivity then # For transitive representations, more info may be available. if r.isPrimitive then if IsBound( r.stabilizer ) and r.stabilizer <> "???" then Add( disp, Concatenation( sep, "on cosets of " ) ); Add( disp, r.stabilizer ); if IsBound( r.maxnr ) and r.maxnr <> "???" then Add( disp, Concatenation( " (", Ordinal( r.maxnr ), " max.)" ) ); else Add( disp, "" ); fi; elif IsBound( r.maxnr ) and r.maxnr <> "???" then Add( disp, Concatenation( sep, "on cosets of ", Ordinal( r.maxnr ), " max." ) ); else Add( disp, "primitive" ); fi; elif IsBound( r.stabilizer ) and r.stabilizer <> "???" then Add( disp, Concatenation( sep, "on cosets of " ) ); Add( disp, r.stabilizer ); fi; fi; fi; return disp; end, TestFileHeaders := function( tocid, groupname, entry, type ) local name, filename, len, file, line; if tocid = "local" then tocid:= "datagens"; fi; # Each generator is stored in a file of its own. for name in entry[ Length( entry ) ] do # Fetch the file if necessary. filename:= AtlasOfGroupRepresentationsLocalFilenameTransfer( tocid, groupname, name, type ); if filename = fail then return Concatenation( "filename `", name, "' not found" ); fi; filename:= filename[1]; len:= Length( filename ); if 3 < len and filename{ [ len-2 .. len ] } = ".gz" then filename:= filename{ [ 1 .. len-3 ] }; fi; # Read the first line of the file. file:= InputTextFile( filename ); if file = fail then return Concatenation( "cannot create input stream for file `", filename,"'" ); fi; InfoRead1( "#I reading `",filename,"' started\n" ); line:= ReadLine( file ); if line = fail then CloseStream( file ); return Concatenation( "no first line in file `",filename,"'" ); fi; while not '\n' in line do Append( line, ReadLine( file ) ); od; CloseStream( file ); InfoRead1( "#I reading `",filename,"' done\n" ); # The header must consist of four nonnegative integers. line:= CMeatAxeFileHeaderInfo( line ); if line = fail then return Concatenation( "illegal header of file `", filename,"'" ); fi; # Start the specific tests for permutations. # Check mode, number of permutations, and degree. if line[1] <> 12 then return Concatenation( "mode of file `", name, "' differs from 12" ); elif line[4] <> 1 then return Concatenation( "more than one permutation in file `", name, "'" ); elif line[3] <> entry[2] then return Concatenation( "perm. degree in file `", name, "' is ", String( line[3] ) ); fi; od; return true; end, TestFiles := AGR.TestFilesMTX, # Permutation representations are sorted according to # degree and identification string. SortTOCEntries := entry -> entry{ [ 2, 3 ] }, PostprocessFileInfo := function( toc, record ) local list, i; list:= record.perm; for i in [ 1 .. Length( list ) ] do if not IsDenseList( list[i][5] ) then #T better check whether the number of generators equals the number of #T standard generators! Info( InfoAtlasRep, 1, "not all generators for ", list[i][5] ); Unbind( list[i] ); fi; od; if not IsDenseList( list ) then record.perm:= Compacted( list ); fi; end, # We store the stem of the filename and the list of CRC values. TOCEntryString := function( typename, entry ) return Concatenation( [ "AGR.TOC(\"", typename, "\",\"", entry[5][1]{ [ 1 .. Length( entry[5][1] ) - 1 ] }, "\",", ReplacedString( String( List( entry[5], f -> First( AtlasOfGroupRepresentationsInfo.filenames, p -> p[1] = f )[2] ) ), " ", "" ), ");\n" ] ); end, # The default access reads the text format files. # Note that `ScanMeatAxeMat' returns a list of permutations. ReadAndInterpretDefault := paths -> Concatenation( List( paths, ScanMeatAxeFile ) ), ) ); ############################################################################# ## #D Matrix representations over finite fields ## ## <#GAPDoc Label="type:matff:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-f<A>q</A>r<A>dim</A><A>id</A>B<A>m</A>.m<A>nr</A></C></Mark> ## <Item> ## a file in &MeatAxe; text file format ## containing the <A>nr</A>-th generator of a matrix representation ## over the field with <A>q</A> elements, of dimension <A>dim</A>. ## An example is <C>S5G1-f2r4aB0.m1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "rep", "matff", rec( # `<groupname>G<i>-f<q>r<dim><id>B<m>.m<nr>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "f", IsDigitChar, "r", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, "B", IsDigitChar, ".m", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], AddDescribingComponents := function( record, type ) local repid, parsed, info, char, pos; repid:= record.identifier[2][1]; parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); record.dim:= Int( parsed[7] ); record.id:= parsed[8]; record.ring:= GF( parsed[5] ); if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ) ) then info:= AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ); char:= Characteristic( record.ring ); if IsBound( info[ char ] ) then info:= info[ char ]; pos:= Position( info[2], repid{ [ 1 .. Position( repid, '.' ) - 1 ] } ); if pos <> fail and info[3][ pos ] <> fail then record.charactername:= info[3][ pos ]; fi; fi; fi; end, # `[ <i>, <q>, <dim>, <id>, <m>, <filenames> ]' AddFileInfo := function( list, entry, name ) local known; if IsPrimePowerInt( entry[5] ) and 0 < entry[7] then known:= First( list, x -> x{ [ 1 .. 5 ] } = entry{ [ 3, 5, 7, 8, 10 ] } ); if known = fail then known:= entry{ [ 3, 5, 7, 8, 10 ] }; Add( known, [] ); Add( list, known ); fi; known[6][ entry[12] ]:= name; return true; fi; return false; end, AccessGroupCondition := function( info, cond ) return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) and AGR.CheckOneCondition( IsMatrixGroup, cond ) and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) and AGR.CheckOneCondition( Characteristic, function( p ) local char; char:= SmallestRootInt( Size( info.ring ) ); return char = p or IsFunction( p ) and p( char ) = true; end, cond ) and AGR.CheckOneCondition( Dimension, x -> ( IsFunction( x ) and x( info.dim ) ) or info.dim = x, cond ) and AGR.CheckOneCondition( Ring, R -> ( IsFunction( R ) and R( info.ring ) ) or ( IsField( R ) and IsFinite( R ) and Size( info.ring ) mod Characteristic( R ) = 0 and DegreeOverPrimeField( R ) mod LogInt( Size( info.ring ), Characteristic( R ) ) = 0 ), cond ) and AGR.CheckOneCondition( Identifier, x -> ( IsFunction( x ) and x( info.id ) = true ) or info.id = x, cond ) and IsEmpty( cond ); end, DisplayGroup := function( r ) local disp; if AGR.ShowOnlyASCII() then disp:= Concatenation( "G <= GL(", String( r.dim ), r.id, ",", String( r.identifier[4] ), ")" ); if IsBound( r.charactername ) then disp:= [ disp, Concatenation( "character ", r.charactername ) ]; fi; else disp:= Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",", String( r.identifier[4] ), ")" ); if IsBound( r.charactername ) then disp:= [ disp, Concatenation( "φ = ", r.charactername ) ]; fi; fi; return disp; end, TestFileHeaders := function( tocid, groupname, entry, type ) local name, filename, len, file, line, errors; if tocid = "local" then tocid:= "datagens"; fi; # Each generator is stored in a file of its own. for name in entry[ Length( entry ) ] do # Fetch the file if necessary. filename:= AtlasOfGroupRepresentationsLocalFilenameTransfer( tocid, groupname, name, type ); if filename = fail then return Concatenation( "filename `", name, "' not found" ); fi; filename:= filename[1]; len:= Length( filename ); if 3 < len and filename{ [ len-2 .. len ] } = ".gz" then filename:= filename{ [ 1 .. len-3 ] }; fi; # Read the first line of the file. file:= InputTextFile( filename ); if file = fail then return Concatenation( "cannot create input stream for file `", filename,"'" ); fi; InfoRead1( "#I reading `",filename,"' started\n" ); line:= ReadLine( file ); if line = fail then CloseStream( file ); return Concatenation( "no first line in file `",filename,"'" ); fi; while not '\n' in line do Append( line, ReadLine( file ) ); od; CloseStream( file ); InfoRead1( "#I reading `",filename,"' done\n" ); # The header must consist of four nonnegative integers. line:= CMeatAxeFileHeaderInfo( line ); if line = fail then return Concatenation( "illegal header of file `", filename,"'" ); fi; # Start the specific tests for matrices over finite fields. # Check mode, field size, and dimension. errors:= ""; if 6 < line[1] then Append( errors, Concatenation( "mode of file `", name, "' is larger than 6" ) ); elif line[2] <> entry[2] then Append( errors, Concatenation( "file `", name, "': field is of size ", String( line[2] ) ) ); elif line[3] <> entry[3] then Append( errors, Concatenation( "file `", name, "': matrix dimension is ", String( line[3] ) ) ); elif line[3] <> line[4] then Append( errors, Concatenation( "file `", name, "': matrix is not square" ) ); fi; if not IsEmpty( errors ) then return errors; fi; od; return true; end, TestFiles := AGR.TestFilesMTX, # Matrix representations over finite fields are sorted according to # field size, dimension, and identification string. SortTOCEntries := entry -> entry{ [ 2 .. 4 ] }, PostprocessFileInfo := function( toc, record ) local list, i; list:= record.matff; for i in [ 1 .. Length( list ) ] do if not IsDenseList( list[i][6] ) then #T better check whether the number of generators equals the number of #T standard generators! Info( InfoAtlasRep, 1, "not all generators for ", list[i][6] ); Unbind( list[i] ); fi; od; if not IsDenseList( list ) then record.matff:= Compacted( list ); fi; end, # We store the stem of the filename and the list of CRC values. TOCEntryString := function( typename, entry ) return Concatenation( [ "AGR.TOC(\"", typename, "\",\"", entry[6][1]{ [ 1 .. Length( entry[6][1] ) - 1 ] }, "\",", ReplacedString( String( List( entry[6], f -> First( AtlasOfGroupRepresentationsInfo.filenames, p -> p[1] = f )[2] ) ), " ", "" ), ");\n" ] ); end, # The default access reads the text format files. ReadAndInterpretDefault := paths -> List( paths, ScanMeatAxeFile ), ) ); ############################################################################# ## #D Matrix representations over the integers ## ## <#GAPDoc Label="type:matint:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-Zr<A>dim</A><A>id</A>B<A>m</A>.g</C></Mark> ## <Item> ## a &GAP; readable file ## containing all generators of a matrix representation ## over the integers, of dimension <A>dim</A>. ## An example is <C>A5G1-Zr4B0.g</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "rep", "matint", rec( # `<groupname>G<i>-Zr<dim><id>B<m>.g' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "Zr", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, "B", IsDigitChar, ".g" ] ], [ ParseBackwards, ParseForwards ] ], AddDescribingComponents := function( record, type ) local repid, parsed, info, pos; repid:= record.identifier[2]; parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); record.dim:= Int( parsed[5] ); record.id:= parsed[6]; record.ring:= Integers; if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ) ) then info:= AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ); if IsBound( info[1] ) then info:= info[1]; pos:= Position( info[2], repid{ [ 1 .. Position( repid, '.' ) - 1 ] } ); if pos <> fail and info[3][ pos ] <> fail then record.charactername:= info[3][ pos ]; fi; fi; fi; end, # `[ <i>, <dim>, <id>, <m>, <filename> ]' AddFileInfo := function( list, entry, name ) if 0 < entry[5] then Add( list, Concatenation( entry{ [ 3, 5, 6, 8 ] }, [ name ] ) ); return true; fi; return false; end, AccessGroupCondition := function( info, cond ) return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) and AGR.CheckOneCondition( IsMatrixGroup, cond ) and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) and AGR.CheckOneCondition( Characteristic, p -> p = 0 or ( IsFunction( p ) and p( 0 ) = true ), cond ) and AGR.CheckOneCondition( Dimension, x -> ( IsFunction( x ) and x( info.dim ) ) or info.dim = x, cond ) and AGR.CheckOneCondition( Ring, R -> ( IsFunction( R ) and R( Integers ) ) or ( IsRing( R ) and IsCyclotomicCollection( R ) ), cond ) and AGR.CheckOneCondition( Identifier, x -> ( IsFunction( x ) and x( info.id ) = true ) or info.id = x, cond ) and IsEmpty( cond ); end, TestFileHeaders := function( tocid, groupname, entry, type ) return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, entry[2], function( entry, mats, filename ) if not ForAll( mats, mat -> ForAll( mat, row -> ForAll( row, IsInt ) ) ) then return Concatenation( "matrices in `",filename, "' are not over the integers" ); fi; return true; end ); end, DisplayGroup := function( r ) local disp; if AGR.ShowOnlyASCII() then disp:= Concatenation( "G <= GL(", String( r.dim ), r.id, ",Z)" ); if IsBound( r.charactername ) then disp:= [ disp, Concatenation( "character ", r.charactername ) ]; fi; else disp:= Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",ℤ)" ); if IsBound( r.charactername ) then disp:= [ disp, Concatenation( "χ = ", r.charactername ) ]; fi; fi; return disp; end, # Matrix representations over the integers are sorted according to # dimension and identification string. SortTOCEntries := entry -> entry{ [ 2, 3 ] }, ReadAndInterpretDefault := path -> AtlasDataGAPFormatFile( path ).generators, ) ); ############################################################################# ## #D Matrix representations over algebraic number fields ## ## <#GAPDoc Label="type:matalg:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-Ar<A>dim</A><A>id</A>B<A>m</A>.g</C></Mark> ## <Item> ## a &GAP; readable file ## containing all generators of a matrix representation of dimension ## <A>dim</A> over an algebraic number field not specified further. ## An example is <C>A5G1-Ar3aB0.g</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "rep", "matalg", rec( # `<groupname>G<i>-Ar<dim><id>B<m>.g' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "Ar", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, "B", IsDigitChar, ".g" ] ], [ ParseBackwards, ParseForwards ] ], AddDescribingComponents := function( record, type ) local repid, parsed, info, pos; repid:= record.identifier[2]; parsed:= AGR.ParseFilenameFormat( repid, type[2].FilenameFormat ); record.dim:= Int( parsed[5] ); record.id:= parsed[6]; info:= record.identifier[2]; info:= info{ [ 1 .. Position( info, '.' )-1 ] }; info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, x -> x[1] = info ); if info <> fail then record.ring:= info[3]; fi; if IsBound( AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ) ) then info:= AtlasOfGroupRepresentationsInfo.characterinfo.( record.groupname ); if IsBound( info[1] ) then info:= info[1]; pos:= Position( info[2], repid{ [ 1 .. Position( repid, '.' ) - 1 ] } ); if pos <> fail and info[3][ pos ] <> fail then record.charactername:= info[3][ pos ]; fi; fi; fi; end, # `[ <i>, <dim>, <id>, <m>, <filename> ]' AddFileInfo := function( list, entry, name ) if 0 < entry[5] then Add( list, Concatenation( entry{ [ 3, 5, 6, 8 ] }, [ name ] ) ); return true; fi; return false; end, AccessGroupCondition := function( info, cond ) return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) and AGR.CheckOneCondition( IsMatrixGroup, cond ) and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) and AGR.CheckOneCondition( Characteristic, p -> p = 0 or ( IsFunction( p ) and p( 0 ) = true ), cond ) and AGR.CheckOneCondition( Dimension, x -> ( IsFunction( x ) and x( info.dim ) = true ) or info.dim = x, cond ) and AGR.CheckOneCondition( Ring, x -> IsIdenticalObj( x, Cyclotomics ) or ( IsBound( info.ring ) and ( ( IsFunction( x ) and x( info.ring ) = true ) or ( IsRing( x ) and IsCyclotomicCollection( x ) and IsSubset( x, info.ring ) ) ) ), cond ) and AGR.CheckOneCondition( Identifier, x -> ( IsFunction( x ) and x( info.id ) = true ) or info.id = x, cond ) and IsEmpty( cond ); end, TestFileHeaders := function( tocid, groupname, entry, type ) return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, entry[2], function( entry, mats, filename ) local info; if not IsCyclotomicCollCollColl( mats ) then return Concatenation( "matrices in `",filename, "' are not over cyclotomics" ); elif ForAll( Flat( mats ), IsInt ) then return Concatenation( "matrices in `",filename, "' are over the integers" ); fi; filename:= filename{ [ 1 .. Position( filename, '.' )-1 ] }; info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, triple -> triple[1] = filename ); if info = fail then return Concatenation( "field info for `",filename, "' missing" ); elif Field( Rationals, Flat( mats ) ) <> info[3] then return Concatenation( "field info for `",filename, "' should be ", String( Field( Rationals, Flat( mats ) ) ) ); fi; return true; end ); end, DisplayGroup := function( r ) local fld, disp; fld:= r.identifier[2]; fld:= fld{ [ 1 .. Length( fld )-2 ] }; fld:= First( AtlasOfGroupRepresentationsInfo.ringinfo, p -> p[1] = fld ); if AGR.ShowOnlyASCII() then if fld <> fail then fld:= fld[2]; else fld:= "C"; fi; disp:= Concatenation( "G <= GL(", String( r.dim ), r.id, ",", fld, ")" ); if IsBound( r.charactername ) then disp:= [ disp, Concatenation( "character ", r.charactername ) ]; fi; else if fld <> fail then fld:= fld[2]; else fld:= "ℂ"; fi; disp:= Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",", fld, ")" ); if IsBound( r.charactername ) then disp:= [ disp, Concatenation( "χ = ", r.charactername ) ]; fi; fi; return disp; end, # Matrix representations over algebraic extension fields are sorted # according to dimension and identification string. SortTOCEntries := entry -> entry{ [ 2, 3 ] }, ReadAndInterpretDefault := path -> AtlasDataGAPFormatFile( path ).generators, ) ); ############################################################################# ## #D Matrix representations over residue class rings ## ## <#GAPDoc Label="type:matmodn:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-Z<A>n</A>r<A>dim</A><A>id</A>B<A>m</A>.g</C></Mark> ## <Item> ## a &GAP; readable file ## containing all generators of a matrix representation of dimension ## <A>dim</A> over the ring of integers mod <A>n</A>. ## An example is <C>2A8G1-Z4r4aB0.g</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "rep", "matmodn", rec( # `<groupname>G<i>-Z<n>r<dim><id>B<m>.g' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "Z", IsDigitChar, "r", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, "B", IsDigitChar, ".g" ] ], [ ParseBackwards, ParseForwards ] ], AddDescribingComponents := function( record, type ) local parsed; parsed:= AGR.ParseFilenameFormat( record.identifier[2], type[2].FilenameFormat ); record.dim:= Int( parsed[7] ); record.id:= parsed[8]; record.ring:= ZmodnZ( parsed[5] ); end, # `[ <i>, <n>, <dim>, <id>, <m>, <filename> ]' AddFileInfo := function( list, entry, name ) if 0 < entry[5] and 0 < entry[7] then Add( list, Concatenation( entry{ [ 3, 5, 7, 8, 10 ] }, [ name ] ) ); return true; fi; return false; end, AccessGroupCondition := function( info, cond ) return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) and AGR.CheckOneCondition( IsMatrixGroup, cond ) and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) and AGR.CheckOneCondition( Characteristic, p -> p = fail or ( IsFunction( p ) and p( fail ) = true ), cond ) and AGR.CheckOneCondition( Dimension, x -> ( IsFunction( x ) and x( info.dim ) ) or info.dim = x, cond ) and AGR.CheckOneCondition( Ring, R -> ( IsFunction( R ) and R( info.ring ) ) or ( IsRing( R ) and IsZmodnZObjNonprimeCollection( R ) and ModulusOfZmodnZObj( One( R ) ) = Size( info.ring ) ), cond ) and AGR.CheckOneCondition( Identifier, x -> ( IsFunction( x ) and x( info.id ) = true ) or info.id = x, cond ) and IsEmpty( cond ); end, DisplayGroup := function( r ) if AGR.ShowOnlyASCII() then return Concatenation( "G <= GL(",String( r.dim ), r.id, ",Z/", String( r.identifier[4] ),"Z)" ); else return Concatenation( "G ≤ GL(",String( r.dim ), r.id, ",ℤ/", String( r.identifier[4] ),"ℤ)" ); fi; end, TestFileHeaders := function( tocid, groupname, entry, type ) return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, entry[3], function( entry, mats, filename ) if not IsZmodnZObjNonprimeCollCollColl( mats ) then return Concatenation( "matrices in `", filename, "' are not over a residue class ring" ); elif ModulusOfZmodnZObj( mats[1][1][1] ) <> entry[2] then return Concatenation( "matrices in `", filename, "' are not over Z/", entry[2], "Z" ); fi; return true; end ); end, # Matrix representations over residue class rings are sorted according # to modulus, dimension, and identification string. SortTOCEntries := entry -> entry{ [ 2 .. 4 ] }, ReadAndInterpretDefault := path -> AtlasDataGAPFormatFile( path ).generators, ) ); ############################################################################# ## #D Quaternionic matrix representations ## ## <#GAPDoc Label="type:quat:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-Hr<A>dim</A><A>id</A>B<A>m</A>.g</C></Mark> ## <Item> ## a &GAP; readable file ## containing all generators of a matrix representation ## over a quaternion algebra over an algebraic number field, ## of dimension <A>dim</A>. ## An example is <C>2A6G1-Hr2aB0.g</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "rep", "quat", rec( # `<groupname>G<i>-Hr<dim><id>B<m>.g' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "Hr", IsDigitChar, AGR.IsLowerAlphaOrDigitChar, "B", IsDigitChar, ".g" ] ], [ ParseBackwards, ParseForwards ] ], AddDescribingComponents := function( record, type ) local parsed, info; parsed:= AGR.ParseFilenameFormat( record.identifier[2], type[2].FilenameFormat ); record.dim:= Int( parsed[5] ); record.id:= parsed[6]; info:= record.identifier[2]; info:= info{ [ 1 .. Position( info, '.' )-1 ] }; info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, x -> x[1] = info ); if info <> fail then record.ring:= info[3]; fi; end, # `[ <i>, <dim>, <id>, <m>, <filename> ]' AddFileInfo := function( list, entry, name ) if 0 < entry[5] then Add( list, Concatenation( entry{ [ 3, 5, 6, 8 ] }, [ name ] ) ); return true; fi; return false; end, AccessGroupCondition := function( info, cond ) return AGR.CheckOneCondition( IsMatrixGroup, x -> x = true, cond ) and AGR.CheckOneCondition( IsMatrixGroup, cond ) and AGR.CheckOneCondition( IsPermGroup, x -> x = false, cond ) and AGR.CheckOneCondition( Characteristic, p -> p = 0 or ( IsFunction( p ) and p( 0 ) = true ), cond ) and AGR.CheckOneCondition( Dimension, x -> ( IsFunction( x ) and x( info.dim ) = true ) or info.dim = x, cond ) and AGR.CheckOneCondition( Ring, x -> IsBound( info.ring ) and ( ( IsFunction( x ) and x( info.ring ) = true ) or ( IsRing( x ) and IsQuaternionCollection( x ) and IsSubset( x, info.ring ) ) ), cond ) and AGR.CheckOneCondition( Identifier, x -> ( IsFunction( x ) and x( info.id ) = true ) or info.id = x, cond ) and IsEmpty( cond ); end, TestFileHeaders := function( tocid, groupname, entry, type ) return AGR.TestFileHeadersDefault( tocid, groupname, entry, type, entry[2], function( entry, mats, filename ) local info; if not ForAll( mats, IsQuaternionCollColl ) then return Concatenation( "matrices in `",filename, "' are not over the quaternions" ); fi; filename:= filename{ [ 1 .. Position( filename, '.' )-1 ] }; info:= First( AtlasOfGroupRepresentationsInfo.ringinfo, triple -> triple[1] = filename ); if info = fail then return Concatenation( "field info for `",filename, "' missing" ); elif Field( Flat( List( Flat( mats ), ExtRepOfObj ) ) ) <> EvalString( Concatenation( "Field", info[2]{ [ Position( info[2], '(' ) .. Length( info[2] ) ] } ) ) then return Concatenation( "field info for `", filename, "' should involve ", Field( Flat( List( Flat( mats ), ExtRepOfObj ) ) ) ); fi; return true; end ); end, DisplayGroup := function( r ) local fld; fld:= r.identifier[2]; fld:= fld{ [ 1 .. Length( fld )-2 ] }; fld:= First( AtlasOfGroupRepresentationsInfo.ringinfo, p -> p[1] = fld ); if AGR.ShowOnlyASCII() then if fld = fail then fld:= "QuaternionAlgebra(C)"; else fld:= fld[2]; fi; return Concatenation( "G <= GL(", String( r.dim ), r.id, ",", fld, ")" ); else if fld = fail then fld:= "QuaternionAlgebra(ℂ)"; else fld:= fld[2]; fi; return Concatenation( "G ≤ GL(", String( r.dim ), r.id, ",", fld, ")" ); fi; end, # Matrix representations over the quaternions are sorted according to # dimension and identification string. SortTOCEntries := entry -> entry{ [ 2, 3 ] }, ReadAndInterpretDefault := path -> AtlasDataGAPFormatFile( path ).generators, ) ); ############################################################################# ## #D Straight line programs for generators of maximal subgroups ## ## <#GAPDoc Label="type:maxes:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-max<A>k</A>W<A>n</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that takes ## generators of <M>G</M> w.r.t. the <A>i</A>-th set of standard ## generators, ## and returns a list of generators ## (in general <E>not</E> standard generators) ## for a subgroup <M>U</M> in the <A>k</A>-th class of maximal subgroups ## of <M>G</M>. ## An example is <C>J1G1-max7W1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "maxes", rec( # `<groupname>G<i>-max<k>W<n>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "max", IsDigitChar, "W", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], # `[ <i>, <k>, <filename> ]' AddFileInfo := function( list, entry, name ) if 0 < entry[5] then Add( list, Concatenation( entry{ [ 3, 5 ] }, [ name ] ) ); return true; fi; return false; end, DisplayOverviewInfo := [ "maxes", "r", function( conditions ) local groupname, tocs, std, value, private, toc, record, comp, new; groupname:= conditions[1][2]; tocs:= AGR.TablesOfContents( conditions ); if Length( conditions ) = 1 or not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then std:= true; else std:= conditions[2]; if IsInt( std ) then std:= [ std ]; fi; fi; value:= []; private:= false; for toc in tocs do if IsBound( toc.( groupname ) ) then record:= toc.( groupname ); for comp in [ "maxes", "maxext" ] do if IsBound( record.( comp ) ) then new:= List( Filtered( record.( comp ), x -> std = true or x[1] in std ), x -> x[2] ); if IsBound( toc.diridPrivate ) and not IsEmpty( new ) then private:= true; fi; UniteSet( value, new ); fi; od; fi; od; if IsEmpty( value ) then value:= ""; else value:= String( Length( value ) ); fi; return [ value, private ]; end ], DisplayPRG := function( tocs, name, std, stdavail ) local maxes, maxstd, maxprv, j, toc, record, comp, i, private, pos, pi, result, entry, line, width; maxes := []; maxstd := []; maxprv := []; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); for comp in [ "maxes", "maxext" ] do if IsBound( record.( comp ) ) then for i in record.( comp ) do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then private:= AtlasOfGroupRepresentationsInfo.markprivate; else private := ""; fi; if i[2] in maxes then pos:= Position( maxes, i[2] ); Add( maxstd[ pos ], i[1] ); Add( maxprv[ pos ], private ); else Add( maxes, i[2] ); Add( maxstd, [ i[1] ] ); Add( maxprv, [ private ] ); fi; fi; od; fi; od; fi; od; pi:= Sortex( maxes ); maxstd:= Permuted( maxstd, pi ); maxprv:= Permuted( maxprv, pi ); result:= []; if not IsEmpty( maxes ) then entry:= First( AtlasOfGroupRepresentationsInfo.GAPnames, x -> x[2] = name ); if IsBound( entry[3].nrMaxes ) then line:= "maxes ("; if Length( Set( maxes ) ) = entry[3].nrMaxes then Append( line, "all " ); else Append( line, String( Length( Set( maxes ) ) ) ); Append( line, " out of " ); fi; Append( line, String( entry[3].nrMaxes ) ); Append( line, ")" ); else line:= "maxes"; fi; Add( result, line ); width:= Length( String( maxes[ Length( maxes ) ] ) ); for i in [ 1 .. Length( maxes ) ] do if 1 < Length( stdavail ) then for j in [ 1 .. Length( maxstd[i] ) ] do line:= ""; Append( line, String( maxes[i], width ) ); Append( line, " (w.r.t. std. gen. " ); Append( line, String( maxstd[i][j] ) ); Append( line, maxprv[i][j] ); Append( line, ")" ); Add( result, line ); od; else line:= ""; Append( line, String( maxes[i], width ) ); Append( line, maxprv[i][1] ); if IsBound( entry[3].structureMaxes ) and IsBound( entry[3].structureMaxes[ maxes[i] ] ) then Append( line, ": " ); Append( line, entry[3].structureMaxes[ maxes[i] ] ); fi; Add( result, line ); fi; od; fi; return result; end, # Create the program info from the identifier. AtlasProgramInfo := function( type, identifier, prefix, groupname ) local i, result, gapname; i:= identifier[2]; if not IsString( i ) then i:= i[1]; fi; i:= AGR.ParseFilenameFormat( i, type[2].FilenameFormat ); if i = fail then return fail; fi; i:= i[5]; result:= rec( standardization := identifier[3], identifier := identifier ); # Set the size if available. gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, pair -> pair[2] = groupname ); if IsBound( gapname[3].sizesMaxes ) and IsBound( gapname[3].sizesMaxes[i] ) then result.size:= gapname[3].sizesMaxes[i]; fi; if IsBound( gapname[3].structureMaxes ) and IsBound( gapname[3].structureMaxes[i] ) then result.subgroupname:= gapname[3].structureMaxes[i]; fi; return result; end, # Create the program from the identifier. AtlasProgram := function( type, identifier, prefix, groupname ) local i, prog, info, entry, result, gapname; i:= identifier[2]; if not IsString( i ) then i:= i[1]; fi; i:= AGR.ParseFilenameFormat( i, type[2].FilenameFormat ); if i = fail then return fail; fi; i:= i[5]; # The second entry is either a filename or a filename plus info about # additional generators. if ForAll( identifier[2], IsString ) then # One program for a factor group and some kernel generators # must be integrated. prog:= AGR.FileContents( prefix, groupname, identifier[2][1], type ); if prog = fail then return fail; fi; prog:= [ prog.program ]; info:= AGR.InfoForName( identifier[1] ); if IsBound( info[3].kernelPrograms ) then for entry in info[3].kernelPrograms do if entry[1] = identifier[3] and entry[2] = identifier[2][2] then Add( prog, StraightLineProgram( entry[3], NrInputsOfStraightLineProgram( prog[1] ) ) ); break; fi; od; fi; if Length( prog ) = 1 then return fail; fi; prog:= IntegratedStraightLineProgramExt( prog ); result:= rec( program := prog, standardization := identifier[3], identifier := identifier ); else result:= AtlasProgramDefault( type, identifier, prefix, groupname ); fi; # Set subgroup size and subgroup name if available. if result <> fail then gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, pair -> pair[2] = groupname ); if IsBound( gapname[3].sizesMaxes ) and IsBound( gapname[3].sizesMaxes[i] ) then result.size:= gapname[3].sizesMaxes[i]; fi; if IsBound( gapname[3].structureMaxes ) and IsBound( gapname[3].structureMaxes[i] ) then result.subgroupname:= gapname[3].structureMaxes[i]; fi; fi; return result; end, # entry: `[ <std>, <maxnr>, <file> ]', # conditions: `[ "maxes", <maxnr> ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 2 and conditions[1] = "maxes" and IsPosInt( conditions[2] ) then if IsBound( record.maxes ) then for entry in record.maxes do if ( std = true or entry[1] in std ) and entry[2] = conditions[2] then return entry{ [ 3, 1 ] }; fi; od; fi; if IsBound( record.maxext ) then for entry in record.maxext do if ( std = true or entry[1] in std ) and entry[2] = conditions[2] then if Length( entry[3] ) = 1 then return [ entry[3][1], entry[1] ]; else return entry{ [ 3, 1 ] }; fi; fi; od; fi; fi; return fail; end, # Maxes are sorted according to their natural position. SortTOCEntries := entry -> entry[2], # In addition to the tests in `AGR.TestWordsSLPDefault', # compute the images in a representation if available, # and compare the group order with that stored in the # GAP Character Table Library (if available). TestWords:= function( tocid, name, file, type, verbose ) local prog, prg, gens, pos, pos2, maxnr, gapname, storedsize, tbl, subname, subtbl, std, grp, size; # Read the program. if tocid = "local" then tocid:= "dataword"; fi; prog:= AGR.FileContents( tocid, name, file, type ); if prog = fail then Print( "#E file `", file, "' is corrupted\n" ); return false; fi; # Check consistency. if prog = fail or not IsInternallyConsistent( prog.program ) then Print( "#E program `", file, "' not internally consistent\n" ); return false; fi; prg:= prog.program; # Create a list of trivial generators. gens:= ListWithIdenticalEntries( NrInputsOfStraightLineProgram( prg ), () ); # Run the program. gens:= ResultOfStraightLineProgram( prg, gens ); # Compute the position in the `Maxes' list. pos:= PositionSublist( file, "-max" ); pos2:= pos + 4; while file[ pos2 ] <> 'W' do pos2:= pos2 + 1; od; maxnr:= Int( file{ [ pos+4 .. pos2-1 ] } ); # Fetch a perhaps stored value. gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, pair -> name = pair[2] ); if gapname = fail then Print( "#E problem: no GAP name for `", name, "'\n" ); return false; fi; storedsize:= fail; if IsBound( gapname[4] ) and IsBound( gapname[4][ maxnr ] ) then storedsize:= gapname[4][ maxnr ]; fi; # Identify the group in the GAP Character Table Library. tbl:= CharacterTable( gapname[1] ); if tbl = fail and storedsize = fail then if verbose then Print( "#I no character table for `", gapname[1], "', no check for `", file, "'\n" ); fi; return true; fi; # Identify the subgroup in the GAP Character Table Library. if tbl <> fail then if HasMaxes( tbl ) then if Length( Maxes( tbl ) ) < maxnr then Print( "#E program `", file, "' contradicts `Maxes( ", tbl, " )'\n" ); return false; fi; subname:= Maxes( tbl )[ maxnr ]; else subname:= Concatenation( Identifier( tbl ), "M", String( maxnr ) ); fi; subtbl:= CharacterTable( subname ); if IsCharacterTable( subtbl ) then if storedsize <> fail and storedsize <> Size( subtbl ) then Print( "#E program `", file, "' contradicts stored subgroup order'\n" ); return false; elif storedsize = fail then storedsize:= Size( subtbl ); fi; elif storedsize = fail then if verbose then Print( "#I no character table for `", subname, "', no check for `", file, "'\n" ); fi; return true; fi; fi; if storedsize = fail then return true; fi; # Compute the standardization. pos2:= pos - 1; while file[ pos2 ] <> 'G' do pos2:= pos2-1; od; std:= Int( file{ [ pos2+1 .. pos-1 ] } ); # Get a representation if available, and map the generators. gapname:= gapname[1]; gens:= OneAtlasGeneratingSetInfo( gapname, std, NrMovedPoints, [ 2 .. AGR.Test.MaxTestDegree ] ); if gens = fail then if verbose then Print( "#I no perm. repres. for `", gapname, "', no check for `", file, "'\n" ); fi; else gens:= AtlasGenerators( gens ); grp:= Group( gens.generators ); if tbl <> fail then if IsBound( gens.size ) and gens.size <> Size( tbl ) then Print( "#E wrong size for group`", gapname, "'\n" ); return false; fi; SetSize( grp, Size( tbl ) ); fi; gens:= ResultOfStraightLineProgram( prg, gens.generators ); size:= Size( SubgroupNC( grp, gens ) ); if size <> storedsize then Print( "#E program `", file, "' for group of order ", size, " not ", storedsize, "\n" ); if subtbl <> fail then Print( "#E (contradicts character table of `", Identifier( subtbl ), "')\n" ); fi; return false; fi; fi; # No more tests are available. return true; end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Straight line programs for class representatives ## ## <#GAPDoc Label="type:classes:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-cclsW<A>n</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that returns ## a list of conjugacy class representatives of <M>G</M>. ## An example is <C>RuG1-cclsW1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "classes", rec( # `<groupname>G<i>-cclsW<n>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "cclsW", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], # `[ <i>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, Concatenation( entry{ [ 3 ] }, [ name ] ) ); return true; end, DisplayOverviewInfo := [ "cl", "c", function( conditions ) local groupname, tocs, std, value, private, toc, record, i, pos, rel; groupname:= conditions[1][2]; tocs:= AGR.TablesOfContents( conditions ); if Length( conditions ) = 1 or not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then std:= true; else std:= conditions[2]; if IsInt( std ) then std:= [ std ]; fi; fi; value:= false; private:= false; for toc in tocs do if IsBound( toc.( groupname ) ) then record:= toc.( groupname ); if IsBound( record.classes ) and ( ( std = true and not IsEmpty( record.classes ) ) or ForAny( record.classes, l -> l[1] in std ) ) then value:= true; elif IsBound( record.cyc2ccl ) and IsBound( record.cyclic ) then for i in record.cyc2ccl do # Check that for scripts of the form # `<groupname>G<i>cycW<n>-cclsW<m>', # a script of the form `<groupname>G<i>-cycW<n>' is available. pos:= PositionSublist( i[2], "cycW" ); rel:= Concatenation( i[2]{ [ 1 .. pos-1 ] }, "-", i[2]{ [ pos .. Position( i[2], '-' ) - 1 ] } ); if ( std = true or i[1] in std ) and ForAny( record.cyclic, x -> x[2] = rel and ( std = true or x[1] in std ) ) then value:= true; break; fi; od; fi; if value then if IsBound( toc.diridPrivate ) then private:= true; fi; break; fi; fi; od; if value then value:= "+"; else value:= ""; fi; return [ value, private ]; end ], DisplayPRG := function( tocs, name, std, stdavail ) local ccl, c2c, cyc, private, toc, record, i, pos, rel; # (The information can be stored either directly or via two scripts # in `cyclic' and `cyc2ccl'.) ccl:= []; c2c:= []; cyc:= []; private:= ""; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.classes ) then for i in record.classes do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then private:= AtlasOfGroupRepresentationsInfo.markprivate; fi; Add( ccl, i ); fi; od; fi; if IsBound( record.cyc2ccl ) then for i in record.cyc2ccl do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then private:= AtlasOfGroupRepresentationsInfo.markprivate; fi; Add( c2c, i ); fi; od; fi; if IsBound( record.cyclic ) then for i in record.cyclic do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then private:= AtlasOfGroupRepresentationsInfo.markprivate; fi; Add( cyc, i ); fi; od; fi; fi; od; for i in c2c do # Check if for scripts of the form `<groupname>G<i>cycW<n>-cclsW<m>', # a script of the form `<groupname>G<i>-cycW<n>' is available. pos:= PositionSublist( i[2], "cycW" ); rel:= Concatenation( i[2]{ [ 1 .. pos-1 ] }, "-", i[2]{ [ pos .. Position( i[2], '-' ) - 1 ] } ); if ForAny( cyc, x -> x[2] = rel ) then Add( ccl, i ); fi; od; if IsEmpty( ccl ) then return []; elif 1 < Length( stdavail ) then return [ Concatenation( "class repres.", " for std. generators ", String( Set( List( ccl, x -> x[1] ) ) ), private ) ]; else return [ Concatenation( "class repres.", private ) ]; fi; end, # entry: `[ <std>, <file> ]', # conditions: `[ "classes" ]' AccessPRG := function( record, std, conditions ) local entry, pos, rel, entry2; if not ( Length( conditions ) = 1 and conditions[1] = "classes" ) then return fail; elif IsBound( record.classes ) then for entry in record.classes do if std = true or entry[1] in std then return entry{ [ 2, 1 ] }; fi; od; fi; if IsBound( record.cyclic ) and IsBound( record.cyc2ccl ) then for entry in record.cyc2ccl do if std = true or entry[1] in std then # Check if for scripts of the form # `<groupname>G<i>cycW<n>-cclsW<m>', # a script of the form `<groupname>G<i>-cycW<n>' is available. pos:= PositionSublist( entry[2], "cycW" ); rel:= Concatenation( entry[2]{ [ 1 .. pos-1 ] }, "-", entry[2]{ [ pos .. Position( entry[2], '-' ) - 1 ] } ); for entry2 in record.cyclic do if entry2[2] = rel and ( std = true or entry2[1] in std ) then return [ [ entry[2], entry2[2] ], entry[1] ]; fi; od; fi; od; fi; return fail; end, # Create the program info from the identifier. AtlasProgramInfo := function( type, identifier, prefix, groupname ) # The second entry is either a filename or a pair of filenames. if ForAll( identifier[2], IsString ) then return rec( standardization := identifier[3], identifier := identifier ); elif IsString( identifier[2] ) then return AtlasProgramInfoDefault( type, identifier, prefix, groupname ); fi; return fail; end, # Create the program from the identifier. AtlasProgram := function( type, identifier, prefix, groupname ) local progs, prog, i, result; # The second entry is either a filename or a pair of filenames. if ForAll( identifier[2], IsString ) then # Two programs have to be composed. progs:= List( identifier[2], name -> AGR.FileContents( prefix, groupname, name, type ) ); if fail in progs then return fail; fi; prog:= progs[1].program; for i in [ 2 .. Length( progs ) ] do prog:= CompositionOfStraightLinePrograms( prog, progs[i].program ); if prog = fail then return fail; fi; od; result:= rec( program := prog, standardization := identifier[3], identifier := identifier ); if IsBound( progs[1].outputs ) then # Take the outputs of the last program in the composition. result.outputs:= progs[1].outputs; fi; return result; elif IsString( identifier[2] ) then return AtlasProgramDefault( type, identifier, prefix, groupname ); fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLPDefault( tocid, name, file, type, true, verbose ); end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Straight line programs for representatives of cyclic subgroups ## ## <#GAPDoc Label="type:cyclic:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-cycW<A>n</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that returns ## a list of representatives of generators ## of maximally cyclic subgroups of <M>G</M>. ## An example is <C>Co1G1-cycW1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "cyclic", rec( # `<groupname>G<i>-cycW<n>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "cycW", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], # `[ <i>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, Concatenation( entry{ [ 3 ] }, [ name ] ) ); return true; end, DisplayOverviewInfo := AGR.DisplayOverviewInfoDefault( "cyc", "c", "cyclic" ), DisplayPRG := function( tocs, name, std, stdavail ) local cyc, private, toc, record, i; cyc:= []; private:= ""; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.cyclic ) then for i in record.cyclic do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then private:= AtlasOfGroupRepresentationsInfo.markprivate; fi; Add( cyc, i[2] ); fi; od; fi; fi; od; if IsEmpty( cyc ) then return []; elif 1 < Length( stdavail ) then return [ Concatenation( "repr. cyc. subg.", " for std. generators ", String( Set( List( cyc, x -> x[1] ) ) ), private ) ]; else return [ Concatenation( "repr. cyc. subg.", private ) ]; fi; end, # entry: `[ <std>, <file> ]', # conditions: `[ "cyclic" ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 1 and conditions[1] = "cyclic" and IsBound( record.cyclic ) then for entry in record.cyclic do if std = true or entry[1] in std then return entry{ [ 2, 1 ] }; fi; od; fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLPDefault( tocid, name, file, type, true, verbose ); end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Straight line programs for computing class representatives from #D representatives of cyclic subgroups ## ## <#GAPDoc Label="type:cyc2ccls:format"> ## <Mark><C><A>groupname</A>G<A>i</A>cycW<A>n</A>-cclsW<A>m</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that takes ## the return value of the program in the file ## <A>groupname</A><C>G</C><A>i</A><C>-cycW</C><A>n</A> ## (see above), ## and returns a list of conjugacy class representatives of <M>G</M>. ## An example is <C>M11G1cycW1-cclsW1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "cyc2ccl", rec( # `<groupname>G<i>cycW<n>-cclsW<m>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar, "cycW", IsDigitChar ], [ "cclsW", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], # `[ <i>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, Concatenation( entry{ [ 3 ] }, [ name ] ) ); return true; end, # entry: `[ <std>, <file> ]', # conditions: `[ "cyc2ccl" ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 1 and conditions[1] = "cyc2ccl" and IsBound( record.cyc2ccl ) then for entry in record.cyc2ccl do if std = true or entry[1] in std then return entry{ [ 2, 1 ] }; fi; od; fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLPDefault( tocid, name, file, type, true, verbose ); end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Straight line programs for computing standard generators of #D maximal subgroups ## ## <#GAPDoc Label="type:maxstd:format"> ## <Mark><C><A>groupname</A>G<A>i</A>max<A>k</A>W<A>n</A>-<A>subgroupname</A>G<A>j</A>W<A>m</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that takes ## the return value of the program in the file ## <A>groupname</A><C>G</C><A>i</A><C>-max</C><A>k</A><C>W</C><A>n</A> ## (see above), ## which are generators for a group <M>U</M>, say; ## <A>subgroupname</A> is a name for <M>U</M>, ## and the return value is a list of standard generators for <M>U</M>, ## w.r.t. the <A>j</A>-th set of standard generators. ## (Of course this implies that the groups in the <A>k</A>-th class of ## maximal subgroups of <M>G</M> are isomorphic to the group with name ## <A>subgroupname</A>.) ## An example is <C>J1G1max1W1-L211G1W1</C>; ## the first class of maximal subgroups of the Janko group <M>J_1</M> ## consists of groups isomorphic to the linear group <M>L_2(11)</M>, ## for which standard generators are defined. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "maxstd", rec( # `<groupname>G<i>max<k>W<n>-<subgroupname>G<j>W<m>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar, "max", IsDigitChar, "W", IsDigitChar ], [ IsChar, "G", IsDigitChar, "W", IsDigitChar ] ], [ ParseBackwards, ParseBackwards ] ], # `[ <i>, <k>, <subgroupname>, <j>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, Concatenation( entry{ [ 3, 5, 8, 10 ] }, [ name ] ) ); return true; end, PostprocessFileInfo := function( toc, record ) local list, i; list:= record.maxstd; for i in [ 1 .. Length( list ) ] do if not IsBound( toc.( list[i][3] ) ) then Info( InfoAtlasRep, 3, "t.o.c. construction: ignoring name `", list[i][5], "'" ); Unbind( list[i] ); fi; od; if not IsDenseList( list ) then record.maxstd:= Compacted( list ); fi; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Straight line programs for computing images of standard generators #D under outer automorphisms ## ## <#GAPDoc Label="type:out:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-a<A>outname</A>W<A>n</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that takes ## generators of <M>G</M> w.r.t. the <A>i</A>-th set of standard ## generators, ## and returns the list of their images ## under the outer automorphism <M>\alpha</M> of <M>G</M> ## given by the name <A>outname</A>; ## if this name is empty then <M>\alpha</M> is the unique nontrivial ## outer automorphism of <M>G</M>; ## if it is a positive integer <M>k</M> then <M>\alpha</M> is a ## generator of the unique cyclic order <M>k</M> subgroup of the outer ## automorphism group of <M>G</M>; ## if it is of the form <C>2_1</C> or <C>2a</C>, ## <C>4_2</C> or <C>4b</C>, <C>3_3</C> or <C>3c</C> ## <M>\ldots</M> then <M>\alpha</M> ## generates the cyclic group of automorphisms induced on <M>G</M> by ## <M>G.2_1</M>, <M>G.4_2</M>, <M>G.3_3</M> <M>\ldots</M>; ## finally, if it is of the form <A>k</A><C>p</C><A>d</A>, ## with <A>k</A> one of the above forms and <A>d</A> an integer then ## <A>d</A> denotes the number of dashes ## appended to the automorphism described by <A>k</A>; ## if <M><A>d</A> = 1</M> then <A>d</A> can be omitted. ## Examples are <C>A5G1-aW1</C>, <C>L34G1-a2_1W1</C>, ## <C>U43G1-a2_3pW1</C>, and <C>O8p3G1-a2_2p5W1</C>; ## these file names describe the outer order <M>2</M> automorphism of ## <M>A_5</M> (induced by the action of <M>S_5</M>) ## and the order <M>2</M> automorphisms of ## <M>L_3(4)</M>, <M>U_4(3)</M>, and <M>O_8^+(3)</M> ## induced by the actions of ## <M>L_3(4).2_1</M>, <M>U_4(3).2_2^{\prime}</M>, ## and <M>O_8^+(3).2_2^{{\prime\prime\prime\prime\prime}}</M>, ## respectively. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "out", rec( # `<groupname>G<i>-a<outname>W<n>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "a", IsChar, "W", IsDigitChar ] ], [ ParseBackwards, ParseBackwardsWithPrefix ] ], # `[ <i>, <nam>, <filename> ]' AddFileInfo := function( list, entry, name ) local std, descr, pos, dashes, order, index; std:= entry[3]; descr:= entry[5]; pos:= Position( descr, 'p' ); if pos = fail then dashes:= ""; pos:= Length( descr ) + 1; elif pos = Length( descr ) then dashes:= "'"; else dashes:= Int( descr{ [ pos+1 .. Length( descr ) ] } ); if dashes = fail then return false; fi; dashes:= ListWithIdenticalEntries( dashes, '\'' ); fi; descr:= descr{ [ 1 .. pos-1 ] }; pos:= Position( descr, '_' ); if pos = fail then order:= descr; index:= ""; else order:= descr{ [ 1 .. pos-1 ] }; index:= descr{ [ pos+1 .. Length( descr ) ] }; fi; if Int( order ) = fail or Int( index ) = fail then return false; elif order = "" then order:= "2"; fi; if index <> "" then order:= Concatenation( order, "_", index ); fi; order:= Concatenation( order, dashes ); Add( list, [ std, order, name ] ); return true; end, DisplayOverviewInfo := [ "out", "r", function( conditions ) local groupname, tocs, std, value, private, toc, record, new; groupname:= conditions[1][2]; tocs:= AGR.TablesOfContents( conditions ); if Length( conditions ) = 1 or not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then std:= true; else std:= conditions[2]; if IsInt( std ) then std:= [ std ]; fi; fi; value:= [];; private:= false; for toc in tocs do if IsBound( toc.( groupname ) ) then record:= toc.( groupname ); if IsBound( record.out ) then new:= Set( List( Filtered( record.out, x -> std = true or x[1] in std ), x -> x[2] ) ); if IsBound( toc.diridPrivate ) and not IsEmpty( new ) then private:= true; fi; UniteSet( value, new ); fi; fi; od; value:= JoinStringsWithSeparator( value, "," ); return [ value, private ]; end ], DisplayPRG := function( tocs, name, std, stdavail ) local out, private, toc, record, i; out:= []; private:= AtlasOfGroupRepresentationsInfo.markprivate; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.out ) then for i in record.out do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then Add( out, Concatenation( i[2], private ) ); else Add( out, i[2] ); fi; fi; od; fi; fi; od; if not IsEmpty( out ) then out:= Concatenation( [ "automorphisms" ], out ); fi; return out; end, # entry: `[ <std>, <autname>, <file> ]', # conditions: `[ "automorphism", <autname> ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 2 and conditions[1] = "automorphism" and IsBound( record.out ) then for entry in record.out do if ( std = true or entry[1] in std ) and entry[2] = conditions[2] then return entry{ [ 3, 2 ] }; fi; od; fi; return fail; end, # It would be good to check whether the order of the automorphism # fits to the name of the script, but the scripts do not describe # automorphisms of minimal possible order. # (So the power given by the name of the script is an inner # automorphism; how could we check this with reasonable effort?) # Thus we check just whether the name fits to the structure of the # outer automorphism group and to the order of the automorphism. # (We copy the relevant part of the code of `AGR.TestWordsSLPDefault' # into this function.) TestWords := function( tocid, name, file, type, verbose ) local filename, prog, prg, gens, gapname, pos, claimedorder, tbl, outinfo, bound, imgs, order; # Read the program. if tocid = "local" then tocid:= "dataword"; fi; prog:= AGR.FileContents( tocid, name, file, type ); if prog = fail then Print( "#E file `", file, "' is corrupted\n" ); return false; fi; # Check consistency. if prog = fail or not IsInternallyConsistent( prog.program ) then Print( "#E program `", file, "' not internally consistent\n" ); return false; fi; prg:= prog.program; # Create the list of (trivial) generators. gens:= ListWithIdenticalEntries( NrInputsOfStraightLineProgram( prg ), () ); # Run the program. gens:= ResultOfStraightLineProgram( prg, gens ); # Get the GAP name of `name'. gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, pair -> name = pair[2] ); if gapname = fail then Print( "#E problem: no GAP name for `", name, "'\n" ); return false; fi; gapname:= gapname[1]; # Get the order of the automorphism from the filename. pos:= PositionSublist( file, "-a" ); claimedorder:= file{ [ pos+2 .. Length( file ) ] }; pos:= Position( claimedorder, 'W' ); claimedorder:= claimedorder{ [ 1 .. pos-1 ] }; pos:= Position( claimedorder, 'p' ); if pos <> fail then if not ForAll( claimedorder{ [ pos+1 .. Length( claimedorder ) ] }, IsDigitChar ) then Print( "#E wrong number of dashes in `", file, "'\n" ); return false; elif claimedorder{ [ pos+1 .. Length( claimedorder ) ] } = "0" then Print( "#E wrong name `", file, "'\n" ); return false; fi; claimedorder:= claimedorder{ [ 1 .. pos-1 ] }; fi; pos:= Position( claimedorder, '_' ); if pos <> fail then claimedorder:= claimedorder{ [ 1 .. pos-1 ] }; fi; if not ForAll( claimedorder, IsDigitChar ) then Print( "#E wrong name `", file, "'\n" ); return false; fi; claimedorder:= Int( claimedorder ); # Get the structure of the automorphism group. # If this group is cyclic then we compare orders. tbl:= CharacterTable( gapname ); if tbl <> fail and IsBound( AGR.HasExtensionInfoCharacterTable ) and AGR.HasExtensionInfoCharacterTable( tbl ) then outinfo:= AGR.ExtensionInfoCharacterTable( tbl )[2]; if outinfo = "" then Print( "#E automorphism `", file, "' for group without outer automorphisms\n" ); return false; elif outinfo <> "2" and claimedorder = 0 then Print( "#E automorphism `", file, "' but the outer automorphism is not unique\n" ); return false; elif Int( outinfo ) <> fail and claimedorder <> 0 and Int( outinfo ) mod claimedorder <> 0 then Print( "#E automorphism `", file, "' for outer automorphism group ", outinfo, "\n" ); return false; fi; fi; if claimedorder = 0 then claimedorder:= 2; fi; # Get generators of the group in question. gens:= OneAtlasGeneratingSetInfo( gapname ); if gens <> fail and tbl <> fail then gens:= AtlasGenerators( gens ); if gens <> fail then gens:= gens.generators; bound:= Exponent( tbl ) * claimedorder; # Compute the order of the automorphism. imgs:= ResultOfStraightLineProgram( prg, gens ); order:= 1; while order < bound and imgs <> gens do imgs:= ResultOfStraightLineProgram( prg, imgs ); order:= order + 1; od; if imgs <> gens then Print( "#E order ", order, " of automorphism `", file, "' is larger than ", bound, "\n" ); return false; elif order mod claimedorder <> 0 then Print( "#E order ", order, " of automorphism `", file, "' not divisible by ", claimedorder, "\n" ); return false; fi; fi; fi; return true; end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Straight line programs for switching between different standardizations ## ## <#GAPDoc Label="type:switch:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-G<A>j</A>W<A>n</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that takes ## generators of <M>G</M> w.r.t. the <A>i</A>-th set of standard ## generators, and returns standard generators of <M>G</M> ## w.r.t. the <A>j</A>-th set of standard generators. ## An example is <C>L35G1-G2W1</C>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "switch", rec( # `<groupname>G<i>-G<j>W<n>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "G", IsDigitChar, "W", IsDigitChar ] ], [ ParseBackwards, ParseForwards ] ], # `[ <i>, <j>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, [ entry[3], entry[5], name ] ); return true; end, DisplayPRG := function( tocs, name, std, stdavail ) local switch, private, toc, record, i; switch:= []; private:= AtlasOfGroupRepresentationsInfo.markprivate; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.switch ) then for i in record.switch do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then Add( switch, Concatenation( String( i[1] ), " -> ", String( i[2] ), private ) ); else Add( switch, Concatenation( String( i[1] ), " -> ", String( i[2] ) ) ); fi; fi; od; fi; fi; od; if not IsEmpty( switch ) then switch:= Concatenation( [ "restandardizations" ], switch ); fi; return switch; end, # entry: `[ <std>, <descr>, <file> ]', # conditions: `[ "restandardize", <std2> ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 2 and conditions[1] = "restandardize" and IsBound( record.switch ) then for entry in record.switch do if ( std = true or entry[1] in std ) and conditions[2] = entry[2] then return entry{ [ 3, 1, 2 ] }; fi; od; fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## #D Black box programs for finding standard generators ## ## <#GAPDoc Label="type:find:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-find<A>n</A></C></Mark> ## <Item> ## <Index Subkey="for finding standard generators">black box program ## </Index> ## In this case, the file contains a black box program that takes ## a group, and returns (if it is successful) a set of standard generators ## for <A>G</A>, w.r.t. the <A>i</A>-th standardization. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "find", rec( # `<groupname>G<i>-find<j>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "find", IsDigitChar ] ], [ ParseBackwards, ParseBackwardsWithPrefix ] ], # `[ <i>, <j>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, [ entry[3], entry[5], name ] ); return true; end, DisplayOverviewInfo := AGR.DisplayOverviewInfoDefault( "fnd", "c", "find" ), DisplayPRG := function( tocs, name, std, stdavail ) local find, private, toc, record, i; find:= []; private:= ""; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.find ) then for i in record.find do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then private:= AtlasOfGroupRepresentationsInfo.markprivate; fi; AddSet( find, String( i[1] ) ); fi; od; fi; fi; od; if IsEmpty( find ) then return []; elif 1 < Length( stdavail ) then return [ Concatenation( "std. gen. finder", " for std. generators ", JoinStringsWithSeparator( find, ", " ), private ) ]; else return [ Concatenation( "std. gen. finder", private ) ]; fi; end, # entry: `[ <std>, <version>, <file> ]', # conditions: `[ "find" ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 1 and conditions[1] = "find" and IsBound( record.find ) then for entry in record.find do if std = true or entry[1] in std then # the part of the identifier return entry{ [ 3, 1, 2 ] }; fi; od; fi; return fail; end, ReadAndInterpretDefault := path -> ScanBBoxProgram( StringFile( path ) ), # If there is a representation for this group (independent of the # standardization) then we apply the script, and check whether at least # the whole group is generated by the result; if also a `check' script # is available for this standardization then we run it on the result. TestWords := function( tocid, name, file, type, verbose ) local prog, prg, gapname, gens, G, res, pos, pos2, std, check; # Read the program. if tocid = "local" then tocid:= "dataword"; fi; prog:= AGR.FileContents( tocid, name, file, type ); if prog = fail then Print( "#E file `", file, "' is corrupted\n" ); return false; fi; prg:= prog.program; # Get the GAP name of `name'. gapname:= First( AtlasOfGroupRepresentationsInfo.GAPnames, pair -> name = pair[2] ); if gapname = fail then Print( "#E problem: no GAP name for `", name, "'\n" ); return false; fi; # Get generators of the group in question. gens:= OneAtlasGeneratingSetInfo( gapname[1] ); if gens <> fail then gens:= AtlasGenerators( gens ); if gens <> fail then gens:= gens.generators; G:= Group( gens ); if IsBound( gapname[3].size ) then SetSize( G, gapname[3].size ); fi; res:= ResultOfBBoxProgram( prg, G ); if IsList( res ) and not IsString( res ) then # Compute the standardization. pos:= Position( file, '-' ); pos2:= pos - 1; while file[ pos2 ] <> 'G' do pos2:= pos2-1; od; std:= Int( file{ [ pos2+1 .. pos-1 ] } ); check:= AtlasProgram( gapname[1], std, "check" ); if check <> fail then if not ResultOfStraightLineDecision( check.program, res ) then Print( "#E return values of `", file, "' do not fit to the check file\n" ); return false; fi; fi; # Check the group order only for permutation groups. if IsPermGroup( G ) then if not IsSubset( G, res ) then Print( "#E return values of `", file, "' do not lie in the group\n" ); return false; elif Size( SubgroupNC( G, res ) ) <> Size( G ) then Print( "#E return values of `", file, "' do not generate the group\n" ); return false; fi; fi; fi; fi; fi; return true; end, ) ); ############################################################################# ## #D Straight line programs for checking standard generators ## ## <#GAPDoc Label="type:check:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-check<A>n</A></C></Mark> ## <Item> ## <Index>semi-presentation</Index> ## In this case, the file contains a straight line decision that takes ## generators of <M>G</M>, and returns <K>true</K> if these generators are ## standard generators w.r.t. the <A>i</A>-th standardization, ## and <K>false</K> otherwise. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "check", rec( # `<groupname>G<i>-check<j>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "check", IsDigitChar ] ], [ ParseBackwards, ParseBackwardsWithPrefix ] ], # `[ <i>, <j>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, [ entry[3], entry[5], name ] ); return true; end, DisplayOverviewInfo := [ "chk", "c", function( conditions ) local groupname, tocs, std, value, private, toc, record; groupname:= conditions[1][2]; tocs:= AGR.TablesOfContents( conditions ); if Length( conditions ) = 1 or not ( IsInt( conditions[2] ) or IsList( conditions[2] ) ) then std:= true; else std:= conditions[2]; if IsInt( std ) then std:= [ std ]; fi; fi; value:= ""; private:= false; for toc in tocs do if IsBound( toc.( groupname ) ) then record:= toc.( groupname ); if ( IsBound( record.check ) and ForAny( record.check, x -> std = true or x[1] in std ) ) or ( IsBound( record.pres ) and ForAny( record.pres, x -> std = true or x[1] in std ) ) then value:= "+"; if IsBound( toc.diridPrivate ) then private:= true; fi; break; fi; fi; od; return [ value, private ]; end ], DisplayPRG := function( tocs, name, std, stdavail ) local check, private, toc, record, comp, i; check:= []; private:= AtlasOfGroupRepresentationsInfo.markprivate; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); for comp in [ "check", "pres" ] do if IsBound( record.( comp ) ) then for i in record.( comp ) do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then AddSet( check, Concatenation( i[1], private ) ); else AddSet( check, i[1] ); fi; fi; od; fi; od; fi; od; if IsEmpty( check ) then return []; elif 1 < Length( stdavail ) then return [ Concatenation( "std. gen. checker", " for std. generators ", JoinStringsWithSeparator( check, ", " ) ) ]; else return [ "std. gen. checker" ]; fi; end, # entry: `[ <std>, <version>, <file> ]', # conditions: `[ "check" ]' AccessPRG := function( record, std, conditions ) local entry, comp; if Length( conditions ) = 1 and conditions[1] = "check" then for comp in [ "check", "pres" ] do if IsBound( record.( comp ) ) then for entry in record.( comp ) do if std = true or entry[1] in std then # the part of the identifier return entry{ [ 3, 1, 2 ] }; fi; od; fi; od; fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLDDefault( tocid, name, file, type, [ IsChar, "G", IsDigitChar, "-check", IsDigitChar ], verbose ); end, ReadAndInterpretDefault := path -> ScanStraightLineDecision( StringFile( path ) ), ) ); ############################################################################# ## #D BBox programs representing presentations ## ## <#GAPDoc Label="type:pres:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-P<A>n</A></C></Mark> ## <Item> ## <Index>presentation</Index> ## In this case, the file contains a straight line decision that takes ## some group elements, and returns <K>true</K> if these elements are ## standard generators for <A>G</A>, ## w.r.t. the <A>i</A>-th standardization, ## and <K>false</K> otherwise. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "pres", rec( # `<groupname>G<i>-P<j>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "P", IsDigitChar ] ], [ ParseBackwards, ParseBackwardsWithPrefix ] ], # `[ <i>, <j>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, [ entry[3], entry[5], name ] ); return true; end, DisplayOverviewInfo := AGR.DisplayOverviewInfoDefault( "prs", "c", "pres" ), DisplayPRG := function( tocs, name, std, stdavail ) local pres, private, toc, record, i; pres:= []; private:= AtlasOfGroupRepresentationsInfo.markprivate; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.pres ) then for i in record.pres do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then AddSet( pres, Concatenation( String( i[1] ), private ) ); else AddSet( pres, String( i[1] ) ); fi; fi; od; fi; fi; od; if IsEmpty( pres ) then return []; elif 1 < Length( stdavail ) then return [ Concatenation( "presentation", " for std. generators ", JoinStringsWithSeparator( pres, ", " ) ) ]; else return [ "presentation" ]; fi; end, # entry: `[ <std>, <version>, <file> ]', # conditions: `[ "presentation" ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 1 and conditions[1] = "presentation" and IsBound( record.pres ) then for entry in record.pres do if std = true or entry[1] in std then # the part of the identifier return entry{ [ 3, 1, 2 ] }; fi; od; fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLDDefault( tocid, name, file, type, [ IsChar, "G", IsDigitChar, "-P", IsDigitChar ], verbose ); end, ReadAndInterpretDefault := path -> ScanStraightLineDecision( StringFile( path ) ), ) ); ############################################################################# ## #D Other straight line programs ## ## <#GAPDoc Label="type:otherscripts:format"> ## <Mark><C><A>groupname</A>G<A>i</A>-X<A>descr</A>W<A>n</A></C></Mark> ## <Item> ## In this case, the file contains a straight line program that takes ## generators of <M>G</M> w.r.t. the <A>i</A>-th set of standard ## generators, and whose return value corresponds to <A>descr</A>. ## This format is used only in private extensions ## (see Chapter <Ref Chap="chap:Private Extensions"/>), ## such a script can be accessed with <A>descr</A> as the third argument ## of <Ref Func="AtlasProgram"/>. ## </Item> ## <#/GAPDoc> ## AGR.DeclareDataType( "prg", "otherscripts", rec( # `<groupname>G<i>-X<descr>W<n>' FilenameFormat := [ [ [ IsChar, "G", IsDigitChar ], [ "X", IsChar, "W", IsDigitChar ] ], [ ParseBackwards, ParseBackwardsWithPrefix ] ], # `[ <i>, <descr>, <filename> ]' AddFileInfo := function( list, entry, name ) Add( list, Concatenation( entry{ [ 3, 5 ] }, [ name ] ) ); return true; end, DisplayPRG := function( tocs, name, std, stdavail ) local result, other, private, toc, record, i; other:= []; private:= AtlasOfGroupRepresentationsInfo.markprivate; for toc in tocs do if IsBound( toc.( name ) ) then record:= toc.( name ); if IsBound( record.otherscripts ) then for i in record.otherscripts do if std = true or i[1] in std then if IsBound( toc.diridPrivate ) then Add( other, Concatenation( "\"", i[2], "\"", private ) ); else Add( other, Concatenation( "\"", i[2], "\"" ) ); fi; fi; od; fi; fi; od; if not IsEmpty( other ) then other:= Concatenation( [ "other scripts" ], other ); fi; return other; end, # entry: `[ <std>, <descr>, <file> ]', # conditions: `[ "other", <descr> ]' AccessPRG := function( record, std, conditions ) local entry; if Length( conditions ) = 2 and conditions[1] = "other" and IsBound( record.otherscripts ) then for entry in record.otherscripts do if ( std = true or entry[1] in std ) and entry[2] = conditions[2] then return entry{ [ 3, 1 ] }; fi; od; fi; return fail; end, TestWords := function( tocid, name, file, type, verbose ) return AGR.TestWordsSLPDefault( tocid, name, file, type, false, verbose ); end, ReadAndInterpretDefault := ScanStraightLineProgram, ) ); ############################################################################# ## ## Read the server's table of contents. ## Preferably a user file is taken because it might be a more recent version, ## otherwise the file that was distributed with the package is read. ## ## Note that the file <F>types.g</F> is notified with ## <C>DeclareAutoreadableVariables</C>, ## in order to delay the evaluation of the data. ## ## <#GAPDoc Label="ATLASREP_TOCFILE"> ## Alternatively, one can add a line to the user's <F>gaprc</F> file ## (see <Ref Sect="The gap.ini and gaprc files" BookName="ref"/>), ## which assigns the filename of the current <F>gap/atlasprm.g</F> file ## (as an absolute path or relative to the user's home directory, ## cf. <Ref Func="Directory" BookName="ref"/>) ## to the global variable <C>ATLASREP_TOCFILE</C>; ## <Index Key="ATLASREP_TOCFILE"><C>ATLASREP_TOCFILE</C></Index> ## in this case, this file is read instead of the one from the package ## distribution when the package is loaded. ## <#/GAPDoc> ## if IsBound( ATLASREP_TOCFILE ) then if not IsReadableFile( ATLASREP_TOCFILE ) then Error( "the file for the global `ATLASREP_TOCFILE' is not readable" ); elif not READ( ATLASREP_TOCFILE ) then Error( "problem reading the file for the global `ATLASREP_TOCFILE'" ); fi; else ReadPackage( "atlasrep", "gap/atlasprm.g" ); fi; ############################################################################# ## #E