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

Quelle  schumu.gi   Sprache: unbekannt

 
############################################################################
##
#W  schumu.gi   LPRES    René Hartung
##

# TODO: inducing endomorphisms of the group to endomorphisms of the Schur
# multiplier (Psi!)

############################################################################
##
#A  GeneratingSetOfMultiplier( <LpGroup> )
##
## computes a generating set for the Schur multiplier by modifying the 
## L-presentation of <LpGroup>
##
InstallMethod( GeneratingSetOfMultiplier,
  "for an invariantly L-presented group", true,
  [ IsLpGroup and HasIsInvariantLPresentation and 
    IsInvariantLPresentation ], 0,
  function( G )
  local GensMultiplier,# generators of the multiplier
 frels, # fixed relators of <G>
        frelsEV,# exponent vectors of the fixed relators of <G>
        irels, # iterated relators of <G>
        irelsEV,# exponent vectors of the iterated relators of <G>
        irel, # an iterated relator of <G>
        irelEV, # an exponent vector of an iterated relator of <G>
 obj, # external representation of a free group element
 mat, # an induced endomorphism of the free abelian group
 endo, # an endomorphism of the LpGroup <G>
 endos, # the induced endomorphisms of the free abelian group
 n, # number of generators of <G>
 HNF,hnf,# Hermite normal forms
 basis,  # current basis for the free abelian complement
 basN, # updated basis for the free abelian complement
 elm, # an element of the free group
 i,j,k; # loop variables

  GensMultiplier := rec( FixedGens     := [],
                         IteratedGens  := [] );

  # the number of generators of <G>
  n := Length( GeneratorsOfGroup( G ) );

  # the exponent vectors of the fixed relators
  frels   := ShallowCopy( FixedRelatorsOfLpGroup( G ) );
  frelsEV := NullMat( Length( frels ), n );
  i := 1;;
  while i <= Length( frels ) do 
    obj := ExtRepOfObj( frels[i] );
    for j in [ 1, 3..Length(obj)-1 ] do 
      frelsEV[i][ obj[j] ] := frelsEV[i][ obj[j] ] + obj[j+1];
    od;

    # filter which relators are already contained in the derived subgroup
    if IsZero( frelsEV[i] ) then 
      Add( GensMultiplier.FixedGens, frels[i] );
      Remove( frels, i );
      Remove( frelsEV, i );
    else
      i := i + 1;
    fi;
  od;

  # the exponent vectors of the iterated relators
  irels   := ShallowCopy( IteratedRelatorsOfLpGroup( G ) );
  irelsEV := NullMat( Length( irels), n );
  i := 1;
  while i <= Length( irels ) do 
    obj := ExtRepOfObj( irels[i] );
    for j in [ 1, 3 .. Length(obj)-1 ] do 
      irelsEV[i][ obj[j] ] := irelsEV[i][ obj[j] ] + obj[j+1];
    od;
    # filter which relators are already contained in the derived subgroup
    if IsZero( irelsEV[i] ) then
      Add( GensMultiplier.IteratedGens, irels[i] );
      Remove( irels, i ); 
      Remove( irelsEV, i ); 
    else 
      i := i + 1;
    fi;
  od;

  # induce the endomorphisms to endomorphisms of the free abelian group
  endos := [];
  for endo in EndomorphismsOfLpGroup( G ) do
    mat := NullMat( n, n );
    obj := List( GeneratorsOfGroup( G ), 
                 x -> ExtRepOfObj( UnderlyingElement( x ) ^ endo ) );
    for i in [ 1 .. n ] do 
      for j in [ 1, 3 .. Length(obj[i])-1 ] do
        mat[i][ obj[i][j] ] := mat[i][ obj[i][j] ] + obj[i][j+1] ;;
      od;
    od;
    Add( endos, mat );
  od;

  # initialize the basis and the Hermite normal form (of basis elements)
  basis := [];
  HNF   := rec( mat := [], Heads := [] );

  # check the fixed relators for basis elements
  while IsBound( frels[1] ) do 
    if IsEmpty( HNF.Heads ) then
      LPRES_AddRow( HNF, frelsEV[1] );
      Add( basis, frels[1] );
    else
      hnf := ShallowCopy( HNF.mat );
      if LPRES_AddRow( HNF, frelsEV[1] ) then 
        # obtained a new basis-element...
          # either we just add frels[1]
          # or we move a basis element to GensMultiplier.FixedGens
        Add( hnf, frelsEV[1] );
        Add( basis, frels[1] );
        hnf  := HermiteNormalFormIntegerMatTransform( hnf );

        # initialize the new basis
        basN := ListWithIdenticalEntries( Length(HNF.Heads), 
                                          One( FreeGroupOfLpGroup( G ) ) );
 
        for i in [ 1 .. Length(hnf.normal) ] do 
          if IsZero( hnf.normal[i] ) then 
            elm := One( FreeGroupOfLpGroup( G ) );
            for j in [1..Length(hnf.rowtrans[i])] do
              elm := elm * basis[j] ^ hnf.rowtrans[i][j];
            od;
            Add( GensMultiplier.FixedGens, elm );
          else 
            for j in [1..Length(hnf.rowtrans[i])] do 
              basN[i] := basN[i] * basis[j] ^ hnf.rowtrans[i][j];
            od;
          fi;
        od;
        basis := basN;
      else
        # already contained in the span...
        
        # reduce and add modified relator to GensMultiplier.FixedGens
        i := PositionNonZero( frelsEV[1] );;
        while i <= n do 
          j := Position( HNF.Heads, i );
          k := frelsEV[1][i] / HNF.mat[j][HNF.Heads[j]];
          frels[1]   := frels[1] * basis[j] ^ -k;
          frelsEV[1] := frelsEV[1] - k * HNF.mat[j];
          i := PositionNonZero( frelsEV[1] );
        od;
        if not frels[1] = One( FreeGroupOfLpGroup( G ) ) then 
          Add( GensMultiplier.FixedGens, frels[1] );
        fi;
      fi;
    fi;
    Remove( frels, 1 );
    Remove( frelsEV, 1 );
  od;

  # check the iterated relators for basis elements (use spinning)
  while IsBound( irels[1] ) do 
    if IsEmpty( HNF.Heads ) then
      LPRES_AddRow( HNF, irelsEV[1] );
      Add( basis, irels[1] );
      Append( irels, List( EndomorphismsOfLpGroup( G ), x -> irels[1] ^ x ));
      Append( irelsEV, List( endos, x -> irelsEV[1] * x ));
    else
      hnf := ShallowCopy( HNF.mat );
      if LPRES_AddRow( HNF, irelsEV[1] ) then 
        # obtained a new basis-element...
          # either we just add frels[i]
          # or we move a basis element to GensMultiplier.FixedGens
        Add( hnf, irelsEV[1] );
        Add( basis, irels[1] );
        hnf  := HermiteNormalFormIntegerMatTransform( hnf );

        # initialize the new basis
        basN := ListWithIdenticalEntries( Length(HNF.Heads), 
                                          One( FreeGroupOfLpGroup( G ) ) );
 
        for i in [ 1 .. Length(hnf.normal) ] do 
          if IsZero( hnf.normal[i] ) then 
            elm := One( FreeGroupOfLpGroup( G ) );
            for j in [1..Length(hnf.rowtrans[i])] do
              elm := elm * basis[j] ^ hnf.rowtrans[i][j];
            od;
            Add( GensMultiplier.IteratedGens, elm );
          else 
            for j in [1..Length(hnf.rowtrans[i])] do 
              basN[i] := basN[i] * basis[j] ^ hnf.rowtrans[i][j];
            od;
            Append( irels, List( EndomorphismsOfLpGroup( G ), 
                                 x -> irels[1] ^ x ));
            Append( irelsEV, List( endos, x -> irelsEV[1] * x ));
          fi;
        od;
        basis := basN;
      else
        # already contained in the span...
        irel := ShallowCopy( irels[1] );
        irelEV := ShallowCopy( irelsEV[1] );
        
        # reduce and add modified relator to GensMultiplier.FixedGens
        i := PositionNonZero( irelsEV[1] );;
        while i <= n do 
          j := Position( HNF.Heads, i );
          k := irelsEV[1][i] / HNF.mat[j][HNF.Heads[j]];
          irels[1]   := irels[1] * basis[j] ^ -k;
          irelsEV[1] := irelsEV[1] - k * HNF.mat[j];
          i := PositionNonZero( irelsEV[1] );
        od;

        if not irels[1] = One( FreeGroupOfLpGroup( G ) ) then 
          Add( GensMultiplier.IteratedGens, irels[1] );
        else
          # since we may loose the images of irel, we need to add its
          # image as iterated relators (for FpGroups there's only the 
          # identity in EndomorphismsOfLpGroup
          if not HasIsFinitelyPresentable( G ) or 
             not IsFinitelyPresentable( G ) then
            Append( irels, List( EndomorphismsOfLpGroup( G ),
                                 x -> irel ^ x ) );
            Append( irelsEV, List( endos, x -> irelEV * x ) );
          fi;
#         Append( irels, List( EndomorphismsOfLpGroup( G ),
#                              x -> irels[1] ^ x ) );
#         Append( irelsEV, List( endos, x -> irelsEV[1] * x ) );
        fi;
      fi;
    fi;
    Remove( irels, 1 );
    Remove( irelsEV, 1 );
  od;
  GensMultiplier.BasisGens     := basis;
  GensMultiplier.Endomorphisms := EndomorphismsOfLpGroup( G );
  return(GensMultiplier);
  end);

############################################################################
##
#M  FiniteRankSchurMultiplier( <LpGroup>, <int> )
##
## computes the image of the Schur multiplier of <LpGroup> in the Schur
## multiplier of the class-<int> quotient of <LpGroup>.
##
InstallMethod( FiniteRankSchurMultiplier, 
  "for invariantly L-presented groups", true,
  [ IsLpGroup and HasIsInvariantLPresentation and
    IsInvariantLPresentation, IsPosInt ], 0,
  function( G, c ) 
  local endos; # a list of the induced endomorphisms
  endos := EndomorphismsOfFRSchurMultiplier( G, c );
  if endos = fail then 
    return( fail );
  else
    if not IsBound( endos[1] ) then Error("list of induced endomorphisms"); fi; 
    return( Source( endos[1] ) );
  fi;
  end);

############################################################################
##
#M  EndomorphismsOfFRSchurMultiplier( <LpGroup>, <int> )
##
## induces the endomorphisms of the invariant L-presentation of <LpGroup>
## to the `FiniteRankSchurMultiplier' of <LpGroup>.
##
InstallMethod( EndomorphismsOfFRSchurMultiplier,
  "for invariantly L-presented groups", true,
  [ IsLpGroup and HasIsInvariantLPresentation and
    IsInvariantLPresentation, IsPosInt ], 0,
  function( G, c )
  local Q, QS, # weighted nilpotent quotient systems for nilpotent quotients
 weights,# list of weights of the generators of <Q>
  Defs, # list of definitions of the generators of <Q>
 Imgs, # images of the generators of <G> 
 ftl, # <FromTheLeftCollector> of the covering group
 b, # Position of the tails in the generating set of <ftl>
  HNF, # Hermite normal form of the consistency relations and relations
 H,  # the covering group
 gens, # generators of the covering group <H> or the image of M(G)
 T, # the multiplier of the covering group <H>
 stack, # stack for the spinning algorithm
 g,gImg, # an iterated relators and its image in <T>
 GensMultiplier,# generators of the multiplier 
 endo, # an endomorphism of the free group underlying <G>
 imgs, # for inducing the endomorphisms
 endos, # the induced endomorphisms of the covering group
 SchuMu, # a finitely generated quotient of the Schur multiplier of <G>
 Cov, # covering groups (Attribute)
 i; # loop variables

  if HasCoveringGroups( G ) then 
    if IsBound( CoveringGroups( G )[c] ) then
      if IsBound( CoveringGroups( G )[c].IndEndosOfFRMult ) then 
        return( CoveringGroups( G )[c].IndEndosOfFRMult );
      fi;
      QS := CoveringGroups( G )[c];
    else
      if HasNilpotentQuotientSystem( G ) and 
         Maximum( NilpotentQuotientSystem( G ).Weights ) > c then
        Q := SmallerQuotientSystem( NilpotentQuotientSystem( G ), c );;
      else 
        if NilpotencyClassOfGroup( NilpotentQuotient( G, c ) ) < c then 
          Info( InfoLPRES, 1, "The group has a maximal nilpotent quotient of",
                            " class ", Maximum( Q.Weights ) );
          return( fail );
        fi;
        Q := NilpotentQuotientSystem( G );
      fi;

      QS := LPRES_QSystemOfCoveringGroup( Q );
   
      Cov    := ShallowCopy( CoveringGroups( G ) );
      Cov[c] := QS;
      ResetFilterObj( G, CoveringGroups );
      SetCoveringGroups( G, Cov );
    fi;
  else
    if HasNilpotentQuotientSystem( G ) and
       Maximum( NilpotentQuotientSystem( G ).Weights ) > c then 
      Q := SmallerQuotientSystem( NilpotentQuotientSystem( G ), c );
    else 
      if NilpotencyClassOfGroup( NilpotentQuotient( G, c ) ) < c then 
        Info( InfoWarning, 0, "The group has a maximal nilpotent quotient of",
                              " class ", Maximum( Q.Weights ) );
        return( fail );
      fi;
      Q := NilpotentQuotientSystem( G );
    fi;

    QS := LPRES_QSystemOfCoveringGroup( Q );
  
    Cov := []; Cov[c] := QS;
    SetCoveringGroups( G, Cov );
  fi;

  # the covering group
  H := Range( QS.Epimorphism );

  # induce EndomorphismsOfLpGroup to endomorphisms of the covering group <H>
# endos := LPRES_InduceEndosToCover( QS, Q.Lpres );
  endos := LPRES_InduceEndosToCover( G, EndomorphismsOfLpGroup( G ), c );

  # modify the invariant L-presentation 
  GensMultiplier := GeneratingSetOfMultiplier( G );;

  # start the spinning algorithm
##  gens   := Set ( List( Concatenation( GensMultiplier.FixedGens, 
##                  GensMultiplier.IteratedGens ), x -> x ^ QS.Epimorphism ) );
##  SchuMu := Subgroup( H, gens );

##  stack  := ShallowCopy( GensMultiplier.IteratedGens );
##  while IsBound( stack[1] ) do 
##    for endo in GensMultiplier.Endomorphisms do
##      g    := stack[1] ^ endo;
##      gImg := g ^ QS.Epimorphism;
##      if not gImg in SchuMu then 
##        Add( gens, gImg );
##        SchuMu := Subgroup( H, gens );
##        Add( stack, g );
##      fi;
##    od;
##    Remove( stack, 1 );
##  od;

##  stack := List( GensMultiplier.IteratedGens, x -> Image( QS.Epimorphism, x ) );
##  while IsBound( stack[1] ) do
##    for endo in endos do
##      g := Image( endo, stack[1] );
##      if not g in SchuMu then 
##        Add( gens, g );
##        SchuMu := Subgroup( H, gens );
##        Add( stack, g );
##      fi;
##    od;
##    Remove( stack, 1 );
##  od;

  SchuMu := LPRES_SchuMuFromCover( QS, GensMultiplier, endos );;

  # return the restriction of the induced endomorphisms to the subgroup <SchuMu>
  for i in [ 1 .. Length( endos ) ] do
    endos[i] := GroupGeneralMappingByImages( SchuMu, SchuMu, 
                GeneratorsOfGroup( SchuMu ),
                List( GeneratorsOfGroup( SchuMu ), x -> Image( endos[i], x )));
  od;

  # store as an attribute
  Cov := ShallowCopy( CoveringGroups( G ) );
  Cov[c] := ShallowCopy( Cov[c] );
  Cov[c].IndEndosOfFRMult := endos; 
  ResetFilterObj( G, CoveringGroups );
  SetCoveringGroups( G, Cov );

  return( endos );
  end);

############################################################################
##
#F  LPRES_SchuMuFromCover( <QS>, <GensMult>, <Endos> )
##
InstallGlobalFunction( LPRES_SchuMuFromCover, 
  function( QS, GensMult, endos )
  local SchuMu, # the (finite rank) Schur multiplier
 b, # position of the first generators of the multiplier
 H,  # the covering group (represented by <QS>)
 orders, # relative orders of the covering group
 n, # number of generators of the covering group
 ev, # exponent vector of an element in the covering group <H>
 mat,  # an endomorphism of the multiplier written as a matrix
 Endos, # endomorphisms of the multiplier written as matrices
 HNF, # the Hermite normal form
 stack, # stack of exponent vectors for the spinning algorithm
 gens, # generators of the finite rank Schur multiplier
 i,j; # loop variables
  
  # position of the generators of the multiplier
  b := Position( QS.Weights, Maximum( QS.Weights ) );;
  n := Length( QS.Weights );;
  
  # the covering group with its relative orders
  H      := Range( QS.Epimorphism );;
  orders := RelativeOrders( QS.Pccol );;

  # compute the Hermite normal form from the covering group
  HNF := rec( mat := [], Heads := [] );
  for i in Filtered( [ b .. n ], x -> orders[x] <> 0 ) do
    ev := ExponentsByObj( QS.Pccol, GetPower( QS.Pccol, i ));;
    ev[i] := - orders[i];;
    LPRES_AddRow( HNF, ev{[b..n]} );
  od;

  # compute a matrix for our endomorphisms (of the multiplier)
  Endos := [];;
  for i in [ 1 .. Length( endos ) ] do 
    mat := [];;
    for j in [ b .. n ] do 
      ev := Exponents( Image( endos[i], GeneratorsOfGroup( H )[j] ) );;
      if not IsZero( ev{[1..b-1]} ) then 
        Error("endos are not endomorphisms of the multiplier");
      fi;
      Add( mat, ev{[b..n]} );;
    od;
    Add( Endos, mat );
  od;

  gens  := List( GensMult.IteratedGens, x -> Image( QS.Epimorphism, x ) );
  stack := List( gens, x -> Exponents( x ){[b..n]} );

  Append( gens, List( GensMult.FixedGens, x -> Image( QS.Epimorphism, x ) ) );
  gens  := Filtered( gens, y -> y <> One( H ) );;

  # use spinning for computing a generating set of the (f.r.) Schur multiplier
  while IsBound( stack[1] ) do
    for mat in Endos do
      ev := stack[1] * mat;;
      if LPRES_AddRow( HNF, ev ) then 
        Add( gens, PcpElementByExponents( QS.Pccol, 
                   Concatenation( ListWithIdenticalEntries( b-1, 0 ), ev ) ));
        Add( stack, ev );
      fi;
    od;
    Remove( stack, 1 );
  od;

  return( Subgroup( H, gens ) );
  end);

############################################################################
##
#F  LPRES_BuildCoveringGroup( <Q>, <ftl>, <HNF>, <weights>, <Defs>, <Imgs> )
##
## computes the covering group from a given quotient system
## 
InstallGlobalFunction( LPRES_BuildCoveringGroup, 
  function( Q, ftl, HNF, weights, Defs, Imgs )
  local col, # collector of the covering group
 c, # nilpotency class of the covering group
 b, # position of the first tail in the generating set of <ftl>
 Gens,  # tails which are still generators
 orders, # relative orders of <Q.Pccol>
 QS, # quotient system of the covering group
 rhs, # right-hand-side of a relation
 rhsTails,# tails on the right-hand-side of a relation
 endo, # an endomorphism of the LpGroup-presentation
 i,j,k; # loop variables

  # nilpotency class of the covering group
  c := Maximum( weights );
  
  # position of the first tails in the generating set of <ftl>
  b :=  Position( weights, c );

  # relative orders of <Q.Pccol>
  orders := RelativeOrders( Q.Pccol );

  # find non-trivial tails from <HNF>
  Gens := HNF.Heads{ Filtered( [1..Length(HNF.Heads)],
                               x -> HNF.mat[x][HNF.Heads[x]] <> 1 ) };
  Append( Gens, Filtered( [ 1..Length( Filtered( weights, x -> x = c ) ) ],
                           x -> not x in HNF.Heads));
  Sort( Gens );
  
  if Length( Gens ) = 0 then
    return( Q );
  fi;

  QS := rec( Pccol := FromTheLeftCollector( b-1 + Length(Gens) ), 
             Imgs  := [] );

  # restore the images (these tails are part of the free abelian complement)
  for i in [ 1..Length(Imgs) ] do 
    if IsPosInt( Imgs[i] ) then 
      QS.Imgs[i] := Imgs[i];
    else
      rhs      := ExponentsByObj( ftl, Imgs[i] );
      rhsTails := rhs{[b..Length(rhs)]};
      if rhsTails <> LPRES_RowReduce( rhsTails, HNF ) then 
        Error("got torsion from a tail of a non-defining image");
      else 
        rhs := Concatenation( rhs{[1..b-1]}, rhsTails{Gens} );
      fi;
      QS.Imgs[i] := ObjByExponents(QS.Pccol, rhs );
    fi;
  od;

  # the weights and definitions of the new quotient system
  QS.Definitions := Concatenation( Defs{[1..b-1]}, Defs{Gens+(b-1)} );
  QS.Weights     := Concatenation( weights{[1..b-1]}, weights{Gens+(b-1)} );
  
  # the power relations of the quotient system <Q>
  for i in Filtered( [1..Length(orders)], x -> orders[x] <> 0 ) do 
    rhs      := ExponentsByObj( ftl, GetPower( ftl, i ) );
    rhsTails := rhs{ [ b..Length(rhs) ] };
    if weights[i] = 1 and rhsTails <> LPRES_RowReduce( rhsTails, HNF ) then
       Error("got torsion from a tail of a power relation with weight 1");
    fi;
    rhs := Concatenation( rhs{[1..b-1]}, LPRES_RowReduce( rhsTails, HNF ){Gens} );
    SetRelativeOrder( QS.Pccol, i, orders[i] );
    SetPower( QS.Pccol, i, ObjByExponents( QS.Pccol, rhs ) );
  od;

  # set the conjugacy relations 
  for i in [1..(b-1)-1] do 
    for j in [i+1..(b-1)] do 
      # a_j a_i = a_i a_j  u_{ij}^++
      rhs      := ExponentsByObj( ftl, GetConjugate( ftl, j, i ) );
      rhsTails := rhs{[b..Length(rhs)]};
      if not IsZero( rhsTails ) then 
        rhs := Concatenation( rhs{[1..b-1]}, 
                              LPRES_RowReduce( rhsTails, HNF ){Gens});
      else
        rhs := Concatenation( rhs{[1..b-1]}, 0 * Gens );
      fi;
      SetConjugate( QS.Pccol, j, i, ObjByExponents( QS.Pccol, rhs ) );

      if orders[i] = 0 then 
        # a_j a_i^-1 = a_i^-1 a_j u_{ij}^{-+}
        rhs      := ExponentsByObj( ftl, GetConjugate( ftl, j, -i ) );
        rhsTails := rhs{[b..Length(rhs)]};
        if not IsZero( rhsTails ) then 
          rhs := Concatenation( rhs{[1..b-1]},
                                LPRES_RowReduce( rhsTails, HNF ){Gens} );
        else 
          rhs := Concatenation( rhs{[1..b-1]}, 0 * Gens );
        fi;
        SetConjugate( QS.Pccol, j, -i, ObjByExponents( QS.Pccol, rhs ) );
       
        if orders[i] = 0 then 
          # a_j^-1 a_i^-1 = a_i^-1 a_j^-1 u_{ij}^{--}
          rhs      := ExponentsByObj( ftl, GetConjugate( ftl, -j, -i ) );
          rhsTails := rhs{[b..Length(rhs)]};
          if not IsZero( rhsTails ) then
            rhs := Concatenation( rhs{[1..b-1]},
                                  LPRES_RowReduce( rhsTails, HNF ){Gens} );
          else
            rhs := Concatenation( rhs{[1..b-1]}, 0 * Gens );
          fi;
          SetConjugate( QS.Pccol, -j, -i, ObjByExponents( QS.Pccol, rhs ) );
        fi;
      elif orders[j] = 0 then 
        # a_j^-1 a_i = a_i a_j^-1 u_{ij}^{+-}
        rhs      := ExponentsByObj( ftl, GetConjugate( ftl, -j, i ) );
        rhsTails := rhs{[1..b-1]};
        if not IsZero( rhsTails ) then 
          rhs := Concatenation( rhs{[1..b-1]}, 
                                LPRES_RowReduce( rhsTails, HNF ){Gens} );
        else
          rhs := Concatenation( rhs{[1..b-1]}, 0 * Gens );
        fi;
        SetConjugate( QS.Pccol, -j, i, ObjByExponents( QS.Pccol, rhs ) );
      fi;
    od;
  od;

  # power relations for the tails
  for i in Filtered( [1..Length(HNF.Heads)], 
                     x -> HNF.mat[x][ HNF.Heads[x] ] <> 1 ) do
    k := Position( Gens, HNF.Heads[i] );
    SetRelativeOrder( QS.Pccol, k + (b-1), HNF.mat[i][ HNF.Heads[i] ] );
    rhs := ListWithIdenticalEntries( Length(weights)-(b-1), 0 );
    rhs[ HNF.Heads[i] ] := HNF.mat[i][ HNF.Heads[i] ];
    rhs := Concatenation( ListWithIdenticalEntries( b-1, 0 ), 
                          LPRES_RowReduce( rhs, HNF ){Gens} );
    SetPower( QS.Pccol, k+(b-1), ObjByExponents( QS.Pccol, rhs ) );
  od;

  FromTheLeftCollector_SetCommute( QS.Pccol );
  SetFilterObj( QS.Pccol, IsUpToDatePolycyclicCollector );
  FromTheLeftCollector_CompleteConjugate( QS.Pccol );
  FromTheLeftCollector_CompletePowers( QS.Pccol );

  SetFilterObj( QS.Pccol, IsUpToDatePolycyclicCollector );

  # build the epimorphism from the free group onto the cover
  Imgs := [];
  for i in [1..Length(QS.Imgs)] do
    if IsInt( QS.Imgs[i] ) then
      Imgs[i] := PcpElementByGenExpList( QS.Pccol, [ QS.Imgs[i], 1 ] );
    else
      Imgs[i] := PcpElementByGenExpList( QS.Pccol, QS.Imgs[i] );
    fi;
  od;
  QS.Epimorphism := GroupHomomorphismByImagesNC( FreeGroupOfLpGroup( Q.Lpres ), 
                         PcpGroupByCollectorNC( QS.Pccol ),
                         GeneratorsOfGroup( FreeGroupOfLpGroup( Q.Lpres ) ),
                         Imgs );

  return( QS );
  end);

############################################################################
##
#F  LPRES_InduceEndosToCover( <LpGroup>, <int> )
##
## induces the endomorphisms of the invariant L-presentation of <LpGroup>
## to the covering group of the class-<int> quotient.
##
InstallGlobalFunction( LPRES_InduceEndosToCover, 
  function( G, Endos, c )
  local QS, # quotient system of the covering group of the class-c quotient
 endos, # the induced endomorphisms
 endo, # an endomorphism of the L-presentation
 Defs, # definitions of generators
 H,  # the covering group
 imgs, # images of the generators
 obj,w, # 
 Cov, # covering groups of the nilpotent quotients
 i,j; # loop variables
 
  # if we already induced the endomorphism to the cover
  if IsBound( CoveringGroups( G )[c].IndEndosOfCover ) then 
    return( CoveringGroups( G )[c].IndEndosOfCover ); 
  fi;

  # the quotient system of the covering group of the class-c quotient
  QS   := CoveringGroups( G )[c];
  H    := Range( QS.Epimorphism );
  Defs := QS.Definitions;

  endos := [];
  for endo in Endos do
    imgs := [];
    for i in [ 1 .. Length( Defs ) ] do
      if IsPosInt( Defs[i] ) and QS.Weights[i] = 1 then 
        # a generator of G/G'
        imgs[i] := Image( QS.Epimorphism, Image( endo, 
                          FreeGeneratorsOfLpGroup( G )[ Defs[i] ] ));
      elif IsPosInt( Defs[i] ) and QS.Weights[i] > 1 then 
        # a tail added to an image
        w := QS.Imgs[ Defs[i] ];
        if not w{ [ Length(w)-1, Length(w) ] } = [ i, 1 ] then
          Error("in inducing the endomorphisms to the cover");
        fi;
        obj := PcpElementByGenExpList( QS.Pccol, [] );
        for j in [ 1, 3 .. Length( w ) - 3 ] do 
          obj := obj * imgs[ w[j] ] ^ w[j+1];
        od;
        imgs[i] := obj ^ -1 * Image( QS.Epimorphism, Image( endo, 
                              FreeGeneratorsOfLpGroup( G )[ Defs[i] ] ) );
      elif IsInt( Defs[i] ) and Defs[i] < 0 then 
        if not IsBound( imgs[ -Defs[i] ] ) then 
           Error("in inducing the endomorphisms to the cover");
        fi;
        w := GetPower( QS.Pccol, - Defs[i] );
        if not w{ [ Length( w ) - 1, Length( w ) ] } = [ i, 1 ] then
          Error("in inducing the endomorphisms to the cover");
        fi;
        obj := PcpElementByGenExpList( QS.Pccol, [] );
        for j in [ 1, 3 .. Length(w) - 3 ] do 
          obj := obj * imgs[ w[j] ] ^ w[j+1];;
        od;
       
        imgs[i] := obj^-1 * 
                   imgs[ - Defs[i] ] ^ RelativeOrders( QS.Pccol )[ - Defs[i] ];
      elif IsList( Defs[i] ) then 
        if not ( IsBound( imgs[ Defs[i][1] ] ) and 
                 IsBound( imgs[ Defs[i][2] ] ) ) then 
           Error("in inducing the endomorphisms to the cover");
        fi;
        w := GetConjugate( QS.Pccol, Defs[i][1], Defs[i][2] );
        if not w{ [ Length( w ) - 1, Length( w ) ] } = [ i, 1 ] then
          Error("in inducing the endomorphisms to the cover");
        fi;
        obj := PcpElementByGenExpList( QS.Pccol, [] );
        for j in [ 3, 5 .. Length( w ) - 3 ] do 
          obj := obj * imgs[ w[j] ] ^ w[j+1];
        od;
        imgs[i] := obj^-1 * Comm( imgs[ Defs[i][1] ], imgs[ Defs[i][2] ] );
      fi;
    od;
    if not IsDenseList( imgs ) then 
      Error("in inducing the endomorphisms to the cover");
    fi;
 
    Add( endos, GroupHomomorphismByImagesNC( H, H, 
                GeneratorsOfGroup(H), imgs ));
  od;  

  # store the induced endomorphisms of the L-presentation 
  if Endos = EndomorphismsOfLpGroup( G ) then 
    Cov := ShallowCopy( CoveringGroups( G ) );
    Cov[c] := ShallowCopy( Cov[c] );
    Cov[c].IndEndosOfCover := endos;    
    ResetFilterObj( G, CoveringGroups );
    SetCoveringGroups( G, Cov );
  fi;

  return( endos );
  end);

############################################################################
##
#F  LPRES_QSystemOfCoveringGroup( <QS> )
##
## computes a quotient system of the covering group.
##
InstallGlobalFunction( LPRES_QSystemOfCoveringGroup,
  function( Q )
  local QS, # quotient system of the covering group
 weights,# weight function
 Imgs, # images of the free group generators
 Defs, # definitions of the nilpotent presentation
 ftl,  # FromTheLeftCollector of the covering group
 HNF, # Hermite normal form from the consistency checks
 b, # position of the new generators
 i; # loop variable

  # definitions for the covering algorithm 
  weights := ShallowCopy( Q.Weights );
  Defs    := ShallowCopy( Q.Definitions );
  Imgs    := ShallowCopy( Q.Imgs );

  # compute a polycyclic presentation for the covering group
  ftl := LPRES_QSystemOfCoveringGroupByQSystem( Q.Pccol, weights, Defs, Imgs);

  # use tails routine to complete the polycyclic presentation <ftl>
  UpdateNilpotentCollector( ftl, weights, Defs );

  # enforce consistency of the polycyclic presentation for the covering group
  b   := Position( weights, Maximum( weights ) );
  HNF := LPRES_CheckConsistencyRelations( ftl, weights );
  for i in [ 1 .. Length( HNF.mat ) ] do 
    HNF.mat[i]   := HNF.mat[i]{[ b .. Length( weights ) ]};
    HNF.Heads[i] := HNF.Heads[i] - b + 1;
  od;

  # consistent polycyclic presentation for the covering group and epimorphism
  QS := LPRES_BuildCoveringGroup( Q, ftl, HNF, weights, Defs, Imgs );
  QS.Lpres := Q.Lpres;
  if Q.Weights = QS.Weights then
    Info( InfoLPRES, 1, "failed in computing the covering group");
    return( fail );
  else 
    return( QS );
  fi;

  end);

  
############################################################################
##
#M  EpimorphismCoveringGroups( <LpGroup>, <int1>, <int2> )
##
## computes an epimorphism from the covering group of the class-<int1> 
## quotient onto the covering group of the class-<int2> quotient.
##
InstallMethod( EpimorphismCoveringGroups,
  "for invariantly L-presented groups", true, 
  [ IsLpGroup and HasIsInvariantLPresentation and 
    IsInvariantLPresentation, IsPosInt, IsPosInt ], 0, 
  function( G, d, c ) 
  local Qc,Qd, # quotient systems of the nilpotent quotients
   QSc,QSd,# quotient systems of the covering groups
 gens, # generators that will be mapped
 imgs, # images of the generators of the cover
 pos, # generators of <QSc> corresponding to a tail (of an image)
 Cov, # list of quotient systems of the covering groups
 i; # loop variable
  
  if d <= c then return( fail ); fi;

  if HasCoveringGroups( G ) then 
    if IsBound( CoveringGroups( G )[d] ) then 
      QSd := CoveringGroups( G )[d];
    else
      if HasNilpotentQuotientSystem( G ) and 
         Maximum( NilpotentQuotientSystem( G ).Weights ) > d then 
        Qd := SmallerQuotientSystem( NilpotentQuotientSystem( G ), d );
      else
        if NilpotencyClassOfGroup( NilpotentQuotient( G, d ) ) < d then 
          Info( InfoLPRES, 1, "The group has a maximal nilpotent quotient of",
                            " class ", Maximum( Qd.Weights ) );
          return( fail );
        fi;
        Qd  := NilpotentQuotientSystem( G );
      fi;

      # compute a q-system of the covering group (of the class-d quotient)
      QSd := LPRES_QSystemOfCoveringGroup( Qd );

      # store the new covering group
      Cov    := ShallowCopy( CoveringGroups( G ) );; 
      Cov[d] := QSd;
      ResetFilterObj( G, CoveringGroups );
      SetCoveringGroups( G, Cov );
    fi;

    if IsBound( CoveringGroups( G )[c] ) then 
      QSc := CoveringGroups( G )[c];
    else
      # rebuild the quotient system of the class-c quotient (already known)
      Qc := SmallerQuotientSystem( NilpotentQuotientSystem( G ), c );

      # compute a q-system of the covering group (of the class-d quotient)
      QSc := LPRES_QSystemOfCoveringGroup( Qc );

      # store the new covering group
      Cov    := ShallowCopy( CoveringGroups( G ) );; 
      Cov[c] := QSc;
      ResetFilterObj( G, CoveringGroups );
      SetCoveringGroups( G, Cov );
    fi;
  else
    if HasNilpotentQuotientSystem( G ) and 
       Maximum( NilpotentQuotientSystem( G ).Weights ) > d then 
      Qc := SmallerQuotientSystem( NilpotentQuotientSystem( G ), c );
      Qd := SmallerQuotientSystem( NilpotentQuotientSystem( G ), d );
    else
      if NilpotencyClassOfGroup( NilpotentQuotient( G, d ) ) < d then
        Info( InfoLPRES, 1, "The group has a maximal nilpotent quotient of",
                          " class ", Maximum( Qd.Weights ) );
        return( fail );
      fi;
      Qc := SmallerQuotientSystem( NilpotentQuotientSystem( G ), c );
      Qd := NilpotentQuotientSystem( G );
    fi;   

    # compute quotient systems for the covering groups
    QSc := LPRES_QSystemOfCoveringGroup( Qc );
    QSd := LPRES_QSystemOfCoveringGroup( Qd );
    Cov := []; Cov[c] := QSc;; Cov[d] := QSd;
    SetCoveringGroups( G, Cov );
  fi;

  # compute the images of generators using their definitions
  gens := [];
  imgs := [];
  for i in Filtered( [ 1 .. Length( QSd.Weights ) ], 
                     x -> IsPosInt( QSd.Definitions[x] ) and 
                          QSd.Weights[x] = 1 ) do
    if not QSc.Definitions[i] = QSd.Definitions[i] then   
      Error("in computing corresponding generators");
    fi;
    Add( gens, GeneratorsOfGroup( Range( QSd.Epimorphism ) )[i] );
    Add( imgs, GeneratorsOfGroup( Range( QSc.Epimorphism ) )[i] );
  od;
 
  # the tails added to a non-defining image
  for i in Filtered( [ 1 .. Length( QSd.Weights ) ], 
                     x -> IsPosInt( QSd.Definitions[x] ) and 
                          QSd.Weights[x] > 1 ) do
    pos := Position( QSc.Definitions, QSd.Definitions[i] ); 

    Add( gens, GeneratorsOfGroup( Range( QSd.Epimorphism ) )[i] );
    Add( imgs, GeneratorsOfGroup( Range( QSc.Epimorphism ) )[pos] );
  od;

  return( GroupHomomorphismByImagesNC( Range( QSd.Epimorphism ),
          Range( QSc.Epimorphism ), gens, imgs ) );
  end);

############################################################################
##
#M  EpimorphismFiniteRankSchurMultipliers( <LpGroup>, <int1>, <int2> )
##
## computes an epimorphism from the FiniteRankSchurMultiplier of the class-
## <int1> quotient onto the FiniteRankSchurMultiplier of the class-<int2>
## quotient by restricting `EpimorphismCoveringGroups'.
##
InstallMethod( EpimorphismFiniteRankSchurMultipliers,
  "for invariantly L-presented groups", true, 
  [ IsLpGroup and HasIsInvariantLPresentation and 
    IsInvariantLPresentation, IsPosInt, IsPosInt ], 0, 
  function( G, d, c ) 
  if d < c then
    Error( "epimorphism from ", d," onto ",c," Schur multiplier");
  fi;
  return( GroupHomomorphismByImagesNC( FiniteRankSchurMultiplier( G, d ),
          FiniteRankSchurMultiplier( G, c ),
          GeneratorsOfGroup( FiniteRankSchurMultiplier( G, d ) ),
          List( GeneratorsOfGroup( FiniteRankSchurMultiplier( G, d ) ),
                x -> Image( EpimorphismCoveringGroups( G, d, c ), x ) ) ) );
  end);


############################################################################
##
#F  ImageInFiniteRankSchurMultiplier( <LpGroup>, <int>, <elm> )
##
## computes the image of <elm> in the <int>-th finite rank Schur multiplier
## of <LpGroup>.
##
InstallGlobalFunction( ImageInFiniteRankSchurMultiplier,
  function( G, c, elm )
  local M, # the <c>-th finite rank Schur multiplier
 QS, # covering group of the class-<c> quotient
 img; # image of <elm> in the covering group

  M   := FiniteRankSchurMultiplier( G, c );
  QS  := CoveringGroups( G )[c];
  img := Image( QS.Epimorphism, elm );
 
  if not img in M then 
    return( fail );
  else
    return( img );
  fi;
  end);

############################################################################
##
#M DwyerQuotient
##
InstallMethod( DwyerQuotient, 
    "for an LpGroup", true,
    [ IsLpGroup, IsPosInt ], 0, 
    function( G, c ) 
    return( FiniteRankSchurMultiplier( G, c ) );
    end );

InstallMethod( DwyerQuotient, 
    "for an arbitrary group", true,
    [ IsGroup, IsPosInt ], 0, 
    function( G, c ) 
    return( FiniteRankSchurMultiplier( Range( IsomorphismLpGroup( G ) ), c ) );
    end );

[ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ]