Welcome To Our Shell

Mister Spy & Souheyl Bypass Shell

Current Path : /usr/share/gap/lib/

Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
Upload File :
Current File : //usr/share/gap/lib/grppcatr.gi

#############################################################################
##
#W  grppcatr.gi                 GAP Library                      Frank Celler
#W                                                             & Bettina Eick
##
##
#Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
#Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
#Y  Copyright (C) 2002 The GAP Group
##
##  This file contains the methods for attributes of polycylic groups.
##


#############################################################################
##
#M  AsSSortedList( <pcgrp> )
##
InstallMethod( AsSSortedListNonstored,"pcgs computable groups",true,
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],0,
function( grp )
    local   elms,  pcgs,  g,  u,  e,  i;

    elms := [ One(grp) ];
    pcgs := Pcgs(grp);

    for g  in pcgs  do
        u := One(grp);
        e := ShallowCopy(elms);
        for i  in [ 1 .. RelativeOrderOfPcElement(pcgs,g)-1 ]  do
            u := u * g;
            UniteSet( elms, e * u );
        od;
    od;

    return elms;

end );

InstallMethod( AsSSortedList,"pcgs computable groups",true,
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],0,
  AsSSortedListNonstored);

#############################################################################
##
#M  AsList(<G>)
##
InstallMethod(AsList,"pc group",true,[IsPcGroup],0,AsSSortedListNonstored);


#############################################################################
##
#M  CompositionSeries( <G> )
##
InstallMethod( CompositionSeries, "pcgs computable groups", true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ], 0,
function( G )
    local   pcgsG,  m,  S,  parent,  i,  igs,  U;

    # get a pcgs of <G>
    pcgsG := Pcgs(G);
    m     := Length(pcgsG);
    S     := [];

    # if <pcgsG> is induced use the parent
    parent := ParentPcgs(pcgsG);
    #if IsInducedPcgs(pcgsG)  then
    #    parent := ParentPcgs(pcgsG);
    #else
    #    parent := pcgsG;
    #fi;

    # compute the pcgs of the composition subgroups
    for i  in [ 1 .. m+1 ]  do
        igs := InducedPcgsByPcSequenceNC( parent, pcgsG{[i..m]} );
        U   := SubgroupByPcgs( G, igs );
        Add( S, U );
    od;

    # and return
    return S;

end );


#############################################################################
##
#M  DerivedSubgroup( <G> )
##
InstallMethod( DerivedSubgroup,
    "pcgs computable groups",
    true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],
    0,

function( U )
    local   pcgsU,  parent,  C,  i,  j,  tmp;

    # compute the commutators of the elements of a pcgs
    pcgsU := Pcgs(U);
    parent := ParentPcgs( pcgsU );
    C := [];
    for i  in [ 1 .. Length(pcgsU) ]  do
        for j  in [ i+1 .. Length(pcgsU) ]  do
            AddSet( C, Comm( pcgsU[j], pcgsU[i] ) );
        od;
    od;

    # if <pcgsU> is induced use the parent
    tmp := InducedPcgsByGeneratorsNC( parent, C );
    C := SubgroupByPcgs( U, tmp );
    return C;
end);

    
#############################################################################
##
#M  ElementaryAbelianSeries( <G> )
##
InstallMethod( ElementaryAbelianSeries,
    "pcgs computable groups using `PcgsElementaryAbelianSeries'", true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ], 0,
  G->EANormalSeriesByPcgs(PcgsElementaryAbelianSeries(G)));


#############################################################################
##
#M  FrattiniSubgroup( <G> )
##
InstallMethod( FrattiniSubgroup,
    "pcgs computable groups using prefrattini and core",
    true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],
    0,

function( G )
    G := Core( G, PrefrattiniSubgroup( G ) );
    Assert( 2, IsNilpotentGroup( G) );
    SetIsNilpotentGroup( G, true );
    return G;
end);


#############################################################################
##
#M  HallSubgroupOp( <G>, <pi> )
##
##  compute and use special pcgs of <G>.
##
InstallMethod( HallSubgroupOp, 
    "pcgs computable groups using special pcgs",
    true,
    [ IsGroup and CanEasilyComputePcgs and IsFinite, IsList ],
    0,

function( G, pi )
    local spec, weights, gens, i, S;

    spec := SpecialPcgs( G );
    weights := LGWeights( spec );
    gens := [];
    for i in [1..Length(spec)] do
        if weights[i][3] in pi then Add( gens, spec[i] ); fi;
    od;
    gens := InducedPcgsByPcSequenceNC( spec, gens );
    S := SubgroupByPcgs( G, gens );
    return S;
end );

RedispatchOnCondition(HallSubgroupOp,true,[IsGroup,IsList],
  [IsGroup and IsSolvableGroup and CanEasilyComputePcgs and IsFinite,
  IsList ],0);


#############################################################################
##
#M  PrefrattiniSubgroup( <G> )
##
InstallMethod( PrefrattiniSubgroup,
    "pcgs computable groups using special pcgs",
    true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],
    0,

function( G )
    local   pcgs,  spec,  first,  weights,  m,  pref,  i,  start,  
            next,  p,  pcgsS,  pcgsN,  pcgsL,  mats,  modu,  rad,  
            elms,  P;

    spec    := SpecialPcgs( G );
    first   := LGFirst( spec );
    weights := LGWeights( spec );
    m       := Length( spec );
    pref    := [];
    for i in [1..Length(first)-1] do
        start := first[i];
        next  := first[i+1];
        p     := weights[start][3];
        if weights[start][1] > 1 and weights[start][2] = 1 and 
           next-start > 1 then
         
            pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
            pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
            pcgsL := pcgsS mod pcgsN;

            mats  := LinearOperationLayer( spec, pcgsL );
            modu  := GModuleByMats( mats, GF(p) );
            rad   := MTX.BasisRadical( modu );
            elms  := List( rad, x -> PcElementByExponentsNC( pcgsL, x ) );
            Append( pref, elms );

        elif weights[start][2] > 1 then
            Append(pref, spec{[start..next-1]} );
        fi;
    od;
    pref := InducedPcgsByPcSequenceNC( spec, pref );
    P    := SubgroupByPcgs( G, pref );
    return P;
end);

#############################################################################
##
#M  IsFinite( <pcgrp> )
##
InstallMethod( IsFinite,
    "pcgs computable groups",
    true,
    [ IsGroup and CanEasilyComputePcgs ],
    0,
    grp -> not 0 in RelativeOrders( Pcgs( grp ) ) );
#T is this method necessary at all?


#############################################################################
##
#M  Size( <pcgrp> )
##
InstallMethod( Size, "pcgs computable groups", true,
    [ IsGroup and CanEasilyComputePcgs ], 0,

function( grp )
    local   ords;

    ords := RelativeOrders(Pcgs(grp));
    if 0 in ords  then
        return infinity;
    else
        return Product(ords);
    fi;
end );


#############################################################################
##
#M  SylowComplementOp( <G>, <p> )
##
##  compute and use special pcgs of <G>.
##
InstallMethod( SylowComplementOp, 
    "pcgs computable groups using special pcgs",
    true,
    [ IsGroup and CanEasilyComputePcgs and IsFinite,
      IsPosInt ],
    80,

function( G, p )
    local   spec,  weights,  gens,  i,  S,  pi;

    spec := SpecialPcgs( G );
    weights := LGWeights( spec );
    gens := [];
    pi := [];
    for i in [1..Length(spec)] do
        if weights[i][3] <> p then
            Add( gens, spec[i] );
            AddSet( pi, weights[i][3] );
        fi;
    od;
    gens := InducedPcgsByPcSequenceNC( spec, gens );
    S := SubgroupByPcgs( G, gens );
    SetHallSubgroup( G, pi, S );
    if Length( pi ) = 1 then
        SetSylowSubgroup( G, pi[1], S );
    fi;
    return S;
end );

RedispatchOnCondition(SylowComplementOp,true,[IsGroup,IsPosInt],
  [IsGroup and IsSolvableGroup and CanEasilyComputePcgs and IsFinite,
  IsPosInt ],0);


#############################################################################
##
#M  SylowSubgroupOp( <G>, <p> )
##  
##  compute and use special pcgs of <G>.
##
InstallMethod( SylowSubgroupOp, 
    "pcgs computable groups using special pcgs",
    true,
    [ IsGroup and CanEasilyComputePcgs and IsFinite,
      IsPosInt ],
    100,

function( G, p )
    local   spec,  weights,  gens,  i,  S;

    spec := SpecialPcgs( G );
    weights := LGWeights( spec );
    gens := [];
    for i  in [1..Length(spec)]  do
        if weights[i][3] = p then Add( gens, spec[i] ); fi;
    od;
    gens := InducedPcgsByPcSequenceNC( spec, gens );
    S := SubgroupByPcgs( G, gens );
    if Size(S) > 1 then
        SetIsPGroup( S, true );
        SetPrimePGroup( S, p );
        SetHallSubgroup(G, [p], S);
    fi;
    return S;
end );


#############################################################################
##

#F  MaximalSubgroupClassesRepsLayer( <pcgs>, <layer> )
##
MaximalSubgroupClassesRepsLayer := function( pcgs, l )
    local first, weights, m, start, next, pcgsS, pcgsN, pcgsL, p, mats, 
          modu, maxi, i, elms, sub, M, G;

    first   := LGFirst( pcgs );
    weights := LGWeights( pcgs );
    m       := Length( pcgs );
    start   := first[l];
    next    := first[l+1];
    G       := GroupOfPcgs( pcgs );

    # catch the trivial case
    if weights[start][2] <> 1 then
        return [];
    fi;

    pcgsS := InducedPcgsByPcSequenceNC( pcgs, pcgs{[start..m]} );
    pcgsN := InducedPcgsByPcSequenceNC( pcgs, pcgs{[next..m]} );
    pcgsL := pcgsS mod pcgsN;
    p     := weights[start][3];

    mats  := LinearOperationLayer( pcgs, pcgsL );
    modu  := GModuleByMats( mats,  GF(p) );
    maxi  := MTX.BasesMaximalSubmodules( modu );

    for i in [1..Length( maxi )] do
        maxi[i] := ShallowCopy( maxi[i] );
        TriangulizeMat( maxi[i] );
        elms := List( maxi[i], x -> PcElementByExponentsNC( pcgsL, x ) );
        sub  := Concatenation( pcgs{[1..start-1]}, elms, pcgsN );
        sub  := InducedPcgsByPcSequenceNC( pcgs, sub );
        M    := SubgroupByPcgs( G, sub );
        maxi[i] := M;
    od;
    return maxi;
end;


MAXSUBS_BY_PCGS:=function( G )
    local spec, first, max, i, new;

    TryMaxSubgroupTainter(G);
    spec  := SpecialPcgs(G);
    first := LGFirst( spec );
    max   := [];
    for i in [1..Length(first)-1] do
        new := MaximalSubgroupClassesRepsLayer( spec, i );
        Append( max, new );
    od;
    return max;

end;

#############################################################################
##
#M  MaximalSubgroupClassReps( <G> )
##
InstallMethod( TryMaximalSubgroupClassReps,
    "pcgs computable groups using special pcgs",
    true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],
    0,
    MAXSUBS_BY_PCGS);

#fallback
InstallMethod( TryMaximalSubgroupClassReps,
    "pcgs computable groups using special pcgs",
    true, 
    [ IsGroup and IsSolvableGroup and IsFinite ],
    0,
    MAXSUBS_BY_PCGS);

#############################################################################
##
#M  MaximalSubgroups( <G> )
##
InstallMethod( MaximalSubgroups,
    "pcgs computable groups using special pcgs",
    true, 
    [ IsGroup and HasFamilyPcgs and IsFinite ],
    0,

function( G )
    local spec, first, m, max, i, U, new, M;

    spec  := SpecialPcgs(G);
    first := LGFirst( spec );
    m     := Length( spec );
    max   := [];
    for i in [1..Length(first)-1] do
        U   := Subgroup( G, spec{[first[i]..m]} );
        new := MaximalSubgroupClassesRepsLayer( spec, i );
        for M in new do
            if IsNormal( G, M ) then
                Add( max, M );
            else
                Append( max, ConjugateSubgroups( U, M ) );
            fi;
        od; 
    od;
    return max;

end );


#############################################################################
##
#M  ConjugacyClassesMaximalSubgroups( <G> )
##
#T InstallMethod( ConjugacyClassesMaximalSubgroups,
#T     "generic method for groups with pcgs",
#T    true, 
#T    [ IsGroup and CanEasilyComputePcgs ],
#T    0,
#T
#T function( G )
#T    return List( MaximalSubgroupClassReps(G), 
#T           x -> ConjugacyClassSubgroup( G, x ) );
#T end);


#############################################################################
##
#M  NormalMaximalSubgroups( <G> )
##
InstallMethod( NormalMaximalSubgroups,
    "pcgs computable groups using special pcgs",
    true, 
    [ IsGroup and CanEasilyComputePcgs and IsFinite ],
    0,

function( G )
    local   spec,  first,  weights,  max,  i,  new;

    spec    := SpecialPcgs( G );
    first   := LGFirst( spec );
    weights := LGWeights( spec );
    max     := [];
    for i in [1..Length(first)-1] do
        if weights[first[i]][1] = 1 then
            new := MaximalSubgroupClassesRepsLayer( spec, i );
            Append( max, new );
        fi;
    od;
    return max;

end );


#############################################################################
##
#M  MaximalNormalSubgroups( <G> )
##
InstallMethod( MaximalNormalSubgroups, "for abelian groups",
               [ IsGroup and IsAbelian ],
               # IsGroup and IsFinite ranks higher than IsGroup and IsAbelian,
               # so we have to increase the rank, otherwise the method for
               # normal subgroup computation is selected.
               RankFilter( IsGroup and IsFinite and IsAbelian )
               - RankFilter( IsGroup and IsAbelian ),
function( G )
    local Gf,     # FactorGroup of G
          hom,    # homomorphism from G to Gf
          MaxGf,  # MaximalNormalSubgroups of Gf
          AbInv;  # abelian invariants of G
    if not IsPcGroup(G) then
        AbInv := AbelianInvariants(G);
        if 0 in AbInv then
            # (p) is a maximal normal subgroup in Z for every prime p
            Error("number of maximal normal subgroups is infinity");
        else
            # convert it to an abelian PcGroup with same invariants
            hom := IsomorphismPcGroup(G);
            Gf := Image(hom);
            # for abelian groups all maximal normal subgroup are also
            # normal maximal subgroups and vice-versa
            MaxGf := NormalMaximalSubgroups(Gf);
            return List(MaxGf, N -> PreImage(hom, N));
        fi;
    else
        # for abelian groups all maximal normal subgroup are also
        # normal maximal subgroups and vice-versa
        # for abelian pc groups return all maximal subgroups
        # NormalMaximalSubgroups seems to omit some unnecessary checks,
        # hence faster than MaximalSubgroups
        return NormalMaximalSubgroups(G);
    fi;
end);

InstallMethod( MaximalNormalSubgroups, "for solvable groups",
              [ IsGroup and IsSolvableGroup ],
               # IsGroup and IsFinite ranks higher than
               # IsGroup and IsSolvableGroup, so we have to increase the
               # rank, otherwise the method for normal subgroup computation
               # is selected.
               RankFilter( IsGroup and IsFinite and IsSolvableGroup )
               - RankFilter( IsGroup and IsSolvableGroup ),
function( G )
    local Gf,     # FactorGroup of G
          hom,    # homomorphism from G to Gf
          MaxGf;  # MaximalNormalSubgroups of Gf
    # every maximal normal subgroup is above the derived subgroup
    hom := MaximalAbelianQuotient(G);
    Gf := Image(hom);
    # One would hope this is true
    SetIsAbelian(Gf, true);
    MaxGf := MaximalNormalSubgroups(Gf);
    return List(MaxGf, N -> PreImage(hom, N));
end);

RedispatchOnCondition( MaximalNormalSubgroups, true,
    [ IsGroup ],
    [ IsSolvableGroup ], 0);


#############################################################################
##
#F  ModifyMinGens( <pcgsG>, <pcgsS>, <pcgsL>, <min> )
##
ModifyMinGens := function( pcgs, pcgsS, pcgsL, min )
    local pcgsF, g, i, new, pcgsT, pcgsV;

    # set up
    pcgsF := pcgsS mod pcgsL;

    # try to modify mingens
    for g in pcgsF do
        for i in [1..Length( min )] do 
            new := ShallowCopy( min );
            new[i] := min[i] * g;
            pcgsT := InducedPcgsByPcSequenceAndGenerators(pcgs, pcgsL, new);
            pcgsT := Pcgs( ZassenhausIntersection( pcgs, pcgsS, pcgsT ) );
            if Length( pcgsT ) > Length( pcgsL ) then
                min[i] := new[i];
                return;
            fi;
        od;
    od;

    # mingens cannot be modified - add new generator
    Add( min, pcgsF[1] );
end;

#############################################################################
##
#F  MinimalGensLayer( <pcgsG>, <pcgsS>, <pcgsN>, <min> )
##
MinimalGensLayer := function( pcgs, pcgsS, pcgsN, min )
    local series, pcgsL, pcgsU, pcgsV, pcgsM;

    series := [pcgsN];

    # set up
    pcgsL  := pcgsN;
    pcgsU  := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min );
    pcgsV  := pcgsU;

    # loop
    while Length( pcgsU ) < Length( pcgs ) do

        # get intersection of V with layer
        pcgsM := Pcgs( ZassenhausIntersection( pcgs, pcgsS, pcgsV ) );
        if Length( pcgsM ) <> Length( pcgsL ) then
            Add( series, pcgsM );
        fi;
        pcgsL := series[Length(series)];

        # modify minimal gens
        ModifyMinGens( pcgs, pcgsS, pcgsL, min );
        pcgsV := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsL, min );
        pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min );
        if Length( pcgs ) = Length( pcgsV ) then
            pcgsS := pcgsL;
            Unbind( series[Length(series)] );
        fi;
    od;
    return min;
end;

#############################################################################
##
#M  MinimalGeneratingSet( <G> )
##
InstallMethod( MinimalGeneratingSet,
    "pcgs computable groups using special pcgs",
    true, [ IsPcGroup and IsFinite ], 0,

function( G )
    local spec, weights, first, m, mingens, i, start, next, j,
          pcgsN, pcgsS, pcgsU;

    if IsTrivial(G)  then
        return [];
    fi;
    spec    := SpecialPcgs( G );
    weights := LGWeights( spec );
    first   := LGFirst( spec );
    m       := Length( spec );

    # the first head
    mingens := spec{[1..first[2]-1]};
    i := 2;
    while i <= Length( first ) -1 and
        weights[first[i]][1] = 1 and weights[first[i]][2] = 1 do
        start := first[i];
        next  := first[i+1];
        for j in [1..next-start]  do
            if j <= Length(mingens)  then
                mingens[j] := mingens[j] * spec[ start+j-1 ];
            else
                Add(mingens, spec[ start+j-1 ] );
            fi;
        od;
        i := i + 1;
    od;
             
    # the other heads
    while i <= Length( first ) -1 do
        if weights[first[i]][2] = 1 then
            start := first[i];
            next  := first[i+1];
            pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
            pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
            mingens := MinimalGensLayer( spec, pcgsS, pcgsN, mingens );
        fi;
        i := i + 1;
    od;
    return Set(mingens);
end );

#############################################################################
##
#M  SmallGeneratingSet(<G>) 
##
InstallMethod(SmallGeneratingSet,"using minimal generating set",true,
  [IsPcGroup and IsFinite],0,
function (G)
  if Length(Pcgs(G))>14 then
    TryNextMethod();
  fi;
  return MinimalGeneratingSet(G);
end);

#############################################################################
##
#M  GeneratorsSmallest(<pcgrp>)
##
InstallMethod(GeneratorsSmallest,"group of pc words which is full family",
  true, [IsGroup and HasFamilyPcgs],0,
function(G)
local pcgs,gens,U,e,i,j,pa,ros,smallpcgs,exp;

  # the smallest generating system is obtained from the
  # family pcgs by throwing out redundant generators.
  pcgs:=InducedPcgsWrtFamilyPcgs(G);

  # normalize leading exponent to one
  pa  := ParentPcgs(pcgs);
  ros := RelativeOrders(pcgs);
  smallpcgs := [];
  for i  in [ 1 .. Length(pcgs) ]  do
      exp := LeadingExponentOfPcElement( pa, pcgs[i] );
      smallpcgs[i] := pcgs[i] ^ (1/exp mod ros[i]);
  od;


  # make entry 1 above the diagonale
  for i  in [ 1 .. Length(smallpcgs)-1 ]  do
      for j  in [ i+1 .. Length(smallpcgs) ]  do
	  exp := ExponentOfPcElement( pa, smallpcgs[i], DepthOfPcElement(
	      pa, smallpcgs[j] ) );
	  if exp <> 1  then
	      smallpcgs[i]:=smallpcgs[i]*smallpcgs[j]^(ros[j]-exp+1);
	  fi;
      od;
  od;

  gens:=[];
  U:=TrivialSubgroup(G);
  for i in [1..Length(smallpcgs)] do
    e:=Product(smallpcgs{[1..i]});
    if not e in U then
      Add(gens,e);
      U:=ClosureGroup(U,e);
    fi;
  od;
  return gens;

end);


#############################################################################
##
#F  NextStepCentralizer( <gens>, <cent>, <pcgsF>, <field> )
##
NextStepCentralizer := function( gens, cent, pcgsF, field )
    local   g,  newgens,  matlist,  notcentral,  h,  comm,  null,  j,  elm;
  
    for g in gens do
        if Length( cent ) = 0 then return []; fi;

        newgens := [];
        matlist := [];
        notcentral := [];
        for h in cent do
            comm := ExponentsOfPcElement( pcgsF, Comm( h, g ) ) * One(field);
            if comm = Zero( field ) * comm  then
                Add( newgens, h );
            else
                Add( notcentral, h );
                Add( matlist, comm );
            fi;
        od;
       
        if Length( matlist ) > 0  then
    
            # get nullspace
            null := TriangulizedNullspaceMat( matlist );

            # calculate elements corresponding to null
            for j  in [1..Length(null)]  do
                elm := PcElementByExponentsNC( pcgsF, notcentral, null[j] );
                Add( newgens, elm );
            od;
        fi;
        cent := newgens;
    od;
    return cent;
end;


#############################################################################
##
#F  GeneratorsCentrePGroup( <U> )
##
InstallGlobalFunction( GeneratorsCentrePGroup, function( U )
    local pcgs, spec, n, firs, p, field, ser, gens, cent, i, pcgsF;

    # catch the trivial case
    pcgs := Pcgs(U);
    if Length( pcgs ) = 0 then return []; fi;

    # set up series
    spec  := SpecialPcgs( U );
    n     := Length( spec );
    firs  := LGFirst( spec );
    p     := PrimePGroup( U );
    field := GF(p);
    ser   := List( firs, x ->
                   InducedPcgsByPcSequenceNC( spec, spec{[x..n]} ) );
    gens  := spec{[1..firs[2]-1]};
    cent  := gens;
    for i in [2..Length(ser)-1] do
        pcgsF := ser[i] mod ser[i+1];
        cent := NextStepCentralizer( gens, cent, pcgsF, field );
        Append( cent, AsList( pcgsF ) );
    od;
    return cent;
end ); 


#############################################################################
##
#F  CentrePcGroup( <G> )
##
InstallGlobalFunction (CentrePcGroup, function( G )
    local   spec,  first,  weights,  m,  primes,  cent,  i,  gens,  
            start,  next,  p,  j,  field,  pcgsS,  pcgsN,  pcgsF,  q,  
            U,  newgens,  matlist,  g,  conj,  expo,  order,  eigen,  
            null,  n,  elm, r, ksi, large, pcgsH, H, oper;

    # get special pcgs
    spec    := SpecialPcgs( G );
    first   := LGFirst( spec );
    weights := LGWeights( spec );
    m       := Length( spec );

    # get primes and set up
    primes   := Set( List( weights, x -> x[3] ) );
    cent     := List( primes, x -> [] );

    # the first nilpotent factor
    i := 1;
    gens := [];
    while i <= Length( first ) - 1 and weights[first[i]][1] = 1 do
        start := first[i];
        next  := first[i+1];
        p     := weights[start][3];
        j     := Position( primes, p );
        if weights[start][2] = 1 then
            gens[j] := spec{[start..next-1]};
            cent[j] := spec{[start..next-1]};
        elif weights[start][3] = p then
            field   := GF(p);
            pcgsS   := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
            pcgsN   := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
            pcgsF   := pcgsS mod pcgsN;
            cent[j] := NextStepCentralizer( gens[j], cent[j], pcgsF, field );
            Append( cent[j], AsList( pcgsF ) );
        fi;
        i := i + 1;
    od;

    # the remaining layers
    while i <= Length( first ) - 1 do
        start := first[i];
        next  := first[i+1];
        q     := weights[start][3];
        field := GF(q); 
        pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
        pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
        pcgsF := pcgsS mod pcgsN;
       
        for j in [1..Length(primes)] do
            p := primes[j]; 
            if p = q and (weights[start][2] > 1 or Length( cent[j] ) > 0) then
                
                pcgsH := spec mod pcgsN;
                H := GroupByPcgs( pcgsH );
                gens := List(cent[j], x->MappedPcElement(x, pcgsH, Pcgs(H)));
                Append( gens, Pcgs(H){[start..next-1]} );

                # calculate centre of centF 
                U    := Subgroup( H, gens );
                gens := GeneratorsCentrePGroup( U );
                gens := List( gens, x -> MappedPcElement(x,Pcgs(H),pcgsH));

                # get centralizer
                oper := spec{Filtered([1..start-1], x -> weights[x][2] = 1)};
                cent[j] := NextStepCentralizer( oper, gens, pcgsF, field ); 

            # case p <> q
            elif Length( cent[j] ) > 0 then
                # get operation of centF on M
                newgens := [];
                matlist := [];
                for g in cent[j] do
                    conj := List( pcgsF, 
                            x -> ExponentsOfPcElement( pcgsF, x^g ) ) 
                            * One( field );
                    if conj = conj^0  then
                        AddSet( newgens, g );
                    else
                        Add( matlist, conj );  
                    fi;
                od;       
                cent[j] := Filtered( cent[j], g -> not g in newgens );

                if Length( matlist ) > 0  then

                    # get exponent of <cent[j]> mod N 
                    expo := 1;
                    for g in cent[j] do
                        order := 1;
                        while SiftedPcElement( pcgsN, g ) <> Identity(G) do
                            g := g ^ p;
                            order := order * p;
                        od;
                        expo := Maximum( expo, order );
                    od;

                    # get splitting field
                    r := 1;
                    while EuclideanRemainder( q^r - 1, expo ) <> 0  do
                        r := r+1;
                    od;
                    if q^r >= 2^16 then
                        TryNextMethod();
                    fi;
                    large := GF(q^r);
                    ksi   := GeneratorsOfField(large)[1]^((q^r - 1) / expo);

                    # calculate simultaneous eigenvalues
                    eigen := SimultaneousEigenvalues( matlist, expo, ksi );
    
                    # solve system
                    null := BasisNullspaceModN( eigen, expo );

                    # calculate elements corresponding to null
                    for n in null do
                        elm := PcElementByExponentsNC( pcgsF, cent[j], n );
                        if elm <> Identity( G ) then
                            AddSet( newgens, elm );
                        fi;
                    od;
                fi;
                cent[j] := newgens;
            fi;
        od;
        i := i + 1;
    od;

   # return centre as direct product of p-parts
    G:= SubgroupNC( G, Concatenation( cent ) );
    Assert( 1, IsAbelian( G ) );
    SetIsAbelian( G, true );
    return G;
end);

#############################################################################
##
#M  Centre( <G> )
##

InstallMethod( Centre,
   "pcgs computable groups using special pcgs",
   [ IsGroup and CanEasilyComputePcgs and IsFinite ],
   CentrePcGroup);
	
	
#############################################################################
##
#M  OmegaSeries( G )
##
InstallMethod( OmegaSeries,
               "for p-groups",
               true,
               [IsGroup and CanEasilyComputePcgs and IsFinite],
               0,
function( G )
    local pcgs, cl, U, series, exp, sub, p, M;

    pcgs := Pcgs( G );
    if Length( pcgs ) = 0 then return [G]; fi;
    if Length( pcgs ) = 1 then return [G,TrivialSubgroup(G)]; fi;

    U      := TrivialSubgroup( G );
    series := [U];
    p      := PrimePGroup( G );
    cl     := ConjugacyClasses( G );
    exp    := 1;
    while Size( U ) < Size( G ) do
        sub := Filtered( cl, x -> Order( Representative( x ) ) = p ^ exp );
        sub := Concatenation( List( sub, x -> AsList(x) ) );
        sub := InducedPcgsByPcSequenceAndGenerators( pcgs, Pcgs(U), sub );
        M   := SubgroupByPcgs( G, sub );
        if Size( M ) > Size( U ) then 
            Add( series, M );
        fi;
        U := M;
        exp := exp + 1;
    od;
    return Reversed( series );
end);

#############################################################################
##
#M  PCentralSeriesOp( <G>, <p> )  . . . . . .  . . . . . . <p>-central series
##
InstallMethod( PCentralSeriesOp,
    "method for pc groups and prime",
    true, 
    [ IsPcGroup and IsFinite, IsPosInt ], 
    0,

function( G, p )
    local spec, weig, firs, ser, int, i, t, s, w, sub, N;

    spec := SpecialPcgs(G);
    weig := LGWeights( spec );
    firs := LGFirst( spec );
    ser  := [G];
    int  := [];
    for i in [1..Length(firs)-1] do
        t := firs[i];
        s := firs[i+1];
        w := weig[t];
        if w[1] = 1 and w[3] = p then
            sub := Concatenation( int, spec{[s..Length(spec)]} );
            sub := InducedPcgsByPcSequenceNC( spec, sub );
            N := SubgroupByPcgs( G, sub );
            Add( ser, N );
        else
            Append( int, spec{[t..s-1]} );
        fi;
    od;
    return ser;
end );

#############################################################################
##

#E  grppcatr.gi . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
##

bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped)
Email: contact@elmoujehidin.net bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped) Email: contact@elmoujehidin.net