diff --git a/doc/overview.xml b/doc/overview.xml
index 4d8be7a..9e5c53d 100644
--- a/doc/overview.xml
+++ b/doc/overview.xml
@@ -139,6 +139,7 @@ the one used here. See https://gap-packages.github.io/sotgrps/.
<#Include Label="IdsOfAllSmallGroups">
<#Include Label="IdGap3SolvableGroup">
<#Include Label="SmallGroupsInformation">
+ <#Include Label="SmallGroupsInformationRecord">
<#Include Label="SmallGroupsAddLayer">
<#Include Label="UnloadSmallGroupsData">
<#Include Label="SMALL_GROUPS_OLD_ORDER">
diff --git a/gap/addlayer.gi b/gap/addlayer.gi
index 1ce8727..df9d44b 100644
--- a/gap/addlayer.gi
+++ b/gap/addlayer.gi
@@ -87,6 +87,17 @@ SMALL_GROUPS_LAYERS.SmallGrp := rec(
information := function( size, inforec, num )
SMALL_GROUPS_INFORMATION[ inforec.func ]( size, inforec, num );
end,
+ informationRecord := function( size, inforec, num )
+ local r;
+ # orders added the old way may come without a record
+ if not IsBound( SMALL_GROUPS_INFORMATION_RECORDS[ inforec.func ] ) then
+ return fail;
+ fi;
+ r := SMALL_GROUPS_INFORMATION_RECORDS[ inforec.func ]
+ ( size, inforec, num );
+ r.sources := SMALL_GROUPS_SOURCES( inforec );
+ return r;
+ end,
);
SMALL_GROUPS_LAYER_LIST[ 1 ] := SMALL_GROUPS_LAYERS.SmallGrp;
@@ -149,8 +160,8 @@ InstallGlobalFunction( SmallGroupsAddLayer, function( desc )
fi;
known := [ "name", "available", "group", "id", "idAvailable", "number",
- "properties", "information", "select", "count",
- "before", "after" ];
+ "properties", "information", "informationRecord", "select",
+ "count", "before", "after" ];
for comp in RecNames( desc ) do
if not comp in known then
Error( "unknown component .", comp );
@@ -168,7 +179,8 @@ InstallGlobalFunction( SmallGroupsAddLayer, function( desc )
Error( "a layer named \"", desc.name, "\" is already registered" );
fi;
for comp in [ "available", "group", "id", "idAvailable", "number",
- "properties", "information", "select", "count" ] do
+ "properties", "information", "informationRecord",
+ "select", "count" ] do
if IsBound( desc.( comp ) ) and not IsFunction( desc.( comp ) ) then
Error( ".", comp, " must be a function" );
fi;
diff --git a/gap/small.gd b/gap/small.gd
index c351d54..a7dc1e8 100644
--- a/gap/small.gd
+++ b/gap/small.gd
@@ -977,6 +977,83 @@ DeclareGlobalFunction( "IdStandardPresented512Group" );
##
DeclareGlobalFunction( "SmallGroupsInformation" );
+#############################################################################
+##
+#F SmallGroupsInformationRecord( )
+##
+## <#GAPDoc Label="SmallGroupsInformationRecord">
+##
+##
+##
+##
+## returns the information that prints
+## as a record, or fail if the groups of order order are not
+## available. Its components are:
+##
+## order, number
+## -
+## the order and the number of groups of that order.
+##
+## layer
+## -
+## the name of the layer that provides the groups, see
+##
; it is "SmallGrp" for the
+## layers of this package, which are then numbered by
+## layerNumber as in Chapter .
+##
+## idAvailable
+## -
+## whether
is available for this order.
+##
+## indexed
+## -
+## the names of the selection criteria that the selection functions know
+## for this order without constructing groups.
+##
+## ranges
+## -
+## a list describing how the groups are arranged, possibly empty. Each
+## entry is a record with components from and to, the first
+## and the last index of a range of groups; text, a description
+## of what these groups have in common; and values, a record
+## mapping names of attributes to the value that all these groups have.
+##
+## sortedBy
+## -
+## optional, a description of the invariant by which the groups are
+## sorted.
+##
+## comment
+## -
+## optional, further text about these groups.
+##
+## sources
+## -
+## optional, the keys of the publications that determined these groups,
+## in the bibliography of the package providing the layer.
+##
+## description
+## -
+## optional, the text that
prints
+## between the number of groups and the indexed selection criteria.
+##
+##
+## r := SmallGroupsInformationRecord( 32 );;
+## gap> r.number;
+## 51
+## gap> r.ranges[ 2 ];
+## rec( from := 2, text := "rank 2", to := 20, values := rec( RankPGroup := 2 ) )
+## gap> r.sources;
+## [ "OBr90", "JNO90", "OBr91", "BescheEick98", "BescheEick1000",
+## "BescheEick768" ]
+## ]]>
+##
+##
+## <#/GAPDoc>
+##
+DeclareGlobalFunction( "SmallGroupsInformationRecord" );
+
#############################################################################
##
#F SmallGroupsAddLayer( )
@@ -1039,6 +1116,17 @@ DeclareGlobalFunction( "SmallGroupsInformation" );
## should say about that order
## beyond the number of groups.
##
+## informationRecord
+## -
+## optional, a function
+## ( order, inforec, number ) returning
+## fail or a record with some of the components ranges,
+## sortedBy, comment, sources and
+## description described in
+##
. If it returns a
+## description, prints that
+## instead of calling information.
+##
## properties
## -
## optional, a function ( order, inforec ) reporting
diff --git a/gap/smlinfo.gi b/gap/smlinfo.gi
index 4d9ba0f..722f7a1 100644
--- a/gap/smlinfo.gi
+++ b/gap/smlinfo.gi
@@ -6,11 +6,26 @@
## This file contains the ...
##
+#############################################################################
+##
+#V SMALL_GROUPS_INFORMATION_RECORDS
+##
+## for each value of 'func' of the layers of this package, a function
+## '( size, smav, num )' returning what 'SmallGroupsInformationRecord'
+## reports beyond the generic components: 'description', the text that
+## 'SmallGroupsInformation' prints; 'ranges', the groups of this order
+## grouped by what they have in common; and optionally 'sortedBy',
+## 'comment' and 'indexed'
+SMALL_GROUPS_INFORMATION_RECORDS := [ ];
+
#############################################################################
##
#F SMALL_GROUPS_INFORMATION
##
-## ...
+## for each value of 'func', a function '( size, smav, num )' printing the
+## description of the groups of order 'size'. Other packages can fill
+## further entries; the entries for the layers of this package print what
+## 'SMALL_GROUPS_INFORMATION_RECORDS' returns.
SMALL_GROUPS_INFORMATION := [ ];
#############################################################################
@@ -51,255 +66,526 @@ end;
#############################################################################
##
-#F SmallGroupsInformation( size )
+#F SMALL_GROUPS_INFO_RANGE( from, to, text, values )
##
-## ...
-InstallGlobalFunction( SmallGroupsInformation, function( size )
- local smav, idav, num, lib, props, names;
+## the groups with ids 'from' to 'to', which share what 'text' says and the
+## attribute values in the record 'values'
+SMALL_GROUPS_INFO_RANGE := function( from, to, text, values )
+ return rec( from := from, to := to, text := text, values := values );
+end;
- if not IsPosInt(size) then
- ErrorNoReturn("usage: SmallGroupsInformation( size )");
+#############################################################################
+##
+#F SMALL_GROUPS_INFO_STREAM( str )
+##
+## a stream appending to the string 'str', without the line breaks the
+## output to the screen would insert, so that printing 'str' later gives
+## exactly the output of the same calls to 'Print'
+SMALL_GROUPS_INFO_STREAM := function( str )
+ local out;
+ out := OutputTextString( str, true );
+ SetPrintFormattingStatus( out, false );
+ return out;
+end;
+
+#############################################################################
+##
+#V SMALL_GROUPS_LAYER_SOURCES
+##
+## for each layer of this package, the keys in the bibliography of this
+## package of the publications that determined its groups, as listed in the
+## chapter on the organisation of the library
+SMALL_GROUPS_LAYER_SOURCES := [
+ [ "Hoelder1893" ],
+ [ "OBr90", "JNO90", "OBr91", "BescheEick98", "BescheEick1000",
+ "BescheEick768" ],
+ [ "BescheEick768" ],
+ [ "OBr90", "BescheEick768" ],
+ [ "OBr90", "JNO90", "OBr91", "BescheEick98", "BescheEick1000",
+ "BescheEick768" ],
+ [ "BEO01", "BescheEick98" ],
+ [ "EOB98", "EOB99", "OBr90", "BEO01" ],
+ [ "BescheEick98", "BescheEick768" ],
+ [ "Hoelder1893", "Bagnera1898", "NOV04", "Gir03" ],
+ [ "Hoelder1895", "DEi05" ],
+ [ "OV05" ] ];
+
+#############################################################################
+##
+#F SMALL_GROUPS_SOURCES( smav )
+##
+SMALL_GROUPS_SOURCES := function( smav )
+ local lib;
+
+ lib := 1;
+ if IsBound( smav.lib ) then
+ lib := smav.lib;
+ fi;
+ # layer 10 holds the squarefree orders (func 24) and the cubefree ones
+ if lib = 10 and smav.func = 25 then
+ return [ "DEi05" ];
fi;
+ if not IsBound( SMALL_GROUPS_LAYER_SOURCES[ lib ] ) then
+ return [ ];
+ fi;
+ return ShallowCopy( SMALL_GROUPS_LAYER_SOURCES[ lib ] );
+end;
+#############################################################################
+##
+#F SMALL_GROUPS_INFORMATION_DATA( size )
+##
+## 'fail' if the groups of order 'size' are not available, otherwise a record
+## with components 'record', the result of 'SmallGroupsInformationRecord';
+## 'smav' and 'number', as needed to call the 'information' function of the
+## layer; and 'printed', whether 'record.description' replaces that call
+SMALL_GROUPS_INFORMATION_DATA := function( size )
+ local smav, num, r, info, props, nam;
+
+ # the number is known, the groups are not
if size = 1024 then
- Print( "The groups of size 1024 are not available. \n");
- return;
+ return fail;
fi;
smav := SMALL_AVAILABLE( size );
if smav = fail then
- Print( "The groups of size ", size, " are not available. \n");
- return;
- fi;
+ return fail;
+ fi;
if IsBound( smav.number ) then
num := smav.number;
else
num := smav.layer.numberOf( size, smav ).number;
fi;
- if num = 1 then
- Print("\n There is 1 group of order ",size,".\n");
- else
- Print("\n There are ",num," groups of order ",size,".\n" );
- fi;
-
- smav.layer.information( size, smav, num );
-
- # report those properties whose value the selection functions can read
- # off from the position a group has in this list
- if IsBound( smav.layer.properties ) then
- if not IsBound( smav.number ) then
- smav.number := num;
+
+ r := rec( order := size, number := num, layer := smav.layer.name,
+ ranges := [ ] );
+ if smav.layer.name = "SmallGrp" then
+ r.layerNumber := 1;
+ if IsBound( smav.lib ) then
+ r.layerNumber := smav.lib;
fi;
- props := smav.layer.properties( size, smav );
- if props <> fail then
- names := List( Filtered( Concatenation(
- SMALL_GROUPS_INDEXED_PROPERTIES,
- SMALL_GROUPS_INDEXED_ATTRIBUTES ),
- t -> IsBound( props.( t[ 1 ] ) ) ),
- t -> t[ 3 ] );
- SMALL_GROUPS_PRINT_INDEXED( names );
+ fi;
+
+ info := fail;
+ if IsBound( smav.layer.informationRecord ) then
+ info := smav.layer.informationRecord( size, smav, num );
+ fi;
+ if info <> fail then
+ for nam in RecNames( info ) do
+ r.( nam ) := info.( nam );
+ od;
+ fi;
+
+ # those properties whose value the selection functions can read off
+ # from the position a group has in this list
+ if not IsBound( r.indexed ) then
+ r.indexed := [ ];
+ if IsBound( smav.layer.properties ) then
+ if not IsBound( smav.number ) then
+ smav.number := num;
+ fi;
+ props := smav.layer.properties( size, smav );
+ if props <> fail then
+ r.indexed := List( Filtered( Concatenation(
+ SMALL_GROUPS_INDEXED_PROPERTIES,
+ SMALL_GROUPS_INDEXED_ATTRIBUTES ),
+ t -> IsBound( props.( t[ 1 ] ) ) ),
+ t -> t[ 3 ] );
+ fi;
fi;
fi;
- if IsBound( smav.lib ) then
- lib := smav.lib;
+ r.idAvailable := ID_AVAILABLE( size ) <> fail;
+
+ return rec( record := r, smav := smav, number := num,
+ printed := IsBound( r.description ) );
+end;
+
+#############################################################################
+##
+#F SmallGroupsInformationRecord( size )
+##
+InstallGlobalFunction( SmallGroupsInformationRecord, function( size )
+ local data;
+
+ if not IsPosInt( size ) then
+ ErrorNoReturn( "usage: SmallGroupsInformationRecord( size )" );
+ fi;
+
+ data := SMALL_GROUPS_INFORMATION_DATA( size );
+ if data = fail then
+ return fail;
+ fi;
+ return data.record;
+end );
+
+#############################################################################
+##
+#F SmallGroupsInformation( size )
+##
+InstallGlobalFunction( SmallGroupsInformation, function( size )
+ local data, r;
+
+ if not IsPosInt(size) then
+ ErrorNoReturn("usage: SmallGroupsInformation( size )");
+ fi;
+
+ data := SMALL_GROUPS_INFORMATION_DATA( size );
+ if data = fail then
+ Print( "The groups of size ", size, " are not available. \n");
+ return;
+ fi;
+ r := data.record;
+
+ if r.number = 1 then
+ Print("\n There is 1 group of order ",size,".\n");
else
- lib := 1;
+ Print("\n There are ",r.number," groups of order ",size,".\n" );
fi;
- if smav.layer.name = "SmallGrp" then
- Print("\n This size belongs to layer ",lib,
+
+ if data.printed then
+ Print( r.description );
+ else
+ data.smav.layer.information( size, data.smav, data.number );
+ fi;
+
+ SMALL_GROUPS_PRINT_INDEXED( r.indexed );
+
+ if r.layer = "SmallGrp" then
+ Print("\n This size belongs to layer ",r.layerNumber,
" of the SmallGroups library. \n");
else
- Print("\n This size belongs to the layer \"",smav.layer.name,
- "\". \n");
+ Print("\n This size belongs to the layer \"",r.layer,"\". \n");
fi;
- idav := ID_AVAILABLE( size );
- if idav <> fail then
+ if r.idAvailable then
Print(" IdSmallGroup is available for this size. \n \n");
- else
+ else
Print(" IdSmallGroup is not available for this size. \n \n");
fi;
end );
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 1 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 1 .. 7 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 1 ] := function( size, smav, num )
- Print("\n");
- Print(" The groups whose order factorises in at most 3 primes \n");
- Print(" have been classified by O. Hoelder. This classification is \n");
- Print(" used in the SmallGroups library. \n");
+SMALL_GROUPS_INFORMATION_RECORDS[ 1 ] := function( size, smav, num )
+ local str;
+
+ str := Concatenation(
+ "\n",
+ " The groups whose order factorises in at most 3 primes \n",
+ " have been classified by O. Hoelder. This classification is \n",
+ " used in the SmallGroups library. \n" );
+ return rec( description := str, ranges := [ ],
+ comment := NormalizedWhitespace( str ) );
end;
-SMALL_GROUPS_INFORMATION[ 2 ] := SMALL_GROUPS_INFORMATION[ 1 ];
-SMALL_GROUPS_INFORMATION[ 3 ] := SMALL_GROUPS_INFORMATION[ 1 ];
-SMALL_GROUPS_INFORMATION[ 4 ] := SMALL_GROUPS_INFORMATION[ 1 ];
-SMALL_GROUPS_INFORMATION[ 5 ] := SMALL_GROUPS_INFORMATION[ 1 ];
-SMALL_GROUPS_INFORMATION[ 6 ] := SMALL_GROUPS_INFORMATION[ 1 ];
-SMALL_GROUPS_INFORMATION[ 7 ] := SMALL_GROUPS_INFORMATION[ 1 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 2 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 1 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 3 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 1 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 4 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 1 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 5 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 1 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 6 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 1 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 7 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 1 ];
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 8 .. 10 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 8 .. 10 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 8 ] := function( size, smav, num )
- local ffid, prop, i, l;
+SMALL_GROUPS_INFORMATION_RECORDS[ 8 ] := function( size, smav, num )
+ local ffid, prop, i, l, str, out, r, from, to;
ffid := IdGroup( OneSmallGroup( size, FrattinifactorSize, size ) );
prop := PROPERTIES_SMALL_GROUPS[ size ].frattFacs;
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( ranges := [ ] );
if not IsPrimePowerInt( size ) then
- Print(" They are sorted by their Frattini factors. \n");
+ r.sortedBy := "Frattini factor";
+ PrintTo( out, " They are sorted by their Frattini factors. \n");
i := 1;
if ffid[ 2 ] > 1 then
- repeat
- if prop.pos[ i ][ 1 ] = -prop.pos[ i ][ 2 ] then
- Print( " ", prop.pos[ i ][ 1 ],
+ repeat
+ from := prop.pos[ i ][ 1 ];
+ to := -prop.pos[ i ][ 2 ];
+ if from = to then
+ PrintTo( out, " ", from,
" has Frattini factor ", prop.frattFacs[ i ], ".\n" );
else
- Print( " ", prop.pos[ i ][ 1 ], " - ",
- -prop.pos[ i ][ 2 ], " have Frattini factor ",
- prop.frattFacs[ i ], ".\n" );
+ PrintTo( out, " ", from, " - ", to,
+ " have Frattini factor ", prop.frattFacs[ i ], ".\n" );
fi;
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( from, to,
+ Concatenation( "Frattini factor ",
+ String( prop.frattFacs[ i ] ) ),
+ rec( FrattinifactorId := prop.frattFacs[ i ] ) ) );
i := i + 1;
until prop.frattFacs[ i ] = ffid;
fi;
- Print(" ", ffid[2], " - ", num,
+ PrintTo( out, " ", ffid[2], " - ", num,
" have trivial Frattini subgroup.\n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( ffid[ 2 ], num,
+ "trivial Frattini subgroup",
+ rec( FrattinifactorSize := size ) ) );
+ r.indexed := [ "IsAbelian", "IsNilpotentGroup",
+ "IsSupersolvableGroup", "IsSolvableGroup", "LGLength",
+ "FrattinifactorSize", "FrattinifactorId" ];
else
- Print(" They are sorted by their ranks. \n");
- Print(" ", 1, " is cyclic. \n");
+ r.sortedBy := "rank";
+ PrintTo( out, " They are sorted by their ranks. \n");
+ PrintTo( out, " ", 1, " is cyclic. \n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( 1, 1, "cyclic",
+ rec( RankPGroup := 1 ) ) );
i := 2;
- repeat
+ repeat
l := Length( Factors( prop.frattFacs[ i ][1] ) );
- if prop.pos[ i ][ 1 ] = -prop.pos[ i ][ 2 ] then
- Print( " ", prop.pos[ i ][ 1 ], " has rank ", l, ".\n" );
+ from := prop.pos[ i ][ 1 ];
+ to := -prop.pos[ i ][ 2 ];
+ if from = to then
+ PrintTo( out, " ", from, " has rank ", l, ".\n" );
else
- Print( " ", prop.pos[ i ][ 1 ], " - ",
- -prop.pos[ i ][ 2 ], " have rank ", l, ".\n" );
+ PrintTo( out, " ", from, " - ", to, " have rank ", l,
+ ".\n" );
fi;
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( from, to,
+ Concatenation( "rank ", String( l ) ),
+ rec( RankPGroup := l ) ) );
i := i + 1;
until prop.frattFacs[ i ] = ffid;
- Print(" ", ffid[2], " is elementary abelian. \n");
- fi;
-
- if IsPrimePowerInt( size ) then
- SMALL_GROUPS_PRINT_INDEXED( [ "IsAbelian", "IsNilpotentGroup",
+ PrintTo( out, " ", ffid[2], " is elementary abelian. \n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( ffid[ 2 ], ffid[ 2 ],
+ "elementary abelian",
+ rec( RankPGroup := Length( Factors( size ) ) ) ) );
+ r.indexed := [ "IsAbelian", "IsNilpotentGroup",
"IsSupersolvableGroup", "IsSolvableGroup", "PClassPGroup",
- "RankPGroup", "FrattinifactorSize", "FrattinifactorId" ] );
- else
- SMALL_GROUPS_PRINT_INDEXED( [ "IsAbelian", "IsNilpotentGroup",
- "IsSupersolvableGroup", "IsSolvableGroup", "LGLength",
- "FrattinifactorSize", "FrattinifactorId" ] );
+ "RankPGroup", "FrattinifactorSize", "FrattinifactorId" ];
fi;
+
+ CloseStream( out );
+ r.description := str;
+ return r;
end;
-SMALL_GROUPS_INFORMATION[ 9 ] := SMALL_GROUPS_INFORMATION[ 8 ];
-SMALL_GROUPS_INFORMATION[ 10 ] := SMALL_GROUPS_INFORMATION[ 8 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 9 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 8 ];
+SMALL_GROUPS_INFORMATION_RECORDS[ 10 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 8 ];
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 11, 17 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 11, 17 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 11 ] := function( size, smav, num )
- local i, q;
+SMALL_GROUPS_INFORMATION_RECORDS[ 11 ] := function( size, smav, num )
+ local i, q, str, out, r, text;
q := 2;
if IsBound( smav.q ) then q := smav.q; fi;
-
- Print(" They are sorted by normal Sylow subgroups. \n");
- Print( " 1 - ", smav.pos[ 2 ], " are the nilpotent groups.\n" );
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( sortedBy := "normal Sylow subgroups", ranges := [ ] );
+
+ PrintTo( out, " They are sorted by normal Sylow subgroups. \n");
+ PrintTo( out, " 1 - ", smav.pos[ 2 ], " are the nilpotent groups.\n" );
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( 1, smav.pos[ 2 ], "nilpotent",
+ rec( IsNilpotentGroup := true ) ) );
for i in [ 2 .. Length( smav.types ) ] do
- Print( " ", smav.pos[i] + 1, " - ", smav.pos[i+1] );
- if smav.types[ i ] = "p-autos" then
- Print( " have a normal Sylow ", q,"-subgroup. \n");
- elif smav.types[ i ] = "none-p-nil" then
- Print( " have no normal Sylow subgroup. \n");
+ PrintTo( out, " ", smav.pos[i] + 1, " - ", smav.pos[i+1] );
+ text := fail;
+ if smav.types[ i ] = "p-autos" then
+ PrintTo( out, " have a normal Sylow ", q,"-subgroup. \n");
+ text := Concatenation( "normal Sylow ", String( q ), "-subgroup" );
+ elif smav.types[ i ] = "none-p-nil" then
+ PrintTo( out, " have no normal Sylow subgroup. \n");
+ text := "no normal Sylow subgroup";
elif IsInt( smav.types[ i ] ) then
- Print( " have a normal Sylow ", smav.p, "-subgroup \n");
- Print( " with centralizer of index ");
- Print( q^smav.types[i],".\n");
+ PrintTo( out, " have a normal Sylow ", smav.p, "-subgroup \n");
+ PrintTo( out, " with centralizer of index ");
+ PrintTo( out, q^smav.types[i],".\n");
+ text := Concatenation( "normal Sylow ", String( smav.p ),
+ "-subgroup with centralizer of index ",
+ String( q^smav.types[ i ] ) );
+ fi;
+ if text <> fail then
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( smav.pos[ i ] + 1,
+ smav.pos[ i + 1 ], text,
+ rec() ) );
fi;
od;
+
+ CloseStream( out );
+ r.description := str;
+ return r;
+end;
+SMALL_GROUPS_INFORMATION_RECORDS[ 17 ] := SMALL_GROUPS_INFORMATION_RECORDS[ 11 ];
+
+#############################################################################
+##
+#F SMALL_GROUPS_INFO_FIXED( header, sortedBy, ranges )
+##
+## the information for an order whose groups are described by the fixed
+## list 'ranges' of entries '[ from, to, printed, text, values ]', where
+## 'printed' is what the line of the range prints after the ids; 'header',
+## if not 'fail', is the line printed before the ranges
+SMALL_GROUPS_INFO_FIXED := function( header, sortedBy, ranges )
+ local str, out, r, t;
+
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( sortedBy := sortedBy, ranges := [ ] );
+ if header <> fail then
+ PrintTo( out, header );
+ fi;
+ for t in ranges do
+ PrintTo( out, " ", t[ 1 ], " - ", t[ 2 ], " ", t[ 3 ], ".\n" );
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( t[ 1 ], t[ 2 ], t[ 4 ],
+ t[ 5 ] ) );
+ od;
+ CloseStream( out );
+ r.description := str;
+ return r;
end;
-SMALL_GROUPS_INFORMATION[ 17 ] := SMALL_GROUPS_INFORMATION[ 11 ];
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 12 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 12 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 12 ] := function( size, smav, num )
+SMALL_GROUPS_INFORMATION_RECORDS[ 12 ] := function( size, smav, num )
if size = 1152 then
- Print(" They are sorted using Sylow subgroups. \n");
- Print(" 1 - 2328 are nilpotent with Sylow 3-subgroup c9.\n" );
- Print(" 2329 - 4656 are nilpotent with Sylow 3-subgroup 3^2.\n");
- Print(" 4657 - 153312 are non-nilpotent with normal ");
- Print("Sylow 3-subgroup.\n");
- Print(" 153313 - 157877 have no normal Sylow 3-subgroup.\n");
- return;
+ return SMALL_GROUPS_INFO_FIXED(
+ " They are sorted using Sylow subgroups. \n",
+ "Sylow subgroups",
+ [ [ 1, 2328, "are nilpotent with Sylow 3-subgroup c9",
+ "nilpotent with Sylow 3-subgroup c9",
+ rec( IsNilpotentGroup := true ) ],
+ [ 2329, 4656, "are nilpotent with Sylow 3-subgroup 3^2",
+ "nilpotent with Sylow 3-subgroup 3^2",
+ rec( IsNilpotentGroup := true ) ],
+ [ 4657, 153312, "are non-nilpotent with normal Sylow 3-subgroup",
+ "non-nilpotent with normal Sylow 3-subgroup",
+ rec( IsNilpotentGroup := false ) ],
+ [ 153313, 157877, "have no normal Sylow 3-subgroup",
+ "no normal Sylow 3-subgroup", rec() ] ] );
fi;
- Print(" They are sorted using Hall subgroups. \n");
- Print( " 1 - 2328 are the nilpotent groups.\n" );
- Print( " 2329 - 236344 have a normal Hall (3,5)-subgroup.\n");
- Print( " 236345 - 240416 are solvable without normal Hall",
- " (3,5)-subgroup.\n");
- Print( " 240417 - 241004 are not solvable.\n" );
+ return SMALL_GROUPS_INFO_FIXED(
+ " They are sorted using Hall subgroups. \n",
+ "Hall subgroups",
+ [ [ 1, 2328, "are the nilpotent groups", "nilpotent",
+ rec( IsNilpotentGroup := true ) ],
+ [ 2329, 236344, "have a normal Hall (3,5)-subgroup",
+ "normal Hall (3,5)-subgroup", rec() ],
+ [ 236345, 240416, "are solvable without normal Hall (3,5)-subgroup",
+ "solvable without normal Hall (3,5)-subgroup",
+ rec( IsSolvableGroup := true ) ],
+ [ 240417, 241004, "are not solvable", "not solvable",
+ rec( IsSolvableGroup := false ) ] ] );
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 14 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 14 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 14 ] := function( size, smav, num )
+SMALL_GROUPS_INFORMATION_RECORDS[ 14 ] := function( size, smav, num )
- Print( " 1 - 10494213 are the nilpotent groups.\n" );
- Print( " 10494214 - 408526597 have a normal Sylow 3-subgroup.\n" );
- Print( " 408526598 - 408544625 have a normal Sylow 2-subgroup.\n" );
- Print( " 408544626 - 408641062 have no normal Sylow subgroup.\n" );
+ return SMALL_GROUPS_INFO_FIXED( fail, "normal Sylow subgroups",
+ [ [ 1, 10494213, "are the nilpotent groups", "nilpotent",
+ rec( IsNilpotentGroup := true ) ],
+ [ 10494214, 408526597, "have a normal Sylow 3-subgroup",
+ "normal Sylow 3-subgroup", rec() ],
+ [ 408526598, 408544625, "have a normal Sylow 2-subgroup",
+ "normal Sylow 2-subgroup", rec() ],
+ [ 408544626, 408641062, "have no normal Sylow subgroup",
+ "no normal Sylow subgroup", rec() ] ] );
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 18 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 18 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 18 ] := function( size, smav, num )
- local i, t;
+SMALL_GROUPS_INFORMATION_RECORDS[ 18 ] := function( size, smav, num )
+ local i, t, str, out, r;
- Print( " 1 is cyclic. \n");
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( sortedBy := "rank and p-class", ranges := [ ] );
+
+ PrintTo( out, " 1 is cyclic. \n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( 1, 1, "cyclic",
+ rec( RankPGroup := 1 ) ) );
for i in [ 2 .. Length( SMALL_GROUPS_512_TYPES ) - 1 ] do
t := SMALL_GROUPS_512_TYPES[ i ];
if t[ 1 ] = t[ 2 ] then
- Print( " ", t[ 1 ], " has rank " );
+ PrintTo( out, " ", t[ 1 ], " has rank " );
else
- Print( " ", t[ 1 ], " - ", t[ 2 ], " have rank " );
+ PrintTo( out, " ", t[ 1 ], " - ", t[ 2 ], " have rank " );
fi;
- Print( t[ 3 ], " and p-class ", t[ 4 ], ".\n" );
+ PrintTo( out, t[ 3 ], " and p-class ", t[ 4 ], ".\n" );
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( t[ 1 ], t[ 2 ],
+ Concatenation( "rank ", String( t[ 3 ] ), " and p-class ",
+ String( t[ 4 ] ) ),
+ rec( RankPGroup := t[ 3 ], PClassPGroup := t[ 4 ] ) ) );
od;
- Print( " ", num, " is elementary abelian.\n");
+ PrintTo( out, " ", num, " is elementary abelian.\n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( num, num, "elementary abelian",
+ rec( RankPGroup := 9, PClassPGroup := 1 ) ) );
+
+ CloseStream( out );
+ r.description := str;
+ return r;
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 19 ]( size, smav, num )
-##
-SMALL_GROUPS_INFORMATION[ 19 ] := function( size, smav, num )
+#F SMALL_GROUPS_INFO_RANKS( header, size, bounds, ending )
+##
+## the information for the groups of order 'size' = p^n, sorted by their
+## ranks: 1 is cyclic, then 'bounds[ i - 1 ] + 1' to 'bounds[ i ]' have rank
+## i + 1, and the last group is elementary abelian; 'ending' follows the
+## period of the line of the cyclic group
+SMALL_GROUPS_INFO_RANKS := function( header, size, bounds, ending )
+ local str, out, r, i, from, n;
+
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( sortedBy := "rank", ranges := [ ] );
+ n := Length( Factors( size ) );
+
+ PrintTo( out, header );
+ PrintTo( out, " 1 is cyclic.", ending, "\n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( 1, 1, "cyclic",
+ rec( RankPGroup := 1 ) ) );
+ from := 2;
+ for i in [ 1 .. Length( bounds ) ] do
+ PrintTo( out, " ", from, " - ", bounds[ i ], " have rank ", i + 1,
+ ". \n" );
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( from, bounds[ i ],
+ Concatenation( "rank ", String( i + 1 ) ),
+ rec( RankPGroup := i + 1 ) ) );
+ from := bounds[ i ] + 1;
+ od;
+ PrintTo( out, " ", from, " is elementary abelian. \n");
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( from, from, "elementary abelian",
+ rec( RankPGroup := n ) ) );
- Print(" They are sorted by their ranks. \n");
- Print( " 1 is cyclic. \n");
- Print( " 2 - 10 have rank 2. \n");
- Print( " 11 - 14 have rank 3. \n");
- Print( " 15 is elementary abelian. \n");
+ CloseStream( out );
+ r.description := str;
+ return r;
+end;
+
+#############################################################################
+##
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 19 ]( size, smav, num )
+##
+SMALL_GROUPS_INFORMATION_RECORDS[ 19 ] := function( size, smav, num )
+ return SMALL_GROUPS_INFO_RANKS( " They are sorted by their ranks. \n",
+ size, [ 10, 14 ], " " );
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 20 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 20 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 20 ] := function( size, smav, num )
+SMALL_GROUPS_INFORMATION_RECORDS[ 20 ] := function( size, smav, num )
local p, a, b, c;
p := Factors(size)[1];
@@ -307,159 +593,228 @@ SMALL_GROUPS_INFORMATION[ 20 ] := function( size, smav, num )
b:=54 + 2*p + 2*GcdInt(p-1,3) + GcdInt(p-1,4);
c:=60 + 2*p + 2*GcdInt(p-1,3) + GcdInt(p-1,4);
- Print( " They are sorted by their ranks.\n" );
- Print( " 1 is cyclic.\n");
- Print( " 2 - ",a," have rank 2. \n");
- Print( " ",a+1," - ",b," have rank 3. \n");
- Print( " ",b+1," - ",c," have rank 4. \n");
- Print( " ",c+1," is elementary abelian. \n");
+ return SMALL_GROUPS_INFO_RANKS( " They are sorted by their ranks.\n",
+ size, [ a, b, c ], "" );
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 21 ]( size, smav, num )
-##
-SMALL_GROUPS_INFORMATION[ 21 ] := function( size, smav, num )
-
- Print( " \n");
- Print( " Easterfield (1940) constructed a list of the groups of\n");
- Print( " order p^6 for p >= 5.\n \n");
-
- Print( " The database of parametrised presentations for the groups \n");
- Print( " with order p^6 for p >= 5 is based on the Easterfield \n");
- Print( " list, corrected by Newman, O'Brien and Vaughan-Lee (2004).\n");
- Print( " It differs only in the addition of groups in isoclinism \n");
- Print( " family $\\Phi_{13}$, in using the James (1980) presentations \n");
- Print( " for the groups in $\\Phi_{19}$, and a small number of \n");
- Print( " typographical amendments. The linear ordering employed is \n");
- Print( " very close to that of Easterfield. \n \n");
-
- Print( " Each group with order $p^6$ is described by a power- \n");
- Print( " commutator presentation on 6 generators and 21 relations:\n");
- Print( " 15 are commutator relations and 6 are power relations. \n");
- Print( " Each presentation has the prime $p$ as a parameter. \n");
- Print( " The database contains about 500 parametrised \n");
- Print( " presentations, most of these have $p$ as the only \n");
- Print( " parameter. \n");
-
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 21 ]( size, smav, num )
+##
+SMALL_GROUPS_INFORMATION_RECORDS[ 21 ] := function( size, smav, num )
+ local str;
+
+ str := Concatenation(
+ " \n",
+ " Easterfield (1940) constructed a list of the groups of\n",
+ " order p^6 for p >= 5.\n \n",
+
+ " The database of parametrised presentations for the groups \n",
+ " with order p^6 for p >= 5 is based on the Easterfield \n",
+ " list, corrected by Newman, O'Brien and Vaughan-Lee (2004).\n",
+ " It differs only in the addition of groups in isoclinism \n",
+ " family $\\Phi_{13}$, in using the James (1980) presentations \n",
+ " for the groups in $\\Phi_{19}$, and a small number of \n",
+ " typographical amendments. The linear ordering employed is \n",
+ " very close to that of Easterfield. \n \n",
+
+ " Each group with order $p^6$ is described by a power- \n",
+ " commutator presentation on 6 generators and 21 relations:\n",
+ " 15 are commutator relations and 6 are power relations. \n",
+ " Each presentation has the prime $p$ as a parameter. \n",
+ " The database contains about 500 parametrised \n",
+ " presentations, most of these have $p$ as the only \n",
+ " parameter. \n" );
+ return rec( description := str, ranges := [ ],
+ comment := NormalizedWhitespace( str ) );
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 24 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 24 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 24 ] := function( size, smav, num )
- local i, set, c;
+SMALL_GROUPS_INFORMATION_RECORDS[ 24 ] := function( size, smav, num )
+ local i, set, c, str, out, r, text;
- Print( "\n" );
- Print( " The groups of squarefree order have a cyclic socle and a " );
- Print( "cyclic socle factor.\n" );
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( ranges := [ ], comment := Concatenation(
+ "The groups of squarefree order have a cyclic socle and a ",
+ "cyclic socle factor." ) );
- Print( "\n" );
+ PrintTo( out, "\n" );
+ PrintTo( out, " The groups of squarefree order have a cyclic socle and a " );
+ PrintTo( out, "cyclic socle factor.\n" );
+
+ PrintTo( out, "\n" );
i := 0;
for set in smav.sets do
c := Product( smav.primes{ set.kp } );
if c = 1 then
- Print( " 1 is abelian\n" );
- elif set.number = 1 then
- Print( " ", i + 1, " has socle C_" );
- Print( size / c, " and factor C_", c, "\n" );
+ PrintTo( out, " 1 is abelian\n" );
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( i + 1, i + set.number,
+ "abelian", rec( IsAbelian := true ) ) );
else
- Print( " ", i + 1, " - ", i + set.number, " have socle C_" );
- Print( size / c, " and factor C_", c, "\n" );
+ if set.number = 1 then
+ PrintTo( out, " ", i + 1, " has socle C_" );
+ else
+ PrintTo( out, " ", i + 1, " - ", i + set.number,
+ " have socle C_" );
+ fi;
+ PrintTo( out, size / c, " and factor C_", c, "\n" );
+ text := Concatenation( "socle C_", String( size / c ),
+ " and factor C_", String( c ) );
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( i + 1, i + set.number,
+ text, rec() ) );
fi;
i := i + set.number;
od;
+
+ CloseStream( out );
+ r.description := str;
+ return r;
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 25 ]( size, smav, num )
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 25 ]( size, smav, num )
##
-SMALL_GROUPS_INFORMATION[ 25 ] := function( size, smav, num )
- local i, set, c;
- Print( "\n" );
- Print( " The groups of cubefree order are either solvable or a direct ",
+SMALL_GROUPS_INFORMATION_RECORDS[ 25 ] := function( size, smav, num )
+ local i, set, str, out, r, text, s;
+
+ str := "";
+ out := SMALL_GROUPS_INFO_STREAM( str );
+ r := rec( ranges := [ ], comment := Concatenation(
+ "The groups of cubefree order are either solvable or a direct ",
+ "product of the form PSL( 2, p ) x solvable group. The cubefree ",
+ "solvable groups are determined by their Frattini factor." ) );
+
+ PrintTo( out, "\n" );
+ PrintTo( out, " The groups of cubefree order are either solvable or a direct ",
"product of \n the form PSL( 2, p ) x solvable group. ",
"The cubefree solvable groups are \n determined by their Frattini",
" factor.\n\n" );
i := 0;
for set in smav.sets do
+ if set.number = 1 then
+ s := String( i + 1 );
+ else
+ s := Concatenation( String( i + 1 ), " - ", String( i + set.number ) );
+ fi;
if set.psl_p = 1 then
if set.size_phi = 1 then
+ text := "solvable and Frattini free";
if set.number = 1 then
- Print( " ", i + 1, " is solvable and Frattini free\n" );
+ PrintTo( out, " ", s, " is solvable and Frattini free\n" );
else
- Print( " ", i + 1, " - ", i + set.number, " are solvable ",
+ PrintTo( out, " ", s, " are solvable ",
"and Frattini free\n" );
fi;
else
+ text := Concatenation( "solvable with Frattini factor of size ",
+ String( set.size_ff ) );
if set.number = 1 then
- Print( " ", i + 1, " is solvable with Frattini factor of ",
+ PrintTo( out, " ", s, " is solvable with Frattini factor of ",
"size ", set.size_ff, "\n" );
else
- Print( " ", i + 1, " - ", i + set.number, " are solvable ",
+ PrintTo( out, " ", s, " are solvable ",
"with Frattini factor of size ", set.size_ff, "\n" );
fi;
fi;
elif
set.size_ff = 1 then
- Print( " ", i + 1, " is PSL( 2, ", set.psl_p, " )\n" );
+ text := Concatenation( "PSL( 2, ", String( set.psl_p ), " )" );
+ PrintTo( out, " ", s, " is PSL( 2, ", set.psl_p, " )\n" );
else
if set.size_phi = 1 then
+ text := Concatenation( "PSL( 2, ", String( set.psl_p ),
+ " ) x F with F solvable and Frattini free of order ",
+ String( set.size_ff ) );
if set.number = 1 then
- Print( " ", i + 1, " is PSL( 2, ", set.psl_p, " ) x F, F ",
+ PrintTo( out, " ", s, " is PSL( 2, ", set.psl_p, " ) x F, F ",
"solvable and Frattini free of order ", set.size_ff, "\n");
else
- Print( " ", i + 1, " - ", i + set.number, " are PSL( 2, ",
+ PrintTo( out, " ", s, " are PSL( 2, ",
set.psl_p, " ) x F_i, F_i solvable ",
"Frattini free of order ", set.size_ff, "\n" );
fi;
else
+ text := Concatenation( "PSL( 2, ", String( set.psl_p ),
+ " ) x G with G solvable of order ",
+ String( set.size_ff * set.size_phi ),
+ " with a Frattini factor of order ",
+ String( set.size_ff ) );
if set.number = 1 then
- Print( " ", i + 1, " is PSL( 2, ", set.psl_p, " ) x G, G ",
+ PrintTo( out, " ", s, " is PSL( 2, ", set.psl_p, " ) x G, G ",
"solvable of order ", set.size_ff * set.size_phi,
" with a Frattini factor\n of order ", set.size_ff,
"\n");
else
- Print( " ", i + 1, " - ", i + set.number, " are PSL( 2, ",
+ PrintTo( out, " ", s, " are PSL( 2, ",
set.psl_p, " ) x G_i, G_i ", "solvable of order ",
set.size_ff * set.size_phi, " with a",
"\n Frattini factor of order ", set.size_ff, "\n");
fi;
fi;
fi;
+ Add( r.ranges, SMALL_GROUPS_INFO_RANGE( i + 1, i + set.number, text,
+ rec() ) );
i := i + set.number;
od;
+
+ CloseStream( out );
+ r.description := str;
+ return r;
end;
#############################################################################
##
-#F SMALL_GROUPS_INFORMATION[ 26 ]( size, smav, num )
-##
-SMALL_GROUPS_INFORMATION[ 26 ] := function( size, smav, num )
-
- Print( " \n");
- Print( " E.A. O'Brien and M.R. Vaughan-Lee determined presentations\n");
- Print( " of the groups with order p^7. A preprint of their paper is\n");
- Print( " available at\n" );
- Print( " http://www.math.auckland.ac.nz/%7Eobrien/research/p7/paper-p7.pdf\n\n" );
- Print( " For p in { 3, 5, 7, 11 } explicit lists of groups of order\n");
- Print( " p^7 have been produced and stored into the database.\n\n");
- Print( " Giving the power commutator presentations of any of these\n");
- Print( " groups using a standard notation they might be reduced to 35\n");
- Print( " elements of the group or a 245 p-digit number.\n\n");
- Print( " Only 56 of these digits may be unlike 0 for any group and\n");
- Print( " even these 56 digits are mostly like 0. Further on these\n");
- Print( " digits are often quite likely for sequences of subsequent\n");
- Print( " groups. Thus storage of groups was done by finding a so\n");
- Print( " called head group and a so called tail. Along the tail\n");
- Print( " only the different digits compared to the head are relevant.\n");
- Print( " Even the tails occur more or less often and this is used\n");
- Print( " to improve storage too. Since p^7 is too big the data is\n");
- Print( " stored into some remaining holes of SMALL_GROUP_LIB at\n");
- Print( " Primes[ p + 10 ].\n");
-
+#F SMALL_GROUPS_INFORMATION_RECORDS[ 26 ]( size, smav, num )
+##
+SMALL_GROUPS_INFORMATION_RECORDS[ 26 ] := function( size, smav, num )
+ local str;
+
+ str := Concatenation(
+ " \n",
+ " E.A. O'Brien and M.R. Vaughan-Lee determined presentations\n",
+ " of the groups with order p^7. A preprint of their paper is\n",
+ " available at\n",
+ " http://www.math.auckland.ac.nz/%7Eobrien/research/p7/paper-p7.pdf\n\n",
+ " For p in { 3, 5, 7, 11 } explicit lists of groups of order\n",
+ " p^7 have been produced and stored into the database.\n\n",
+ " Giving the power commutator presentations of any of these\n",
+ " groups using a standard notation they might be reduced to 35\n",
+ " elements of the group or a 245 p-digit number.\n\n",
+ " Only 56 of these digits may be unlike 0 for any group and\n",
+ " even these 56 digits are mostly like 0. Further on these\n",
+ " digits are often quite likely for sequences of subsequent\n",
+ " groups. Thus storage of groups was done by finding a so\n",
+ " called head group and a so called tail. Along the tail\n",
+ " only the different digits compared to the head are relevant.\n",
+ " Even the tails occur more or less often and this is used\n",
+ " to improve storage too. Since p^7 is too big the data is\n",
+ " stored into some remaining holes of SMALL_GROUP_LIB at\n",
+ " Primes[ p + 10 ].\n" );
+ return rec( description := str, ranges := [ ],
+ comment := NormalizedWhitespace( str ) );
end;
+#############################################################################
+##
+#F SMALL_GROUPS_INFORMATION[ ... ]( size, smav, num )
+##
+## the entries for the layers of this package, printing what the
+## corresponding entries of 'SMALL_GROUPS_INFORMATION_RECORDS' return
+Perform( [ 1 .. Length( SMALL_GROUPS_INFORMATION_RECORDS ) ], function( f )
+ if IsBound( SMALL_GROUPS_INFORMATION_RECORDS[ f ] ) then
+ SMALL_GROUPS_INFORMATION[ f ] := function( size, smav, num )
+ local r;
+ r := SMALL_GROUPS_INFORMATION_RECORDS[ f ]( size, smav, num );
+ Print( r.description );
+ if IsBound( r.indexed ) then
+ SMALL_GROUPS_PRINT_INDEXED( r.indexed );
+ fi;
+ end;
+ fi;
+end );
diff --git a/tst/addlayer.tst b/tst/addlayer.tst
index 7145d05..06bf3b4 100644
--- a/tst/addlayer.tst
+++ b/tst/addlayer.tst
@@ -60,6 +60,11 @@ gap> SmallGroupsInformation( 2016 );
This size belongs to the layer "two of them".
IdSmallGroup is available for this size.
+gap> r := SmallGroupsInformationRecord( 2016 );;
+gap> [ r.layer, r.number, r.idAvailable, r.indexed, r.ranges ];
+[ "two of them", 2, true, [ ], [ ] ]
+gap> IsBound( r.layerNumber ) or IsBound( r.description );
+false
#
# The layer is registered by name, behind the layers of this library.
@@ -232,6 +237,9 @@ gap> NumberSmallGroups( 2079 );
9
gap> SMALL_AVAILABLE( 2079 ).layer.name;
"SmallGrp"
+gap> r := SmallGroupsInformationRecord( 2079 );;
+gap> [ r.layer, r.layerNumber, r.number, r.ranges, IsBound( r.sources ) ];
+[ "SmallGrp", 12, 9, [ ], false ]
gap> claim( "epsilon", 8, rec() );
gap> NumberSmallGroups( 2079 );
9
@@ -300,6 +308,42 @@ gap> SmallGroupsAddLayer( rec( name := "no id", available := ReturnFail,
> idAvailable := ReturnFail ) );
Error, .idAvailable is of no use without .id
+#
+# 'informationRecord' describes the groups of an order as data; its
+# 'description' is what 'SmallGroupsInformation' prints
+#
+gap> SmallGroupsAddLayer( rec(
+> name := "described",
+> available := function( order )
+> if order <> 2088 then
+> return fail;
+> fi;
+> return rec( number := 1 );
+> end,
+> group := { order, i, inforec } -> CyclicGroup( order ),
+> informationRecord := function( order, inforec, num )
+> return rec( description := "\n Just the cyclic one.\n",
+> ranges := [ rec( from := 1, to := 1,
+> text := "cyclic",
+> values := rec( IsCyclic := true ) ) ],
+> sources := [ "Hoelder1893" ] );
+> end ) );
+gap> SmallGroupsInformation( 2088 );
+
+ There is 1 group of order 2088.
+
+ Just the cyclic one.
+
+ This size belongs to the layer "described".
+ IdSmallGroup is not available for this size.
+
+gap> r := SmallGroupsInformationRecord( 2088 );;
+gap> [ r.ranges[ 1 ].text, r.sources ];
+[ "cyclic", [ "Hoelder1893" ] ]
+gap> SmallGroupsAddLayer( rec( name := "uninformed", available := ReturnFail,
+> group := ReturnFail, informationRecord := 42 ) );
+Error, .informationRecord must be a function
+
#
# put the library back as it was, so the stand-ins do not follow the rest of
# the tests around
@@ -307,8 +351,8 @@ Error, .idAvailable is of no use without .id
gap> SMALL_GROUPS_LAYERS := saved.byName;;
gap> SMALL_GROUPS_LAYER_LIST := saved.layers;;
gap> SMALL_AVAILABLE_FUNCS := saved.avail;;
-gap> List( [ 2016, 2025, 2040, 2052, 2064, 2072 ], SmallGroupsAvailable );
-[ false, false, false, false, false, false ]
+gap> List( [ 2016, 2025, 2040, 2052, 2064, 2072, 2088 ], SmallGroupsAvailable );
+[ false, false, false, false, false, false, false ]
gap> NumberSmallGroups( 96 );
231
diff --git a/tst/smallgrp01.tst b/tst/smallgrp01.tst
index 1aa98fb..5555fac 100644
--- a/tst/smallgrp01.tst
+++ b/tst/smallgrp01.tst
@@ -103,6 +103,16 @@ gap> SmallGroupsInformation( 32 );
IdSmallGroup is available for this size.
+# doc/../gap/small.gd:1041-1050
+gap> r := SmallGroupsInformationRecord( 32 );;
+gap> r.number;
+51
+gap> r.ranges[ 2 ];
+rec( from := 2, text := "rank 2", to := 20, values := rec( RankPGroup := 2 ) )
+gap> r.sources;
+[ "OBr90", "JNO90", "OBr91", "BescheEick98", "BescheEick1000",
+ "BescheEick768" ]
+
# doc/../gap/small.gd:854-856
gap> UnloadSmallGroupsData();
diff --git a/tst/smlinfo.tst b/tst/smlinfo.tst
index ad3d576..37e065f 100644
--- a/tst/smlinfo.tst
+++ b/tst/smlinfo.tst
@@ -629,5 +629,78 @@ gap> SmallGroupsInformation(2187);
IdSmallGroup is not available for this size.
+#
+# SmallGroupsInformationRecord returns what SmallGroupsInformation prints
+#
+gap> r := SmallGroupsInformationRecord( 96 );;
+gap> [ r.order, r.number, r.layer, r.layerNumber, r.idAvailable, r.sortedBy ];
+[ 96, 231, "SmallGrp", 2, true, "Frattini factor" ]
+gap> r.ranges[ 1 ];
+rec( from := 1, text := "Frattini factor [ 6, 1 ]", to := 1,
+ values := rec( FrattinifactorId := [ 6, 1 ] ) )
+gap> r.ranges[ Length( r.ranges ) ];
+rec( from := 226, text := "trivial Frattini subgroup", to := 231,
+ values := rec( FrattinifactorSize := 96 ) )
+gap> r.indexed;
+[ "IsAbelian", "IsNilpotentGroup", "IsSupersolvableGroup", "IsSolvableGroup",
+ "LGLength", "FrattinifactorSize", "FrattinifactorId" ]
+gap> r := SmallGroupsInformationRecord( 512 );;
+gap> r.ranges[ 2 ];
+rec( from := 2, text := "rank 2 and p-class 3", to := 10,
+ values := rec( PClassPGroup := 3, RankPGroup := 2 ) )
+gap> List( r.ranges{ [ 1, Length( r.ranges ) ] }, x -> [ x.from, x.text ] );
+[ [ 1, "cyclic" ], [ 10494213, "elementary abelian" ] ]
+gap> [ r.layerNumber, r.idAvailable, r.sources ];
+[ 7, false, [ "EOB98", "EOB99", "OBr90", "BEO01" ] ]
+gap> r := SmallGroupsInformationRecord( 1536 );;
+gap> List( r.ranges, x -> [ x.from, x.to, x.text ] );
+[ [ 1, 10494213, "nilpotent" ],
+ [ 10494214, 408526597, "normal Sylow 3-subgroup" ],
+ [ 408526598, 408544625, "normal Sylow 2-subgroup" ],
+ [ 408544626, 408641062, "no normal Sylow subgroup" ] ]
+gap> r := SmallGroupsInformationRecord( 2010 );;
+gap> List( r.ranges, x -> [ x.from, x.to, x.text ] );
+[ [ 1, 1, "abelian" ], [ 2, 2, "socle C_670 and factor C_3" ],
+ [ 3, 9, "socle C_1005 and factor C_2" ],
+ [ 10, 12, "socle C_335 and factor C_6" ] ]
+gap> r := SmallGroupsInformationRecord( 30 );;
+gap> [ r.ranges, r.sources ];
+[ [ ], [ "Hoelder1893" ] ]
+gap> SmallGroupsInformationRecord( 1024 );
+fail
+
+# the ranges list all groups, in order, and agree with the groups
+gap> covers := function( n )
+> local r, prev, x;
+> r := SmallGroupsInformationRecord( n );
+> prev := 0;
+> for x in r.ranges do
+> if x.from <> prev + 1 or x.to < x.from then
+> return false;
+> fi;
+> prev := x.to;
+> od;
+> return prev = r.number;
+> end;;
+gap> Filtered( [ 32, 96, 243, 486, 512, 729, 768, 1152, 1536, 1920, 2010, 2401,
+> 3645, 11^4, 7^5, 17325 ], n -> not covers( n ) );
+[ ]
+gap> agrees := function( n )
+> local x, G, nam;
+> for x in SmallGroupsInformationRecord( n ).ranges do
+> for G in [ SmallGroup( n, x.from ), SmallGroup( n, x.to ) ] do
+> for nam in RecNames( x.values ) do
+> if ValueGlobal( nam )( G ) <> x.values.( nam ) then
+> return [ x, nam ];
+> fi;
+> od;
+> od;
+> od;
+> return true;
+> end;;
+gap> Filtered( [ 32, 96, 512, 1152, 1920, 2010, 2401, 11^4, 7^5 ],
+> n -> agrees( n ) <> true );
+[ ]
+
#
gap> STOP_TEST("smlinfo.tst");