From 716fa52f234ad08717532d67a47c2e5e782c648b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 16 Oct 2026 02:09:34 +0200 Subject: [PATCH] Add SmallGroupsInformationRecord SmallGroupsInformation only prints, so other software cannot use what it knows about the groups of an order. SmallGroupsInformationRecord returns the same information as a record: the number of groups, the layer, whether identification is available, the indexed selection criteria, how the groups are arranged as a list of id ranges with the attribute values they share, and the publications behind the layer. SmallGroupsInformation now prints from that record; its output is unchanged. Layers added with SmallGroupsAddLayer can supply the record through the new optional component informationRecord. Assisted-by: Generative AI --- doc/overview.xml | 1 + gap/addlayer.gi | 18 +- gap/small.gd | 88 +++++ gap/smlinfo.gi | 799 ++++++++++++++++++++++++++++++++------------- tst/addlayer.tst | 48 ++- tst/smallgrp01.tst | 10 + tst/smlinfo.tst | 73 +++++ 7 files changed, 810 insertions(+), 227 deletions(-) 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");