diff --git a/doc/ref/pcgs.xml b/doc/ref/pcgs.xml index 5af593e828..289ea4ff65 100644 --- a/doc/ref/pcgs.xml +++ b/doc/ref/pcgs.xml @@ -373,6 +373,8 @@ series. See also Section for a more explicit possibil <#Include Label="ChiefNormalSeriesByPcgs"> <#Include Label="IndicesNormalSteps"> <#Include Label="NormalSeriesByPcgs"> +<#Include Label="PcgsSeriesInfo"> +<#Include Label="IndicesNormalStepsBounded"> diff --git a/lib/claspcgs.gi b/lib/claspcgs.gi index e5e14dad1a..9f669040b5 100644 --- a/lib/claspcgs.gi +++ b/lib/claspcgs.gi @@ -546,6 +546,7 @@ local G, home, # the group and the home pcgs step, # counter looping over K, L, # members of indstep, # indice normal steps + info, # pcgs and indices of the series used Ldep, # depth of L in pcgs Kp,mK,Lp,mL, # induced and modulo pcgs's LcapH,KcapH, # intersections @@ -627,17 +628,22 @@ local G, home, # the group and the home pcgs # we prescribed a series home:=opt.pcgs; eas:=EANormalSeriesByPcgs(home); + indstep:=IndicesEANormalSteps(home); cent:=false; elif IsPGroup(G) then - home:=PcgsPCentralSeriesPGroup(G); + info:=PcgsPCentralSeriesPGroupInfo(G); + home:=info.pcgs; eas:=PCentralNormalSeriesByPcgsPGroup(home); + indstep:=info.indices; cent:=ReturnTrue; else - home:=PcgsElementaryAbelianSeries(G); + info:=PcgsElementaryAbelianSeriesInfo(G); + home:=info.pcgs; eas:=EANormalSeriesByPcgs(home); + indstep:=info.indices; cent:=function(cl, N, L) return ForAll(N, k -> ForAll @@ -657,10 +663,9 @@ local G, home, # the group and the home pcgs if cent=false then cent:=PcClassFactorCentralityTest; fi; - indstep:=IndicesEANormalSteps(home); # is the series large (but can be rectified)? - step:=IndicesEANormalStepsBounded(home,2^15); + step:=IndicesNormalStepsBounded(home,indstep,2^15); if indstep<>step then indstep:=step; eas:=List(indstep,x->SubgroupByPcgs(GroupOfPcgs(home), @@ -990,6 +995,7 @@ local G,home, # the group and the home pcgs step, # counter looping over K, L, # members of indstep, # indice normal steps + info, # pcgs and indices of the series used Ldep, # depth of L in pcgs Kp,Lp,mL, # induced and modulo pcgs's N, cent, # elementary abelian factor, for affine action @@ -1024,21 +1030,23 @@ local G,home, # the group and the home pcgs # w.r.t. . if IsPGroup(G) then - home:=PcgsPCentralSeriesPGroup(G); + info:=PcgsPCentralSeriesPGroupInfo(G); + home:=info.pcgs; eas:=PCentralNormalSeriesByPcgsPGroup(home); cent:=ReturnTrue; else - home:=PcgsElementaryAbelianSeries(G); + info:=PcgsElementaryAbelianSeriesInfo(G); + home:=info.pcgs; eas:=EANormalSeriesByPcgs(home); cent:=PcClassFactorCentralityTest; fi; - indstep:=IndicesEANormalSteps(home); + indstep:=info.indices; # is the series large (but can be rectified)? - step:=IndicesEANormalStepsBounded(home,2^15); + step:=IndicesNormalStepsBounded(home,indstep,2^15); if indstep<>step then indstep:=step; eas:=List(indstep,x->SubgroupByPcgs(GroupOfPcgs(home), diff --git a/lib/grppc.gi b/lib/grppc.gi index f01a7af92d..e070f9da26 100644 --- a/lib/grppc.gi +++ b/lib/grppc.gi @@ -1271,7 +1271,7 @@ local G, home, # the supergroup (of and ), the home pcgs N, cent, # elementary abelian factor, for affine action cls, # classes in range/source of homomorphism opr, # (elm^opr)=cls.representative - nexpo,indstep,Ldep,allcent; + nexpo,indstep,info,Ldep,allcent; # Treat the case of a trivial group. if IsTrivial( U ) then @@ -1294,16 +1294,18 @@ local G, home, # the supergroup (of and ), the home pcgs # w.r.t. . if IsPGroup( G ) then - home:=PcgsCentralSeries(G); + info:=PcgsCentralSeriesInfo(G); + home:=info.pcgs; eas:=CentralNormalSeriesByPcgs(home); cent:=ReturnTrue; else - home:=PcgsElementaryAbelianSeries(G); + info:=PcgsElementaryAbelianSeriesInfo(G); + home:=info.pcgs; eas:=EANormalSeriesByPcgs(home); cent:=PcClassFactorCentralityTest; fi; - indstep:=IndicesEANormalSteps(home); + indstep:=info.indices; Hp:=InducedPcgs(home,H); @@ -1451,7 +1453,7 @@ local G, # common parent KcapH,LcapH, # pcgs's of intersections with N, cent, # elementary abelian factor, for affine action tra, # transversal for candidates - nexpo,indstep,Ldep,allcent, + nexpo,indstep,info,Ldep,allcent, cl, i; # loop variables # Treat trivial cases. @@ -1479,10 +1481,12 @@ local G, # common parent eas:=fail; if IsPGroup( G ) then - home:=PcgsPCentralSeriesPGroup(G); + info:=PcgsPCentralSeriesPGroupInfo(G); + home:=info.pcgs; eas:=PCentralNormalSeriesByPcgsPGroup(home); if NT in eas then cent := ReturnTrue; + indstep:=info.indices; else eas:=fail; # useless fi; @@ -1492,8 +1496,8 @@ local G, # common parent home:=PcgsElementaryAbelianSeries([G,NT]); eas:=EANormalSeriesByPcgs(home); cent:=PcClassFactorCentralityTest; + indstep:=IndicesEANormalSteps(home); fi; - indstep:=IndicesEANormalSteps(home); # series to NT ea2:=List(eas,i->ClosureGroup(NT,i)); diff --git a/lib/pcgs.gd b/lib/pcgs.gd index e1cf7172d8..8982cf5e98 100644 --- a/lib/pcgs.gd +++ b/lib/pcgs.gd @@ -718,6 +718,88 @@ DeclareAttribute( "IndicesNormalSteps", IsPcgs ); ## DeclareAttribute( "NormalSeriesByPcgs", IsPcgs); + +############################################################################# +## +#A PcgsElementaryAbelianSeriesInfo( ) +#A PcgsCentralSeriesInfo( ) +#A PcgsPCentralSeriesPGroupInfo( ) +#A PcgsChiefSeriesInfo( ) +#O PcgsSeriesInfo( , ) +## +## <#GAPDoc Label="PcgsSeriesInfo"> +## +## Pcgs together with the indices of its series +## +## +## +## +## +## +## +## These attributes return a record with the components pcgs, a pcgs +## for G refining a normal series of the kind in question, and +## indices, the list of indices in this pcgs at which the steps of +## that series start, as described for +## . +##

+## Obtaining both from one call is preferable to obtaining the pcgs and +## then asking it for its indices: a pcgs can belong to several series, and +## the indices stored on it need not be the ones of the series that was +## asked for. +##

+## dispatches on filt, which must be one +## of the properties , +## , +## or +## , and returns what the corresponding +## attribute returns. It is a tag based operation +## (see ), so a package can support +## further kinds of series by installing a method for its own property. +##

+## G := DihedralGroup( 16 );; +## gap> info := PcgsSeriesInfo( IsPcgsCentralSeries, G );; +## gap> info.indices = PcgsCentralSeriesInfo( G ).indices; +## true +## gap> info.indices = IndicesCentralNormalSteps( info.pcgs ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareAttribute( "PcgsElementaryAbelianSeriesInfo", IsGroup ); +DeclareAttribute( "PcgsCentralSeriesInfo", IsGroup ); +DeclareAttribute( "PcgsPCentralSeriesPGroupInfo", IsGroup ); +DeclareAttribute( "PcgsChiefSeriesInfo", IsGroup ); + +DeclareTagBasedOperation( "PcgsSeriesInfo", [ IsOperation, IsGroup ] ); + + +############################################################################# +## +#F IndicesNormalStepsBounded( , , ) +## +## <#GAPDoc Label="IndicesNormalStepsBounded"> +## +## +## +## +## Let indices be the indices of the steps of a normal series +## refined by pcgs. This function returns a refinement of +## indices, aiming to ensure that no factor of the series is larger +## than bound, without changing pcgs. +##

+## is the special case in which +## the indices are taken from . +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "IndicesNormalStepsBounded" ); + + ############################################################################# ## #P IsPrimeOrdersPcgs( ) diff --git a/lib/pcgs.gi b/lib/pcgs.gi index 8b93ad4f6a..9c7f76ec05 100644 --- a/lib/pcgs.gi +++ b/lib/pcgs.gi @@ -1488,12 +1488,57 @@ InstallPcgsSeriesFromIndices(PCentralNormalSeriesByPcgsPGroup, ############################################################################# ## -#M IndicesEANormalStepsBounded( , ) +#M PcgsElementaryAbelianSeriesInfo( ) . . . . pcgs and its own indices +#M PcgsCentralSeriesInfo( ) +#M PcgsPCentralSeriesPGroupInfo( ) +#M PcgsChiefSeriesInfo( ) +#M PcgsSeriesInfo( , ) +## +## Each kind asks for the indices belonging to *its own* series, rather +## than for `IndicesEANormalSteps' which a pcgs may carry for a different +## series it also belongs to. +## +BindGlobal( "InstallPcgsSeriesInfo", function( info, pcgsattr, indices, filt ) + + InstallMethod( info, "from pcgs and its indices", [ IsGroup ], + function( G ) + local pcgs; + pcgs:= pcgsattr( G ); + return rec( pcgs:= pcgs, indices:= indices( pcgs ) ); + end ); + + InstallTagBasedMethod( PcgsSeriesInfo, filt, { f, G } -> info( G ) ); + +end ); + +InstallPcgsSeriesInfo( PcgsElementaryAbelianSeriesInfo, + PcgsElementaryAbelianSeries, IndicesEANormalSteps, + IsPcgsElementaryAbelianSeries ); +InstallPcgsSeriesInfo( PcgsCentralSeriesInfo, + PcgsCentralSeries, IndicesCentralNormalSteps, IsPcgsCentralSeries ); +InstallPcgsSeriesInfo( PcgsPCentralSeriesPGroupInfo, + PcgsPCentralSeriesPGroup, IndicesPCentralNormalStepsPGroup, + IsPcgsPCentralSeriesPGroup ); +InstallPcgsSeriesInfo( PcgsChiefSeriesInfo, + PcgsChiefSeries, IndicesChiefNormalSteps, IsPcgsChiefSeries ); + +InstallTagBasedMethod( PcgsSeriesInfo, function( filt, G ) + Error( "no method for series kind ", NameFunction( filt ), + " installed for `PcgsSeriesInfo'" ); +end ); + +############################################################################# +## +#F IndicesNormalStepsBounded( ,, ) +#F IndicesEANormalStepsBounded( , ) ## InstallGlobalFunction(IndicesEANormalStepsBounded,function(pcgs,bound) -local rel,ind,gp,i,j,try; + return IndicesNormalStepsBounded(pcgs,IndicesEANormalSteps(pcgs),bound); +end); + +InstallGlobalFunction(IndicesNormalStepsBounded,function(pcgs,ind,bound) +local rel,gp,i,j,try; rel:=RelativeOrders(pcgs); - ind:=IndicesEANormalSteps(pcgs); gp:=GroupOfPcgs(pcgs); i:=2; while i<=Length(ind) do diff --git a/tst/testinstall/pcgsseriesinfo.tst b/tst/testinstall/pcgsseriesinfo.tst new file mode 100644 index 0000000000..3f19f2df02 --- /dev/null +++ b/tst/testinstall/pcgsseriesinfo.tst @@ -0,0 +1,79 @@ +#@local G, P, ind, kinds, info, series, checkinfo, isEA, isCentral +gap> START_TEST("pcgsseriesinfo.tst"); + +# the indices returned must describe a normal series refined by the pcgs +# returned, and that series must be of the kind that was asked for +gap> series := info -> List( info.indices, +> i -> SubgroupByPcgs( GroupOfPcgs( info.pcgs ), +> InducedPcgsByPcSequence( info.pcgs, +> info.pcgs{[ i .. Length( info.pcgs ) ]} ) ) );; +gap> isEA := ser -> ForAll( [ 2 .. Length( ser ) ], +> i -> HasElementaryAbelianFactorGroup( ser[i-1], ser[i] ) );; +gap> isCentral := ser -> ForAll( [ 2 .. Length( ser ) ], +> i -> IsSubset( ser[i], CommutatorSubgroup( ser[1], ser[i-1] ) ) );; +gap> checkinfo := function( info, prop ) +> local ser; +> if info.indices[1] <> 1 or +> Last( info.indices ) <> Length( info.pcgs ) + 1 then +> return "indices do not start with 1 or do not end with n+1"; +> fi; +> ser := series( info ); +> if not ForAll( ser, N -> IsNormal( ser[1], N ) ) then +> return "series is not normal"; +> elif not prop( ser ) then +> return "series is not of the kind that was asked for"; +> fi; +> return true; +> end;; + +# pc groups, permutation groups, direct products; the codes are those of +# SmallGroup( 96, 3 ) and SmallGroup( 64, 10 ), spelled out so that this test +# does not need the small groups library +gap> for G in [ DihedralGroup( 16 ), PcGroupCode( 55306968584587147680, 96 ), +> SylowSubgroup( SymmetricGroup( 8 ), 2 ), +> DirectProduct( DihedralGroup( 8 ), CyclicGroup( 4 ) ) ] do +> info := PcgsElementaryAbelianSeriesInfo( G ); +> if checkinfo( info, isEA ) <> true then +> Error( checkinfo( info, isEA ), " for ", G ); +> elif info.indices <> +> PcgsSeriesInfo( IsPcgsElementaryAbelianSeries, G ).indices then +> Error( "tag based dispatch disagrees for ", G ); +> fi; +> od; + +# the central kinds need a nilpotent group; their indices must be the ones of +# the central series, not the ones of some elementary abelian series which +# the same pcgs may also belong to +gap> for G in [ DihedralGroup( 16 ), PcGroupCode( 217336074077211757, 64 ), +> SylowSubgroup( SymmetricGroup( 8 ), 2 ) ] do +> for kinds in [ [ PcgsCentralSeriesInfo, IsPcgsCentralSeries, +> IndicesCentralNormalSteps ], +> [ PcgsPCentralSeriesPGroupInfo, +> IsPcgsPCentralSeriesPGroup, +> IndicesPCentralNormalStepsPGroup ] ] do +> info := kinds[1]( G ); +> if checkinfo( info, isCentral ) <> true then +> Error( checkinfo( info, isCentral ), " for ", G ); +> elif info.indices <> kinds[3]( info.pcgs ) then +> Error( "indices are not the ones of this kind, for ", G ); +> elif info.indices <> PcgsSeriesInfo( kinds[2], G ).indices then +> Error( "tag based dispatch disagrees for ", G ); +> fi; +> od; +> od; + +# an unknown kind is reported as such +gap> PcgsSeriesInfo( IsFinite, DihedralGroup( 8 ) ); +Error, no method for series kind IsFinite installed for `PcgsSeriesInfo' + +# refining indices, without taking them off the pcgs +gap> P := SylowSubgroup( SymmetricGroup( 8 ), 2 );; +gap> info := PcgsPCentralSeriesPGroupInfo( P );; +gap> IndicesNormalStepsBounded( info.pcgs, info.indices, 2^15 ) = info.indices; +true +gap> ind := IndicesNormalStepsBounded( info.pcgs, info.indices, 2 );; +gap> IsSubset( ind, info.indices ) and Length( ind ) >= Length( info.indices ); +true + +# that's all, folks +gap> STOP_TEST( "pcgsseriesinfo.tst" );