############################################################################# ## #W interfac.gi GAP 4 package AtlasRep Thomas Breuer ## ## This file contains the implementation part of the ''high level'' GAP ## interface to the ATLAS of Group Representations. ##
############################################################################# ## #F AGR.Pager( <string> ) ## ## Simply calling 'Pager' is not good enough, because GAP introduces ## line breaks in too long lines, and GAP does not compute the printable ## length of the line but the length as a string. ## ## If <string> is empty then the builtin pager runs into an error, ## therefore we catch this case. ##
AGR.Pager:= function( string ) if string <> ""then
Pager( rec( lines:= string, formatted:= true ) ); fi; end;
############################################################################# ## #F AGR.ShowOnlyASCII() ## ## Show nicer grids and symbols such as ℤ if the terminal admits this. ## Currently we do *not* do this if 'Print' is used to show the data, ## because of the automatically inserted line breaks. ##
AGR.ShowOnlyASCII:= function()
return UserPreference( "AtlasRep", "DisplayFunction" ) = "Print" or
GAPInfo.TermEncoding <> "UTF-8"; end;
# Consider only those names for which actually information is available. # (The ordering shall be the same as in the input.) if gapnames = "all"then
gapnames:= AtlasOfGroupRepresentationsInfo.GAPnamesSortDisp; else
gapnames:= Filtered( List( gapnames, AGR.InfoForName ),
x -> x <> fail ); fi; if IsEmpty( gapnames ) then
return []; fi;
# If 'conditions' restricts the representations then omit rows # with empty representations part.
rep_rest_funs:= [ Characteristic, Dimension, Identifier, IsMatrixGroup,
IsPermGroup, IsPrimitive, IsTransitive, NrMovedPoints,
RankAction, Ring, Transitivity ];
only_if_rep:= ForAny( conditions, x -> x in rep_rest_funs );
# Compute the data of the columns.
columns:= [ [ "group", "l", List( gapnames, x -> [ x[1], false ] ) ] ];
len:= 0; for type in AGR.DataTypes( "rep", "prg" ) do if type[2].DisplayOverviewInfo <> fail then
Add( columns, [
type[2].DisplayOverviewInfo[1],
type[2].DisplayOverviewInfo[2],
List( gapnames,
n -> type[2].DisplayOverviewInfo[3](
Concatenation( [ n ], conditions ) ) ) ] ); if only_if_rep then if type[3] = "rep"then
len:= Length( columns ); fi; else
len:= Length( columns ); fi; fi;
od;
# Initialize the column widths; the header string shall fit.
widths:= List( columns, c -> [ Length( c[1] ), c[2] ] );
# Restrict the lists to the nonempty rows.
choice:= []; for i in [ 1 .. Length( gapnames ) ] do if ForAny( [ 2 .. len ],
c -> columns[c][3][i][1] <> "" ) then
Add( choice, i );
# Evaluate the privacy flag. if ForAny( columns, x -> x[3][i][2] ) then
columns[1][3][i][1]:= Concatenation( columns[1][3][i][1],
UserPreference( "AtlasRep", "AtlasRepMarkNonCoreData" ) ); fi;
for j in [ 1 .. Length( columns ) ] do
widths[j][1]:= Maximum( widths[j][1],
Length( columns[j][3][i][1] ) );
od;
fi;
od;
if IsEmpty( choice ) then
return []; fi;
fstring:= function( string, width )
local strwidth, n, n1, n2;
# Add the information for each group. for i in choice do
Add( result, JoinStringsWithSeparator( List( [ 1 .. Length( columns ) ],
j -> fstring( columns[j][3][i][1], widths[j] ) ), mid ) );
od;
return result; end;
############################################################################# ## #F AGR.StringAtlasInfoContents() ##
AGR.StringAtlasInfoContents:= function()
local datadir, result, mid, dir, header, table, info, n, path, subdir,
dstfile, prefix, ncols, widths, i, row, sep;
if Length( conditions ) = 0 or
not ( IsInt( conditions[1] ) or IsList( conditions[1] ) ) then
std:= true;
argpos:= 1; else
std:= conditions[1]; if IsInt( std ) then
std:= [ std ]; fi;
argpos:= 2; fi;
# If the standardization is prescribed then do not mention it. # Otherwise if all information refers to the same standardization then # print just one line. # Otherwise print the standardization for each entry.
stdavail:= []; if std = true or 1 < Length( std ) then for toc in tocs do if IsBound( toc.( name ) ) then
record:= toc.( name ); for type in AGR.DataTypes( "prg" ) do if IsBound( record.( type[1] ) ) then for list in record.( type[1] ) do if std = true or list[1] in std then
AddSet( stdavail, list[1] ); fi;
od; fi;
od; fi;
od; fi;
# Create the header line. # (Because of 'AGR.CreateHTMLInfoForGroup', # the group name must occur as an entry of its own .)
header:= [ "Programs for G = ", groupname[1], ":" ]; if Length( stdavail ) = 1then
Append( header, [ " (all refer to std. generators ",
String( stdavail[1] ), ")" ] ); fi;
# Collect the info lines for the scripts.
list:= [];
nams:= [];
sort:= []; if ( Length( conditions ) = argpos and
conditions[ argpos ] = IsStraightLineProgram )
or ( Length( conditions ) = argpos + 1
and conditions[ argpos ] = IsStraightLineProgram
and conditions[ argpos + 1 ] = true )
or Length( conditions ) < argpos then for type in AGR.DataTypes( "prg" ) do
info:= type[2].DisplayPRG( tocs, [ gapname, groupname[2] ], std,
stdavail );
Add( list, info ); if IsEmpty( info ) then
Add( sort, [ 0 ] ); elif IsString( info[2] ) then
Add( sort, [ 0, info[1] ] ); else
Add( sort, [ 1, info[1] ] ); fi;
Add( nams, type[1] );
od; fi;
# Sort the information such that those come first for which a single # line is given. # (This is because 'BrowseAtlasInfo' turns the parts with more than # one line into a subcategory which is created from the first line.) # Inside this ordering of entries, sort the information alphabetically.
pi:= Sortex( sort );
return rec( header := header,
list := Permuted( list, pi ),
nams := Permuted( nams, pi ) ); end;
############################################################################# ## #F AGR.EvaluateMinimalityCondition( <gapname>, <conditions> ) ## ## Evaluate conditions involving '"minimal"': ## Replace the string '"minimal"' by the number in question if known, ## return 'true' in this case and 'false' otherwise. ## (In the 'false' case, an info message is printed.) ##
AGR.EvaluateMinimalityCondition:= function( gapname, conditions )
local pos, info, pos2;
pos:= Position( conditions, "minimal" ); if pos <> fail and pos <> 1then if IsIdenticalObj( conditions[ pos-1 ], NrMovedPoints ) then # ..., NrMovedPoints, "minimal", ...
info:= MinimalRepresentationInfo( gapname, NrMovedPoints ); if info = fail then
Info( InfoAtlasRep, 1, "minimal perm. repr. of '", gapname, "' not known" );
return false; fi;
conditions[ pos ]:= info.value; elif IsIdenticalObj( conditions[ pos-1 ], Dimension ) then
pos2:= Position( conditions, Characteristic ); if pos2 <> fail and pos2 < Length( conditions ) then # ..., Characteristic, <p>, ..., Dimension, "minimal", ...
info:= MinimalRepresentationInfo( gapname,
Characteristic, conditions[ pos2+1 ] ); if info = fail then
Info( InfoAtlasRep, 1, "minimal matrix repr. of '", gapname, "' in characteristic ", conditions[ pos2+1 ], " not known" );
return false; fi;
conditions[ pos ]:= info.value; else
pos2:= Position( conditions, Ring ); if pos2 <> fail and pos2 < Length( conditions )
and IsField( conditions[ pos2+1 ] )
and IsFinite( conditions[ pos2+1 ] ) then # ..., Ring, <R>, ..., Dimension, "minimal", ...
info:= MinimalRepresentationInfo( gapname,
Size, Size( conditions[ pos2+1 ] ) ); if info = fail then
Info( InfoAtlasRep, 1, "minimal matrix repr. of '", gapname, "' over '", conditions[ pos2+1 ], "' not known" );
return false; fi;
conditions[ pos ]:= info.value; fi; fi; fi; fi;
return true; end;
############################################################################# ## #F AGR.InfoReps( <conditions> ) ## ## This function is used by 'AGR.StringAtlasInfoGroup' and ## 'BrowseData.AtlasRepGroupInfoTable'. ##
AGR.InfoReps:= function( conditions )
local info, stdavail, header, list, types, r, type, entry;
# If all information refers to the same standardization then # print just one line. # Otherwise print the standardization for each entry.
stdavail:= Set( List( info, x -> x.standardization ) );
# Construct the header line. # (Because of 'AGR.CreateHTMLInfoForGroup', # 'gapname' must occur as an entry of its own .)
header:= [ "Representations for G = ", AGR.GAPName( conditions[1] ), ":" ]; if Length( stdavail ) = 1then
Add( header, Concatenation( " (all refer to std. generators ", String( stdavail[1] ), ")" ) ); fi;
list:= [];
types:= AGR.DataTypes( "rep" ); for r in info do
type:= First( types, t -> t[1] = r.type );
entry:= type[2].DisplayGroup( r ); if IsString( entry ) then
entry:= [ entry ]; fi;
entry:= [ [ String( r.repnr ), ":" ], [ entry[1], "" ],
entry{ [ 2 .. Length( entry ) ] } ]; if not ( IsString( r.identifier[2] ) or
ForAll( r.identifier[2], IsString ) ) then
entry[2][2]:= UserPreference( "AtlasRep", "AtlasRepMarkNonCoreData" ); fi; if1 < Length( stdavail ) then
Add( entry, [ ", w.r.t. std. gen. ", String( r.standardization ) ] ); fi;
Add( list, entry );
od;
return rec( header := header,
list := list ); end;
############################################################################# ## #F AGR.StringAtlasInfoGroup( <conditions> ) ## ## Deal with the detailed overview for one group. ##
AGR.StringAtlasInfoGroup:= function( conditions )
local result, screenwidth, inforeps, list, line, len1, len2, indent,
underline, bullet, bulletlength, i, prefix, entry, infoprgs, j,
colsep;
result:= [];
screenwidth:= SizeScreen()[1] - 1;
# 'DisplayAtlasInfo( <gapname>[, <std>][, <conditions>] )'
inforeps:= AGR.InfoReps( conditions ); if not IsEmpty( inforeps.list ) then
list:= List( inforeps.list, line -> Concatenation(
[ Concatenation( line[1] ), Concatenation( line[2] ) ],
Concatenation( line{ [ 3 .. Length( line ) ] } ) ) );
len1:= Maximum( List( list, x -> WidthUTF8String( x[1] ) ) );
len2:= Maximum( List( list, x -> WidthUTF8String( x[2] ) ) );
indent:= 0;
line:= Concatenation( inforeps.header{ [ 1 .. 3 ] } ); if AGR.ShowOnlyASCII() then
underline:= RepeatedString( "-", Sum( List(
inforeps.header{ [ 1 .. 3 ] }, Length ) ) ); else
underline:= RepeatedUTF8String( "─", Sum( List(
inforeps.header{ [ 1 .. 3 ] }, Length ) ) ); fi; for i in [ 4 .. Length( inforeps.header ) ] do if WidthUTF8String( line ) + WidthUTF8String( inforeps.header[i] )
>= screenwidth
and WidthUTF8String( line ) <> indent then
Add( result, line );
Add( result, underline );
underline:= "";
line:= ""; fi;
Append( line, inforeps.header[i] );
od; if line <> ""then
Add( result, line ); fi; if underline <> ""then
Add( result, underline ); fi;
indent:= len1 + len2 + 2; if indent >= screenwidth then
indent:= 1; fi;
prefix:= RepeatedString( " ", indent ); for entry in list do # right-aligned number, left-aligned description
line:= Concatenation( String( entry[1], len1 ), " ",
entry[2],
RepeatedString( " ", len2
- WidthUTF8String( entry[2] ) ), " " ); for i in [ 3 .. Length( entry ) ] do if WidthUTF8String( line ) + WidthUTF8String( entry[i] )
>= screenwidth
and Length( line ) <> indent then
Add( result, line );
line:= ShallowCopy( prefix ); fi;
Append( line, entry[i] );
od;
Add( result, line );
od; fi;
# 'DisplayAtlasInfo( <gapname>[, <std>][, IsStraightLineProgram] )'
infoprgs:= AGR.InfoPrgs( conditions ); if ForAny( infoprgs.list, x -> not IsEmpty( x ) ) then if IsBound( inforeps ) and not IsEmpty( inforeps.list ) then
Add( result, "" ); fi;
indent:= 0;
# Format the header.
line:= Concatenation( infoprgs.header{ [ 1 .. 3 ] } ); if AGR.ShowOnlyASCII() then
underline:= RepeatedString( "-", Sum( List(
infoprgs.header{ [ 1 .. 3 ] }, Length ) ) );
bullet:= "- "; else
underline:= RepeatedUTF8String( "─", Sum( List(
infoprgs.header{ [ 1 .. 3 ] }, Length ) ) );
bullet:= "• "; fi;
bulletlength:= 2; for i in [ 4 .. Length( infoprgs.header ) ] do if WidthUTF8String( line ) + WidthUTF8String( infoprgs.header[i] )
>= screenwidth
and WidthUTF8String( line ) <> indent then
Add( result, line );
Add( result, underline );
underline:= "";
line:= ""; fi;
Append( line, infoprgs.header[i] );
od; if line <> ""then
Add( result, line ); fi; if underline <> ""then
Add( result, underline ); fi;
# Format the info list. Each entry is a list of the following type: # - empty or # - consists of two strings (corresponding to table columns), # plus a program identifier, or # - has a string at position 1 # and non-string lists of length 3 at the other positions, # each representing the columns of a table row, # plus a program identifier.
len1:= 0;
len2:= 0; for i in infoprgs.list do if not IsEmpty( i ) then if IsString( i[2] ) then # This happens if only one program is available, # and if the type is not "automorphisms", "kernels", or "maxes".
len1:= Maximum( len1, WidthUTF8String( i[1] ) ); if Length( i ) = 2then
len2:= Maximum( len2, WidthUTF8String( i[2] ) ); fi; else # This happens for "automorphisms", "kernels", and "maxes", # and whenever more than one program is available for a type.
len1:= Maximum( len1, WidthUTF8String( i[1] ) + 1 ); for j in [ 2 .. Length( i ) ] do
len1:= Maximum( len1, WidthUTF8String( i[j][1] ) );
len2:= Maximum( len2, WidthUTF8String( i[j][2] ) );
od; fi; fi;
od;
# The two columns shall be left aligned.
len1:= -len1;
len2:= -len2;
colsep:= " ";
indent:= RepeatedString( " ", bulletlength );
for i in infoprgs.list do if not IsEmpty( i ) then if IsString( i[2] ) then
Add( result, Concatenation( bullet,
String( i[1], len1 ),
colsep,
String( i[2], len2 ) ) ); else
Add( result, Concatenation( bullet, i[1], ":" ) ); for j in [ 2 .. Length( i ) ] do
Add( result, Concatenation( indent,
String( i[j][1], len1 ),
colsep,
String( i[j][2], len2 ) ) );
od; fi; fi;
od; fi;
############################################################################# ## #F AtlasGenerators( <gapname>, <repnr>[, <maxnr>] ) #F AtlasGenerators( <identifier> ) #F AtlasGenerators( <inforecord> ) ## ## <identifier> is a list containing at the first position the string ## <gapname>, ## at the second position a string or a list of strings ## (describing filenames), ## at the third position a positive integer denoting the standardization of ## the representation, ## at the fourth position a positive integer describing the common ring of ## the generators, ## and at the fifth position, if bound, a positive integer denoting the ## number of the maximal subgroup to which the representation is restricted. ##
InstallGlobalFunction( AtlasGenerators, function( arg )
local identifier, gapname, id, maxnr, rep, repnr, reps, prog, filenames,
i, groupname, type, gens, result;
if Length( arg ) = 1then
# 'AtlasGenerators( <identifier> )'
identifier:= arg[1]; if IsRecord( identifier ) and IsBound( identifier.identifier ) then
identifier:= identifier.identifier; fi;
gapname:= identifier[1];
id:= identifier; if IsBound( identifier[5] ) then
maxnr:= identifier[5];
id:= identifier{ [ 1 .. 4 ] }; fi;
rep:= First( AGR.MergedTableOfContents( "all", gapname ),
r -> r.identifier = id );
elif ( Length( arg ) = 2 and IsString( arg[1] ) and IsPosInt( arg[2] ) )
or ( Length( arg ) = 3 and IsString( arg[1] ) and IsPosInt( arg[2] )
and IsPosInt( arg[3] ) ) then
# If the restriction to a subgroup is required then # try to fetch the program (w.r.t. the correct standardization) # *before* reading the generators; # if we do not get the program then the generators are not needed. if IsBound( maxnr ) then
prog:= AtlasProgram( gapname, identifier[3], maxnr ); if prog = fail then
return fail; fi; fi;
filenames:= identifier[2]; if IsString( filenames ) then
filenames:= [ [ "datagens", filenames ] ]; else
filenames:= ShallowCopy( filenames ); for i in [ 1 .. Length( filenames ) ] do if IsString( filenames[i] ) then
filenames[i]:= [ "datagens", filenames[i] ]; fi;
od; fi;
# Access the data file(s).
groupname:= AGR.InfoForName( gapname ); if groupname = fail then
Info( InfoAtlasRep, 1, "AtlasGenerators: no group with GAP name '", gapname, "'" );
return fail; fi;
type:= First( AGR.DataTypes( "rep" ), l -> l[1] = rep.type ); if IsRecord( arg[1] ) then
PushOptions( rec( inforecord:= arg[1] ) ); fi;
gens:= AGR.FileContents( filenames, type ); if IsRecord( arg[1] ) then
PopOptions(); fi; if gens = fail then
return fail; fi;
result:= ShallowCopy( rep ); if IsRecord( arg[1] ) then if IsBound( arg[1].givenRing ) then
result.givenRing:= arg[1].givenRing; fi; if IsBound( arg[1].constructingFilter ) then
result.constructingFilter:= arg[1].constructingFilter; fi; fi;
if IsBound( maxnr ) then
result.identifier:= identifier;
# Evaluate the straight line program.
result.generators:= ResultOfStraightLineProgram( prog.program, gens );
# Add/adjust info. if IsBound( groupname[3].sizesMaxes )
and IsBound( groupname[3].sizesMaxes[ maxnr ] ) then
result.size:= groupname[3].sizesMaxes[ maxnr ]; fi; if IsBound( groupname[3].structureMaxes )
and IsBound( groupname[3].structureMaxes[ maxnr ] ) then
result.groupname:= groupname[3].structureMaxes[ maxnr ]; fi;
else
result.generators:= gens; fi;
# Return the result.
return Immutable( result ); end );
############################################################################# ## #F AGR.MergedTableOfContents( <tocid>, <gapname> ) ## ## 'AGR.MergedTableOfContents' returns a list of the known representations ## for the group with name <gapname>. ## This list is sorted by types and for each type by its 'SortTOCEntries' ## function. ## The list is cached in the component <gapname> of the global record ## 'AtlasOfGroupRepresentationsInfo.TableOfContents.merged'. ## When a new table of contents is notified with ## 'AtlasOfGroupRepresentationsNotifyPrivateDirectory' then the cache is ## cleared. ##
AGR.MergedTableOfContents:= function( tocid, gapname )
local merged, label, groupname, result, tocs, type, typeresult, sortkeys,
toc, record, id, i, repname, oneresult, types, r, loc;
merged:= AtlasOfGroupRepresentationsInfo.TableOfContents.merged; if IsString( tocid ) then
tocid:= [ tocid ]; fi;
label:= Concatenation( JoinStringsWithSeparator( tocid, "|" ), "|", gapname ); if IsBound( merged.( label ) ) then
return merged.( label ); fi;
groupname:= AGR.InfoForName( gapname ); if groupname = fail then
return []; elif tocid = [ "all" ] then
result:= [];
# collect all representations, sort them for each type.
tocs:= AGR.TablesOfContents( [ "contents", "all" ] ); for type in AGR.DataTypes( "rep" ) do
typeresult:= [];
sortkeys:= []; for toc in tocs do if IsBound( toc.( groupname[2] ) ) then
record:= toc.( groupname[2] ); if IsBound( record.( type[1] ) ) then for i in record.( type[1] ) do
repname:= i[ Length(i) ]; if not IsString( repname ) then
repname:= repname[1]; fi;
repname:= repname{ [ 1 .. Position( repname, '.' )-1 ] };
id:= i[ Length(i) ];
if toc.TocID <> "core"then if IsString( id ) then
id:= [ [ toc.TocID, id ] ]; else
id:= List( id, x -> [ toc.TocID, x ] ); fi; fi;
if IsBound( groupname[3].size ) then for i in result do
i.size:= groupname[3].size;
od; fi; for i in [ 1 .. Length( result ) ] do
result[i].repnr:= i;
od; elif tocid = [ "local" ] then
types:= AGR.DataTypes( "rep" );
result:= []; for r in AGR.MergedTableOfContents( "all", gapname ) do
type:= First( types, x -> x[1] = r.type ); if r.contents <> "core"then
loc:= AtlasOfGroupRepresentationsLocalFilename(
r.identifier[2], type ); elif IsString( r.identifier[2] ) then
loc:= AtlasOfGroupRepresentationsLocalFilename(
[ [ "datagens", r.identifier[2] ] ], type ); else
loc:= AtlasOfGroupRepresentationsLocalFilename(
List( r.identifier[2], x -> [ "datagens", x ] ), type ); fi; if not IsEmpty( loc ) and ForAll( loc[1][2], x -> x[2] ) then
Add( result, r ); fi;
od; else # Now we know that we have to filter a list which we can compute. if"local" in tocid then
result:= AGR.MergedTableOfContents( "local", gapname ); else
result:= AGR.MergedTableOfContents( "all", gapname ); fi;
tocid:= Difference( tocid, [ "all", "local" ] );
result:= Filtered( result, r -> r.contents in tocid ); fi;
merged.( label ):= result;
return result; end;
############################################################################# ## #F AGR.EvaluateCharacterCondition( <gapname>, <conditions>, <reps> ) ## ## Evaluate conditions involving 'Character'. ## The list <conditions> is changed in place such that the first occurrence ## of 'Character' and the subsequent entry (the condition on the character) ## are removed. ## The return value is the sublist of those entries in <reps> that satisfy ## the condition. ##
AGR.EvaluateCharacterCondition:= function( gapname, conditions, reps )
local pos, map, pos2, p, chars, primes, consts, i, chi, tbl, ordtbl, dec,
const, j, repnames, mapi, len;
# If 'Character' does not occur then we need not work.
pos:= Position( conditions, Character ); if pos = fail then
return reps; elif pos = Length( conditions ) then
return []; fi;
map:= AtlasOfGroupRepresentationsInfo.characterinfo; if not IsBound( map.( gapname ) ) then
Info( InfoAtlasRep, 1, "no character information for ", gapname, " known" );
return []; fi;
map:= map.( gapname );
# Check whether also 'Characteristic' is specified.
pos2:= Position( conditions, Characteristic ); if pos2 = fail then
p:= "?"; elif pos2 = Length( conditions ) then
return []; else
p:= conditions[ pos2+1 ]; if IsInt( p ) then
p:= [ p ]; fi; fi;
# Interpret the character(s).
chars:= conditions[ pos+1 ]; if IsClassFunction( chars ) then
chars:= [ chars ]; fi; if IsList( chars ) and ForAll( chars, IsClassFunction ) then # The characters are explicitly given. # Compute the positions of their irreducible constituents.
primes:= [];
consts:= []; for i in [ 1 .. Length( chars ) ] do
chi:= chars[i];
tbl:= UnderlyingCharacterTable( chi ); if IsOrdinaryTable( tbl ) then
ordtbl:= tbl; else
ordtbl:= OrdinaryCharacterTable( tbl ); fi; if gapname = Identifier( ordtbl ) and
( p = "?" or
( IsFunction( p ) and p( UnderlyingCharacteristic( tbl ) ) = true ) or
( IsList( p ) and UnderlyingCharacteristic( tbl ) in p ) ) then if IsOrdinaryTable( tbl ) then
dec:= MatScalarProducts( tbl, Irr( tbl ), [ chi ] )[1]; else
dec:= Decomposition( Irr( tbl ), [ chi ], "nonnegative" )[1]; fi;
const:= []; if dec <> fail and ForAll( dec, x -> IsInt( x ) and 0 <= x ) then
AddSet( primes, UnderlyingCharacteristic( tbl ) ); for j in [ 1 .. Length( dec ) ] do if dec[j] = 1then
Add( const, j ); elif1 < dec[j] then
Add( const, [ j, dec[j] ] ); fi;
od; if Length( const ) = 1 and IsInt( const[1] ) then
const:= const[1]; fi;
Add( consts, const ); fi; fi;
od;
p:= primes;
chi:= consts; elif not ( IsPosInt( chars ) or IsString( chars ) ) then #T perhaps admit a list of positions or strings?
return []; else # The position in the list of irreducibles or the name is given. if p = "?"then # No characteristic is specified, this means *ordinary* character.
p:= [ 0 ]; fi;
chi:= chars; fi;
# Look for the character(s) in the info lists.
repnames:= []; for i in [ 1 .. Length( map ) ] do if IsBound( map[i] ) and
( ( IsFunction( p ) and ( ( i = 1 and p( 0 ) = true ) or
( 1 < i and p( i ) = true ) ) ) or
( IsList( p ) and ( ( i = 1 and 0 in p ) or i in p ) ) ) then
mapi:= map[i]; for j in [ 1 .. Length( mapi[1] ) ] do if ( IsPosInt( chi ) and mapi[1][j] = chi ) or
( IsString( chi ) and mapi[3][j] = chi ) or
( IsList( chi ) and mapi[1][j] in chi ) then # We have found a character that matches.
Add( repnames, mapi[2][j] ); fi;
od; fi;
od;
if Length( repnames ) = 0then
return []; fi;
# We will return a nonempty list. Remove 'Character' from 'conditions'. for i in [ pos .. Length( conditions )-2 ] do
conditions[i]:= conditions[ i+2 ];
od;
Remove( conditions );
Remove( conditions );
return Filtered( reps, r -> r.repname in repnames ); end;
############################################################################# ## #F AGR.AtlasGeneratingSetInfo( <conditions>, "one" ) #F AGR.AtlasGeneratingSetInfo( <conditions>, "all" ) #F AGR.AtlasGeneratingSetInfo( <conditions>, <types> ) ## ## This function does the work for 'OneAtlasGeneratingSetInfo', ## 'AllAtlasGeneratingSetInfos', and 'AGR.InfoReps'. ## The first entry in <conditions> can be a group name ## or a list of group names. ##
AGR.AtlasGeneratingSetInfo:= function( conditions, mode )
local pos, tocid, gapnames, types, std, filter, givenRing, position,
result, gapname, reps, cond, info, type, F;
# Ignore the condition that no straight line programs are wanted.
pos:= Position( conditions, IsStraightLineProgram ); if pos <> fail and
pos < Length( conditions ) and conditions[ pos + 1 ] = false then
conditions:= Concatenation( conditions{ [ 1 .. pos-1 ] },
conditions{ [ pos+2 .. Length( conditions ) ] } ); fi;
# The first argument (if there is one) is a group name, # or a list of group names, # or an integer (denoting a standardization), # or a function (denoting the first condition). if Length( conditions ) = 0 or IsInt( conditions[1] )
or IsFunction( conditions[1] ) then # The group is not restricted.
gapnames:= List( AtlasOfGroupRepresentationsInfo.GAPnamesSortDisp,
pair -> pair[1] ); elif IsString( conditions[1] ) then # Only one group is considered.
gapnames:= [ AGR.GAPName( conditions[1] ) ];
conditions:= conditions{ [ 2 .. Length( conditions ) ] }; elif IsList( conditions[1] ) and ForAll( conditions[1], IsString ) then # A list of group names is prescribed.
gapnames:= List( conditions[1], AGR.GAPName );
conditions:= conditions{ [ 2 .. Length( conditions ) ] }; else
Error( "invalid first argument ", conditions[1] ); fi;
types:= AGR.DataTypes( "rep" );
# Deal with a prescribed standardization. if1 <= Length( conditions ) and
( IsInt( conditions[1] ) or
( IsList( conditions[1] ) and ForAll( conditions[1], IsInt ) ) ) then
std:= conditions[1]; if IsInt( std ) then
std:= [ std ]; fi;
conditions:= conditions{ [ 2 .. Length( conditions ) ] }; else
std:= true; fi;
# Extract a prescribed 'ConstructingFilter'.
filter:= fail;
pos:= Position( conditions, ConstructingFilter ); if pos <> fail then if pos = Length( conditions ) or not IsFilter( conditions[ pos+1 ] ) then
Error( "condition 'ConstructingFilter' must be followed by a filter" ); fi;
filter:= conditions[ pos+1 ];
conditions:= Concatenation( conditions{ [ 1 .. pos-1 ] },
conditions{ [ pos+2 .. Length( conditions ) ] } ); fi;
# Extract a prescribed ring (but leave it in 'conditions').
givenRing:= fail;
pos:= Position( conditions, Ring ); if pos <> fail then if pos = Length( conditions ) or not ( IsRing( conditions[ pos+1 ] ) #T admit a list of rings!
or IsFunction( conditions[ pos+1 ] )
or conditions[ pos+1 ] = fail ) then
Error( "condition 'Ring' must be followed by a ring" ); elif IsRing( conditions[ pos+1 ] ) then
givenRing:= conditions[ pos+1 ]; fi; fi;
# A prescribed ring prescribes also a characteristic. if givenRing <> fail and Position( conditions, Characteristic ) = fail then
conditions:= Concatenation( conditions,
[ Characteristic, Characteristic( givenRing ) ] ); fi;
# Deal with a prescribed representation number.
pos:= Position( conditions, Position ); if pos <> fail then if pos = Length( conditions ) or not IsPosInt( conditions[ pos+1 ] ) then
Error( "condition 'Position' must be followed by a pos. integer" ); fi;
position:= conditions[ pos+1 ];
conditions:= Concatenation( conditions{ [ 1 .. pos-1 ] },
conditions{ [ pos+2 .. Length( conditions ) ] } ); fi;
# Evaluate the 'Position' condition. if pos <> fail then
reps:= Filtered( reps, r -> r.repnr = position ); fi;
cond:= ShallowCopy( conditions );
# Evaluate conditions involving '"minimal"' (modify 'cond' in place). if AGR.EvaluateMinimalityCondition( gapname, cond ) then # Evaluate the 'Character' condition. if Character in cond then
reps:= AGR.EvaluateCharacterCondition( gapname, cond, reps ); fi;
# Loop over the relevant representations. for info in reps do
type:= First( types, t -> t[1] = info.type ); if ( std = true or info.standardization in std ) and
type[2].AccessGroupCondition( info, ShallowCopy( cond ) ) then # Hack: # Store the desired ring/field if there is one, # in order to create the matrices over the correct ring/field. if givenRing <> fail and IsBound( info.ring )
and not IsIdenticalObj( givenRing, info.ring ) then
info:= ShallowCopy( info );
info.givenRing:= givenRing; fi; if filter <> fail then
info:= ShallowCopy( info ); #T twice copy?
info.constructingFilter:= filter; fi;
if mode = "one"then
return info; else
Add( result, info ); fi; fi;
od; fi;
od;
# We have checked all available representations. if mode = "one"then
return fail; else
return result; fi; end;
maxes:= [];
maxstd:= []; for toc in AGR.TablesOfContents( "all" ) do if IsBound( toc.( name ) ) then
record:= toc.( name ); if IsBound( record.maxes ) then for i in record.maxes do if i[2] in maxes then
AddSet( maxstd[ Position( maxes, i[2] ) ], i[1] ); else
Add( maxes, i[2] );
Add( maxstd, [ i[1] ] ); fi;
od; fi; fi;
od; if IsBound( info.maxext ) then for i in info.maxext do if i[2] in maxes then
AddSet( maxstd[ Position( maxes, i[2] ) ], i[1] ); else
Add( maxes, i[2] );
Add( maxstd, [ i[1] ] ); fi;
od; fi; if not IsEmpty( maxes ) then
SortParallel( maxes, maxstd );
ConvertToRangeRep( maxes );
result.slpMaxes:= [ maxes, maxstd ]; fi;
if Length( arg ) = 1 and IsRecord( arg[1] ) then
info:= arg[1]; elif Length( arg ) = 1 and IsList( arg[1] ) and not IsString( arg[1] ) then # Find the info record with this identifier.
identifier:= arg[1];
gapname:= identifier[1];
info:= First( AGR.MergedTableOfContents( "all", gapname ),
r -> r.identifier = identifier ); else
info:= CallFuncList( OneAtlasGeneratingSetInfo, arg ); fi; if info <> fail then
gens:= AtlasGenerators( info ); if gens <> fail then
result:= GroupWithGenerators( gens.generators ); if IsBound( gens.isPrimitive ) then
SetIsPrimitive( result, gens.isPrimitive ); fi; # Note that it would *not* be safe to set 'NrMovedPoints' # or 'LargestMovedPoint' to 'gens.p'. if IsBound( gens.rankAction ) then
SetRankAction( result, gens.rankAction ); fi; if IsBound( gens.size ) then
SetSize( result, gens.size ); fi; if IsBound( gens.transitivity ) then
SetTransitivity( result, gens.transitivity );
SetIsTransitive( result, gens.transitivity > 0 ); fi; #T Set known info about the *group* (IsSimple etc., not stored in 'gens')!
SetAtlasRepInfoRecord( result, info );
return result; fi; fi;
return fail; end );
maxnr:= arg[ Length( arg ) ]; if not IsPosInt( maxnr ) then
Error( "<maxnr> must be a positive integer" ); fi;
if Length( arg ) = 2 and IsRecord( arg[1] ) then
info:= arg[1];
groupname:= info.groupname; elif Length( arg ) = 2 and IsGroup( arg[1] ) then if not HasAtlasRepInfoRecord( arg[1] ) then
Error( "the 'AtlasRepInfoRecord' value is not set for the group" ); fi;
info:= AtlasRepInfoRecord( arg[1] );
groupname:= info.groupname; elif Length( arg ) = 2 and IsList( arg[1] ) and not IsString( arg[1] ) then
info:= rec( identifier:= arg[1], standardization:= arg[1][3] );
groupname:= arg[1][1]; elif1 < Length( arg ) then
info:= CallFuncList( OneAtlasGeneratingSetInfo,
arg{ [ 1 .. Length( arg ) - 1 ] } );
groupname:= arg[1]; else
info:= fail; fi;
if info = fail then
return fail; fi;
std:= info.standardization;
prog:= AtlasProgram( groupname, std, "maxes", maxnr ); if prog = fail then
return fail; fi;
if Length( arg ) = 2 and IsGroup( arg[1] ) then # We need not load the generators from files.
result:= GroupWithGenerators( ResultOfStraightLineProgram( prog.program,
GeneratorsOfGroup( arg[1] ) ) ); else
result:= AtlasGenerators( info ); if result = fail then
return fail; fi;
result:= GroupWithGenerators( ResultOfStraightLineProgram( prog.program,
result.generators ) ); fi;
if IsBound( prog.size ) then
SetSize( result, prog.size ); fi;
inforec:= rec( identifier:= Concatenation( info.identifier,
[ maxnr ] ),
standardization:= std ); if IsBound( info.repnr ) then
inforec.repnr:= info.repnr; fi; if IsBound( prog.subgroupname ) then
inforec.groupname:= prog.subgroupname; fi; if IsBound( prog.size ) then
inforec.size:= prog.size; fi;
SetAtlasRepInfoRecord( result, inforec );
return result; end );
############################################################################# ## #M ConjugacyClasses( <G> ) ## ## For a group with stored 'AtlasRepInfoRecord' value, ## there may be a straight line program that computes class representatives. ## If yes then use it, otherwise give up. ## ## Note that the 'ccls' straight line programs output the representatives ## in Atlas ordering, in particular the identity element comes first. ## #T Is there a way to express that a group constructed with 'AtlasSubgroup' #T does in fact have standard generators, #T such that class representatives can be computed with this method? ##
InstallMethod( ConjugacyClasses,
[ "IsGroup and IsFinite and HasAtlasRepInfoRecord" ],
OVERRIDENICE + RankFilter( IsPermGroup ), # adjust to other uprankings function( G )
local info, prg, reps;
info:= AtlasRepInfoRecord( G ); if info.groupname <> info.identifier[1] then # The group is just a subgroup of an Atlas group.
TryNextMethod(); fi;
prg:= AtlasProgram( info.groupname, info.standardization, "classes" ); if prg = fail then # We do not know a straight line program for computing class reps.
TryNextMethod(); fi;
reps:= ResultOfStraightLineProgram( prg.program,
GeneratorsOfGroup( G ) );
return List( reps, x -> ConjugacyClass( G, x ) ); end );
# 'AtlasProgramInfo( <identifier> )'
identifier:= arg[1];
gapname:= identifier[1];
groupname:= AGR.InfoForName( gapname ); if groupname = fail then
return fail; fi; for type in AGR.DataTypes( "prg" ) do
result:= type[2].AtlasProgramInfo( type, identifier, groupname[2] ); if result <> fail then
result.groupname:= gapname;
result.version:= AGR.VersionOfSLP( identifier[2] );
return Immutable( result ); fi;
od;
return fail;
elif Length( arg ) = 0 or not IsString( arg[1] ) then
Error( "the first argument must be the GAP name of a group" ); fi;
# Now handle the cases of more than one argument.
gapname:= arg[1];
groupname:= AGR.InfoForName( gapname ); if groupname = fail then
Info( InfoAtlasRep, 1, "AtlasProgramInfo: no group with GAP name '", gapname, "'" );
return fail; fi;
if IsInt( arg[2] ) and 2 < Length( arg ) then
std:= [ arg[2] ];
argpos:= 3; elif IsBool( arg[2] ) and 2 < Length( arg ) then
std:= true;
argpos:= 3; else
std:= true;
argpos:= 2; fi;
conditions:= arg{ [ argpos .. Length( arg ) ] };
# Restrict to a prescribed selection of tables of contents.
tocs:= AGR.TablesOfContents( conditions );
# 'AtlasProgramInfo( <gapname>[, <std>][, "maxes"], <maxnr> )' if ( Length( conditions ) = 1 and IsInt( conditions[1] ) ) or
( Length( conditions ) = 3 and IsInt( conditions[1] )
and conditions[2] = "version" ) then
conditions:= Concatenation( [ "maxes" ], conditions ); fi;
for toc in tocs do # Note that 'toc.( groupname[2] )' need not be bound # if database extensions provide straight line pograms. for type in AGR.DataTypes( "prg" ) do
id:= type[2].AccessPRG( toc, groupname[2], std, conditions ); if id <> fail then # The table of contents provides a program as is required.
return AtlasProgramInfo( Concatenation( [ groupname[1] ], id ) ); fi;
od;
od;
# No program was found.
Info( InfoAtlasRep, 2, "no program for conditions ", conditions, "\n", "#I of the group with GAP name '", groupname[1], "'" );
return fail; end );
############################################################################# ## #F AtlasProgram( <gapname>[, <std>][, "maxes"], <maxnr> ) #F AtlasProgram( <gapname>[, <std>], "maxes", <maxnr>[, <std2>] ) #F AtlasProgram( <gapname>[, <std>], "maxstd", <maxnr>, <vers>, <substd> ) #F AtlasProgram( <gapname>[, <std>], "kernel", <factname> ) #F AtlasProgram( <gapname>[, <std>], "classes" ) #F AtlasProgram( <gapname>[, <std>], "cyclic" ) #F AtlasProgram( <gapname>[, <std>], "cyc2ccl"[, <vers>] ) #F AtlasProgram( <gapname>[, <std>], "automorphism", <autname> ) #F AtlasProgram( <gapname>[, <std>], "check" ) #F AtlasProgram( <gapname>[, <std>], "presentation" ) #F AtlasProgram( <gapname>[, <std>], "find" ) #F AtlasProgram( <gapname>, <std>, "restandardize", <std2> ) #F AtlasProgram( <gapname>[, <std>], "other", <descr> ) #F AtlasProgram( <identifier> ) ## ## <identifier> is a list containing at the first position the string ## <gapname>, ## at the second position a string or a list of strings ## (describing the filenames involved), ## and at the third position a positive integer denoting the standardization ## of the program. ##
InstallGlobalFunction( AtlasProgram, function( arg )
local identifier, gapname, groupname, type, result, info;
if Length( arg ) = 1then
# 'AtlasProgram( <identifier> )'
identifier:= arg[1];
gapname:= identifier[1];
groupname:= AGR.InfoForName( gapname ); if groupname = fail then
return fail; fi; for type in AGR.DataTypes( "prg" ) do
result:= type[2].AtlasProgram( type, identifier, groupname[2] ); if result <> fail then
result.groupname:= groupname[1];
result.version:= AGR.VersionOfSLP( identifier[2] );
return Immutable( result ); fi;
od;
return fail;
elif Length( arg ) = 0 or not IsString( arg[1] ) then
Error( "the first argument must be the GAP name of a group" ); fi;
# Now handle the cases of more than one argument.
info:= CallFuncList( AtlasProgramInfo, arg ); if info = fail then
return fail; fi;
return AtlasProgram( info.identifier ); end );
prg:= AtlasProgram( gapname, std, "find" ); if prg = fail then
return fail; fi;
prg:= prg.program;
if ValueOption( "projective" ) = true then # This is supported only for FFE matrix groups. # We do not check this condition, # 'ProjectiveOrder' will run into an error if it is not satisfied.
options:= rec( orderfunction:= mat -> ProjectiveOrder( mat )[1] ); else
options:= rec(); fi;
mgens:= GeneratorsWithMemory( gens );
res:= ResultOfBBoxProgram( prg, GroupWithGenerators( mgens ),
options ); if res = "timeout"then
return "timeout"; elif res = fail then # The program has detected that 'gens' cannot belong to 'gapname'.
return fail; fi;
return rec( gapname:= gapname,
givengens:= gens,
stdgens:= StripMemory( res ),
givengenstostdgens:= SLPOfElms( res ),
std:= std ); end );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.