Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/lpres/gap/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 12.6.2024 mit Größe 24 kB image not shown  

Quelle  subgrps.gi   Sprache: unbekannt

 
############################################################################
##
#W  subgrps.gi   The LPRES-package  René Hartung
##

############################################################################
##
#M IndexInWholeGroup
##
InstallMethod( IndexInWholeGroup,
  "for a subgroup of an LpGroup", true,
  [ IsSubgroupLpGroup ], 0,
  function( H )
  local Tab;
  Tab := CosetTableInWholeGroup( H );
  if Length( Tab ) = 0 then 
    return( 1 );
  else
    return( Length( Tab[1] ) );
  fi;
  end);

InstallMethod( IndexInWholeGroup, 
  "for a full L-presented group", true, 
  [ IsSubgroupLpGroup and IsWholeFamily ], 0, 
  function( G )
  SetCosetTableInWholeGroup( G, 
      ListWithIdenticalEntries( 2 * Length( GeneratorsOfGroup( G ) ), [ 1 ] ) );
  return( 1 );
  end);

############################################################################
##
#M  IndexOp
##
InstallMethod( IndexOp,
  "for an LpGroup and a subgroup of an LpGroup", true, 
  [ IsSubgroupLpGroup, IsSubgroupLpGroup ], 0, 
  function( G, H )

  if IsIdenticalObj( G, H ) then return( 1 ); fi;
  
  if HasParent( H ) and IsIdenticalObj( Parent( H ), G ) then 
    return( IndexInWholeGroup( H ) );
  else
    if not IsSubset( G, H ) then 
      Error( "<H> must be a subgroup of <G>" );
    fi;
    return( IndexInWholeGroup( H ) / IndexInWholeGroup( G ) );
  fi;
  end);

############################################################################
##
#M CosetTableInWholeGroup
##
InstallMethod( CosetTableInWholeGroup,
  "for a subgroup of an LpGroup", true, 
  [ IsSubgroupLpGroup ], 1, 
  function( H )
  local G, # the parent of <H>
 sig, # the iterating endomorphism
 Tab, # the current coset-table
 ind, # the current index
 phi,  # permutation representation 
 map, # commuting map
 img,  # images of the iterated relators
 Sym,  # symmetric group on <ind> letters
 Maps,  # a whole bunch of mappings <F> -> <Sym>
 g,h, # an FpGroup and its subgroup
 fam, # ElementsFamily of <g>
 rels,  # finitely many relators for <g>
 prd, # `periodicity' of <map>
 U,V, # Source and Range for <map>
 i,j,l;  # loop variables

  # the parent LpGroup
  G := Parent( H );
  if Length( EndomorphismsOfLpGroup( G ) ) > 1 then 
    TryNextMethod();
  elif Length( EndomorphismsOfLpGroup( G ) ) = 0 then 
    # catch the trivial case
    g := FreeGroupOfLpGroup( G ) / Concatenation( FixedRelatorsOfLpGroup( G ),
                                   IteratedRelatorsOfLpGroup( G ) );
    fam := ElementsFamily( FamilyObj( g ) );
    h := Subgroup( g, List( GeneratorsOfGroup( H ), 
                   x -> ElementOfFpGroup( fam, UnderlyingElement( x ) ) ) );
    return( CosetTableInWholeGroup( h ) );
  fi;

  sig := EndomorphismsOfLpGroup( G )[1];

  # find an FpGroup which has <H> as a finite ind. subgroup and maps onto <G>
  l := LPRES_TCSTART;
  repeat
    g   := Source( EpimorphismFromFpGroup( G , l ) );
    fam := ElementsFamily( FamilyObj( g ) );
    h   := Subgroup( g, List( GeneratorsOfGroup( H ), 
                     x -> ElementOfFpGroup( fam, UnderlyingElement( x ) ) ) );
   
    Info( InfoLPRES, 1, "Trying FpGroup with ", l, " iterations..." );

    # call usual Todd-Coxeter algorithm for this finitely presented group
    Tab := LPRES_CosetEnumerator( h );

    if Tab <> fail then 
      if Length( Tab ) = 0 or Length( Tab[1] ) = 0 then 
        Info( InfoLPRES, 1, "Coset-enumeration succeeded: the index is 1" ); 
      else
        Info( InfoLPRES, 1, "Coset-enumeration succeeded: the index is ", 
                          Length( Tab[1] ) ); 
      fi;
    fi;
    
    l := l + 1;
  until Tab <> fail;

  if Length( Tab ) = 0 or Length( Tab[1] ) = 0 then return( Tab ); fi;

  ind := Length( Tab[1] );;
  Sym := SymmetricGroup( ind );

  # proof that all relator-tables are closed or enforce coincidences
  phi := GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( G ), Sym,
      FreeGeneratorsOfLpGroup( G ),
                          List( Tab{[ 1, 3 .. Length(Tab)-1 ]}, PermList ) );

  # check if <Tab> is a already a coset-table; otherwise enforce coincidences
  Maps := [ phi ];;
  img  := FreeGeneratorsOfLpGroup( G );
  j    := 1;
  prd  := 0;
  repeat 
    img := List( img, x -> Image( sig, x ) );
    j := j + 1;;

    Add( Maps, GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( G ), Sym,
                                  FreeGeneratorsOfLpGroup( G ),
                                  List( img, x -> Image( phi, x ) ) ) );

    if ForAny( IteratedRelatorsOfLpGroup( G ), 
       x -> not IsOne( Image( Maps[j], x ) ) ) then 
 
      Info( InfoLPRES, 1, "An iterated relator yields a coincidence..." );
    
      Tab := LPRES_EnforceCoincidences( Tab, H, Maps[ Length( Maps ) ] );
      
      if Length( Tab ) = 0 then return( Tab ); fi;

      ind := Length( Tab[1] );
      Info( InfoLPRES, 1, "  -> the index is ", ind );
 
      # continue with the new coset-table setting
      Sym := SymmetricGroup( ind );
      j := 0;;
      prd := 0;;
      phi := GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( G ), Sym, 
                             FreeGeneratorsOfLpGroup( G ), 
                             List( Tab{[ 1, 3 .. Length(Tab)-1 ]}, PermList ) );
      Maps := [ phi ]; 
      img  := FreeGeneratorsOfLpGroup( G );
    fi;

    for i in [ 1 .. j-1 ] do 
      U := Image( Maps[i] );
      V := Image( Maps[j] );
      map := GroupHomomorphismByImages( U, V, 
                       MappingGeneratorsImages( Maps[i] )[2],
                       MappingGeneratorsImages( Maps[j] )[2] );

      if map <> fail then 
        prd := j-i; break;
      fi;
    od;
  until prd > 0;

  SetIndexInWholeGroup( H, ind );
  return( Tab );
  end );

InstallMethod( CosetTableInWholeGroup,
  "for a subgroup of an LpGroup", true, 
  [ IsSubgroupLpGroup ], 0, 
  function( H )
  local G, # the parent of <H>
 g,h, # an FpGroup and its subgroup
 fam, # ElementsFamily of <g>
 rels,  # finitely many relators for <g>
 Tab, # the current coset-table
 ind, # the current index
 phi,  # permutation representation 
 map, # commuting map
 img,  # vertices of the tree in End(F)
 Img,  # vertices of the tree in <Sym>^rk(F)
 Sym,  # symmetric group on <ind> letters
 stack, # current stack
 Stack, # new stack
 ModTab, # modified the coset-table by enforcing coincidences
 i,j,l,k;# loop variables

  # initialization
  G := Parent( H );

  # find an FpGroup which has <H> as a f.i.-subgroup and maps onto <G>
  l := LPRES_TCSTART;
  repeat
    g   := Source( EpimorphismFromFpGroup( G, l ) );
    fam := ElementsFamily( FamilyObj( g ) );
    h   := Subgroup( g, List( GeneratorsOfGroup( H ), 
                     x -> ElementOfFpGroup( fam, UnderlyingElement( x ) ) ) );
   
    Info( InfoLPRES, 1, "Trying FpGroup with ", l, " iterations..." );

    # call usual Todd-Coxeter algorithm for this finitely presented group
    Tab := LPRES_CosetEnumerator( h );

    if Tab <> fail then 
      if Length( Tab ) = 0 or Length( Tab[1] ) = 0 then 
        Info( InfoLPRES, 1, "Coset-enumeration succeeded: the index is 1" );
      else
        Info( InfoLPRES, 1, "Coset-enumeration succeeded: the index is ", 
                          Length( Tab[1] ) );
      fi;
    fi;
    
    l := l + 1;
  until Tab <> fail;

  # catch trivial case
  if Length( Tab ) = 0 or Length( Tab[1] ) = 0 then return( Tab ); fi;

  # prove or disprove that all relator-tables are closed 
  ind    := Length( Tab[1] );;
  Sym    := SymmetricGroup( ind );
  phi    := GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( G ), Sym,
      FreeGeneratorsOfLpGroup( G ),
                          List( Tab{[ 1, 3 .. Length(Tab)-1 ]}, PermList ) );
  img    := [ List( FreeGeneratorsOfLpGroup( G ), x -> Image( phi, x ) ) ];
  stack  := [ FreeGeneratorsOfLpGroup( G ) ];
  ModTab := false;
  l := 0;;
  repeat 
    l := l + 1;
    Stack := [];

    for i in [ 1 .. Length( stack ) ] do
      for k in [ 1 .. Length( EndomorphismsOfLpGroup(G) ) ] do 
        Img := List( stack[i], x -> Image( EndomorphismsOfLpGroup(G)[k], x ) );
        map := GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( G ), Sym,
                                            FreeGeneratorsOfLpGroup( G ), 
                                            List( Img, x -> Image( phi, x ) ) );

        # check if a relator yields a coincidence
        if ForAny( IteratedRelatorsOfLpGroup( G ), 
                   x -> not IsOne( Image( map, x ) ) ) then 

          Info( InfoLPRES, 1, "An iterated relator yields a coincidence..." );

          # enforce this coincidence 
          Tab := LPRES_EnforceCoincidences( Tab, H, map );

          if Length( Tab ) = 0 or Length( Tab[1] ) = 0 then
            Info( InfoLPRES, 1, "  -> the index is 1 ");
            return( Tab );
          else 
            Info( InfoLPRES, 1, " -> the index is ", Length( Tab[1] ) );
          fi;

          ModTab := true;

          # continue with the new coset-table
          ind   := Length( Tab[1] );
          Sym   := SymmetricGroup( ind );
          phi   := GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( G ), Sym, 
                            FreeGeneratorsOfLpGroup( G ), 
                            List( Tab{[ 1, 3 .. Length(Tab)-1 ]}, PermList ) );
          stack := [ FreeGeneratorsOfLpGroup( G ) ];
          img   := [ List( FreeGeneratorsOfLpGroup(G), x -> Image( phi, x ) ) ];
          break;
        fi;

        if ForAll( img, x -> GroupHomomorphismByImages( Group( x ), Sym, x,
                             List( Img, y -> Image( phi, y ) ) ) = fail ) then
          Add( img, List( Img, y -> Image( phi, y ) ) );
          Add( Stack, Img );
        fi;
      od;
      if ModTab then ModTab := false; break; fi;
    od;

    stack := Stack;
  until IsEmpty( stack );

  SetIndexInWholeGroup( H, ind );
  return( Tab );
  end );

############################################################################
##
#M CosetTable 
##
InstallMethod( CosetTable,
  "for an LpGroup and a subgroup of an LpGroup", true,
  [ IsLpGroup, IsSubgroupLpGroup ], 0,
  function( G, H )
  
  if HasParent( H ) and IsIdenticalObj( Parent( H ), G ) then
    return( CosetTableInWholeGroup( H ) );
  else
    Error("not implemented yet in <lpres/gap/subgrps.gi>");
  fi;
  end);


############################################################################
##
#M TraceCosetTableLpGroup
##
InstallMethod( TraceCosetTableLpGroup,
  "for a coset-table, an element of an LpGroup, and a coset number", true,
  [ IsList, IsElementOfLpGroup, IsPosInt ], 0, 
  function( Tab, elm, p )
  return( TraceCosetTableLpGroup( Tab, UnderlyingElement( elm ), p ) );
  end);

InstallMethod( TraceCosetTableLpGroup,
  "for a coset-table, an element of the free group, and a coset number", true,
  [ IsList, IsElementOfFreeGroup, IsPosInt ], 0,
  function( Tab, elm, p )
   local i, j, e, pos, ex;
   ex := ExtRepOfObj( elm );
   for i in [ 1, 3 .. Length(ex)-1 ] do
     # exponent of this generator
     e := ex[i+1];
     # choose position in the coset table g_1, g_1^{-1}, g_2, g_2^{-1} ...
     if e < 0 then
       pos := 2 * ex[i];
       e := -e;
     else
       pos := 2 * ex[i] - 1;
     fi;
     # walk along the coset table as often as |e|
     for j in [ 1 .. e ] do
       p := Tab[pos][p];
     od;
   od;
   return( p );
  end);

############################################################################
##
#M \in 
##
InstallMethod( \in,
  "for an element of an LpGroup and a subgroup of an LpGroup", IsElmsColls,
  [ IsElementOfLpGroup, IsSubgroupLpGroup ], 0,
  function( g, U )
    local Tab;

    if not HasCosetTableInWholeGroup( U ) then 
      Info( InfoWarning, 1, "IN using coset enumeration for a subgroup of",
                            " an LpGroup" );
    fi;
   
    Tab := CosetTableInWholeGroup( U );
    return( TraceCosetTableLpGroup( Tab, g, 1 ) = 1 );
  end);


############################################################################
##
#M \=
##
InstallMethod( \=,
  "for two subgroups of an LpGroup", IsIdenticalObj,
  [ IsSubgroupLpGroup, IsSubgroupLpGroup ], 0,
  function( U, H )

  # compute a coset table first
  if IndexInWholeGroup( U ) = fail or IndexInWholeGroup( H ) = fail then 
    return( fail );
  fi;

  return( IndexInWholeGroup( U ) = IndexInWholeGroup( H ) and 
          IsSubset( U, H ) and IsSubset( H, U ) );
  end);

############################################################################
##
#M  IsSubSet
##
InstallMethod( IsSubset,
  "for two subgroups of an LpGroup", IsIdenticalObj, 
  [ IsSubgroupLpGroup, IsSubgroupLpGroup ], 0,
  function( G, H )
  return( ForAll( GeneratorsOfGroup( H ), x -> x in G ) );
  end);


############################################################################
##
#M IsNormalOp
##
InstallMethod( IsNormalOp,
  "for two subgroups of an LpGroup", IsIdenticalObj,
  [ IsSubgroupLpGroup, IsSubgroupLpGroup ], 0,
  function( G, H )
    return( ForAll( GeneratorsOfGroup( G ), g ->
            ForAll( GeneratorsOfGroup( H ), h -> h ^ g in H ) ) );
  end);

############################################################################
##
#M NaturalHomomorphismByNormalSubgroupNCOrig
##
InstallMethod( NaturalHomomorphismByNormalSubgroupNCOrig,
  "for a normal subgroup of an LpGroup of finite index", IsIdenticalObj,
  [ IsSubgroupLpGroup, IsSubgroupLpGroup ], 0, 
  function( G, N )
    local i, img, Tab, ind, hom;;  

    if not IsNormal( G, N ) then 
      Error("<N> must be normal in <G>");
    fi;
   
    if IndexInWholeGroup( G ) > 1 then
      Error("not implemented yet in <lpres/gap/subgrps.gi>");
    fi;

    Tab := CosetTableInWholeGroup( N );
    ind := Index( G, N );
    img := ListWithIdenticalEntries( Length( GeneratorsOfGroup( G ) ), 0 );
    for i in [ 1 .. Length( GeneratorsOfGroup( G ) )] do 
      img[i] := PermList( Tab[ 2 * i - 1 ] );
    od;

    hom := GroupGeneralMappingByImages( G, SymmetricGroup( ind ), 
                                        GeneratorsOfGroup( G ), img );

    SetKernelOfMultiplicativeGeneralMapping( hom, N );
    return( hom );
  end);

############################################################################
##
#F SubgroupLpGroupByCosetTable
##
InstallMethod( SubgroupLpGroupByCosetTable,
  "for an LpGroup-family and a coset table", true,
  [ IsFamily, IsList ], 0,
  function( fam, Tab )
  local U;

  U := Objectify( NewType( fam, IsGroup and IsAttributeStoringRep ), rec() );

  SetParent( U, fam!.wholeGroup );
  SetCosetTableInWholeGroup( U, Tab );
 
  if Length( Tab ) = 0 then 
    SetIndexInWholeGroup( U, 1 );
  else 
    SetIndexInWholeGroup( U, Length( Tab[1] ) );
  fi;

  return( U );
  end);

InstallMethod( SubgroupLpGroupByCosetTable, 
  "for an LpGroup and a coset table", true,
  [ IsLpGroup, IsList ], 0, 
  function( G, Tab )
  return( SubgroupLpGroupByCosetTable( FamilyObj( G ), Tab ) );
  end);

############################################################################
##
#M GeneratorsOfMagmaWithInverses
##
InstallMethod( GeneratorsOfMagmaWithInverses,
  "for a subgroup of an LpGroup with a coset table", true, 
  [ IsSubgroupLpGroup and HasCosetTableInWholeGroup ], 0, 
  function( H )
  local Tab,  # the coset table
 ind,  # the index
 trans, # the Schreier transversal
 gens, # the Schreier generators
 t, # a transversal
 Alph, # the underlying alphabet
 fam, # ElementsFamily of <H>
 x,i,j;  # loop variables

  # initialization 
  Tab  := CosetTableInWholeGroup( H );
  Alph := Concatenation( FreeGeneratorsOfWholeGroup( H ), 
          List( FreeGeneratorsOfWholeGroup( H ), x -> x ^ -1 ) );

  if Length( Tab ) = 0 then 
    return( GeneratorsOfGroup( Parent( H ) ) );
  fi;
  ind := Length( Tab[1] );

  # the Schreier transversal
  trans    := ListWithIdenticalEntries( ind, 0 );
  trans[1] := One( FreeGroupOfWholeGroup( H ) );

  # generators by Schreier's theorem.
  gens := [];;

  repeat
    for i in [ 1 .. ind ] do
      if trans[i] <> 0 then 
        for x in Alph do 
          t := trans[i] * x;
          j := TraceCosetTableLpGroup( Tab, x, i );
          if trans[j] = 0 then 
            trans[j] := t;
          elif t <> trans[j] then 
            Add( gens, t * trans[j]^-1 );
          fi;
        od;
      fi;
    od;
  until ForAll( trans, x -> x <> 0 );

  # convert to elements of the LpGroup
  fam := ElementsFamily( FamilyObj( Parent( H ) ) );
  return( List( gens, x -> ElementOfLpGroup( fam, x ) ) );
  end);

############################################################################
##
#F LPRES_EnforceCoincidences
##
InstallGlobalFunction( LPRES_EnforceCoincidences,
  function( tab, H, map )
  local i, j, ind, G, Tab, co, c, Entries, pos, l, Bij, coinc, img;

  # IndexCosetTab
  if Length( tab ) = 0 then 
    ind := 1;;
  else
    ind := Length( tab[1] );
  fi;

  # compute the coincidences
  G   := Parent( H );
  img := List( IteratedRelatorsOfLpGroup( G ), 
               x -> Image( map, x ) );
  coinc := [];
  for i in [ 1 .. Length( img ) ] do 
    if not IsOne( img[i] ) then 
      for j in [ 1 .. ind ] do 
        c := [ j ^ img[i], j ];
        if c[1] < c[2] and 
           not c in coinc then 
          Add( coinc, c );
        elif c[1] > c[2] and 
             not Reversed( c ) in coinc then 
          Add( coinc, Reversed( c ) );
        fi;
      od;
    fi;
  od;

  # enforce coincidences
  Tab := MutableCopyMat( tab );
  Entries := [ 1 .. Length( Tab[1] ) ];
  while IsBound( coinc[1] ) do 
    co := Remove( coinc, Length( coinc ) );

    for i in [ 1 .. Length( Tab ) ] do
      for j in [ 1 .. Length( Tab[1] ) ] do
        if Tab[i][j] = co[2] then Tab[i][j] := co[1]; fi;
      od;
    od;

    pos := Position( Entries, co[2] );
    if pos <> fail then 
      Remove( Entries, pos );
    fi;

    for i in [ 1 .. Length( Tab ) ] do 
      if Tab[i][ co[1] ] > Tab[i][ co[2] ] then 
        c := [ Tab[i][ co[2] ], Tab[i][ co[1] ] ];
      elif Tab[i][ co[1] ] < Tab[i][ co[2] ] then 
        c := [ Tab[i][ co[1] ], Tab[i][ co[2] ] ];
      fi;
    
      if ( c <> co ) and not ( c in coinc ) then
        Add( coinc, c ); 
      fi;
    od;
  od;
   
  # renumbering of the cosets
  Tab := List( [ 1 .. Length( Tab ) ], x -> Tab[x]{Entries} );

  Bij := AsSSortedList( Tab[1] );

  for i in [ 1 .. Length( Tab ) ] do 
    for j in [ 1 .. Length( Tab[1] ) ] do 
      Tab[i][j] := Position( Bij, Tab[i][j] );
    od;
  od;

  StandardizeTable( Tab );;

  return( Tab );
  end);

############################################################################;
##
#F LowIndexSubgroupsLpGroupByFpGroup
##
InstallMethod( LowIndexSubgroupsLpGroupByFpGroup,
  "for an LpGroup, a positive integers, and the index", true,
  [ IsLpGroup, IsPosInt, IsPosInt ], 0,
  function( G, its, ind )
  local g, LIS, fam, it, U;
 
  # elements family of the LpGroup <G>
  fam := ElementsFamily( FamilyObj( G ) );

  # catch the trivial case
  if Length( EndomorphismsOfLpGroup( G ) ) = 0 then
    g := FreeGroupOfLpGroup( G ) / Concatenation( FixedRelatorsOfLpGroup( G ),
         IteratedRelatorsOfLpGroup( G ) );
    LIS := LowIndexSubgroupsFpGroup( g, ind );
    return( List( LIS, x -> Subgroup( G,  List( GeneratorsOfGroup( x ), 
                  y -> ElementOfLpGroup( fam, UnderlyingElement( y ) ) ) ) ) );
  fi;

  # define the FpGroup w.r.t. words of length at most <its> in the monoid
  g   := Source( EpimorphismFromFpGroup( G, its ) );
  it  := LowIndexSubgroupsFpGroupIterator( g, ind );
  LIS := [];;
  while not IsDoneIterator( it ) do 
    U := NextIterator( it );
    U := Subgroup( G, List( GeneratorsOfGroup( U ), 
              x -> ElementOfLpGroup( fam, UnderlyingElement( x ) ) ) );

    if not ( U in LIS ) then Add( LIS, U ); fi;
  od;
  return( LIS );
  end);

InstallOtherMethod( LowIndexSubgroupsLpGroupByFpGroup,
  "for an LpGroup and a positive integer", true, 
  [ IsLpGroup, IsPosInt ], 0, 
  function( G, ind )
  return( LowIndexSubgroupsLpGroupByFpGroup( G, 2, ind ) );
  end);

############################################################################
##
#M DerivedSubgroup
##
InstallMethod( DerivedSubgroup,
  "for an LpGroup", true, 
  [ IsLpGroup ], 0,
  G -> Kernel( NqEpimorphismNilpotentQuotient( G, 1 ) ) );

############################################################################
##
#M NilpotentQuotientIterator
##
InstallMethod( NilpotentQuotientIterator, 
  "for an LpGroup", true, 
  [ IsLpGroup ], 0, 
  function( G )
  local filter, it, NextIterator, IsDoneIterator, ShallowCopyIT;

  NextIterator := function( iter )
    local H;
      iter!.class := iter!.class + 1;;
      H := NilpotentQuotient( iter!.group, iter!.class );
      if NilpotencyClassOfGroup( H ) < iter!.class then 
        iter!.max := iter!.class;
        Error( "exhausted the iterator <iter>" );
      fi;
      return( H );
    end;
 
  IsDoneIterator := function( iter )
      return( iter!.max > 0 );   
    end;

  ShallowCopyIT := function( iter )
    return( rec( group := iter!.group,
                 class := iter!.class, 
                 max   := iter!.max ) );
    end;

  filter := IsIteratorByFunctions and IsAttributeStoringRep and IsMutable;

  it := rec( NextIterator := NextIterator, IsDoneIterator := IsDoneIterator,
             ShallowCopy := ShallowCopyIT );

  it!.group := G;
  it!.class := 0;
  it!.max   := 0;

  return( Objectify( NewType( IteratorsFamily, filter ), it ) );
  end);

############################################################################
##
#M NqEpimorphismNilpotentQuotientIterator
##
InstallMethod( NqEpimorphismNilpotentQuotientIterator, 
  "for an LpGroup", true, 
  [ IsLpGroup ], 0, 
  function( G )
  local filter, it, NextIterator, IsDoneIterator, ShallowCopyIT;

  NextIterator := function( iter )
    local epi;
      iter!.class := iter!.class + 1;;
      epi := NqEpimorphismNilpotentQuotient( iter!.group, iter!.class );
      if NilpotencyClassOfGroup( Range( epi ) ) < iter!.class then 
        iter!.max := iter!.class;
        Error( "exhausted the iterator <iter>" );
      fi;
      return( epi );
    end;
 
  IsDoneIterator := function( iter )
      return( iter!.max > 0 );   
    end;

  ShallowCopyIT := function( iter )
    return( rec( group := iter!.group,
                 class := iter!.class, 
                 max   := iter!.max ) );
    end;

  filter := IsIteratorByFunctions and IsAttributeStoringRep and IsMutable;

  it := rec( NextIterator := NextIterator, IsDoneIterator := IsDoneIterator,
             ShallowCopy := ShallowCopyIT );

  it!.group := G;
  it!.class := 0;
  it!.max   := 0;

  return( Objectify( NewType( IteratorsFamily, filter ), it ) );
  end);

############################################################################
##
#M LowerCentralSeriesIterator
##
InstallMethod( LowerCentralSeriesIterator, 
  "for an LpGroup", true, 
  [ IsLpGroup ], 0, 
  function( G )
  local filter, it, NextIterator, IsDoneIterator, ShallowCopyIT;

  NextIterator := function( iter )
    local epi;
      iter!.class := iter!.class + 1;;
      epi := NqEpimorphismNilpotentQuotient( iter!.group, iter!.class );
      if NilpotencyClassOfGroup( Range( epi ) ) < iter!.class then 
        iter!.max := iter!.class;
        Error( "exhausted the iterator <iter>" );
      fi;
      return( Kernel( epi ) );
    end;
 
  IsDoneIterator := function( iter )
      return( iter!.max > 0 );   
    end;

  ShallowCopyIT := function( iter )
    return( rec( group := iter!.group,
                 class := iter!.class, 
                 max   := iter!.max ) );
    end;

  filter := IsIteratorByFunctions and IsAttributeStoringRep and IsMutable;

  it := rec( NextIterator := NextIterator, IsDoneIterator := IsDoneIterator,
             ShallowCopy := ShallowCopyIT );

  it!.group := G;
  it!.class := 0;
  it!.max   := 0;

  return( Objectify( NewType( IteratorsFamily, filter ), it ) );
  end);

############################################################################
##
#M Size
##
############################################################################
InstallMethod( Size, 
   "for an LpGroup", true, 
   [ IsLpGroup ], 0,  
   G -> IndexInWholeGroup( Subgroup( G, [] ) ) );

############################################################################
##
#M LowIndexSubgroupsLpGroupIterator
##
InstallMethod( LowIndexSubgroupsLpGroupIterator,
  "for an LpGroup and two positive integers", true, 
  [ IsLpGroup, IsPosInt, IsPosInt ], 0,
  function( G, its, ind )
  local NextIT, IsDoneIT, ShallowCopyIT, filter, it, g;

  # initialization
  g := Source( EpimorphismFromFpGroup( G, its ) );

  NextIT := function( iter )
    local G, fam, U, IT;
    
    G := iter!.lpgrp;
    IT := iter!.fpiter;

    fam := ElementsFamily( FamilyObj( G ) );

    repeat 
      if IsDoneIterator( IT ) then break; fi;
      U := Subgroup( G, List( GeneratorsOfGroup( NextIterator( IT ) ),
            x -> ElementOfLpGroup( fam, UnderlyingElement( x ) ) ) );
      if  not ( U in iter!.lis ) then  return( U ); fi;
    until false;
    return( fail );
  end;

  IsDoneIT := function( iter )
   return( IsDoneIterator( iter!.fpiter ) );
  end;

  ShallowCopyIT := function( iter )
    return( rec( lpgrp  := iter!.lpgrp, 
                 lis    := iter!.lis,
                 fpiter := iter!.fpiter ) );
  end;


  filter := IsIteratorByFunctions and IsAttributeStoringRep and IsMutable;

  it := rec( NextIterator := NextIT, IsDoneIterator := IsDoneIT,
             ShallowCopy := ShallowCopyIT );

  it!.lpgrp := G;
  it!.lis := [];
  it!.fpiter := LowIndexSubgroupsFpGroupIterator( g, ind );

  return( Objectify( NewType( IteratorsFamily, filter ), it ) );
  end);

[ Dauer der Verarbeitung: 0.37 Sekunden  (vorverarbeitet)  ]