#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Bettina Eick, Alexander Hulpke.
##
##  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
##
##  This file contains the methods for computing presentations for
##  (permutation) groups.
##

#############################################################################
##
#M  IsomorphismFpGroup( G )
##
InstallOtherMethod( IsomorphismFpGroup, "supply name", true, [IsGroup], 0,
function( G )
  return IsomorphismFpGroup( G, "F" );
end );

InstallGlobalFunction( IsomorphismFpGroupByGenerators,function(arg)
local G,gens,nam;
  G:=arg[1];
  gens:=arg[2];
  if Length(arg)>2 then
    nam:=arg[3];
  else
    nam:="F";
  fi;
  if not ForAll(gens,i->i in G) or Index(G,SubgroupNC(G,gens))>1 then
    Error("<gens> must be a generating set for G");
  fi;
  return IsomorphismFpGroupByGeneratorsNC(G,gens,nam);
end);

InstallOtherMethod(IsomorphismFpGroupByGeneratorsNC,"supply name",
  IsIdenticalObj,[IsGroup,IsList],0,
function(G,gens)
  return IsomorphismFpGroupByGeneratorsNC(G,gens,"F");
end);
  
InstallOtherMethod( IsomorphismFpGroupByCompositionSeries,
                    "supply name", true, [IsGroup], 0,
function( G )
  return IsomorphismFpGroupByCompositionSeries( G, "F" );
end );

InstallOtherMethod( IsomorphismFpGroupByChiefSeries,
                    "supply name", true, [IsGroup], 0,
function( G )
  return IsomorphismFpGroupByChiefSeries( G, "F" );
end );

InstallOtherMethod(IsomorphismFpGroup,"for perm groups",true,
  [IsPermGroup,IsString],0,
function( G,nam )
  # test frequent, special cases
  if (not HasIsSymmetricGroup(G) and IsSymmetricGroup(G)) or
     (not HasIsAlternatingGroup(G) and IsAlternatingGroup(G)) then
    return IsomorphismFpGroup(G,nam);
  fi;

  return IsomorphismFpGroupByChiefSeries( G, nam );
end );

InstallOtherMethod( IsomorphismFpGroup,"for simple solvable permutation groups",
  true,
  [IsPermGroup and IsSimpleGroup and IsSolvableGroup,IsString],0,
function(G,str)
  return IsomorphismFpGroupByPcgs( Pcgs(G), str );
end);

InstallOtherMethod( IsomorphismFpGroup,"for nonabelian simple permutation groups",
  true, [IsPermGroup and IsNonabelianSimpleGroup,IsString],0,
function(G,str)
local l,iso,fp,stbc,gens;
  # use the perfect groups library (as far as hand-created)
  PerfGrpLoad(Size(G));
  if Size(G)<10^6 and IsRecord(PERFRec) and
     ValueOption(NO_PRECOMPUTED_DATA_OPTION)<>true and
     not Size(G) in PERFRec.notKnown then
    Info(InfoPerformance,2,"Using Perfect Groups Library");
    # loop over the groups
    for l in List([1..NrPerfectGroups(Size(G))],
                  i->PerfectGroup(IsPermGroup,Size(G),i)) do
      iso:=IsomorphismGroups(G,l);
      if iso<>fail then
	fp:=IsomorphismFpGroup(l);
        iso:=GroupHomomorphismByImagesNC(G,Range(fp),
	       List(MappingGeneratorsImages(fp)[1],
	            i->PreImagesRepresentative(iso,i)),
	       MappingGeneratorsImages(fp)[2]);
	SetIsBijective(iso,true);
        return iso;
      fi;
    od;
  fi;

  stbc:=StabChainMutable(G);
  gens:=StrongGeneratorsStabChain(stbc);
  iso:=IsomorphismFpGroupByGeneratorsNC( G, gens, str:chunk );
  ProcessEpimorphismToNewFpGroup(iso);
  return iso;
end);

#############################################################################
##
#M  IsomorphismFpGroupByCompositionSeries( G, str )
##
InstallOtherMethod( IsomorphismFpGroupByCompositionSeries,
               "for permutation groups", true,
               [IsPermGroup, IsString], 0,
function( G, str )
    local l, H, gensH, iso, F, gensF, imgsF, relatorsF, free, n, k, N, M,
          hom, preiH, c, new, T, gensT, E, gensE, imgsE, relatorsE, rel,
          w, t, i, j, series;

    if IsSolvableGroup( G ) then
        return IsomorphismFpGroupByPcgs( Pcgs(G), str );
    fi;

    # compute composition series
    series := CompositionSeries( G );
    l      := Length( series );

    # set up
    H := series[l-1];
    # if IsPrime( Size( H ) ) then
    #     gensH := Filtered( GeneratorsOfGroup( H ),
    #                        x -> Order(x)=Size(H) ){[1]};
    # else
    #     gensH := Set( GeneratorsOfGroup( H ) );
    #     gensH := Filtered( gensH, x -> x <> One(H) );
    # fi;

    IsNonabelianSimpleGroup(H); #ensure H knows to be simple, thus the call to
    # `IsomorphismFpGroup' will not yield an infinite recursion.
    IsNaturalAlternatingGroup(H); # We have quite often a factor A_n for
    # which GAP knows better presentations. Thus this test is worth doing.
    iso := IsomorphismFpGroup( H,str );

    F := FreeGroupOfFpGroup( Image( iso ) );
    gensF := GeneratorsOfGroup( F );
    imgsF := MappingGeneratorsImages(iso)[1];
    relatorsF := RelatorsOfFpGroup( Image( iso ) );
    free := GroupHomomorphismByImagesNC( F, series[l-1], gensF, imgsF );
    n := Length( gensF );

    # loop over series upwards
    for k in Reversed( [1..l-2] ) do

        # get composition factor
        N := series[k];
        M := series[k+1];
	# do not call `InParent'-- rather safe than sorry.
        hom := NaturalHomomorphismByNormalSubgroupNC(N, M );
        H := Image( hom );
        # if IsPrime( Size( H ) ) then
        #     gensH := Filtered( GeneratorsOfGroup( H ),
        #                        x -> Order(x)=Size(H) ){[1]};
        # else
        #     gensH := Set( GeneratorsOfGroup( H ) );
        #     gensH := Filtered( gensH, x -> x <> One(H) );
        # fi;

	# compute presentation of H
	IsNonabelianSimpleGroup(H);
	IsNaturalAlternatingGroup(H);
	new:=IsomorphismFpGroup(H,"@");
	gensH:=List(GeneratorsOfGroup(Image(new)),
	              i->PreImagesRepresentative(new,i));
        preiH := List( gensH, x -> PreImagesRepresentative( hom, x ) );

        c     := Length( gensH );

        T   := Image( new );
        gensT := GeneratorsOfGroup( FreeGroupOfFpGroup( T ) );

        # create new free group
        E     := FreeGroup( n+c, str );
        gensE := GeneratorsOfGroup( E );
        imgsE := Concatenation( preiH, imgsF );
        relatorsE := [];

        # modify presentation of H
        for rel in RelatorsOfFpGroup( T ) do
            w := MappedWord( rel, gensT, gensE{[1..c]} );
            t := MappedWord( rel, gensT, imgsE{[1..c]} );
            if not t = One( G ) then
                t := PreImagesRepresentative( free, t );
                t := MappedWord( t, gensF, gensE{[c+1..n+c]} );
            else
                t := One( E );
            fi;
            Add( relatorsE, w/t );
        od;

        # add operation of T on F
        for i in [1..c] do
            for j in [1..n] do
                w := Comm( gensE[c+j], gensE[i] );
                t := Comm( imgsE[c+j], imgsE[i] );
                if not t = One( G ) then
                    t := PreImagesRepresentative( free, t );
                    t := MappedWord( t, gensF, gensE{[c+1..n+c]} );
                else
                    t := One( E );
                fi;
                Add( relatorsE, w/t );
            od;
        od;

        # append relators of F
        for rel in relatorsF do
            w := MappedWord( rel, gensF, gensE{[c+1..c+n]} );
            Add( relatorsE, w );
        od;

        # iterate
        F := E;
        gensF := gensE;
        imgsF := imgsE;
        relatorsF := relatorsE;
        free :=  GroupHomomorphismByImagesNC( F, N, gensF, imgsF );
        n := n + c;
    od;

    # set up
    F := F / relatorsF;
    gensF := GeneratorsOfGroup( F );
    if HasSize(G) then
      SetSize(F,Size(G));
    fi;
    iso := GroupHomomorphismByImagesNC( G, F, imgsF, gensF );
    SetIsBijective( iso, true );
    SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup( G ) );
    ProcessEpimorphismToNewFpGroup(iso);
    return iso;
end );

#############################################################################
##
#M  IsomorphismFpGroupByChiefSeriesFactor( G, str, N )
##
InstallGlobalFunction(IsomorphismFpGroupByChiefSeriesFactor,
function(g,str,N)
  local ser, ab, homs, gens, idx, start, pcgs, hom, f, fgens, auts, sf, orb,
  tra, j, a, ad, lad, n, fg, free, rels, fp, vals, dec, still, lgens, ngens,
  nrels, nvals, p, dodecomp, decomp, hogens, di, i, k, l,
  m,abelianlimit,locallim,abpow,needgens,fampcgs,rad;

  abelianlimit:=ValueOption("abelianlimit");
  if abelianlimit=fail then
    abelianlimit:=infinity;
  fi;

  if Size(g)=1 then
    # often occurs in induction base
    return
    GroupHomomorphismByFunction(g,TRIVIAL_FP_GROUP,x->One(TRIVIAL_FP_GROUP),x->One(g):noassert);
  elif g=N then
    # often occurs in induction base
    return GroupHomomorphismByImagesNC(g,TRIVIAL_FP_GROUP,GeneratorsOfGroup(g),
             List(GeneratorsOfGroup(g),x->One(TRIVIAL_FP_GROUP)):noassert);
  fi;

  if ValueOption("rewrite")=true then
    # try to go through radical (image) and pick generators split in radical factor
    rad:=ClosureGroup(SolvableRadical(g),N);
    ser:=[];
    gens:=[];
    if Size(rad)<Size(g) then
      hom:=NaturalHomomorphismByNormalSubgroupNC(g,rad);
      f:=Image(hom);
      ser:=ShallowCopy(DirectFactorsFittingFreeSocle(f));
      gens:=Concatenation(List(ser,SmallGeneratingSet));
      j:=SubgroupNC(f,gens);
      for i in GeneratorsOfGroup(f) do
        if not i in j then
          Add(gens,i);
          j:=ClosureSubgroupNC(j,i);
        fi;
      od;
      # build series
      for i in [Length(ser)-1,Length(ser)-2..1] do
        ser[i]:=ClosureGroup(ser[i+1],ser[i]);
      od;
      if Size(ser[1])<Size(f) then
        ser:=ChiefSeriesThrough(f,ser);
      fi;
      if f<>g then
        gens:=List(gens,x->PreImagesRepresentative(hom,x));
        ser:=List(ser,x->PreImage(hom,x));
      fi;
      # change generators to make split
      ser:=List(ser,x->ClosureGroup(rad,Filtered(gens,y->y in x)));
    else
      rad:=g;
    fi;
    if Length(ser)=0 or Size(ser[Length(ser)])>Size(rad) then Add(ser,rad);fi;

    if Size(rad)>1 then
      if HasChiefSeries(g) and N in ChiefSeries(g) and rad in ChiefSeries(g) then
        f:=Filtered(ChiefSeries(g),x->IsSubset(rad,x));
      elif IsTrivial(N) then
        if rad=g then
          f:=ChiefSeries(g);
        else
          f:=ChiefSeriesUnderAction(g,rad);
        fi;
      else
        f:=ChiefSeriesThrough(g,[rad,N]);
      fi;
      Append(ser,Filtered(f,x->Size(x)<Size(rad)));
    fi;
  elif IsTrivial(N) then
    ser:=ChiefSeries(g);
  else
    if HasChiefSeries(g) and N in ChiefSeries(g) then
      ser:=ChiefSeries(g);
    else
      ser:=ChiefSeriesThrough(g,[N]);
    fi;
  fi;

  if Size(N)>1 then
    ser:=Filtered(ser,i->IsSubset(i,N));
  fi;

  if IsSolvableGroup(g) then
    fampcgs:=SpecialPcgs(g);
  else
    fampcgs:=fail;
  fi;
  ab:=[];
  homs:=[];
  gens:=[];
  idx:=[];
  abpow:=[]; # store powers for large order abelian
  for i in [2..Length(ser)] do
    start:=Length(gens)+1;
    if HasAbelianFactorGroup(ser[i-1],ser[i]) then
      ab[i-1]:=true;
      if fampcgs<>fail then
        pcgs:=CanonicalPcgs(InducedPcgs(fampcgs,ser[i-1])) mod
        CanonicalPcgs(InducedPcgs(fampcgs,ser[i]));
      else
        pcgs:=ModuloPcgs(ser[i-1],ser[i]);
      fi;
      homs[i-1]:=pcgs;
      Append(gens,pcgs);
      f:=pcgs;
      j:=RelativeOrders(pcgs)[1];
      abpow[i-1]:=[];
      if abelianlimit<>infinity then
        # split up evenly
        k:=LogInt(j-1,abelianlimit)+1; # ensure rounded up
        locallim:=RootInt(j-1,k)+1; # ensure rounded up

        while j>locallim do
          k:=Minimum(locallim,RootInt(j,2));
          Add(abpow[i-1],k);
          f:=List(f,x->x^k);
          Append(gens,f);
          j:=QuoInt(j,k);
        od;
      fi;

    else
      ab[i-1]:=false;
      hom:=NaturalHomomorphismByNormalSubgroup(ser[i-1],ser[i]:noassert);
      IsOne(hom);
      f:=Image(hom);
      # knowing simplicity makes it easy to test whether a map is faithful
      if IsNonabelianSimpleGroup(f) then
        if DataAboutSimpleGroup(f).idSimple.series="A" and
          not IsNaturalAlternatingGroup(f) then
          # force natural alternating 
          hom:=hom*IsomorphismGroups(f,
            AlternatingGroup(DataAboutSimpleGroup(f).idSimple.parameter));
	elif IsPermGroup(f) and
	  NrMovedPoints(f)>SufficientlySmallDegreeSimpleGroupOrder(Size(f)) then
	  hom:=hom*SmallerDegreePermutationRepresentation(f:cheap);
	fi;
      elif IsPermGroup(f) then
	hom:=hom*SmallerDegreePermutationRepresentation(f:cheap);
      fi;

      # the range is elementary. Use this for the fp group isomorphism
      f:=Range(hom);
      # calculate automorphisms of f induced by G
      fgens:=GeneratorsOfGroup(f);
      auts:=List(GeneratorsOfGroup(g),i->
	     GroupHomomorphismByImagesNC(f,f,fgens,
	       List(fgens,j->Image(hom,PreImagesRepresentative(hom,j)^i)):noassert));
      for j in auts do
	SetIsBijective(j,true);
      od;
      # get the minimal normal subgroups, together with isomorphisms
      sf:=CompositionSeries(f); 
      sf:=sf[Length(sf)-1];
      orb:=[sf];
      tra:=[IdentityMapping(f)];
      j:=1;
      while j<=Length(orb) do
	for k in auts do
	  a:=Image(k,orb[j]);
	  if not a in orb then
	    Add(orb,a);
	    Add(tra,tra[j]*k);
	  fi;
	od;
	j:=j+1;
      od;

      # we know sf is simple
      SetIsNonabelianSimpleGroup(sf,true);
      IsNaturalAlternatingGroup(sf);
      if ValueOption("rewrite")=true then
        a:=IsomorphismFpGroupForRewriting(sf:noassert);
      else
        a:=IsomorphismFpGroup(sf:noassert);
      fi;
      ad:=List(GeneratorsOfGroup(Range(a)),i->PreImagesRepresentative(a,i));
      lad:=Length(ad);

      n:=Length(orb);
      if n=1 and ValueOption("rewrite")=true then
        fgens:=ad;
      else
        if ValueOption("rewrite")=true then
          Info(InfoPerformance,1,
          "Rewriting system preservation for direct product not yet written");
        fi;
        fg:=FreeGroup(Length(ad)*n,"@");
        free:=GeneratorsOfGroup(fg);
        rels:=[];
        fgens:=[];
        for j in [1..n] do
          Append(fgens,List(ad,x->Image(tra[j],x)));
          # translate relators
          for k in RelatorsOfFpGroup(Range(a)) do
            Add(rels,MappedWord(k,FreeGeneratorsOfFpGroup(Range(a)),
                                  free{[(j-1)*lad+1..j*lad]}));
          od;
          # commutators with older gens
          for k in [j+1..n] do
            for l in [1..Length(ad)] do
              for m in [1..Length(ad)] do
                Add(rels,Comm(free[(k-1)*lad+l],free[(j-1)*lad+m]));
              od;
            od;
          od;
        od;

        fp:=fg/rels;
        a:=GroupHomomorphismByImagesNC(f,fp,fgens,GeneratorsOfGroup(fp):noassert);
      fi;
      Append(gens,List(fgens,i->PreImagesRepresentative(hom,i)));

      # here we really want a composed homomorphism, to avoid extra work for 
      # a new stabilizer chain
      if not IsOne(hom) then
	hom:=CompositionMapping2General(a,hom);
      else
	hom:=a;
      fi;
      homs[i-1]:=hom;
    fi;
    Add(idx,[start..Length(gens)]);
  od;

  f:=FreeGroup(Length(gens),str);
  free:=GeneratorsOfGroup(f);
  rels:=[];
  vals:=[];

  dec:=[];
  for i in [2..Length(ser)] do
    still:=i<Length(ser);
    lgens:=gens{idx[i-1]};
    ngens:=free{idx[i-1]}; # new generators on this level
    nrels:=[];
    nvals:=[];
    if ab[i-1] then
      pcgs:=homs[i-1];
      needgens:=Length(pcgs);
      p:=RelativeOrders(pcgs)[1];
      # define function in function to preserve local variables
      dodecomp:=function(ngens,pcgs,abpow)
                local l;
                  l:=Length(pcgs);
                  return function(elm)
                  local e,i,j,q;
                    e:=ShallowCopy(ExponentsOfPcElement(pcgs,elm));
                    for i in [1..Length(abpow)] do
                      for j in [1..l] do
                        # reduce entry so far
                        q:=QuotientRemainder(e[l*(i-1)+j],abpow[i]);
                        e[l*(i-1)+j]:=q[2];
                        e[l*i+j]:=q[1];
                      od;
                    od;

                    return LinearCombinationPcgs(ngens,e);
                  end;
		end;
      decomp:=dodecomp(ngens,pcgs,abpow[i-1]);
      for j in [1..Length(pcgs)] do
	Add(nrels,ngens[j]^p);
	if still then
	  Add(nvals,pcgs[j]^p);
	fi;
        for k in [1..j-1] do
	  Add(nrels,Comm(ngens[j],ngens[k]));
	  if still then
	    Add(nvals,Comm(pcgs[j],pcgs[k]));
	  fi;
	od;
      od;

      # generator power relations
      if Length(abpow[i-1])>0 then
        for k in [1..Length(abpow[i-1])] do
          for j in [1..Length(pcgs)] do
            Add(nrels,ngens[Length(pcgs)*(k-1)+j]^abpow[i-1][k]
              /ngens[Length(pcgs)*k+j]);
            if still then
              Add(nvals,One(pcgs[1])); # new generator is just shorthand for
              # power, so no tail to consider
            fi;
          od;
        od;
        
      fi;

    else
      hom:=homs[i-1];
      hogens:=FreeGeneratorsOfFpGroup(Range(hom));
      needgens:=Length(hogens);
      dodecomp:=function(ngens,hogens,hom)
		  return elm->
		          MappedWord(UnderlyingElement(Image(hom,elm)),
		             hogens,ngens);
		end;
      decomp:=dodecomp(ngens,hogens,hom);
      for j in RelatorsOfFpGroup(Range(hom)) do
        a:=MappedWord(j,hogens,ngens);
        Add(nrels,a);
	if still then
	  Add(nvals,MappedWord(j,hogens,lgens));
	fi;
      od;
    fi;
    Add(dec,decomp);
    # change relators by cofactors
    for j in [1..Length(rels)] do
      a:=decomp(vals[j]);
      rels[j]:=rels[j]/a;
      if still then
	vals[j]:=vals[j]/MappedWord(a,ngens,lgens);
      fi;
    od;
    # action relators
    for j in [1..idx[i-1][1]-1] do
      for k in [1..needgens] do
        a:=lgens[k]^gens[j];
	ad:=decomp(a);
	Add(rels,ngens[k]^free[j]/ad);
	if still then
	  Add(vals,a/MappedWord(ad,ngens,lgens));
	fi;
      od;
    od;
    # new level relators
    Append(rels,nrels);
    Append(vals,nvals);
  od;
  Assert(1,ForAll(rels,i->MappedWord(i,GeneratorsOfGroup(f),gens) in N));

  fp:=f/rels;
  di:=rec(gens:=gens,fp:=fp,idx:=idx,dec:=dec,source:=g,homs:=homs,
     abpow:=abpow);
  if IsTrivial(N) then
    hom:=GroupHomomorphismByImagesNC(g,fp,gens,GeneratorsOfGroup(fp):noassert);
    SetIsBijective(hom,true);
  else
    hom:=GroupHomomorphismByImagesNC(g,fp,
	  Concatenation(gens,GeneratorsOfGroup(N)),
	  Concatenation(GeneratorsOfGroup(fp),
	    List(GeneratorsOfGroup(N),i->One(fp))):noassert);
    SetIsSurjective(hom,true);
    SetKernelOfMultiplicativeGeneralMapping(hom,N);
  fi;

  hom!.decompinfo:=MakeImmutable(di);
  SetIsWordDecompHomomorphism(hom,true);
  ProcessEpimorphismToNewFpGroup(hom);
  return hom;
end);

#############################################################################
##
#M  IsomorphismFpGroupByChiefSeries( G, str )
##
InstallMethod( IsomorphismFpGroupByChiefSeries,"permgrp",true,
               [IsPermGroup,IsString], 0,
function(g,str)
  return IsomorphismFpGroupByChiefSeriesFactor(g,str,TrivialSubgroup(g));
end);

InstallMethod( IsomorphismFpGroupByChiefSeries,"pc grp",true,
               [IsPcGroup,IsString], 0,
function(g,str)
  return IsomorphismFpGroupByChiefSeriesFactor(g,str,TrivialSubgroup(g));
end);

BindGlobal("DecompElmHomChiefSer",function(di,elm)
local f, w, a, i;
  f:=FreeGroupOfFpGroup(di.fp);
  w:=One(f);
  for i in di.dec do
    a:=i(elm);
    w:=a*w;
    elm:=elm/MappedWord(a,GeneratorsOfGroup(f),di.gens);
  od;
  return ElementOfFpGroup(ElementsFamily(FamilyObj(di.fp)),w);
end);

InstallMethod(ImagesRepresentative,"word decomp hom",FamSourceEqFamElm,
  [IsGroupGeneralMappingByImages and IsWordDecompHomomorphism,
  IsMultiplicativeElementWithInverse],0,
function(hom,elm)
  return DecompElmHomChiefSer(hom!.decompinfo,elm);
end);

InstallGlobalFunction(LiftFactorFpHom,
function(hom,G,M,N,mnsf)
local fpq, qgens, qreps, fpqg, rels, pcgs, p, f, qimg, idx, nimg, decomp,
      ngen, fp, hom2, di, source, dih, dec, i, j;
  fpq:=Range(hom);
  qgens:=GeneratorsOfGroup(fpq);
  qreps:=List(qgens,i->PreImagesRepresentative(hom,i));
  fpqg:=FreeGeneratorsOfFpGroup(fpq);
  rels:=[];
  if IsModuloPcgs(mnsf) then
    pcgs:=mnsf;
    p:=RelativeOrders(pcgs)[1];
    f:=FreeGroup(Length(fpqg)+Length(pcgs));
    qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]};
    idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)];
    nimg:=GeneratorsOfGroup(f){idx};
    decomp:=function(elm)
      return LinearCombinationPcgs(nimg,ExponentsOfPcElement(pcgs,elm));
    end;
    # n-relators
    for i in [1..Length(pcgs)] do
      Add(rels,nimg[i]^p);
      for j in [1..i-1] do
	Add(rels,Comm(nimg[i],nimg[j]));
      od;
    od;

  elif IsRecord(mnsf) then
    # mnsf is record with components:
    # pcgs: generator list for pcgs
    # p: prime
    # decomp: Exponents for element of pcgs
    pcgs:=mnsf.pcgs;
    p:=mnsf.prime;
    f:=FreeGroup(Length(fpqg)+Length(pcgs));
    qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]};
    idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)];
    nimg:=GeneratorsOfGroup(f){idx};
    decomp:=function(elm)
     local coeff;
      coeff:=mnsf.decomp(elm);
      if LinearCombinationPcgs(pcgs,coeff)<>elm then
	Error("decomperror");
      fi;
      return LinearCombinationPcgs(nimg,mnsf.decomp(elm));
    end;
    # n-relators
    for i in [1..Length(pcgs)] do
      Add(rels,nimg[i]^p);
      for j in [1..i-1] do
	Add(rels,Comm(nimg[i],nimg[j]));
      od;
    od;

  else
    # nonabelian
    p:=Range(mnsf);
    ngen:=FreeGeneratorsOfFpGroup(p);
    # This is not really a pcgs, but treated as layer generators the same
    # way, thus use the same variable name
    pcgs:=List(GeneratorsOfGroup(p),i->PreImagesRepresentative(mnsf,i));
    f:=FreeGroup(Length(fpqg)+Length(pcgs));
    qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]};
    idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)];
    nimg:=GeneratorsOfGroup(f){idx};

    decomp:=function(elm)
      return MappedWord(UnderlyingElement(Image(mnsf,elm)),ngen,nimg);
    end;

    for i in RelatorsOfFpGroup(p) do
      Add(rels,MappedWord(i,ngen,nimg));
    od;

  fi;

  # action on n
  for i in [1..Length(pcgs)] do
    for j in [1..Length(qgens)] do
      Add(rels,nimg[i]^qimg[j]/
	  decomp(pcgs[i]^qreps[j]));
    od;
  od;

  # lift old relators with cofactors
  for i in RelatorsOfFpGroup(fpq) do
    Add(rels,MappedWord(i,fpqg,qimg)/decomp(MappedWord(i,fpqg,qreps)));
  od;
  fp:=f/rels;
  if HasGeneratorsOfGroup(N) then 
    di:=GeneratorsOfGroup(N);
  else
    di:=[];
  fi;
  hom2:=GroupHomomorphismByImagesNC(G,fp,
	 Concatenation(Concatenation(qreps,pcgs),di),
	 Concatenation(GeneratorsOfGroup(fp),
	 List(di,x->One(fp))):noassert);

  # build decompositioninfo
  di:=rec(gens:=Concatenation(qreps,pcgs),fp:=fp,source:=G);
  if IsBound(hom!.decompinfo) then
    dih:=hom!.decompinfo;
    if dih.source=G then
      di.idx:=Concatenation(dih.idx,[idx]);
      dec:=[];
      for i in dih.dec do
	Add(dec,elm->MappedWord(i(elm),fpqg,qimg));
      od;
      Add(dec,decomp);
      di.dec:=dec;
    fi;
  fi;

  if not IsBound(di.dec) then
    di.idx:=[[1..Length(fpqg)],idx];
    di.dec:=[elm->MappedWord(Image(hom,elm),fpqg,qimg),decomp];
  fi;

  hom2!.decompinfo:=MakeImmutable(di);
  SetIsWordDecompHomomorphism(hom2,true);

  SetIsSurjective(hom2,true);
  if N<>false then
    SetKernelOfMultiplicativeGeneralMapping(hom2,N);
  fi;

  return hom2;
end);

InstallGlobalFunction(ComplementFactorFpHom,
function(h,g,m,n,k,ggens,cgens)
local di, hom;
  if IsBound(h!.decompinfo) then
    di:=ShallowCopy(h!.decompinfo);
    if di.gens=ggens or cgens=ggens then
      di.gens:=cgens;
      di.source:=k;
      # this homomorphism is just to store decomposition information and is
      # not declared total, so an assertion test will fail
      hom:=GroupHomomorphismByImagesNC(k,di.fp,cgens,GeneratorsOfGroup(di.fp):noassert);
      hom!.decompinfo:=MakeImmutable(di);
      if HasIsSurjective(h) and IsSurjective(h) 
	and HasKernelOfMultiplicativeGeneralMapping(h)
	and m=KernelOfMultiplicativeGeneralMapping(h) then
	SetIsSurjective(hom,true);
	SetKernelOfMultiplicativeGeneralMapping(hom,n);
      fi;

      SetIsWordDecompHomomorphism(hom,true);
      return hom;
    fi;
  fi;

  if ggens=MappingGeneratorsImages(h)[1] then
    # can we simply translate a map on generators?
    hom:=GroupHomomorphismByImagesNC(k,Range(h),
	  Concatenation(GeneratorsOfGroup(n),cgens),
	  Concatenation(List(GeneratorsOfGroup(n),i->One(Range(h))),
	  MappingGeneratorsImages(h)[2]));
    return hom;
  fi;
  if IsBound(h!.decompinfo) then
    Error("do not know yet how to lift to complement");
  fi;
  hom:=GroupHomomorphismByImagesNC(k,Range(h),
	  Concatenation(GeneratorsOfGroup(n),cgens),
	  Concatenation(List(GeneratorsOfGroup(n),i->One(Range(h))),
	    List(ggens,i->Image(h,i))));
  return hom;
end);

#############################################################################
##
#M  IsomorphismFpGroupByGeneratorsNC( G, gens, str )
##
InstallOtherMethod( IsomorphismFpGroupByGeneratorsNC, "for perm groups",
  IsFamFamX,[IsPermGroup, IsList, IsString], 0,
function( G, gens, str )
    local F, gensF, gensR, gensS, hom, info, iso, method, ngens, R, reg, rel,
          relators, S;

    # check for trivial cases
    ngens := Length( gens );
    if ngens = 0 then
        S := FreeGroup( 0 );
    elif ngens = 1 then
        F := FreeGroup( 1 );
        gensF := GeneratorsOfGroup( F );
        relators := [ gensF[1]^Size( G ) ];
        S := F/relators;
    # check options
    else
        F := FreeGroup( ngens, str );
        gensF := GeneratorsOfGroup( F );
        method := ValueOption( "method" );
        if not IsString( method ) and IsList( method ) and
            Length( method ) = 2 and method[1] = "regular" then
            if not IsInt( method[2] ) then
                Info( InfoFpGroup + InfoWarning, 1, "Warning: function ",
                    "IsomorphismFpGroupByGeneratorsNC encountered an" );
                Info( InfoFpGroup + InfoWarning, 1, "  non-integer bound ",
                    "for method \"regular\"; the option has been ignored" );
            elif Size( G ) <= method[2] then
                method := "regular";
            fi; 
        fi;
        if method = "fast" then
            # use the old method
            hom := GroupHomomorphismByImagesNC( G, F, gens, gensF );
            relators := CoKernelGensPermHom( hom );
        elif method = "regular" and not IsRegular( G ) then
            # construct a regular permutation representation of G and then
            # apply the default method to it
            reg := RegularActionHomomorphism( G );
            R := Image( reg );
            gensR := List( gens, gen -> gen^reg );
            hom := GroupHomomorphismByImagesNC( R, F, gensR, gensF );
            relators := RelatorsPermGroupHom( hom, gensR );
        else
            # apply the default method to G
            hom := GroupHomomorphismByImagesNC( G, F, gens, gensF );
            relators := RelatorsPermGroupHom( hom, gens );
        fi;
        S := F/relators;
    fi;
    gensS := GeneratorsOfGroup( S );
    iso := GroupHomomorphismByImagesNC( G, S, gens, gensS );
    if HasSize(G) then
      SetSize(S,Size(G));
    fi;
    SetIsSurjective( iso, true );
    SetIsInjective( iso, true );
    SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup( G ));
    info := ValueOption( "infolevel" );
    if info <> 2 then
      info := 1;
    fi;
    if ngens = 0 then
      Info( InfoFpGroup, info, "the image fp group is trivial" );
    else
      Info( InfoFpGroup, info, "the image group has ", ngens, " gens and ",
        Length( relators ), " rels of total length ",
        Sum( List( relators, rel -> Length( rel ) ) ) );
    fi;
    ProcessEpimorphismToNewFpGroup(iso);
    return iso;
end );


#############################################################################
##
#M  IsomorphismFpGroupByGeneratorsNC( G, gens, str )
##
InstallMethod( IsomorphismFpGroupByGeneratorsNC, "via cokernel", IsFamFamX,
               [IsGroup, IsList, IsString], 0,
function( G, gens, str )
    local F, hom, rels, H, gensH, iso;
    F   := FreeGroup( Length(gens), str );
    hom := GroupGeneralMappingByImagesNC( G, F, gens, GeneratorsOfGroup(F) );
    rels := GeneratorsOfGroup( CoKernelOfMultiplicativeGeneralMapping( hom ) );
    H := F /rels;
    gensH := GeneratorsOfGroup( H );
    iso := GroupHomomorphismByImagesNC( G, H, gens, gensH );
    if HasSize(G) then
      SetSize(H,Size(G));
    fi;
    SetIsBijective( iso, true );
    SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup(G) );
    ProcessEpimorphismToNewFpGroup(iso);
    return iso;
end );


#############################################################################
##
#M  IsomorphismFpGroupBySubnormalSeries( G, series, str )
##
InstallMethod( IsomorphismFpGroupBySubnormalSeries,
               "for groups",
               true,
               [IsPermGroup, IsList, IsString],
               0,
function( G, series, str )
    local l, H, gensH, iso, F, gensF, imgsF, relatorsF, free, n, k, N, M,
          hom, preiH, c, new, T, gensT, E, gensE, imgsE, relatorsE, rel,
          w, t, i, j,known;

    known:=ValueOption("knownfactor");
    # set up with smallest subgroup of series
    l      := Length( series );
    H := series[l-1];
    gensH := Set( GeneratorsOfGroup( H ) );
    gensH := Filtered( gensH, x -> x <> One(H) );
    iso   := IsomorphismFpGroupByGeneratorsNC( H, gensH, str );
    F     := FreeGroupOfFpGroup( Image( iso ) );
    gensF := GeneratorsOfGroup( F );
    imgsF := MappingGeneratorsImages(iso)[1];
    relatorsF := RelatorsOfFpGroup( Image( iso ) );
    free  := GroupHomomorphismByImagesNC( F, series[l-1], gensF, imgsF );
    n     := Length( gensF );

    # loop over series upwards
    for k in Reversed( [1..l-2] ) do

        N := series[k];
        M := series[k+1];
        if known<>fail and M=KernelOfMultiplicativeGeneralMapping(known) then
          hom:=known;
        else
          # get composition factor
          hom   := NaturalHomomorphismByNormalSubgroupNC( N, M );
        fi;
        H     := Image( hom );

        gensH := GeneratorsOfGroup( H );
        gensH := Filtered( gensH, x -> x <> One(H) );
        preiH := List( gensH, x -> PreImagesRepresentative( hom, x ) );
        c     := Length( gensH );

        # compute presentation of H
        if IsFpGroup(H) then
          new:=IdentityMapping(H);
        else
          new := IsomorphismFpGroupByGeneratorsNC( H, gensH, "g" );
        fi;
        T   := Image( new );
        gensT := GeneratorsOfGroup( FreeGroupOfFpGroup( T ) );

        # create new free group
        E     := FreeGroup( n+c, str );
        gensE := GeneratorsOfGroup( E );
        imgsE := Concatenation( preiH, imgsF );
        relatorsE := [];

        # modify presentation of H
        for rel in RelatorsOfFpGroup( T ) do
            w := MappedWord( rel, gensT, gensE{[1..c]} );
            t := MappedWord( rel, gensT, imgsE{[1..c]} );
            if not t = One( G ) then
                t := PreImagesRepresentative( free, t );
                t := MappedWord( t, gensF, gensE{[c+1..n+c]} );
            else
                t := One( E );
            fi;
            Add( relatorsE, w/t );
        od;

        # add operation of T on F
        for i in [1..c] do
            for j in [1..n] do
                w := Comm( gensE[c+j], gensE[i] );
                t := Comm( imgsE[c+j], imgsE[i] );
                if not t = One( G ) then
                    t := PreImagesRepresentative( free, t );
                    t := MappedWord( t, gensF, gensE{[c+1..n+c]} );
                else
                    t := One( E );
                fi;
                Add( relatorsE, w/t );
            od;
        od;

        # append relators of F
        for rel in relatorsF do
            w := MappedWord( rel, gensF, gensE{[c+1..c+n]} );
            Add( relatorsE, w );
        od;

        # iterate
        F := E;
        gensF := gensE;
        imgsF := imgsE;
        relatorsF := relatorsE;
        free :=  GroupHomomorphismByImagesNC( F, N, gensF, imgsF );
        n := n + c;
    od;

    # set up
    F     := F / relatorsF;
    gensF := GeneratorsOfGroup( F );
    if HasSize(G) then
      SetSize(F,Size(G));
    fi;
    iso   := GroupHomomorphismByImagesNC( G, F, imgsF, gensF );
    SetIsBijective( iso, true );
    SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup( G ) );
    ProcessEpimorphismToNewFpGroup(iso);
    return iso;
end);

InstallOtherMethod( IsomorphismFpGroupBySubnormalSeries, "for groups", true,
               [IsPermGroup, IsList], 0,
function( G, series )
    return IsomorphismFpGroupBySubnormalSeries( G, series, "F" );
end);

InstallOtherMethod(IsomorphismFpGroupForRewriting,
  "generic, deal with large element orders", true,
  [IsGroup],0,
function(G)
local hom;
  IsSimpleGroup(G);
  hom:=IsomorphismFpGroup(G:abelianlimit:=10);
  return hom;
end);

InstallGlobalFunction(MakeFpGroupToMonoidHomType1,function(fp,m)
local fam,mfam,fpfam,mfpfam,hom;
  fam:=FamilyObj(UnderlyingElement(One(fp)));
  mfam:=FamilyObj(UnderlyingElement(One(m)));
  fpfam:=FamilyObj(One(fp));
  mfpfam:=FamilyObj(One(m));
  hom:=MagmaIsomorphismByFunctionsNC(fp,m,
        function(w)
          local l,i;
          l:=[];
          for i in LetterRepAssocWord(UnderlyingElement(w)) do
            if i>0 then Add(l,2*i-1);
            else Add(l,-2*i);fi;
          od;
          return ElementOfFpMonoid(mfpfam,AssocWordByLetterRep(mfam,l));
        end,
        function(w)
          local g,i,x;
          g:=[];
          for i in LetterRepAssocWord(UnderlyingElement(w)) do
            if IsOddInt(i) then x:=(i+1)/2;
            else x:=-i/2;fi;
            # word must be freely cancelled
            if Length(g)>0 and x=-g[Length(g)] then
              Unbind(g[Length(g)]);
            else Add(g,x); fi;
          od;
          return ElementOfFpGroup(fpfam,AssocWordByLetterRep(fam,g));
        end);

  # type 0 is inverses first
  hom!.type:=1;
  if not HasIsomorphismFpMonoid(fp) then
    SetIsomorphismFpMonoid(fp,hom);
  fi;
  return hom;
end);

# return isomorphism G-fp and fp->mon, such that presentation of monoid is
# confluent (wrt wreath order). Returns record with fphom,monhom,ordering
InstallMethod(ConfluentMonoidPresentationForGroup,"generic",
  [IsGroup and IsFinite],
function(G)
local iso,fp,n,dec,homs,mos,i,j,ffp,imo,m,k,gens,fm,mgens,rules,
      loff,off,monreps,left,right,fmgens,r,diff,monreal,nums,reduce,hom,dept,
      lode,lrules,rulet,addrule;
  IsSimpleGroup(G);
  if IsSymmetricGroup(G) then
    i:=SymmetricGroup(SymmetricDegree(G));
    iso:=CheapIsomSymAlt(G,i)*IsomorphismFpGroup(i);
    fp:=Range(iso);
    hom:=IsomorphismFpMonoid(fp);
    m:=Range(hom);
    fm:=FreeMonoidOfFpMonoid(m);
    k:=KnuthBendixRewritingSystem(m);
    MakeConfluent(k);
    rules:=Rules(k);
    dept:=fail;
  else
    iso:=IsomorphismFpGroupByChiefSeries(G:rewrite);

    fp:=Range(iso);
    gens:=GeneratorsOfGroup(fp);
    n:=Length(gens);
    dec:=iso!.decompinfo;

    fmgens:=[];
    mgens:=[];
    for i in gens do
      Add(fmgens,i);
      Add(fmgens,i^-1);
      Add(mgens,String(i));
      Add(mgens,String(i^-1));
    od;
    nums:=List(fmgens,x->LetterRepAssocWord(UnderlyingElement(x))[1]);
    fm:=FreeMonoid(mgens);
    mgens:=GeneratorsOfMonoid(fm);

    rules:=[];
    lrules:=[];
    rulet:=List(mgens,x->[]); # rules involving a particular letter

    addrule:=function(rule)
    local i,p;
      Add(rules,rule);
      rule:=List(rule,LetterRepAssocWord);
      Add(lrules,rule);
      p:=Length(lrules);
      for i in Set(rule[1]) do
        AddSet(rulet[i],p);
      od;
    end;

    reduce:=function(w)
    local red,i,p,pool,wn;
      w:=LetterRepAssocWord(w);
      repeat
        i:=1;
        pool:=Union(rulet{Set(w)});
        red:=false;
        while i<=Length(pool) and red=false do
          p:=fail;
          if Length(w)>=Length(lrules[pool[i]][1]) then
            p:=PositionSublist(w,lrules[pool[i]][1]);
          fi;
          if p<>fail then
            wn:=Concatenation(w{[1..p-1]},lrules[pool[i]][2],
              w{[p+Length(lrules[pool[i]][1])..Length(w)]});
#if Length(wn)>Length(w) then Error("HOH");fi;
             w:=wn;
#            w:=Concatenation(w{[1..p-1]},lrules[pool[i]][2],
#              w{[p+Length(lrules[pool[i]][1])..Length(w)]});
            red:=true;
          else
            i:=i+1;
          fi;
        od;
      until red=false;
      return AssocWordByLetterRep(FamilyObj(One(fm)),w);
    end;


    homs:=ShallowCopy(dec.homs);
    mos:=[];
    off:=Length(mgens);
    dept:=[];
    lode:=[];
    # go up so we may reduce tails
    for i in [Length(homs),Length(homs)-1..1] do
      Add(dept,off);
      if IsGeneralPcgs(homs[i]) then
        if Length(dec.abpow[i])>0 then
          ffp:=FreeAbelianGroup(Length(homs[i])*(Length(dec.abpow[i])+1));
          # relations: order
          m:=GeneratorsOfGroup(ffp);
          r:=List(m,x->x^RelativeOrders(homs[i])[1]);
          # power dependence
          for j in [1..Length(dec.abpow[i])] do
            for k in [1..Length(homs[i])] do
              Add(r,m[Length(homs[i])*(j-1)+k]^dec.abpow[i][j]
                /m[Length(homs[i])*j+k]);
            od;
          od;
          ffp:=ffp/r;

        else
          ffp:=AbelianGroup(IsFpGroup,RelativeOrders(homs[i]));
        fi;
      else
        ffp:=Range(homs[i]);
      fi;

      imo:=IsomorphismFpMonoid(ffp);
      Add(mos,imo);
      m:=Range(imo);
      loff:=off-Length(GeneratorsOfMonoid(m));
      monreps:=fmgens{[loff+1..off]};
      monreal:=mgens{[loff+1..off]};
      if IsBound(m!.rewritingSystem) then
        k:=m!.rewritingSystem;
      else
        k:=KnuthBendixRewritingSystem(m);
      fi;
      if HasLevelsOfGenerators(k!.ordering) then
        Add(lode,LevelsOfGenerators(k!.ordering));
      else
        Add(lode,fail);
      fi;
      MakeConfluent(k);
      # convert rules
      for r in Rules(k) do
        left:=MappedWord(r[1],FreeGeneratorsOfFpMonoid(m),monreps);
        right:=MappedWord(r[2],FreeGeneratorsOfFpMonoid(m),monreps);
        diff:=LeftQuotient(PreImagesRepresentative(iso,right),
                PreImagesRepresentative(iso,left));
        diff:=ImagesRepresentative(iso,diff);

        left:=MappedWord(r[1],FreeGeneratorsOfFpMonoid(m),monreal);
        right:=MappedWord(r[2],FreeGeneratorsOfFpMonoid(m),monreal);
        if not IsOne(diff) then 
          right:=right*Product(List(LetterRepAssocWord(UnderlyingElement(diff)),
            x->mgens[Position(nums,x)]));
        fi;
        right:=reduce(right); # monoid word might change
        addrule([left,right]);
      od;
      for j in [loff+1..off] do
        # if the generator gets reduced away, won't need to use it
        if reduce(mgens[j])=mgens[j] then
          for k in [off+1..Length(mgens)] do
            if reduce(mgens[k])=mgens[k] then
              right:=fmgens[j]^-1*fmgens[k]*fmgens[j];
              #collect
              right:=ImagesRepresentative(iso,PreImagesRepresentative(iso,right));
              right:=Product(List(LetterRepAssocWord(UnderlyingElement(right)),
                x->mgens[Position(nums,x)]));
              right:=reduce(mgens[j]*right);
              #Print("Did rule ",mgens[k],"*",mgens[j],"->",right,"\n");
              addrule([mgens[k]*mgens[j],right]);
            fi;
          od;
        fi;
      od;
      #if i<Length(homs) then Error("ZU");fi;
      off:=loff;
    od;
    Add(dept,off);
    # calculate levels for ordering
    dept:=dept+1;
    dept:=List([1..Length(mgens)],
      x->PositionProperty(dept,y->x>=y)-1);

    # are there local levels to keep? First make them fractional additions
    off:=10^(1+LogInt(Length(dept),10)); # cent level for local depths
    for i in [1..Maximum(dept)] do
      if lode[i]<>fail then
        diff:=Filtered([1..Length(dept)],x->dept[x]=i);
        dept{diff}:=dept{diff}+lode[i]/off;
      fi;
    od;
    if ForAny(dept,x->not IsInt(x)) then
      # reintegralize
      diff:=Set(dept);
      dept:=List(dept,x->Position(diff,x));
    fi;

#    if AssertionLevel()>1 and ForAny(rules,x->x[2]<>reduce(x[2])) then
#      Error("irreduced right");
#    fi;

    # inverses are true inverses, also for extension
    for i in [1..Length(gens)] do
      left:=mgens[2*i-1]*mgens[2*i];
      left:=reduce(left);
      if left<>One(fm) then addrule([left,One(fm)]); fi;
      left:=mgens[2*i]*mgens[2*i-1];
      left:=reduce(left);
      if left<>One(fm) then addrule([left,One(fm)]); fi;
    od;
  fi;

  # finally create 
  m:=FactorFreeMonoidByRelations(fm,rules);
  hom:=MakeFpGroupToMonoidHomType1(fp,m);

  j:=rec(fphom:=iso,monhom:=hom);
  if dept=fail then
    j.ordering:=k!.ordering;
  else
    j.ordering:=WreathProductOrdering(fm,dept);
  fi;
  k:=KnuthBendixRewritingSystem(FamilyObj(One(m)),j.ordering:isconfluent);
  MakeConfluent(k); # will store in monoid as reducedConfluent
  return j;
end);

# special method for pc groups, basically just writing down the pc
# presentation
InstallMethod(ConfluentMonoidPresentationForGroup,"pc",
  [IsGroup and IsFinite and IsPcGroup],
function(G)
local pcgs,iso,fp,i,j,gens,numi,ord,fm,fam,mword,k,r,addrule,a,e,m;
  pcgs:=Pcgs(G);
  iso:=IsomorphismFpGroup(G);
  fp:=Range(iso);
  if List(GeneratorsOfGroup(fp),x->PreImagesRepresentative(iso,x))<>pcgs then 
    Error("pcgs");
  fi;
  gens:=[];
  numi:=[];
  ord:=[];
  for i in [1..Length(pcgs)] do
    Add(gens,String(fp.(i)));
    Add(gens,String(fp.(i)^-1));
    Add(numi,i);
    Add(numi,-i);
    Append(ord,[i,i]);
  od;
  fm:=FreeMonoid(gens);
  fam:=FamilyObj(One(fm));
  mword:=w->AssocWordByLetterRep(fam,
    List(LetterRepAssocWord(UnderlyingElement(w)),x->Position(numi,x)));
  ord:=WreathProductOrdering(fm,Reversed(ord));
  k:=CreateKnuthBendixRewritingSystem(FamilyObj(One(fm/[])),ord);
  if AssertionLevel()<=2 then
    # assertion level <=2 so the auto tests will never trigger it
    Unbind(k!.pairs2check);
  fi;
  addrule:=function(rul)
    #Print("Add:",rul,"\n");
    AddRuleReduced(k,List(rul,LetterRepAssocWord));
    #Print(Rules(k),"\n");
  end;

  for i in [Length(pcgs),Length(pcgs)-1..1] do
    if RelativeOrders(pcgs)[i]>2 then
      addrule([mword(fp.(i))*mword(fp.(i)^-1),One(fm)]);
      addrule([mword(fp.(i)^-1)*mword(fp.(i)),One(fm)]);
    fi;
    for j in [Length(pcgs),Length(pcgs)-1..i+1] do
      for e in [[1,1],[1,-1],[-1,1],[-1,-1]] do
        if (RelativeOrders(pcgs)[j]>2 or e[1]=1) and
          (RelativeOrders(pcgs)[i]>2 or e[2]=1) then
          a:=(pcgs[j]^e[1])^(pcgs[i]^e[2]);
          addrule([mword(fp.(j)^e[1]*fp.(i)^e[2]),mword(fp.(i)^e[2])*mword(a)]);
        fi;
      od;
    od;
    r:=RelativeOrders(pcgs)[i];
    if r=2 then
      a:=ImagesRepresentative(iso,pcgs[i]^2);
      addrule([mword(fp.(i)^2),mword(a)]);
      a:=ImagesRepresentative(iso,pcgs[i]^-2);
      addrule([mword(fp.(i)^-1),mword(fp.(i))*mword(a)]);
    else
      a:=ImagesRepresentative(iso,pcgs[i]^r);
      addrule([mword(fp.(i)^((r+1)/2)),mword(fp.(i)^(-(r-1)/2))*mword(a)]);
      a:=ImagesRepresentative(iso,pcgs[i]^-r);
      addrule([mword(fp.(i)^(-(r+1)/2)),mword(fp.(i)^((r-1)/2))*mword(a)]);
    fi;
  if IsBound(k!.pairs2check) then
    e:=StructuralCopy(Rules(k));
    MakeConfluent(k);
    Assert(3,Set(Rules(k))=Set(e));
  fi;
  od;
  SetIsConfluent(k,true);
  SetIsReduced(k,true);
  m:=fm/Rules(k);
  a:=MakeFpGroupToMonoidHomType1(fp,m);
  SetReducedConfluentRewritingSystem(m,k);
  j:=rec(fphom:=iso,monhom:=a,ordering:=ord);
  return j;
end);


# ser is a string indicating the series (A, B, C, D, E, F), n is a number. If argument `false` is added, only braid
# relations
BindGlobal("WeylGroupFp",function(ser,n,docox...)
local f,rels,i,j,gens,coxrel;
  coxrel:=function(a,b,n)
  local m,f,g;
    if n=2 then Add(rels,Comm(a,b));
    else
      if docox then 
        # coxeter: no negative exponents
        Add(rels,(a*b)^n); 
      else 
        # braid: bababa...  = ababab...
        m:=QuoInt(n+1,2);
        f:=Subword((b*a)^m,1,n);
        g:=Subword((a*b)^m,1,n);
        Add(rels,f/g);
      fi;
    fi;
  end;
  f:=FreeGroup(List([1..n],x->Concatenation("s",String(x))));
  gens:=GeneratorsOfGroup(f);
  if Length(docox)=0 then
    docox:=true;
  else
    docox:=docox[1]=true;
  fi;
  if docox then
    rels:=List(gens,x->x^2);
  else
    rels:=[];
  fi;
  if ser="A" then
    for i in [1..n] do
      for j in [1..i-1] do
        if i-j>1 then
          coxrel(gens[j],gens[i],2);
        else
          coxrel(gens[j],gens[i],3);
        fi;
      od;
    od;
  elif ser="B" or ser="C" then
    for i in [1..n] do
      for j in [1..i-1] do
        if i-j>1 then
          coxrel(gens[j],gens[i],2);
        elif j=1 then
          coxrel(gens[j],gens[i],4);
        else
          coxrel(gens[j],gens[i],3);
        fi;
      od;
    od;
  elif ser="D" and n>=4 then
    coxrel(gens[1],gens[2],2);
    coxrel(gens[1],gens[3],3);
    coxrel(gens[2],gens[3],3);
    for i in [4..n] do
      for j in [1..i-1] do
        if i-j>1 then
          coxrel(gens[j],gens[i],2);
        else
          coxrel(gens[j],gens[i],3);
        fi;
      od;
    od;
  elif ser="E" then
    coxrel(gens[1],gens[2],3);
    coxrel(gens[2],gens[3],3);
    coxrel(gens[3],gens[4],3);
    coxrel(gens[3],gens[5],3);
    coxrel(gens[5],gens[6],3);

    coxrel(gens[1],gens[3],2);
    coxrel(gens[1],gens[4],2);
    coxrel(gens[2],gens[4],2);
    coxrel(gens[1],gens[5],2);
    coxrel(gens[2],gens[5],2);
    coxrel(gens[4],gens[5],2);
    coxrel(gens[1],gens[6],2);
    coxrel(gens[2],gens[6],2);
    coxrel(gens[3],gens[6],2);
    coxrel(gens[4],gens[6],2);
    if n>=7 then
      coxrel(gens[6],gens[7],3);
      for i in [1..5] do
        coxrel(gens[i],gens[7],2);
      od;
    fi;
    if n=8 then
      coxrel(gens[7],gens[8],3);
      for i in [1..6] do
        coxrel(gens[i],gens[7],2);
      od;
    elif n>8 then 
      Error("E>8 does not exist");
    fi;
  elif ser="F" and n=4 then
    coxrel(gens[1],gens[2],3);
    coxrel(gens[2],gens[3],4);
    coxrel(gens[3],gens[4],3);

    coxrel(gens[1],gens[3],2);
    coxrel(gens[1],gens[4],2);
    coxrel(gens[2],gens[4],2);
  elif ser="G" and n=2 then
    coxrel(gens[1],gens[2],6);
  else
    Error("series ",ser," not yet done");
  fi;
  return f/rels;
end);

BindGlobal("IsomorphismFpGroupForWeyl",
function(G)
local iso,n,fn,sz,bigcount,tryweyl;

  tryweyl:=function(ser,n)
  local H,isp,P,iso;
    H:=WeylGroupFp(ser,n);
    isp:=IsomorphismPermGroup(H);
    P:=Image(isp,H);
    iso:=IsomorphismGroups(G,P);
    if iso<>fail then
      P:=List(GeneratorsOfGroup(H),
        x->PreImagesRepresentative(iso,ImagesRepresentative(isp,x)));
      iso:=GroupHomomorphismByImagesNC(G,H,P,GeneratorsOfGroup(H));
    fi;
    return iso;
  end;

  # try to identify Weyl series
  n:=0;
  fn:=1;
  repeat
    n:=n+1;
    fn:=fn*n;
    bigcount:=0;
    sz:=fn*(n+1);
    if Size(G)<sz then bigcount:=bigcount+1;
    elif Size(G)=sz and IsSymmetricGroup(G) then
      # try Sn
      if HasIsomorphismFpGroup(G) then
        # We can access the special `symmetric' presentation only as method
        # for `IsomorphismFp` for the symmetric group. But if such an
        # isomorphism is already stored, it might be a different one.
        # In this case recreate a new group that will then get it (because
        # it is symmetric).
        G:=Group(GeneratorsOfGroup(G));
        SetSize(G,sz);
        SetIsSymmetricGroup(G,true);
      fi;
      return IsomorphismFpGroup(G); # uses symmetric method
    fi;
    sz:=2^n*fn;
    if Size(G)<sz then bigcount:=bigcount+1;
    elif Size(G)=sz then
      iso:=tryweyl("B",n);
      if iso<>fail then return iso;fi;
    fi;
    sz:=2^(n-1)*fn;
    if Size(G)<sz then bigcount:=bigcount+1;
    elif n>=4 and Size(G)=sz then
      iso:=tryweyl("D",n);
      if iso<>fail then return iso;fi;
    fi;
  until bigcount=3;

  if Size(G)=12 then
    iso:=tryweyl("G",2);
    if iso<>fail then return iso;fi;
  elif Size(G)=1152 then
    iso:=tryweyl("F",4);
    if iso<>fail then return iso;fi;
  elif Size(G)=51840 then
    iso:=tryweyl("E",6);
    if iso<>fail then return iso;fi;
  elif Size(G)=72*Factorial(8) then
    iso:=tryweyl("E",7);
    if iso<>fail then return iso;fi;
  elif Size(G)=192*Factorial(10) then
    iso:=tryweyl("E",8);
    if iso<>fail then return iso;fi;
  fi;

  return fail;
end);

# rewriting systems for simple groups based on BN pairs, following 
# (Schmidt,  Finite groups have short rewriting systems. Computational group
# theory and the theory of groups, II, 185–200, Contemp. Math., 511.)
BindGlobal("SplitBNRewritingPresentation",function(group,borel,weyl,newstyle)
local isob,isos,iso,gens,u,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid,
  lev,ord,monb,mons,gp,trawo,trawou,hom,tst,dc,dcreps,act,decomp,ranb,ranw,
  nofob,nofow,reduce,pcgs,can,pri,stb,addrule,invmap,jj,wo,pciso,
  borelelm,borelran,borelreduce,bpairs,brws,specialborelreduce,
  rt,dcnums,rti,sel,maketzf,mytzf,borela,pc,bpcgs,noncomm,noncelm,
  wgens,weylword,borelword,coxrels,ha,directerr,bhom;

  specialborelreduce:=false;
  if Size(ClosureGroup(borel,weyl))<Size(group) then return fail;fi;
  ha:=Intersection(borel,weyl);
  dc:=DoubleCosets(group,borel,borel);

  if newstyle then

    # use exactly the generators of borel
    bpcgs:=PcgsByPcSequence(FamilyObj(One(borel)),GeneratorsOfGroup(borel));
    pc:=PcGroupWithPcgs(bpcgs);
    pciso:=GroupHomomorphismByImages(borel,pc,bpcgs,FamilyPcgs(pc));

    cb:=ConfluentMonoidPresentationForGroup(pc);
  else
    if Size(Intersection(borel,weyl))>1 then
      # can we fix this?
      # asume weyl is not too large
      cs:=Concatenation(List(ConjugacyClassesSubgroups(weyl),AsList));;
      SortBy(cs,x->-Size(x));
      l:=false;
      i:=1;
      while l=false and i<=Length(cs) do
        if Size(Intersection(borel,cs[i]))=1 and Size(cs[i])>=Length(dc)
          and Size(ClosureGroup(borel,cs[i]))=Size(group) and 
          Length(Set(Elements(cs[i]),
            x->PositionProperty(dc,y->x in y)))=Length(dc) then
          Info(InfoFpGroup,1,"replaced weyl candidate with better subgroup\n");
          l:=cs[i];
        fi;
        i:=i+1;
      od;
      if l<>false then
        weyl:=l;
      fi;
    fi;

    # Use SpecialPcgs for borel

    pciso:=IsomorphismSpecialPcGroup(borel);
    cb:=ConfluentMonoidPresentationForGroup(Range(pciso));
  fi;

  brws:=ReducedConfluentRewritingSystem(Range(cb.monhom));

  # force going to pc group, as this will give better ordering
  isob:=GroupHomomorphismByFunction(borel,Range(cb.fphom),
    x->ImagesRepresentative(cb.fphom,ImagesRepresentative(pciso,x)),
    x->PreImagesRepresentative(pciso,PreImagesRepresentative(cb.fphom,x)));

  b:=Range(isob);

  wgens:=GeneratorsOfGroup(weyl);

  bgens:=List(GeneratorsOfGroup(b),x->PreImagesRepresentative(isob,x));
  if newstyle and bgens<>GeneratorsOfGroup(borel) then Error("gens");fi;

  bpairs:=Concatenation(List(bgens,x->[x,x^-1]));
  monoid:=Range(cb.monhom);

  borelran:=[]; # initially no special borelran

  # borel-only reduction to deal with large primes
  borelreduce:=function(w)
  local i,j,need;
    i:=1;
    repeat
      # find borel range 
      while i<Length(w) and not (w[i] in borelran) do
        i:=i+1;
      od;
      if i<Length(w) and w[i+1] in borelran then
        j:=i;
        need:=false;
        while j+1<=Length(w) and w[j+1] in borelran do
          j:=j+1;
          if need=false and QuoInt(w[j-1]+1,2)=QuoInt(w[j]+1,2) # element and inverse
            or w[j]<w[j-1] # wrong order
            then need:=true;
          fi;
        od;
        if need then
          need:=w{[i..j]};
          need:=Product(bpairs{need});
          need:=ImagesRepresentative(cb.monhom,ImagesRepresentative(isob,need));
          need:=UnderlyingElement(need);
          if Length(need)>0 then 
            need:=ReducedForm(brws,need);
          fi;
          w:=Concatenation(w{[1..i-1]},LetterRepAssocWord(need),w{[j+1..Length(w)]});
          i:=i+Length(need);
        else
          i:=j+1;
        fi;
      else
        if i<Length(w) then i:=i+2;fi;
      fi;
    until i>=Length(w);
    return w;
  end;

  maketzf:=function(rules)
  local tzf,tzrules,p,i;
    tzrules:=List(rules,x->List(x,LetterRepAssocWord));
    tzf:=[];
    for i in tzrules do
      p:=i[1][1];
      if not IsBound(tzf[p]) then
        tzf[p]:=[i];
      else
        Add(tzf[p],i);
      fi;
    od;
    return tzf;
  end;

  reduce:=function(wo,rules,tzf)
  local w,fam,red,i,j,p,ww,sp;
    #Print("Reduce ",wo,"\n");
    fam:=FamilyObj(wo);
    # is it in big monoid?

    w:=LetterRepAssocWord(wo);
    sp:=specialborelreduce and fam=FamilyObj(One(f)) and ForAny(w,x->x in borelran);

    if tzf=fail then
      tzf:=maketzf(rules);
    fi;

    # collect from the right
    if sp then
      w:=borelreduce(w);
    fi;
    p:=Length(w);
    while p>0 do
      if IsBound(tzf[w[p]]) then

	red:=tzf[w[p]];
	i:=1;
	while i<=Length(red) do
	  if p+Length(red[i][1])-1<=Length(w) then
	    j:=2;
	    while j<=Length(red[i][1]) and w[p+j-1]=red[i][1][j] do
	      j:=j+1;
	    od;
	    if j>Length(red[i][1]) then
	      # replace
	      w:=Concatenation(w{[1..p-1]},red[i][2],
		w{[p+Length(red[i][1])..Length(w)]});
              #Print("intermed ",red[i],":",AssocWordByLetterRep(fam,w),"\n");
	      p:=Minimum(p+Length(red[i][2]),Length(w));
              if sp then
                ww:=borelreduce(w);
                if ww<>w then
                  w:=ww;
                  p:=Length(w);
                fi;

              fi;
              
	      i:=Length(red);
	    fi;
	  fi;
	  i:=i+1;
	od;

      fi;
      p:=p-1;
    od;

    w:=AssocWordByLetterRep(fam,w);
    #Print("To ",w,"\n");
    #if sp and w<>oreduce(wo,rules) then Error("baeh!");fi;
    return w;
  end;

  nofob:=function(x)
    x:=UnderlyingElement(ImagesRepresentative(cb.monhom,x));
    x:=reduce(x,RelationsOfFpMonoid(monoid),fail);
    x:=ElementOfFpMonoid(FamilyObj(One(monoid)),x);
    return PreImagesRepresentative(cb.monhom,x);
  end;

  if newstyle then

    if IsBound(weyl!.epiweyl) then
      cs:=GroupHomomorphismByImages(weyl,weyl!.epiweyl,
        GeneratorsOfGroup(weyl),GeneratorsOfGroup(weyl!.epiweyl));
      if Size(ha)>1 then
        w:=CompositionSeriesThrough(weyl,[ha]);
        w:=Concatenation([weyl],Filtered(w,x->IsSubset(ha,x)));
        cs:=IsomorphismFpGroupBySubnormalSeries(weyl,w,"w":knownfactor:=cs);
      fi;
    else
      cs:=IsomorphismFpGroupByGenerators(weyl,wgens);
    fi;
    w:=IsomorphismFpMonoid(Range(cs));
    k:=KnuthBendixRewritingSystem(Range(w));
    MakeConfluent(k);
    k:=Rules(k);
    w:=FreeMonoidOfFpMonoid(Range(w))/k;
    w:=MakeFpGroupToMonoidHomType1(Range(cs),w);

    cs:=rec(fphom:=cs,monhom:=w);
  else
    cs:=IsomorphismFpGroupForWeyl(weyl);
    if cs<>fail then
      cs:=rec(fphom:=cs,monhom:=IsomorphismFpMonoid(Range(cs)));
    else
      cs:=ConfluentMonoidPresentationForGroup(weyl);
    fi;

  fi;

  isos:=cs.fphom;
  w:=Range(isos);
  a:=MappingGeneratorsImages(isos)[1];

  nofow:=function(x)
    x:=UnderlyingElement(ImagesRepresentative(cs.monhom,x));
    x:=reduce(x,RelationsOfFpMonoid(Range(cs.monhom)),fail);
    x:=ElementOfFpMonoid(FamilyObj(One(Range(cs.monhom))),x);
    return PreImagesRepresentative(cs.monhom,x);
  end;

  gens:=bgens;
  l:=Length(gens);
  gens:=Concatenation(gens,a);

  # identify double cosets
  rt:=RightTransversal(group,borel);
  # perm action of parent
  a:=Group(SmallGeneratingSet(group)); # so nothing stores
  borela:=List(GeneratorsOfGroup(a),x->Permutation(x,rt,OnRight));
  iso:=EpimorphismFromFreeGroup(a);
  borela:=List(bgens,x->MappedWord(PreImagesRepresentative(iso,x),MappingGeneratorsImages(iso)[1],borela));
  act:=Group(borela,());

  #dcnums:=OrbitsDomain(borel,[1..Length(rt)],
  #  function(num,elm) return PositionCanonical(rt,rt[num]*elm);end);
  dcnums:=OrbitsDomain(act,[1..Length(rt)]);
  dcnums:=List(dcnums,x->Immutable(Set(x)));
  rti:=[];
  for i in [1..Length(dc)] do
    a:=PositionCanonical(rt,Representative(dc[i]));
    a:=PositionProperty(dcnums,x->a in x);
    for j in dcnums[a] do
      rti[j]:=i;
    od;
  od;
  dcnums:=false; # clean memory
  iso:=false;
  act:=false;

  # BN decomposition
  dcreps:=[];
  for i in AsList(weyl) do
    #a:=PositionProperty(dc,y->i in y);
    a:=rti[PositionCanonical(rt,i)];
    if not IsBound(dcreps[a]) then dcreps[a]:=i;fi;
  od;

  if not ForAll([1..Length(dc)],x->IsBound(dcreps[x])) then
    Error("weyl does not cover dc");
  fi;

  iso:=IsomorphismFpGroupByGenerators(group,gens);

  act:=function(r,g)
    return CanonicalRightCosetElement(borel,r*g);
  end;

  bhom:=GroupHomomorphismByImages(borel,Group(borela),bgens,borela);
  Assert(0,bhom<>fail);
  decomp:=function(elm)
  local pos,rep;
    if elm in borel then return [elm,One(borel),One(borel)];fi;
    #pos:=PositionProperty(dc,y->elm in y);
    pos:=rti[PositionCanonical(rt,elm)];
    #rep:=RepresentativeAction(borel,PositionCanonical(rt,elm),
    #       PositionCanonical(rt,dcreps[pos]),bgens,borela,OnPoints);
    rep:=PreImagesRepresentative(bhom,
      RepresentativeAction(Range(bhom),PositionCanonical(rt,elm),
           PositionCanonical(rt,dcreps[pos])));
    rep:=[elm*rep/dcreps[pos],dcreps[pos],rep^-1];
    Assert(0,rep[1] in borel);
    return rep;
  end;

  # now build new presentation
  a:=[];
  for i in [1..Length(GeneratorsOfGroup(b))] do
    Add(a,Concatenation("b",String(i)));
  od;
  borelran:=[1..Length(a)];
  for i in [1..Length(GeneratorsOfGroup(w))] do
    Add(a,Concatenation("w",String(i)));
  od;

  f:=FreeGroup(a);
  gens:=FreeGeneratorsOfFpGroup(f);
  rels:=[];
  # take the relators of both groups
  ranb:=gens{[1..l]};
  for i in RelatorsOfFpGroup(b) do
    Add(rels,MappedWord(i,FreeGeneratorsOfFpGroup(b),ranb));
  od;
  ranw:=gens{[l+1..Length(gens)]};
  for i in RelatorsOfFpGroup(w) do
    Add(rels,MappedWord(i,FreeGeneratorsOfFpGroup(w),ranw));
  od;

  # throw in relators for the whole group, so we guarantee a presentation
  Append(rels,List(RelatorsOfFpGroup(Range(iso)),
    w->MappedWord(w,FreeGeneratorsOfFpGroup(Range(iso)),gens)));
  gp:=f/rels;

  iso:=GroupHomomorphismByImagesNC(group,gp,MappingGeneratorsImages(iso)[1],
         GeneratorsOfGroup(gp));
  SetIsBijective(iso,true);

  # now combine monoid presentations
  rels:=[];
  mytzf:=maketzf(rels);

  directerr:=false;
  if newstyle then directerr:=true;fi;

  addrule:=function(rule)
  local left,right,let,old,p;
    left:=reduce(rule[1],rels,mytzf);
    right:=reduce(rule[2],rels,mytzf);
    if left=right then return;fi;
    if IsLessThanUnder(ord,right,left) then
      rule:=[left,right];
    elif directerr then
      Error("direction!");
      rule:=[right,left];
    else
      rule:=[right,left];
    fi;
    # try to shift
  old:=rule;
    let:=LetterRepAssocWord(rule[1])[1];
    left:=Subword(rule[1],2,Length(rule[1]));
    right:=reduce(invmap[let]*rule[2],rels,mytzf);
    while IsLessThanUnder(ord,right,left) do
      rule:=[left,right];
      let:=LetterRepAssocWord(rule[1])[1];
      left:=Subword(rule[1],2,Length(rule[1]));
      right:=reduce(invmap[let]*rule[2],rels,mytzf);
    od;
    let:=LetterRepAssocWord(rule[1])[Length(rule[1])];
    left:=Subword(rule[1],1,Length(rule[1])-1);
    right:=reduce(rule[2]*invmap[let],rels,mytzf);
    while IsLessThanUnder(ord,right,left) do
      rule:=[left,right];
      let:=LetterRepAssocWord(rule[1])[Length(rule[1])];
      left:=Subword(rule[1],1,Length(rule[1])-1);
      right:=reduce(rule[2]*invmap[let],rels,mytzf);
    od;

    # delete common letters at start/end
    while Length(rule[2])>0 and Subword(rule[1],1,1)=Subword(rule[2],1,1) do
      rule:=[Subword(rule[1],2,Length(rule[1])),
             Subword(rule[2],2,Length(rule[2]))];
    od;
    while Length(rule[2])>0 and Subword(rule[1],Length(rule[1]),Length(rule[1]))
        =Subword(rule[2],Length(rule[2]),Length(rule[2])) do
      rule:=[Subword(rule[1],1,Length(rule[1])-1),
             Subword(rule[2],1,Length(rule[2])-1)];
    od;

# are they now redundant?
left:=reduce(rule[1],rels,mytzf);
right:=reduce(rule[2],rels,mytzf);
if IsLessThanUnder(ord,right,left) then
  rule:=[left,right];
else
  rule:=[right,left];
fi;
if rule[1]=rule[2] then return;fi;

    Add(rels,rule);
    rule:=List(rule,LetterRepAssocWord);
    p:=rule[1][1];
    if not IsBound(mytzf[p]) then
      mytzf[p]:=[rule];
    else
      Add(mytzf[p],rule);
    fi;
  end;

  lev:=ShallowCopy(LevelsOfGenerators(cb.ordering));
  monb:=monoid;
  mons:=Range(cs.monhom);
  l:=Length(GeneratorsOfMonoid(monb));
  a:=[];
  for i in [1..l/2] do
    Add(a,Concatenation("b",String(i)));
    Add(a,Concatenation("B",String(i)));
  od;
  borelran:=[1..Length(a)];
  for i in [1..Length(MappingGeneratorsImages(isos)[2])] do
    Add(a,Concatenation("w",String(i)));
    Add(a,Concatenation("W",String(i)));
  od;
  f:=FreeMonoid(a);

  # translate from fp word to monoid word
  trawo:=function(w)
  local a,i;
    w:=LetterRepAssocWord(w);
    a:=[];
    for i in w do
      if i>0 then
        Add(a,2*i-1); 
      else
        Add(a,-2*i); 
      fi;
    od;
    a:=AssocWordByLetterRep(FamilyObj(One(f)),a);
    return a;
  end;

  trawou:=w->trawo(UnderlyingElement(w));

  lev:=Concatenation(lev,
    ListWithIdenticalEntries(Length(GeneratorsOfMonoid(mons)),Maximum(lev)+1));

  ord:=WreathProductOrdering(f,lev);
  gens:=GeneratorsOfMonoid(f);

  invmap:=[];
  j:=FreeGeneratorsOfFpGroup(gp);
  for i in Concatenation(j,List(j,x->x^-1)) do
    invmap[LetterRepAssocWord(trawo(i))[1]]:=trawo(i^-1);
  od;

  if newstyle then

    weylword:=w->MappedWord(nofow(Image(cs.fphom,w)),
          GeneratorsOfGroup(Range(cs.fphom)),
          GeneratorsOfGroup(gp){[Length(GeneratorsOfGroup(Range(isob)))+1
            ..Length(GeneratorsOfGroup(gp))]});
    borelword:=w->MappedWord(nofob(Image(isob,w)),GeneratorsOfGroup(Range(isob)),
          GeneratorsOfGroup(gp){[1..Length(GeneratorsOfGroup(Range(isob)))]});

    coxrels:=[];
    if Size(ha)>1 then
      for i in Pcgs(ha) do
        a:=[weylword(i),borelword(i)];
        Info(InfoFpGroup,2,"intersection:",a);
        a:=List(a,x->trawou(x));
        addrule(a);
      od;
      b:=IsomorphismFpMonoid(weyl!.epiweyl);
      k:=KnuthBendixRewritingSystem(Range(b));
      MakeConfluent(k);
      for i in Rules(k) do
        a:=List(i,LetterRepAssocWord);
        if ForAll(a,x->ForAll(x,IsOddInt)) then
          #Relation does not involve inverses
          # write with weyl numbers
          a:=List(a,x->List(x,y->(y+1)/2));
          Add(coxrels,a);
        fi;
      od;
    else
      for i in RelationsOfFpMonoid(mons) do
        a:=List(i,LetterRepAssocWord);
        if ForAll(a,x->ForAll(x,IsOddInt)) then
          #Relation does not involve inverses
          # write with weyl numbers
          a:=List(a,x->List(x,y->(y+1)/2));
          Add(coxrels,a);
        fi;
      od;
    fi;

    directerr:=false;
  else

    j:=Intersection(borel,weyl);
    if Size(j)>1 then
      for i in Pcgs(j) do
        a:=[
        MappedWord(Image(cs.fphom,i),GeneratorsOfGroup(Range(cs.fphom)),
          GeneratorsOfGroup(gp){[Length(GeneratorsOfGroup(Range(isob)))+1
            ..Length(GeneratorsOfGroup(gp))]}),
        MappedWord(Image(isob,i),GeneratorsOfGroup(Range(isob)),
          GeneratorsOfGroup(gp){[1..Length(GeneratorsOfGroup(Range(isob)))]})
            ];
        Info(InfoFpGroup,2,"intersection:",a);
        a:=List(a,x->trawo(UnderlyingElement(x)));
        addrule(a);
      od;
    fi;
  fi;

  for i in RelationsOfFpMonoid(monb) do
    addrule(List(i,x->MappedWord(x,FreeGeneratorsOfFpMonoid(monb),
      gens{[1..l]})));
  od;

  for i in RelationsOfFpMonoid(mons) do
    addrule(List(i,x->MappedWord(x,FreeGeneratorsOfFpMonoid(mons),
      gens{[l+1..Length(gens)]})));
  od;
  directerr:=false;

  if newstyle then

    noncomm:=List(wgens,x->[]);
    # To use standard wreath product order, move borel to the right.

    # relations b*w->w*b'
    for i in [1..Length(wgens)] do
      pri:=wgens[i];
      for jj in [1..Length(bgens)] do
        j:=bgens[jj];
        k:=j^pri;
        if k in borel then
          a:=weylword(pri);
          b:=borelword(j);
          k:=borelword(k);
          a:=[b*a,a*k];
          a:=List(a,x->trawou(x));
          addrule(a);
        else
          Add(noncomm[i],jj);
        fi;
      od;
    od;

    noncelm:=List(noncomm,x->Elements(Group(bgens{x})));

    # relations   b*x*w -> x^(b^-1)*reduced(b*w) if xw  does not transform
    for i in [1..Length(wgens)] do
      for jj in Difference(noncelm[i],[One(group)]) do # non-mappable
        for j in [1..Minimum(noncomm[i])-1] do # earlier generators
          a:=weylword(wgens[i]);
          pri:=borelword(bgens[j])*a;
          pri:=reduce(trawou(pri),rels,mytzf); 
          a:=[trawou(borelword(bgens[j])*borelword(jj)*a),
              trawou(borelword(jj^Inverse(bgens[j])))*pri];
          addrule(a);
        od;
      od;
    od;

    # modified coxeter relations with blocking borels in between
    # normalize using bn-pairs
    for pri in coxrels do
      pri:=pri[1];
      a:=List(pri,x->trawou(weylword(wgens[x])));
      for jj in Cartesian(noncelm{pri{[2..Length(pri)]}}) do
        if not ForAll(jj,IsOne) then
          b:=wgens[pri[1]]*Product([1..Length(jj)],x->jj[x]*wgens[pri[x+1]]);
          j:=decomp(b);
          j:=[borelword(j[1]),weylword(j[2]),borelword(j[3])];
          k:=List(jj,x->trawou(borelword(x)));
          b:=a[1]*Product([1..Length(jj)],x->k[x]*a[x+1]);
          j:=j[1]*j[2]*j[3];
          b:=[b,trawou(j)];
          addrule(b);
        fi;
      od;
    od;
  else

    # BN-style reductions
    pcgs:=List(GeneratorsOfGroup(b),x->PreImagesRepresentative(isob,x));
    # remove powers
    pcgs:=pcgs{
      Filtered([1..Length(pcgs)],i->not ForAny([1..i-1],
          j->Order(pcgs[i])=Order(pcgs[j])
            and ForAny([1..Order(pcgs[j])],o->pcgs[j]^o=pcgs[i]))) };
    pcgs:=PcgsByPcSequence(FamilyObj(()),pcgs);

    specialborelreduce:=true;
    wo:=Filtered(w,x->not IsOne(x));
    for i in wo do

      # which elements b*i can we write as i*\tilde b. Then b^i=\tilde b, that
      # is b\in B\cvap B^(i^-1)
      pri:=PreImagesRepresentative(isos,i);
      stb:=Intersection(borel,borel^(pri^-1));
      Info(InfoFpGroup,2,i," ",Size(stb));

      if Size(stb)>1 then 
        can:=CanonicalPcgs(InducedPcgs(pcgs,stb));
        #can:=Filtered(Elements(stb),x->not IsOne(x));
        for j in can do
          #for jj in borel do # Also products borel*stb
          for jj in List(RightTransversal(borel,stb),Inverse) do
            k:=trawo(MappedWord(UnderlyingElement(i),FreeGeneratorsOfFpGroup(w),
              ranw));
            #Print("e.g. ",ImagesRepresentative(isob,jj*j)," => ",
            #        nofob(ImagesRepresentative(isob,jj*j)),"\n");
            a:=[  trawo(MappedWord(UnderlyingElement(
                    nofob(ImagesRepresentative(isob,jj*j))),
                    FreeGeneratorsOfFpGroup(b),ranb))*k,
                trawo(MappedWord(UnderlyingElement(
                    nofob(ImagesRepresentative(isob,jj))),
                    FreeGeneratorsOfFpGroup(b),ranb))*
                k*trawo(MappedWord(UnderlyingElement(
                    nofob(ImagesRepresentative(isob,j^pri))),
                    FreeGeneratorsOfFpGroup(b),ranb))];
            #if not IsLessThanUnder(ord,a[2],a[1]) then Error("ord!");fi;
            #tst:=List(a,LetterRepAssocWord);
            #if not ForAny(rels,x->
            #      PositionSublist(tst[1],LetterRepAssocWord(x[1]))<>fail) then
              addrule(a);
            #fi;
          od;
        od;
      fi;
    od;

    # avoid running through too many elements in borel
    if Size(borel)<100 then borelelm:=AsList(borel);
    else
      a:=Pcgs(borel);
      pri:=RelativeOrders(a);
      k:=[];
      for i in [1..Length(a)] do
        k[i]:=[];
        for j in [0..LogInt(QuoInt(pri[i],2),5)] do
          k[i]:=Union(k[i],5^j*[-2..2]);
        od;
        k[i]:=Intersection(k[i],[-QuoInt(pri[i],2)..QuoInt(pri[i],2)]);
        k[i]:=List(k[i],x->a[i]^x);
      od;
      borelelm:=Set(Cartesian(k),x->Product(x));
    
    fi;

    for i in wo do
      Info(InfoFpGroup,3,"borelrun ",Position(wo,i)," of ",Length(wo));

      # rewrite i*b*j as \tilde b*k*\hat b.
      pri:=PreImagesRepresentative(isos,i);
      stb:=Intersection(borel^pri,borel);

      for j in wo do
        Info(InfoFpGroup,2,"DC:",i,", ",j," from ",Length(rels));
        for k in borelelm do #RightTransversal(borel,stb) do
          a:=PreImagesRepresentative(isos,i)*k*
            PreImagesRepresentative(isos,j);
          a:=decomp(a);
          a:=[nofob(ImagesRepresentative(isob,a[1])),
              nofow(ImagesRepresentative(isos,a[2])),
              nofob(ImagesRepresentative(isob,a[3]))];
          a:=[MappedWord(UnderlyingElement(a[1]),FreeGeneratorsOfFpGroup(b),ranb),
              MappedWord(UnderlyingElement(a[2]),FreeGeneratorsOfFpGroup(w),ranw),
              MappedWord(UnderlyingElement(a[3]),FreeGeneratorsOfFpGroup(b),ranb)
              ];
          a:=List(a,trawo);
          a:=[
          trawo(MappedWord(UnderlyingElement(i),FreeGeneratorsOfFpGroup(w),ranw))
          *trawo(MappedWord(UnderlyingElement(
            nofob(ImagesRepresentative(isob,k))),
            FreeGeneratorsOfFpGroup(b),ranb))*
          trawo(MappedWord(UnderlyingElement(j),FreeGeneratorsOfFpGroup(w),ranw)),
          Product(a)];
          tst:=List(a,LetterRepAssocWord);
          #if ForAny(rels,x->
          #      PositionSublist(tst[1],LetterRepAssocWord(x[1]))<>fail) then
            addrule(a);
          #fi;
        od;
      od;
    od;
  fi;

  # group relators to make sure it's the proper group
  Info(InfoFpGroup,3,"grouprelators");
  for i in RelatorsOfFpGroup(gp) do
    # split in two -- not optimal, want to get minimal offset
    j:=Length(i);
    if IsEvenInt(j) then
      j:=QuoInt(j+1,2);
      a:=[Subword(i,1,j),Subword(i,j+1,Length(i))^-1];
      if a[1]=a[2] then
        a:=[Subword(i,1,j+1),Subword(i,j+2,Length(i))^-1];
      fi;
    else
      j:=QuoInt(j+1,2);
      a:=[Subword(i,1,j),Subword(i,j+1,Length(i))^-1];
    fi;
    a:=List(a,trawo);
    if IsLessThanUnder(ord,a[1],a[2]) then
      a:=Reversed(a);
    fi;
    addrule(a);
  od;

  l:=[];
  for i in FreeGeneratorsOfFpGroup(gp) do
    Add(l,i);
    Add(l,i^-1);
  od;
  tst:=List(rels,x->List(x,w->MappedWord(w,GeneratorsOfMonoid(f),l)));
  tst:=List(tst,x->x[1]/x[2]);
  Assert(2,Size(FreeGroupOfFpGroup(gp)/tst)=Size(group));

  # back-reduce
  Info(InfoFpGroup,3,"backreduce");
  repeat
    jj:=[];
    a:=true;
    i:=1;
    while i<=Length(rels) do
      if IsSubset(borelran,Union(List(rels[i],LetterRepAssocWord))) then
        specialborelreduce:=false;
      fi;
      l:=rels{Difference([1..Length(rels)],[i])};
      mytzf:=maketzf(l);
      tst:=[reduce(rels[i][1],l,mytzf),reduce(rels[i][2],l,mytzf)];
      if tst<>rels[i] then
        Add(jj,i);
        rels:=l; # note that tzf is already set
        if tst[1]<>tst[2] then
          addrule(tst);
        fi;
        a:=false;
        #i:=Length(rels); #just continue
      fi;
      specialborelreduce:=true;
      i:=i+1;
    od;
    Info(InfoFpGroup,2,"rulereduce ",jj);
  until a;

  i:=Length(rels);
  Info(InfoFpGroup,2,"have ",i," rules");
  a:=KnuthBendixRewritingSystem(f/rels,ord);
  MakeConfluent(a);
  Info(InfoFpGroup,1,"confluent RWS ",i," -> ",Length(Rules(a)),"\n");
  b:=f/Rules(a); # make once more for the fp monoid.
  SetReducedConfluentRewritingSystem(b,a);

  l:=[];
  for i in FreeGeneratorsOfFpGroup(gp) do
    Add(l,i);
    Add(l,i^-1);
  od;
  tst:=List(rels,x->List(x,w->MappedWord(w,GeneratorsOfMonoid(f),l)));
  tst:=List(tst,x->x[1]/x[2]);
  #if Size(FreeGroupOfFpGroup(gp)/tst)<>Size(group) then Error("wrong2!");fi;

  b!.rewritingSystem:=a;
  hom:=MagmaIsomorphismByFunctionsNC(gp,b,
      function(w)
        local l,i;
        l:=[];
        for i in LetterRepAssocWord(UnderlyingElement(w)) do
          if i>0 then Add(l,2*i-1);
          else Add(l,-2*i);fi;
        od;
        return ElementOfFpMonoid(FamilyObj(One(b)),
                AssocWordByLetterRep(FamilyObj(One(f)),l));
      end,
      function(w)
        local g,i,x;
        g:=[];
        for i in LetterRepAssocWord(UnderlyingElement(w)) do
          if IsOddInt(i) then x:=(i+1)/2;
          else x:=-i/2;fi;
          # word must be freely cancelled
          if Length(g)>0 and x=-g[Length(g)] then
            Unbind(g[Length(g)]);
          else Add(g,x); fi;
        od;
        return ElementOfFpGroup(FamilyObj(One(gp)),
                AssocWordByLetterRep(FamilyObj(One(FreeGroupOfFpGroup(gp))),g));
      end);
  SetIsomorphismFpMonoid(gp,hom);
  SetIsBijective(hom,true);
  return iso;
end);

# creator function for data in grp/simplrerew.grp -- for documentation
#ConfluentRewritingData:=function(hom)
#local f,miso,lm,mg,l,pre,gens,m,bas,pownum;
#  pownum:=function(w)
#  local l,s,i;
#    l:=LetterRepAssocWord(w);
#    s:=0;
#    for i in [1..Length(l)] do
#      s:=s+l[i]*bas^(i-1);
#    od;
#    return s;
#  end;
#  pre:=DataAboutSimpleGroup(Source(hom));
#  pre:=ShallowCopy(pre.idSimple);
#  if not IsBound(pre.parameter) then pre.parameter:=pre.shortname;fi;
#  f:=Range(hom);
#  miso:=IsomorphismFpMonoid(f);
#  gens:=MappingGeneratorsImages(hom)[2];
#  m:=Range(miso);
#  mg:=List(GeneratorsOfMonoid(m));
#  bas:=Length(mg);
#  l:=[Size(f),pre.series,pre.parameter];
#  if IsBound(pre.shortname) then Add(l,pre.shortname);fi;
#  l:=[l,MappingGeneratorsImages(hom)[1]];
#  Add(l,bas);
#  bas:=bas+1; # need to go one larger, to avoid missing trailing 1's
#  Add(l,List(mg,String));
#  if List(mg,x->LetterRepAssocWord(UnderlyingElement(x)))<>
#    List([1..Length(mg)],x->[x]) then Error("gens!"); fi;
#  pre:=List(mg,x->LetterRepAssocWord(UnderlyingElement(
#    PreImagesRepresentative(miso,x))));
#  if ForAny(pre,x->Length(x)<>1) then Error("double");fi;
#  Add(l,Concatenation(pre));
#  if IsBound(m!.rewritingSystem) then
#    mg:=m!.rewritingSystem;
#    Add(l,LevelsOfGenerators(mg!.ordering));
#  else
#    Add(l,0);
#  fi;
#  Add(l,List(RelationsOfFpMonoid(m),x->List(x,pownum)));
#  return l;
#end;

BindGlobal("BuildRewritingFromData",function(dat)
local bas,fm,fam,mfam,mgens,gens,mrels,rels,i,f,g,m,hom;
  bas:=dat[3]+1;
  fm:=FreeMonoid(dat[4]);
  mfam:=FamilyObj(One(fm));

  f:=Filtered([1..Length(dat[5])],x->dat[5][x]>0);
  f:=FreeGroup(dat[4]{f});
  fam:=FamilyObj(One(f));

  mrels:=[];
  rels:=[];
  for i in dat[7] do
    i:=List(i,x->CoefficientsQadic(x,bas));
    Add(mrels,List(i,x->AssocWordByLetterRep(mfam,x)));
    i:=List(i,x->dat[5]{x});
    # avoid the inverse relations
    if not (Length(i[1])=2 and i[1][1]=-i[1][2]) then
      i:=List(i,x->AssocWordByLetterRep(fam,x));
      Add(rels,i[1]/i[2]);
    fi;
  od;
  m:=fm/mrels;
  if IsList(dat[6]) then
    i:=KnuthBendixRewritingSystem(m,WreathProductOrdering(fm,dat[6]):isconfluent);
    i!.reduced:=true;
    m!.rewritingSystem:=i;
  fi;

  g:=f/rels;
  mgens:=GeneratorsOfMonoid(fm);
  gens:=GeneratorsOfGroup(f);

  MakeFpGroupToMonoidHomType1(g,m);

  hom:=GroupHomomorphismByImagesNC(Group(dat[2]),g,dat[2],GeneratorsOfGroup(g));
  SetIsomorphismFpGroup(Source(hom),hom);
  return hom;
end);


InstallMethod(IsomorphismFpGroupForRewriting,"simple groups: stored",
  [IsSimpleGroup and IsFinite],1,
function(G)
local a,f,iso;

  a:=DataAboutSimpleGroup(G);
  if not IsBound(a.classicalId) 
    or ValueOption(NO_PRECOMPUTED_DATA_OPTION)=true then
    TryNextMethod();
  fi;
  iso:=ShallowCopy(a.idSimple);
  if not IsBound(iso.parameter) then
    iso.parameter:=iso.shortname;
  fi;

  # is it a pre-stored presentation?
  f:=Filename(DirectoriesLibrary("grp"), "simplerew.grp");
  if f<>fail then
    f:=ReadAsFunction(f)();
    f:=First(f,x->x[1][2]=iso.series 
      and x[1][3]=iso.parameter);
    if f<>fail then
      a:=BuildRewritingFromData(f);
      return IsomorphismGroups(G,Source(a))*a;
    fi;
  fi;
  TryNextMethod();
end);

InstallMethod(IsomorphismFpGroupForRewriting,"simple groups: L and C",
  [IsSimpleGroup and IsFinite],0,
function(G)
local d,f,group,act,g,sy,b,c,borel,weyl,a,i,iso,ucs,gens;

  a:=DataAboutSimpleGroup(G);
  if not IsBound(a.classicalId) then
    TryNextMethod();
  fi;

  if a.classicalId.series="L" then
    d:=a.classicalId.parameter[1];
    f:=a.classicalId.parameter[2];

    if d=2 and f=7 then d:=3;f:=2;fi;
    
    group:=PSL(d,f);
    act:=group!.actionHomomorphism;

    # Borel
    g:=Source(act);
    sy:=SylowSubgroup(g,SmallestPrimeDivisor(f));
    b:=Normalizer(g,sy);
    borel:=Image(act,b);

    # Weyl
    weyl:=WeylGroupFp("A",d-1);
    a:=List([1..d-1],x->(x,x+1));
    g:=Group(a,());
    #iso:=GroupHomomorphismByImages(weyl,g,GeneratorsOfGroup(weyl),a);
    #weyl:=g;
    #SetIsomorphismFpGroup(weyl,InverseGeneralMapping(iso));

    a:=List(GeneratorsOfGroup(g),x->PermutationMat(x,d,GF(f)));
    for i in [1..Length(a)] do
      if not IsOne(DeterminantMat(a[i])) then
        a[i][1]:=-a[i][1];
      fi;
    od;
    a:=Group(a);
    a:=Image(act,a);
    a!.epiweyl:=weyl;
    weyl:=a;
    sy:=SylowSubgroup(borel,SmallestPrimeDivisor(f));
    ucs:=Reversed(PCentralSeries(sy));

    gens:=IndependentGeneratorsOfAbelianGroup(Centre(sy));
    gens:=Concatenation(List(gens,x->Filtered(Orbit(weyl,x),x->x in sy)));
    SortBy(gens,x->PositionProperty(ucs,y->x in y));
    a:=gens;
    c:=TrivialSubgroup(sy);
    gens:=[];
    for i in a do
      if not i in c and IsNormal(ClosureGroup(c,i),c) then
        Add(gens,i);
        c:=ClosureGroup(c,i);
      fi;
    od;
    if c<>sy then Error("sylow generators");fi;
    gens:=Reversed(gens);

    if Size(borel)=Size(sy) then
      iso:=SplitBNRewritingPresentation(group,borel,weyl,true);
      return IsomorphismGroups(G,Source(iso))*iso;
    elif IsPrimePowerInt(Index(borel,sy)) then
      gens:=Concatenation(Pcgs(SylowSubgroup(borel,
        SmallestPrimeDivisor(IndexNC(borel,sy)))),gens);
      a:=Group(gens);
      if Size(a)<Size(borel) then Error("wrong");
      else borel:=a;fi;
      iso:=SplitBNRewritingPresentation(group,borel,weyl,true);
      return IsomorphismGroups(G,Source(iso))*iso;
    fi;

  elif a.idSimple.series="C" or
    #B(n,2^m) ~ C(n,2^m)
    (a.idSimple.series="B" and
      SmallestPrimeDivisor(a.classicalId.parameter[2])=2) then
    d:=a.idSimple.parameter[1];
    f:=a.idSimple.parameter[2];
    group:=PSP(2*d,f);
    act:=group!.actionHomomorphism;

    g:=Source(act);
    sy:=SylowSubgroup(g,SmallestPrimeDivisor(f));
    sy:=Image(act,sy);
    borel:=Normalizer(group,sy);

    # Weyl
    weyl:=SymmetricGroup(d);
    a:=[];
    for i in GeneratorsOfGroup(weyl) do
      c:=IdentityMat(2*d,GF(f));
      b:=PermutationMat(i,d,GF(f));
      c{[1..d]}{[1..d]}:=b;
      c{[d+1..2*d]}{[d+1..2*d]}:=Reversed(List(b,Reversed));
      if not IsOne(DeterminantMat(c)) then
        c[1]:=-c[1];
      fi;
      Add(a,c);
    od;
    weyl:=List(a,x->ImagesRepresentative(act,x));
    b:=PermutationMat((d,d+1),2*d,GF(f));
    b[d+1]:=-b[d+1];
    Add(weyl,ImagesRepresentative(act,b));
    weyl:=Group(weyl);
    if group<>ClosureGroup(borel,weyl) then Error("wrong BN");fi;

  else
    TryNextMethod();
  fi;
  iso:=SplitBNRewritingPresentation(group,borel,weyl,false);
  return IsomorphismGroups(G,Source(iso))*iso;
end);

InstallMethod(IsomorphismFpGroupForRewriting,"generic simple",
  [IsSimpleGroup and IsFinite],-1,
function(G)
local p,dat,lev,l,sub,c,s,r,dc;
  # try to find subgroups similar to Borel and Weyl

  dat:=DataAboutSimpleGroup(G);
  if IsBound(dat.idSimple.parameter) and IsList(dat.idSimple.parameter)
     and Length(dat.idSimple.parameter)>1 then
    p:=Factors(dat.idSimple.parameter[2])[1];
    s:=SylowSubgroup(G,p);
    l:=Normalizer(G,s);
    sub:=ComplementClassesRepresentatives(l,s); # torus
    if Length(sub)>0 and Size(sub[1])>1 then
      s:=Normalizer(G,sub[1]);
      r:=ComplementClassesRepresentatives(s,sub[1]);
      if Length(r)>0 then
        s:=r[1];
      fi;
      r:=SplitBNRewritingPresentation(G,l,s,false);
      if r<>fail then return r;fi;
    fi;
  fi;

  lev:=1;
  repeat
    lev:=lev+1;
    l:=LowLayerSubgroups(G,lev);
    l:=Filtered(l,IsSolvableGroup);
  until Length(l)>0;
  SortBy(l,Size);
  l:=l[Length(l)]; # will be "borel"

  dc:=DoubleCosets(G,l,l);

  # small subgroup that will act transitively on the double cosets.
  sub:=ShallowCopy(ConjugacyClassesSubgroups(G));;
  SortBy(sub,x->Size(Representative(x)));

  for c in sub do
    for s in c do
      if Size(Intersection(l,s))=1 and Size(s)>=Length(dc)
        and Size(ClosureGroup(l,s))=Size(G) and 
        Length(Set(Elements(s),
          x->PositionProperty(dc,y->x in y)))=Length(dc) then
        r:=SplitBNRewritingPresentation(G,l,s,false);
        if r<>fail then return r;fi;
      fi;
    od;
  od;

  TryNextMethod();
end);
