Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 51 kB image not shown  

Quelle  grppcaut.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Bettina Eick.
##
##  Copyright of GAP belongs to its developers, whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-2.0-or-later
##

BindGlobal( "VectorStabilizerByFactors", function(group,gens,mats,shadows,vec)
  local PrunedBasis, f, lim, mo, dim, bas, newbas, dims, q, bp, ind, affine,
  acts, nv, stb, idx, idxh, incstb, incperm, notinc, free, freegens, stabp,
  stabm, dict, orb, tp, tm, p, img, sch, incpermstop, sz, sel, nbas, offset,
  i,action,lineflag;

  PrunedBasis:=function(p)
  local b,q,i;
    # prune too small factors
    b:=[p[1]];
    q:=0;
    for i in [2..Length(p)] do
      if i=Length(p) or Length(p[i+1])-q>lim then
        Add(b,p[i]);
        q:=Length(p[i]);
      fi;
    od;
    return b;
  end;

  f:=DefaultScalarDomainOfMatrixList(mats);
  lim:=LogInt(1000,Size(f));
  lim:=2;
  mo:=GModuleByMats(mats,f);
  dim:=mo.dimension;
  bas:=PrunedBasis(MTX.BasesCSSmallDimDown(mo));

  # form new basis of space
  newbas:=ShallowCopy(bas[2]);
  dims:=[0,Length(newbas)];
  for i in [3..Length(bas)] do
    q:=BaseSteinitzVectors(bas[i],newbas);
    Append(newbas,q.factorspace);
    Add(dims,Length(newbas));
  od;

  #base change newbas is matrix new -> old
  q:=newbas^-1;
  mats:=List(mats,i->newbas*i*q);
  #bas:=List(bas{[2..Length(bas)]},i->i*q);
  #bas:=Concatenation([[]],bas);
  vec:=vec*q;

  bp:=Length(dims)-1;
  action:=false;
  lineflag:=true;
  while bp>=1 do
    ind:=[dims[bp]+1..dims[bp+1]];
    q:=[dims[bp+1]+1..dim];
    if bp+1=Length(dims) then
      affine:=false;
      ind:=[dims[bp]+1..dim];
    else
      affine:=List(mats,i->vec{q}*(i{q}{ind}));
      if ForAll(affine,IsZero) then
        affine:=false;
      fi;
    fi;
    Info(InfoMatOrb,2,"Acting dimension ",ind);
    acts:=List(mats,x->ImmutableMatrix(f,x{ind}{ind}));
    nv:=vec{ind};

    if affine=false then
      if lineflag and Size(mo.field)>2 then
        action:=OnLines;
        nv:=NormedRowVector(nv);
      else
        action:=OnRight;
      fi;
    else
      action:=false;
    fi;

    if (affine=false and ForAny([1..Length(acts)],i->nv*acts[i]<>nv))
    or (affine<>false and ForAny([1..Length(acts)],i->nv*acts[i]+affine[i]<>nv))
      then
      # orbit/stabilizer algorithm. We need to carry (pre)images through
      #os:=OrbitStabilizer(group,nv,hocos,ind[2].generators,OnRight);
      stb:=TrivialSubgroup(group);
      idx:=Size(group);idxh:=idx/Factors(idx)[1];
      incstb:=true;
      incperm:=true;
      notinc:=0;
      free:=FreeGroup(Length(gens));
      freegens:=GeneratorsOfGroup(free);
      stabp:=[];
      stabm:=[];
      dict:=NewDictionary(nv,true,f^Length(nv));

      MakeImmutable(nv);
      orb:=[nv];
      AddDictionary(dict,nv,1);
      tp:=[One(group)];
      tm:=[One(free)];
      p:=1;

      while incstb and p<=Length(orb) do
        for i in [1..Length(gens)] do
          if action<>false then
            img:=action(orb[p],acts[i]);
          else
            img:=orb[p]*acts[i]+affine[i];
          fi;
          q:=LookupDictionary(dict,img);
          if q=fail then
            Add(orb,img);
            if incstb and idxh<Length(orb) then
              Info(InfoMatOrb,3,"stopped at orbit length ",
                Length(orb),"/",idx);
              incstb:=false;
            else
              AddDictionary(dict,img,Length(orb));
              if incperm then
                Add(tp,tp[p]*gens[i]);
              fi;
              Add(tm,tm[p]*freegens[i]);
            fi;
          elif incstb then
            if IsBound(tp[p]) and IsBound(tp[q]) then
              sch:=tp[p]*gens[i]/tp[q];
            elif Random(1,200)=1 then
              if IsBound(tp[p]) then
                sch:=tp[p];
              else
                sch:=MappedWord(tm[p],freegens,gens);
              fi;
              sch:=sch*gens[i];
              if IsBound(tp[q]) then
                sch:=sch/tp[q];
              else
                sch:=sch/MappedWord(tm[q],freegens,gens);
              fi;
            else
              sch:=false;
            fi;
            if sch<>false and not sch in stb then
#Print("new schreiergen",Length(orb),"\n");
              stb:=ClosureSubgroupNC(stb,sch);
              idx:=Size(group)/Size(stb);idxh:=idx/Factors(idx)[1];
              if idxh<Length(orb) then
                Info(InfoMatOrb,3,"stopped at orbit length ",
                  Length(orb),"/",idx);
                incstb:=false;
              fi;
              Add(stabp,sch);
              sch:=tm[p]*freegens[i]/tm[q];
              Add(stabm,sch);
              notinc:=0;
            elif incperm then
              notinc:=notinc+1;
              if 20*notinc>idxh and notinc>10000 then
                Info(InfoMatOrb,3, Length(orb),
                " -- not incrementing perms again:",Size(group)/Size(stb));
                incperm:=false;
                incpermstop:=p;
              fi;
#Print("old schreiergen",Length(orb),"\n");
            fi;
          fi;
        od;
        p:=p+1;
      od;
      #sz:=Maximum(Difference(DivisorsInt(sz),[sz]));
      if Length(orb)<=idxh and Length(orb)<idx then
        Info(InfoWarning,1,"too small stabilizer");
        p:=incpermstop;
        sz:=Size(group)/Length(orb);
        while Size(stb)<sz do
          for i in [1..Length(gens)] do
            if action<>false then
              img:=action(orb[p],acts[i]);
            else
              img:=orb[p]*acts[i]+affine[i];
            fi;
            q:=LookupDictionary(dict,img);
            if q=fail then
              Error("error in orbit alg");
            else
              if IsBound(tp[p]) then
                sch:=tp[p];
              else
                sch:=MappedWord(tm[p],freegens,gens);
              fi;
              sch:=sch*gens[i];
              if IsBound(tp[q]) then
                sch:=sch/tp[q];
              else
                sch:=sch/MappedWord(tm[q],freegens,gens);
              fi;
              if not sch in stb then
                stb:=ClosureSubgroupNC(stb,sch);
                Add(stabp,sch);
                sch:=tm[p]*freegens[i]/tm[q];
                Add(stabm,sch);
              fi;
            fi;
          od;
          p:=p+1;
        od;
      fi;
      sz:=Size(stb);
      sel:=[];
      stb:=TrivialSubgroup(group);
      for i in Reversed([1..Length(stabp)]) do
        if not stabp[i] in stb then
          Add(sel,i);
          stb:=ClosureSubgroupNC(stb,stabp[i]);
        fi;
      od;
      stabp:=stabp{sel};
      stabm:=stabm{sel};
      sz:=Size(group)/Size(stb);
      Info(InfoMatOrb,2,"Orbit length ",Length(orb),
           " stabilizer index ",sz,", ",Length(sel)," generators");
      Unbind(orb); Unbind(dict);Unbind(tp);Unbind(tm);
      group:=stb;
      gens:=stabp;
      mats:=List(stabm,i->MappedWord(i,freegens,mats));
      shadows:=List(stabm,i->MappedWord(i,freegens,shadows));
      if AssertionLevel()>0 and (action=false or action=OnRight) then
            ind:=[dims[bp]+1..dim];
            acts:=List(mats,x->ImmutableMatrix(f,x{ind}{ind}));
            nv:=vec{ind};
            Assert(1,ForAll(acts,i->nv*i=nv));
      fi;

      # should we try to refine the next step?
      if Length(mats)>0 and sz>1 and bp>1 and ForAny([2..bp],q->dims[q]-dims[q-1]>lim) then
        mo:=GModuleByMats(mats,f);
        ind:=[1..dims[bp]];
        acts:=List(mats,x->ImmutableMatrix(f,x{ind}{ind}));
        mo:=GModuleByMats(acts,f);
        #if not MTX.IsIrreducible(mo) then
        nbas:=PrunedBasis(MTX.BasesCSSmallDimDown(mo));
        offset:=Length(nbas)-bp;
        if offset>0 then
          #nbas:=nbas{[2..Length(nbas)]};
          q:=IdentityMat(dim,f){ind};
          nbas:=List(nbas,i->List(i,j->j*q));
          Info(InfoMatOrb,2,"Reduction ",List(nbas,Length));
          newbas:=[];
          for i in nbas do
            q:=BaseSteinitzVectors(i,newbas);
            Append(newbas,q.factorspace);
          od;
          Append(newbas,IdentityMat(dim,f){[dims[bp]+1..dim]});
          newbas:=ImmutableMatrix(f,newbas);

          dims:=Concatenation(List(nbas{[1..Length(nbas)]},Length),
                 dims{[bp+1..Length(dims)]});

          #Error("further reduction!");
          #base change newbas is matrix new -> old
          q:=newbas^-1;
          mats:=List(mats,i->newbas*i*q);
          vec:=vec*q;
          bp:=bp+offset;

        fi;
        if AssertionLevel()>0 and (action=false or action=OnRight) then
          ind:=[dims[bp]+1..dim];
          acts:=List(mats,x->ImmutableMatrix(f,x{ind}{ind}));
          nv:=vec{ind};
          Assert(1,ForAll(acts,i->nv*i=nv));
        fi;

      fi;
    fi;
    if action<>OnLines then
      bp:=bp-1;
      lineflag:=true;
    else
      lineflag:=false;
    fi;
  od;
  Assert(1,ForAll(mats,i->vec*i=vec));
  return rec(stabilizer:=group,
             gens:=gens,
             mats:=mats,
             shadows:=shadows);
end );

#############################################################################
##
#F StabilizerByMatrixOperation( C, v, cohom )
##
BindGlobal( "StabilizerByMatrixOperation", function( C, v, cohom )
local translate, gens, oper, tmp;

    # the trivial case
    if Size( C ) = 1 then return C; fi;

    # can we get a permrep?
    if IsBound(C!.permrep) then
      translate:=C!.permrep;
    else
      translate:=EXPermutationActionPairs(C);
    fi;

    # choose gens
    if translate<>false then
      Unbind(translate.isomorphism);
      EXReducePermutationActionPairs(translate);
      gens:=translate.pairgens;
    elif HasPcgs( C ) then
      gens := Pcgs( C );
    else
      gens := GeneratorsOfGroup( C );
    fi;

    # compute matrix operation
    oper := MatrixOperationOfCPGroup( cohom, gens );

    if translate<>false then
      tmp:=VectorStabilizerByFactors(translate.permgroup,translate.permgens,
                                     oper,translate.pairgens,v);
      translate:=rec(permgroup:=tmp.stabilizer,
                     permgens:=tmp.gens,
                     pairgens:=tmp.shadows);
      C:=GroupByGenerators(translate.pairgens,One(C));
      SetSize(C,Size(tmp.stabilizer));
    else
      tmp := OrbitStabilizer( C, v, gens, oper, OnRight );
      Info( InfoMatOrb, 1, " MO: found orbit of length ",Length(tmp.orbit) );
      SetSize( tmp.stabilizer, Size( C ) / Length( tmp.orbit ) );
      C   := tmp.stabilizer;
    fi;

    if translate<>false then
      C!.permrep:=translate;
    fi;
    return C;
end );

#############################################################################
##
#F TransferPcgsInfo( A, pcsA, rels )
##
BindGlobal( "TransferPcgsInfo", function( A, pcsA, rels )
    local pcgsA;
    pcgsA := PcgsByPcSequenceNC( ElementsFamily( FamilyObj( A ) ), pcsA );
    SetRelativeOrders( pcgsA, rels );
    SetOneOfPcgs( pcgsA, One(A) );
    SetPcgs( A, pcgsA );
    SetFilterObj( A, CanEasilyComputePcgs );
end );

#############################################################################
##
#F Fingerprint( G, U )
##
if not IsBound( MyFingerprint ) then MyFingerprint := false; fi;

BindGlobal( "FingerprintSmall", function( G, U )
    Info(InfoPerformance,2,"Using Small Groups Library");
    return [IdGroup( U ), Size( CommutatorSubgroup(G,U) )];
end );

BindGlobal( "FingerprintMedium", function( G, U )
    local w, cl, id;

    # some general stuff
    w := LGWeights( SpecialPcgs( U ) );
    id := [w, Size( CommutatorSubgroup( G, U ) )];

    # about conjugacy classes
    cl := OrbitsDomain( U, AsList( U ), OnPoints );
    cl := List( cl, x -> [Length(x), Order( x[1] ) ] );
    Sort( cl );
    Add( id, cl );

    return id;
end );

BindGlobal( "FingerprintLarge", function( G, U )
    return [Size(U), Size( DerivedSubgroup( U ) ),
            Size( CommutatorSubgroup( G, U ) )];
end );

BindGlobal( "Fingerprint", function ( G, U )
    if not IsBool( MyFingerprint ) then
        return MyFingerprint( G, U );
    fi;
    if ID_AVAILABLE( Size( U ) ) <> fail and
      ValueOption(NO_PRECOMPUTED_DATA_OPTION)<>true then
        return FingerprintSmall( G, U );
    elif Size( U ) <= 1000 then
        return FingerprintMedium( G, U );
    else
        return FingerprintLarge( G, U );
    fi;
end );

#############################################################################
##
#F NormalizingReducedGL( spec, s, n, M [,B] )
##
BindGlobal( "NormalizingReducedGL", function(arg)
local spec,s,n,M,
    G, p, d, field, B, U, hom, pcgs, pcs, rels, w,
          S, L,
          f, P, norm,
          pcgsN, pcgsM, pcgsF,
          orb, part,
          par, done, i, elm, elms, pcgsH, H, tup, pos,
          perms, V;

    spec:=arg[1];
    s:=arg[2];
    n:=arg[3];
    M:=arg[4];

    G      := GroupOfPcgs( spec );
    d      := M.dimension;
    field  := M.field;
    p      := Characteristic( field );

    if Length(arg)>4 then
      B:=arg[5];
    else
      B := GL( d, p );
    fi;
    U      := SubgroupNC( B, M.generators );

    # the trivial case
    if d = 1 then
        hom := IsomorphismPermGroup( B );
        pcgs := Pcgs( Image( hom ) );
        pcs := List( pcgs, x -> PreImagesRepresentative( hom, x ) );
        TransferPcgsInfo( B, pcs, RelativeOrders( pcgs ) );
        return B;
    fi;

    # first find out, whether there are characteristic subspaces
    # -> compute socle series and chain stabilising mat group
    S := B;

    # in case that we cannot compute a perm rep of pgl
    if p^d > 100000 then
        return S;
    fi;

    # otherwise use a perm rep of pgl and find a small admissible subgroup
    norm := NormedRowVectors( field^d );
    f := function( pt, op ) return NormedRowVector( pt * op ); end;
    hom := ActionHomomorphism( S, norm, f );
    P := Image( hom );
    L := ShallowCopy(P);

    # compute corresponding subgroups to mins
    pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[s..Length(spec)]} );
    pcgsM := InducedPcgsByPcSequenceNC( spec, spec{[n..Length(spec)]} );
    pcgsF := pcgsN mod pcgsM;

    # use fingerprints
    done := [];
    part := [];
    for i in [1..Length(norm)] do
        elm := PcElementByExponentsNC( pcgsF, norm[i] );
        elms := Concatenation( [elm], pcgsM );
        pcgsH := InducedPcgsByPcSequenceNC( spec, elms );
        H := SubgroupByPcgs( G, pcgsH );
        tup := Fingerprint( G, H );
        pos := Position( done, tup );
        if IsBool( pos ) then
            Add( part, [i] );
            Add( done, tup );
        else
            Add( part[pos], i );
        fi;
    od;
    SortBy( part, Length );

    # compute partition stabilizer
    if Length(part) > 1 then
        for par in part do
            if Length( part ) = 1 then
                L := Stabilizer( L, par[1], OnPoints );
            else
                L := Stabilizer( L, par, OnSets );
            fi;
        od;
    fi;
    Info( InfoOverGr, 1, "found partition ",part );

    # use operation of G on norm
    orb := OrbitsDomain( U, norm, f );
    part := List( orb, x -> List( x, y -> Position( norm, y ) ) );

    part:=List(part,Set);
    L:=PartitionStabilizerPermGroup(L,part);
    Info( InfoOverGr, 1, "found blocksystem ",part );

    # compute normalizer of module
    perms := List( M.generators, x -> Image( hom, x ) );
    V := SubgroupNC( P, perms );
    L := Normalizer( L, V );
    Info( InfoOverGr, 1, "computed normalizer of size ", Size(L));

    # go back to mat group
    B := List( GeneratorsOfGroup(L), x -> PreImagesRepresentative(hom,x) );
    w := PrimitiveRoot(field)* Immutable( IdentityMat( d, field ) );
    B := SubgroupNC( S, Concatenation( B, [w] ) );

    if IsSolvableGroup( L ) then
        pcgs := List( Pcgs(L), x -> PreImagesRepresentative( hom, x ) );
        Add( pcgs, w );
        rels := ShallowCopy( RelativeOrders( Pcgs(L) ) );
        Add( rels, p-1 );
        TransferPcgsInfo( B, pcgs, rels );
    fi;

    SetSize( B, Size( L )*(p-1) );
    return B;
end );

#############################################################################
##
#F CocycleSQ( epi, field )
##
BindGlobal( "CocycleSQ", function( epi, field )
    local H, F, N, pcsH, pcsN, pcgsH, o, n, d, z, c, i, j, h, exp, p, k;

    # set up
    H     := Source( epi );
    F     := Image( epi );
    N     := KernelOfMultiplicativeGeneralMapping( epi );
    pcsH  := List( Pcgs( F ), x -> PreImagesRepresentative( epi, x ) );
    pcsN  := Pcgs( N );
    pcgsH := PcgsByPcSequence( ElementsFamily( FamilyObj( H ) ),
                               Concatenation( pcsH, pcsN ) );
    o     := RelativeOrders( pcgsH );
    n     := Length( pcsH );
    d     := Length( pcsN );
    z     := One( field );

    # initialize cocycle
    c := List( [1..d*(n^2 + n)/2], x -> Zero( field ) );

    # add relators
    for i in [1..n] do
        for j in [1..i] do
            if i = j then
                h := pcgsH[i]^o[i];
            else
                h := pcgsH[i]^pcgsH[j];
            fi;
            exp := ExponentsOfPcElement( pcgsH, h ){[n+1..n+d]} * z;
            p   := (i^2 - i)/2 + j - 1;
            for k in [1..d] do
                c[p*d+k] := exp[k];
            od;
        od;
    od;

    # check
    if c = 0 * c then return 0; fi;
    return c;
end );

#############################################################################
##
#F InduciblePairs( C, epi, M )
##
BindGlobal( "InduciblePairs", function( C, epi, M )
    local F, cc, c, stab, b;

    if HasSize( C ) and Size( C ) = 1 then return C; fi;

    # get groups
    F := Image( epi );

    # get cohomology
    cc := TwoCohomology( F, M );
    Info( InfoAutGrp, 2, "computed cohomology with dim ",
          Dimension(Image(cc.cohom)));
    # get cocycle
    c := CocycleSQ( epi, M.field );
    b := Image( cc.cohom, c );

    # compute stabilizer of b
    stab := StabilizerByMatrixOperation( C, b, cc );
    return stab;
end );

BindGlobal( "MatricesOfRelator", function( rel, gens, inv, mats, field, d )
    local n, m, L, s, i, mat;

    # compute left hand side
    n := Length( mats );
    m := Length( rel );
    L := ListWithIdenticalEntries( n, Immutable( NullMat( d, d, field ) ) );
    while m > 0 do
        s := Subword( rel, 1, 1 );
        i := Position( gens, s );
        if not IsBool( i ) and m > 1 then
            mat := MappedWord(Subword( rel, 2, m ), gens, mats);
            L[i] := L[i] + mat;
        elif not IsBool( i ) then
            L[i] := L[i] + IdentityMat( d, field );
        else
            i := Position( inv, s );
            mat := MappedWord( rel, gens, mats );
            L[i] := L[i] - mat;
        fi;
        if m > 1 then rel := Subword( rel, 2, m ); fi;
        m   := m - 1;
    od;
    return L;
end );

BindGlobal( "VectorOfRelator", function( rel, gens, imgsF, pcsH, pcsN, nu, field )
    local w, s, r;

    # compute right hand side
    w := MappedWord( rel, gens, imgsF )^-1;
    s := MappedWord( rel, gens, pcsH );
    r := ExponentsOfPcElement( pcsN, w * Image( nu, s ) ) * One(field);
    return r;
end );

#############################################################################
##
#F LiftInduciblePair( epi, ind, M, weight )
##
BindGlobal( "LiftInduciblePair", function( epi, ind, M, weight )
    local H, F, N, pcgsF, pcsH, pcsN, pcgsH, n, d, imgsF, imgsN, nu, P,
          gensP, invP, relsP, l, E, v, k, rel, u, vec, L, r, i,
          elm, auto, imgsH, j, h, opmats;

    # set up
    H := Source( epi );
    F := Image( epi );
    N := KernelOfMultiplicativeGeneralMapping( epi );


    pcgsF := Pcgs( F );
    pcsH  := List( pcgsF, x -> PreImagesRepresentative( epi, x ) );
    pcsN  := Pcgs( N );
    pcgsH := PcgsByPcSequence( ElementsFamily( FamilyObj( H ) ),
                               Concatenation( pcsH, pcsN ) );
    n     := Length( pcsH );
    d     := Length( pcsN );

    # use automorphism of F
    imgsF := List( pcgsF, x -> Image( ind[1], x ) );
    opmats := List( imgsF, x -> MappedPcElement( x, pcgsF, M.generators ) );
    imgsF := List( imgsF, x -> PreImagesRepresentative( epi, x ) );

    # use automorphism of N
    imgsN := List( pcsN, x -> ExponentsOfPcElement( pcsN, x ) );
    imgsN := List( imgsN, x -> x * ind[2] );
    imgsN := List( imgsN, x -> PcElementByExponentsNC( pcsN, x ) );

    # in the split case this is all to do
    if weight[2] = 1 then
        imgsH := Concatenation( imgsF, imgsN );
        auto  := GroupHomomorphismByImagesNC( H, H, AsList(pcgsH), imgsH );

        SetIsBijective( auto, true );
        SetKernelOfMultiplicativeGeneralMapping( auto, TrivialSubgroup( H ) );

        return auto;
    fi;

    # add correction
    nu := GroupHomomorphismByImagesNC( N, N, AsList( pcsN ), imgsN );
    P := Range( IsomorphismFpGroupByPcgs( pcgsF, "g" ) );
    gensP := GeneratorsOfGroup( FreeGroupOfFpGroup( P ) );
    invP  := List( gensP, x -> x^-1 );
    relsP := RelatorsOfFpGroup( P );
    l := Length( relsP );

    E := List( [1..n*d], x -> List( [1..l*d], ReturnTrue ) );
    v := [];
    for k in [1..l] do
        rel := relsP[k];
        L   := MatricesOfRelator( rel, gensP, invP, opmats, M.field, d );
        r   := VectorOfRelator( rel, gensP, imgsF, pcsH, pcsN, nu, M.field );

        # add to big system
        Append( v, r );
        for i in [1..n] do
            for j in [1..d] do
                for h in [1..d] do
                    E[d*(i-1)+j][d*(k-1)+h] := L[i][j][h];
                od;
            od;
        od;
    od;

    # solve system
    u := SolutionMat( E, v );
    if u = fail then Error("no lifting found"); fi;

    # correct images
    for i in [1..n] do
        vec := u{[d*(i-1)+1..d*i]};
        elm := PcElementByExponentsNC( pcsN, vec );
        imgsF[i] := imgsF[i] * elm;
    od;

    # set up automorphisms
    imgsH := Concatenation( imgsF, imgsN );
    auto  := GroupHomomorphismByImagesNC( H, H, AsList( pcgsH ), imgsH );

    SetIsBijective( auto, true );
    SetKernelOfMultiplicativeGeneralMapping( auto, TrivialSubgroup( H ) );

    return auto;
end );

#############################################################################
##
#F AutomorphismGroupElAbGroup( G, B )
##
BindGlobal( "AutomorphismGroupElAbGroup", function( G, B )
    local pcgs, mats, autos, mat, imgs, auto, A;

    # create matrices
    pcgs := Pcgs( G );

    if CanEasilyComputePcgs( B ) then
        mats := Pcgs( B );
    else
        mats := GeneratorsOfGroup( B );
    fi;

    autos := [];
    for mat in mats do
        imgs := List( pcgs, x -> PcElementByExponentsNC( pcgs,
                            ExponentsOfPcElement( pcgs, x ) * mat ) );
        auto := GroupHomomorphismByImagesNC( G, G, AsList( pcgs ), imgs );

        SetIsBijective( auto, true );
        SetKernelOfMultiplicativeGeneralMapping( auto, TrivialSubgroup( G ) );
        Add( autos, auto );
    od;

    A := GroupByGenerators( autos, IdentityMapping( G ) );
    SetSize( A, Size( B ) );
    if IsPcgs( mats ) then
        TransferPcgsInfo( A, autos, RelativeOrders( mats ) );
    fi;

    return A;
end );

#############################################################################
##
#F AutomorphismGroupSolvableGroup( G )
##

# construct subgroup of GL that stabilizes the spaces given and fixes the
# listed spaceorbits.

# auxiliary
BindGlobal( "RedmatSpanningIndices", function(gens)
local bas,n,one,new,a,b,g;
  n:=Length(gens[1]);
  one:=One(gens[1]);
  new:=[];
  bas:=[];
  while Length(bas)<n do
    a:=First(one,x->Length(bas)=0 or SolutionMat(bas,x)=fail);
    Add(new,Position(one,a));
    Add(bas,a);
    # spin
    for b in bas do
      for g in gens do
        a:=b*g;
        if SolutionMat(bas,a)=fail then
          Add(bas,a);
        fi;
      od;
    od;
  od;
  return new;
end );

InstallGlobalFunction(SpaceAndOrbitStabilizer,function(n,field,ospaces,osporb)
local outvecs,l,sub,yet,i,j,k,s,t,new,incl,min,rans,sofar,done,
      gens,one,spl,m,sz,a,sporb,notyet,canonicalform,spaces,
      sofars,b,act,pairs,direct,subs,allstab;

  # replace later by better functions
  canonicalform:=function(space)
    if Length(space)=0 then
      return space;
    else
      space:=TriangulizedMat(space);
      space:=Filtered(space,x->not IsZero(x));
      return space;
    fi;
  end;

  outvecs:=function(space,new)
    return BaseSteinitzVectors(canonicalform(Concatenation(new,space)),space).factorspace;

  end;

  one:=IdentityMat(n,field);
  sub:=[]; # space so far
  spaces:=Unique(List(ospaces,canonicalform));

  SortBy(spaces,Length);
  if not ForAny(spaces,x->Length(x)=n) then
    Add(spaces,List(one,ShallowCopy));
  fi;
  l:=Length(spaces);

  sporb:=List(osporb,ShallowCopy);
  sporb:=List(sporb,x->List(x,canonicalform));
  allstab:=[];

  # do not aim to produce the whole lattice, but ony layers of subspaces that
  # are invariant and always intersect in the next lower layer. (Then deal
  # with the rest by stabilizer).
  # The reason behind this is that the whole lattice could be huge. Also do
  # so layer by layer.

  # As c(a\cap b)<>ca\cap cb in general, there is little value in preserving
  # intersections between rounds

  sub:=[]; # basis
  sofar:=[]; # space spanned so far (canonized)

  gens:=[]; # matrix gens, in new basis (sub)
  sz:=1;
  notyet:=[]; # unstabilized yet (if there are diagonals)

  while Length(sofar)<n do

    new:=Filtered(spaces,x->Length(x)>Length(sofar));
    l:=Length(new);
    min:=[1..Length(new)];
    pairs:=Concatenation(List([1..l],x->List([x+1..l],y->[x,y])));

    # we try to find a direct sum structure (modulo sofar).
    # But since we do not form closures, there could still be intersections,
    # e.g. if <1,0,0>, <0,1,0> and <(1,1,0),(1,1,1)>,
    # Thus, when trying to form a direct sum modulo sofar, we could still find
    # some not minimal, so we might need to iterate

    repeat
      direct:=true;
      i:=1;

      while i<=Length(pairs) do
        # intersect
        s:=SumIntersectionMat(new[pairs[i][1]],new[pairs[i][2]])[2];
        s:=canonicalform(s);
        if Length(s)>Length(sofar) then
          # are intersectants not minimal
          if Length(s)<Length(new[pairs[i][1]]) then
            RemoveSet(min,pairs[i][1]);
          fi;
          if Length(s)<Length(new[pairs[i][2]]) then
            RemoveSet(min,pairs[i][2]);
          fi;
          # is intersection new?
          if not ForAny(new,x->Length(x)=Length(s) and s=x) then
            j:=pairs[i];
            # clean out pairs to save memory?
            if i*4>Length(pairs) then
              pairs:=pairs{[i..Length(pairs)]};
              i:=0;
            fi;

            if Length(s)>Length(sofar)+1 then
              Append(pairs,
                List(Difference([1..Length(new)],j),x->[x,l+1]));
            fi;
            Add(new,s);
            l:=l+1;
            AddSet(min,l);
            # new intersection
          fi;
        fi;
        i:=i+1;
      od;
      pairs:=pairs{[i..Length(pairs)]};
      # now new{min} is a list of spaces that are minimal wrt intersection.

      subs:=List(sub,ShallowCopy);
      sofars:=List(sofar,ShallowCopy);
      rans:=[];
      SortBy(min,x->Length(new[x]));
      i:=1;
      incl:=[];
      done:=[];
      while direct and i<=Length(min) do
        s:=SumIntersectionMat(sofars,new[min[i]]);
        if Length(s[2])=Length(sofar) then
          # trivial intersection (modulo), just add new vectors
          j:=outvecs(sofar,new[min[i]]);
          rans[i]:=[Length(subs)+1..Length(s[1])];
if Length(rans[i])=0 then Error("EGAD");fi;
          Append(subs,j);
          Append(sofars,j);
          sofars:=canonicalform(sofars);
        elif Length(s[2])=Length(new[min[i]]) then
          # space is contained in direct sum so far -- don't grow
          rans[i]:=fail;
        else
          # there is a new intersection, we did not yet know. Add it
          if Length(s[2])>Length(sofar)+1 then
            Append(pairs,List(Difference([1..Length(new)],[min[i]]),x->[x,l+1]));
          fi;
          l:=l+1;
          Add(new,s[2]);
          AddSet(done,min[i]);
          AddSet(incl,l); # i is not minimal
          direct:=false;
        fi;
        i:=i+1;
      od;
      if direct=false then
        min:=Union(Difference(Set(min),done),incl);
      fi;
    until direct;

    # now min and associated rans give us the spaces to add
    Append(allstab,new{min});

    # go through each needed space and add a GL (or GL\wr) in that space
    for i in [1..Length(min)] do
      if rans[i]<>fail then
        spl:=[];
        for j in sporb do
          s:=List(j,x->SumIntersectionMat(x,new[min[i]])[2]);
          # if the dimension changes, its hard to be clever
          if Length(Set(s,Length))=1 and
            Length(s[1])>Length(sofar) and Length(s[1])<Length(new[min[i]]) then
            Add(spl,s);
          fi;
        od;
        if Length(spl)>0 then
          spl:=spl[1]; # so far only use one...
          # new basis vectors
          a:=[];
          for j in spl do
            Add(a,outvecs(sofar,j));
          od;
          if Sum(a,Length)=Length(rans[i]) then
            # otherwise its strange and we can't do...
            Append(sub,Concatenation(a)); # basis vectors for product
            a:=MatWreathProduct(GL(Length(a[1]),field),SymmetricGroup(Length(a)));
          else
            a:=GL(Length(rans[i]),field);
            Append(sub,subs{rans[i]}); # use the existing basis vectors
          fi;
        else
          # make a GL on the space
          a:=GL(Length(rans[i]),field);
          Append(sub,subs{rans[i]}); # use the existing basis vectors
        fi;

        sz:=sz*Size(a);
        for k in GeneratorsOfGroup(a) do
          m:=List(one,ShallowCopy);
          m{rans[i]}{rans[i]}:=k;
          Add(gens,m);
        od;
      else
        # mark that we need to stabilizer this space as well
        Add(notyet,new[min[i]]);
      fi;

    od;

    if Length(sofar)>0 then
      sz:=sz*Size(field)^(Length(sofar)*(Length(sub)-Length(sofar)));
      # add generators for the bimodule.
      rans:=[1..Length(sofar)];
      s:=List(gens,x->x{rans}{rans});
      s:=RedmatSpanningIndices(s);

      rans:=[Length(sofar)+1..Length(sub)];
      t:=List(gens,x->TransposedMat(x{rans}{rans}));
      t:=RedmatSpanningIndices(t);
      for i in s do
        for j in t do
          m:=List(one,ShallowCopy);
          m[Length(sofar)+j][i]:=One(field);
          Add(gens,m);
        od;
      od;
    fi;

    sofar:=canonicalform(List(sub,ShallowCopy));
    if Length(sofar)<n then
      # move spaces to images in factor
      new:=[];
      for i in spaces do
        a:=canonicalform(Concatenation(sofar,i));
        if not a in new then
          Add(new,a);
        fi;
      od;
      spaces:=new;
      new:=[];
      for i in sporb do
        a:=List(i,x->canonicalform(Concatenation(sofar,x)));
        a:=Set(a);
        if not ForAny(new,x->x=a) then
          Add(new,a);
        fi;
      od;
      sporb:=new;
      #Print(Collected(List(spaces,Length)),"\n");
    fi;

  od;

  gens:=Filtered(gens,x->not IsOne(x));
  spl:=gens;

  gens:=List(gens,x->x^sub);
  a:=Group(gens,one);
  SetSize(a,sz);

  # are there diagonals we did not deal with, also original spaces?
  Append(notyet,ospaces);
  SortBy(notyet,Length);
  for i in notyet do
    a:=Stabilizer(a,canonicalform(i),OnSubspacesByCanonicalBasis);
    Add(allstab,canonicalform(i));
  od;

  done:=a;

  if Length(osporb)>0 then
    # we only stabilized one pair so far
    for i in osporb do
      # assumption: orbit is not too long... (i.e. TODO: improve)
      m:=Orbit(a,i[1],OnSubspacesByCanonicalBasis);
      for yet in i do
        if not yet in m then
          m:=Union(m,Orbit(a,yet,OnSubspacesByCanonicalBasis));
        fi;
      od;
      if Length(m)>Length(i) then
        yet:=ActionHomomorphism(a,m,OnSubspacesByCanonicalBasis,"surjective");
        sub:=Stabilizer(Image(yet),Set(i,x->Position(m,x)),OnSets);
        a:=PreImage(yet,sub);
      fi;
    od;
  fi;

  # test for correctness. This is not an assertion for two reasons:
  # - Assertions also turn on heavy checks for homomophisms that can slow
  # the whole calculation down beyond reasonable
  # - This is a hard test which would slow testing down, implying that the
  # tests would be thrown out of the standard test suite.
  if ValueOption("TestSpaces")=true and
   Size(field)^n<=10^5 then
   # test
   Print("Test\n");
   b:=GL(n,field);
   # fixing spaces is projective
   yet:=NormedRowVectors(field^n);
   act:=ActionHomomorphism(b,yet,OnLines,"surjective");
   b:=Image(act,b);
   spaces:=ShallowCopy(ospaces);
   SortBy(spaces,Length);
   for i in spaces do
      i:=Set(NormedRowVectors(VectorSpace(field,i)),x->Position(yet,x));
      b:=Stabilizer(b,i,OnSets);
      Print("Stab ",Size(b),"\n");
    od;
    for i in osporb do
      i:=List(i,x->Set(NormedRowVectors(VectorSpace(field,x)),x->Position(yet,x)));
      b:=Stabilizer(b,Union(i),OnSets);
      b:=Stabilizer(b,Set(i),OnSetsSets);
    od;

    b:=PreImage(act,b);
    if b<>a then Error("WRONG");fi;
    Print("Test succeeded\n");
  fi;


  return a;
end);

BindGlobal( "PcgsCharacteristicTails", function(G,aut)
local gens,ser,new,pcgs,f,mo,i,j,k,s;
  gens:=GeneratorsOfGroup(aut);
  ser:=InvariantElementaryAbelianSeries(G,gens);
  new:=[G];
  for i in [2..Length(ser)] do
    pcgs:=ModuloPcgs(ser[i-1],ser[i]);
    f:=GF(RelativeOrders(pcgs)[1]);
    mo:=List(gens,x->List(pcgs,y->ExponentsOfPcElement(pcgs,y^x))*One(f));
    mo:=GModuleByMats(mo,f);
    for j in
      Reversed(Filtered(MTX.BasesCompositionSeries(mo),
        x->Length(x)<Length(pcgs))) do
      s:=ser[i];
      for k in j do
        s:=ClosureSubgroupNC(s,PcElementByExponents(pcgs,List(k,Int)));
      od;
      Add(new,s);
    od;
  od;
  # build pcgs
  ser:=[];
  for i in [2..Length(new)] do
    pcgs:=ModuloPcgs(new[i-1],new[i]);
    Append(ser,pcgs);
  od;
  pcgs:=PcgsByPcSequence(FamilyObj(One(G)),ser);
  return pcgs;
end );

InstallGlobalFunction(AutomorphismGroupSolvableGroup,function( G )
    local spec, weights, first, m, pcgsU, F, pcgsF, A, i, s, n, p, H,
          pcgsH, pcgsN, N, epi, mats, M, autos, ocr, elms, e, list, imgs,
          auto, tmp, hom, gens, P, C, B, D, pcsA, rels, iso, xset,
          gensA, new,as,somechar,scharorb,asAutom,actbase,
          quotimg,eN,field,spaces,sporb,npcgs,nM;

    asAutom:=function(sub,hom) return Image(hom,sub);end;

    # image of subgroup in quotient by pcgs
    quotimg:=function(F,pcgs,U)
      return SubgroupNC(F,List(GeneratorsOfGroup(U),
        x->PcElementByExponents(pcgs,ExponentsOfPcElement(spec,x){[1..Length(pcgs)]})));
    end;

    actbase:=ValueOption("autactbase");
    PushOptions(rec(actbase:=fail)); # remove this option from concern
    somechar:=ValueOption("someCharacteristics");
    if somechar<>fail then
      scharorb:=somechar.orbits;
      somechar:=somechar.subgroups;
    else
      scharorb:=fail;
    fi;
    # get LG series
    spec    := SpecialPcgs(G);
    weights := LGWeights( spec );
    first   := LGFirst( spec );
    m       := Length( spec );

    # set up with GL
    Info( InfoAutGrp, 2, "set up computation for grp with weights ",
                          weights);
    pcgsU := InducedPcgsByPcSequenceNC( spec, spec{[first[2]..m]} );
    pcgsF := spec mod pcgsU;
    F     := PcGroupWithPcgs( pcgsF );
    M     := rec( field := GF( weights[1][3] ),
                  dimension := first[2]-1,
                  generators := [] );

    spaces:=[];
    sporb:=[];

    if somechar<>fail then
      field:=M.field;
      B:=IdentityMat(M.dimension,field);
      C:=List(somechar,x->quotimg(F,FamilyPcgs(F),x));
      C:=List(C,x->List(SmallGeneratingSet(x),
          x->ExponentsOfPcElement(FamilyPcgs(F),x)*One(field)));
      C:=Filtered(C,x->Length(x)>0);
      C:=List(C,x->Filtered(OnSubspacesByCanonicalBasis(x,One(B)),
              y->not IsZero(y)));
      C:=Unique(C);
      Append(spaces,C);
      if scharorb<>fail then
        C:=List(scharorb,x->List(x,x->quotimg(F,FamilyPcgs(F),x)));
        C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])<Size(F));
        C:=List(C,Set);
        D:=Unique(C);
        for C in D do
          C:=List(C,x->List(SmallGeneratingSet(x),
              x->ExponentsOfPcElement(FamilyPcgs(F),x)*One(field)));
          C:=List(C,x->OnSubspacesByCanonicalBasis(x,One(B)));
          if Length(C)=1 and
            not ForAny(spaces,x->Length(x)=Length(C[1]) and
              RankMat(Concatenation(x,C[1]))=Length(C[1])) then
            Add(spaces,C[1]);
          else
            Add(sporb,C);
          fi;
        od;
      fi;
    fi;

    # fix the spaces first
    B:=SpaceAndOrbitStabilizer(M.dimension,M.field,spaces,sporb);
    B := NormalizingReducedGL( spec, 1, first[2], M, B );

    Assert(2,
      ForAll(spaces,x->Length(Orbit(B,x,OnSubspacesByCanonicalBasis))=1));
    Assert(2,
      ForAll(sporb,x->Length(Orbit(B,x[1],OnSubspacesByCanonicalBasis))<=Length(x)));

    A     := AutomorphismGroupElAbGroup( F, B );
    SetIsGroupOfAutomorphismsFiniteGroup(A,true);

    # for first step
    H:=F;
    pcgsH:=Pcgs(H);

    # run down series
    for i in [2..Length(first)-1] do

        if Length(GeneratorsOfGroup(A))>0 and not HasNiceMonomorphism(A) then
          if Source(A.1)<>H then
            Error("wrong source");
          fi;
          if actbase<>fail then
            e:=List(actbase,x->quotimg(H,pcgsH,x));
            IsGroupOfAutomorphismsFiniteGroup(A);
            NiceMonomorphism(A:autactbase:=e);
          fi;

        fi;
        # get factor
        s := first[i];
        n := first[i+1];
        p := weights[s][3];
        Info( InfoAutGrp, 2, "start ",i,"th layer, weight ",weights[s],
                             "^", n-s, ", aut.grp. size ",Size(A));

        # set up
        pcgsU := InducedPcgsByPcSequenceNC( spec, spec{[n..m]} );
        H     := PcGroupWithPcgs( spec mod pcgsU );
        pcgsH := Pcgs( H );
        ocr   := rec( group := H, generators := pcgsH );
        # we will modify the generators later!


        pcgsN := InducedPcgsByPcSequenceNC( pcgsH, pcgsH{[s..n-1]} );
        eN:=SubgroupNC(G,InducedPcgsByPcSequenceNC( spec, spec{[s..m]}));
        field:=GF(RelativeOrders(pcgsN)[1]);

        ocr.modulePcgs := pcgsN;
        ocr.generators:=ocr.generators mod NumeratorOfModuloPcgs(pcgsN);

        N     := SubgroupByPcgs( H, pcgsN );
        epi := GroupHomomorphismByImagesNC( H, F, AsList( pcgsH ),
               Concatenation( Pcgs(F), List( [s..n-1], x -> One(F) ) ) );
        SetKernelOfMultiplicativeGeneralMapping( epi, N );

        # get module
        mats := LinearOperationLayer( H, pcgsH{[1..s-1]}, pcgsN );
        M    := GModuleByMats( mats, GF( p ) );

        # compatible / inducible pairs
        Info( InfoAutGrp, 2,"compute reduced gl ");

        spaces:=[];
        sporb:=[];

        if somechar<>fail then
          field:=GF(RelativeOrders(pcgsN)[1]);
          B:=IdentityMat(M.dimension,field);
          e:=Product(RelativeOrders(pcgsN));
          C:=List(somechar,x->quotimg(H,pcgsH,Intersection(x,eN)));

          C:=List(C,x->List(SmallGeneratingSet(x),
              x->ExponentsOfPcElement(pcgsH,x){[s..n-1]}*One(field)));
          C:=Filtered(C,x->Length(x)>0);
          C:=List(C,x->Filtered(OnSubspacesByCanonicalBasis(x,One(B)),
                  y->not IsZero(y)));
          C:=Unique(C);
          Append(spaces,C);
          if scharorb<>fail then
            C:=List(scharorb,
              x->List(x,x->quotimg(H,pcgsH,Intersection(x,eN))));
            C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])<Size(F));
            D:=Unique(List(C,Set));
            for C in D do
              C:=List(C,x->List(SmallGeneratingSet(x),
                x->ExponentsOfPcElement(pcgsH,x){[s..n-1]}*One(field)));
              C:=List(C,x->OnSubspacesByCanonicalBasis(x,One(B)));
              if Length(C)=1 and
                not ForAny(spaces,x->Length(x)=Length(C[1]) and
                  RankMat(Concatenation(x,C[1]))=Length(C[1])) then
                Add(spaces,C[1]);
              else
                Add(sporb,C);
              fi;

            od;
          fi;
        fi;

        # fix the spaces first
        B:=SpaceAndOrbitStabilizer(M.dimension,M.field,spaces,sporb);

        B := NormalizingReducedGL( spec, s, n, M,B );
        # A and B will not be used later, so it is no problem to
        # replace them by other groups with fewer generators
        B:=SubgroupNC(B,SmallGeneratingSet(B));

        if weights[s][2] = 1 then
            #Info( InfoAutGrp, 2,"compute reduced gl ");
            #B := MormalizingReducedGL( spec, s, n, M );

            if HasPcgs(A)
             and Length(Pcgs(A))<Length(GeneratorsOfGroup(A)) then
              as:=Size(A);
              A:=Group(Pcgs(A),One(A));
              SetSize(A,as);
              SetIsGroupOfAutomorphismsFiniteGroup(A,true);
            fi;

            D := DirectProduct( A, B );

            Info( InfoAutGrp, 2,"compute compatible pairs in group of size ",
                                  Size(A), " x ",Size(B),", ",
                                  Length(GeneratorsOfGroup(D))," generators");

            if Size(D)>10^10 and Size(A)>4 then
              # translate to different pcgs to make tails A-invariant
              npcgs:=PcgsCharacteristicTails(F,A);
              C:=GroupWithGenerators(npcgs);
              SetPcgs(C,npcgs);
              Assert(1,Pcgs(C)=npcgs); # ensure no magic took place
              as:=GroupHomomorphismByImagesNC(F,Group(M.generators),
                    Pcgs(F),M.generators);
              nM:=rec(field:=M.field,dimension:=M.dimension,
                      generators:=List(npcgs,x->ImagesRepresentative(as,x)));
              C:=CompatiblePairs(C,nM,D);
            else
              C := CompatiblePairs( F, M, D );
            fi;
        else
            #Info( InfoAutGrp, 2,"compute reduced gl ");
            #B := MormalizingReducedGL( spec, s, n, M );

            if HasPcgs(A)
             and Length(Pcgs(A))<Length(GeneratorsOfGroup(A)) then
              as:=Size(A);
              A:=Group(Pcgs(A),One(A));
              SetIsGroupOfAutomorphismsFiniteGroup(A,true);
              SetSize(A,as);
            fi;

            D := DirectProduct( A, B );
            if weights[s][1] > 1 then
                Info( InfoAutGrp, 2,
                      "compute compatible pairs in group of size ",
                       Size(A), " x ",Size(B),", ",
                       Length(GeneratorsOfGroup(D))," generators");
                D := CompatiblePairs( F, M, D );
            fi;
            Info( InfoAutGrp,2, "compute inducible pairs in a group of size ",
                  Size( D ));
            C := InduciblePairs( D, epi, M );
        fi;
        Unbind(A);Unbind(B);Unbind(D);

        # lift
        Info( InfoAutGrp, 2, "lift back ");
        if Size( C ) = 1 then
            gens := [];
        elif CanEasilyComputePcgs( C ) then
            gens := Pcgs( C );
        else
            gens  := GeneratorsOfGroup( C );
        fi;
        autos := List( gens, x -> LiftInduciblePair( epi, x, M, weights[s] ) );

        # add H^1
        Info( InfoAutGrp, 2, "add derivations ");

        elms := BasisVectors( Basis( OCOneCocycles( ocr, false ) ) );
        for e in elms do
            list := ocr.cocycleToList( e );
            imgs := List( [1..s-1], x -> pcgsH[x] * list[x] );
            Append( imgs, pcgsH{[s..n-1]} );
            auto := GroupHomomorphismByImagesNC( H, H,
                        AsList( pcgsH ), imgs );

            SetIsBijective( auto, true );
            SetKernelOfMultiplicativeGeneralMapping(auto, TrivialSubgroup(H));

            Add( autos, auto );
        od;
        Info( InfoAutGrp, 2, Length(autos)," generating automorphisms");

        # set up for iteration
        F := ShallowCopy( H );
        A := GroupByGenerators( autos );
        SetIsGroupOfAutomorphismsFiniteGroup(A,true);
        SetSize( A, Size( C ) * p^Length(elms) );
        if Size(C) = 1 then
            rels := List( [1..Length(elms)], x-> p );
            TransferPcgsInfo( A, autos, rels );
        elif CanEasilyComputePcgs( C ) then
            rels := Concatenation( RelativeOrders(gens),
                                   List( [1..Length(elms)], x-> p ) );
            TransferPcgsInfo( A, autos, rels );
        fi;
        Unbind(C);
        Unbind(gens);

        # if possible reduce the number of generators of A
        if Size( F ) <= 1000 and not CanEasilyComputePcgs( A ) then
            Info( InfoAutGrp, 2, "nice the gen set of A ");
            xset := ExternalSet( A, AsList( F ) );
            hom  := ActionHomomorphism( xset, "surjective");
            P    := Image( hom );
            if IsSolvableGroup( P ) then
                pcsA := List( Pcgs(P), x -> PreImagesRepresentative( hom, x ));
                TransferPcgsInfo( A, pcsA, RelativeOrders( Pcgs(P) ) );
            else
                imgs := SmallGeneratingSet( P );
                gens := List( imgs, x -> PreImagesRepresentative( hom, x ) );
                tmp  := Size( A );
                A := GroupByGenerators( gens, One( A ) );
                SetSize( A, tmp );
            fi;
        fi;

      if somechar<>fail then
        B:=List(somechar,x->quotimg(H,pcgsH,x));
        B:=Unique(B);
        B:=Filtered(B,x->ForAny(GeneratorsOfGroup(A),y->x<>asAutom(x,y)));
        if Length(B)>0 then
          SortBy(B,Size);
          SetIsGroupOfAutomorphismsFiniteGroup(A,true);
          tmp:=Size(A);
          if actbase<>fail then
            e:=List(actbase,x->quotimg(H,pcgsH,x));
            IsGroupOfAutomorphismsFiniteGroup(A);
            NiceMonomorphism(A:autactbase:=e);
          fi;
          for e in B do
            A:=Stabilizer(A,e,asAutom);
          od;
          Info(InfoAutGrp,2,"given chars reduce by ",tmp/Size(A));
        fi;
      fi;

      # as yet disabled
      if false and scharorb<>fail then
        # these are subgroups for which certain orbits must be stabilized.
        B:=List(Reversed(scharorb),x->List(x,x->quotimg(H,pcgsH,x)));
        B:=Filtered(B,x->Size(x[1])>1 and Size(x[1])<Size(H));
        for e in B do
          tmp:=Orbits(A,e,asAutom);
          if Length(tmp)>Length(e) then
            Error("eng");
          fi;
        od;
      fi;

    od;

    # the last step
    gensA := GeneratorsOfGroup( A );
    # try to reduce the generator set
    if HasPcgs(A) and Length(Pcgs(A))<Length(gensA) then
      gensA:=Pcgs(A);
    fi;

    iso   := GroupHomomorphismByImagesNC( F, G, Pcgs(F), spec );
    autos := [];
    for auto in gensA do
        imgs := List( Pcgs(F), x -> Image( iso, Image( auto, x ) ) );
        new  := GroupHomomorphismByImagesNC( G, G, spec, imgs );
        SetIsBijective( new, true );
        SetKernelOfMultiplicativeGeneralMapping(new, TrivialSubgroup(F));
        Add( autos, new );
    od;
    B := GroupByGenerators( autos );
    SetIsGroupOfAutomorphismsFiniteGroup(B,true);
    SetSize( B, Size(A) );
    PopOptions(); # undo the added `fail'
    return B;
end);

#############################################################################
##
#F AutomorphismGroupFrattFreeGroup( G )
##
InstallGlobalFunction(AutomorphismGroupFrattFreeGroup,function( G )
    local F, K, gensF, gensK, gensG, A,
          iso, P, gensU, k, aut, U, hom, N, gensN,
          full, n, imgs, i, m, a, l, new, size,
          pr, p, S, pcgsS, T, ocr, elms, e, list, B;

    # create fitting subgroup
    if HasSocle( G ) and HasSocleComplement( G ) then
        F := Socle( G );
        K := SocleComplement( G );
    else
        F := FittingSubgroup( G );
        K := ComplementClassesRepresentatives( G, F )[1];
    fi;
    gensF := Pcgs( F );
    gensK := Pcgs( K );
    gensG := Concatenation( gensK, gensF );

    # create automorhisms
    Info( InfoAutGrp, 2, "get aut grp of socle ");
    A := AutomorphismGroupAbelianGroup( F );

    # go over to perm rep
    Info( InfoAutGrp, 2, "compute perm rep ");
    iso := IsomorphismPermGroup( A );
    P   := Image( iso );

    # compute subgroup
    Info( InfoAutGrp, 2, "compute subgroup ");
    gensU := [];
    for k in gensK do
        imgs := List( gensF, y -> y ^ k );
        aut := GroupHomomorphismByImagesNC( F, F, gensF, imgs );
        # CheckAuto( aut );
        Add( gensU, Image( iso, aut ) );
    od;
    U := SubgroupNC( P, gensU );
    hom := GroupHomomorphismByImagesNC( K, U, gensK, gensU );


    # get normalizer
    Info( InfoAutGrp, 2, "compute normalizer ");
    N := Normalizer( P, U );
    gensN := GeneratorsOfGroup( N );

    # create automorphisms of G
    Info( InfoAutGrp, 2, "compute preimages ");
    full  := [];
    for n in gensN do
        imgs := [];
        for i in [1..Length(gensK)] do
            m := gensU[i]^n;
            a := PreImagesRepresentative( hom, m );
            Add( imgs, a );
        od;
        l := PreImagesRepresentative( iso, n );
        Append( imgs, List( gensF, x -> Image( l, x ) ) );
        new := GroupHomomorphismByImagesNC( G, G, gensG, imgs );
        SetIsBijective( new, true );
        SetKernelOfMultiplicativeGeneralMapping(new, TrivialSubgroup(G));
        Add( full, new );
    od;
    size := Size(N);

    # add derivations
    Info( InfoAutGrp, 2, "add derivations ");
    pr  := PrimeDivisors( Size( F ) );
    for p in pr do

        # create subgroup
        S := SylowSubgroup( F, p );
        pcgsS := InducedPcgs( gensF, S );
        T := SubgroupNC( G, Concatenation( gensK, pcgsS ) );
        ocr := rec( group := T,
                    generators := gensK,
                    modulePcgs := pcgsS );

        # compute 1-cocycles
        elms := BasisVectors( Basis( OCOneCocycles( ocr, false ) ) );
        for e in elms do
            list := ocr.cocycleToList( e );
            imgs := List( [1..Length(gensK)], x -> gensK[x] * list[x] );
            Append( imgs, gensF );
            new := GroupHomomorphismByImagesNC( G, G, gensG, imgs );
            SetIsBijective( new, true );
            SetKernelOfMultiplicativeGeneralMapping(new, TrivialSubgroup(G));
            Add( full, new );
        od;
        size := size * ocr.char^Length(elms);
    od;

    # create automorphism group
    B := GroupByGenerators( full, IdentityMapping( G ) );
    SetIsGroupOfAutomorphismsFiniteGroup(B,true);
    SetSize( B, size );

    return B;
end);

# The following computes the automorphism group of
# a nilpotent group which is NOT a p-group. It computes
# the automorphism groups of each Sylow subgroup of G
# and then glues these together.
# For p-groups, either the standard GAP functionality, or
# that from the autpgrp package is used.
InstallGlobalFunction(AutomorphismGroupNilpotentGroup,function(G)
    local S, autS, gens, imgs, i, j, x, off, gensAutG, pcgsSi, autG;
    if IsAbelian(G) then
        return AutomorphismGroupAbelianGroup(G);
    fi;

    if not IsNilpotentGroup(G) or not IsFinite(G) then
        return fail;
    fi;

    if IsPGroup(G) then
        return fail;        # p-groups should be handled elsewhere
    fi;

    # Compute the Sylow subgroups of G; G is the direct product of
    # these, and Aut(G) is the direct product of the automorphism
    # groups of the Sylow subgroups.
    S := SylowSystem(G);

    # Compute the automorphism group of each of the p-groups
    autS := List(S, AutomorphismGroup);

    # Compute automorphism group for G from this
    gens := Concatenation(List(S, Pcgs));
    off := 0;
    gensAutG := [];
    for i in [1..Length(S)] do
        # Convert the automorphisms of S[i] into automorphisms of G.
        pcgsSi := Pcgs(S[i]);
        for x in GeneratorsOfGroup(autS[i]) do
            imgs := ShallowCopy( gens );
            for j in [1..Length(pcgsSi)] do
                imgs[off + j] := Image(x, pcgsSi[j]);
            od;
            Add(gensAutG, GroupHomomorphismByImages(G, G, gens, imgs));
        od;
        off := off + Length(pcgsSi);
    od;

    # Now construct autG as "inner" direct product of all the autS
    autG := Group( gensAutG, IdentityMapping(G) );
    SetIsAutomorphismGroup(autG, true);
    SetIsGroupOfAutomorphismsFiniteGroup(autG, true);

    return autG;
end );

[ Dauer der Verarbeitung: 0.41 Sekunden  (vorverarbeitet)  ]