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" );