Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  recograt.gi   Sprache: unbekannt

 
#############################################################################
##
#W  recograt.gi                 matgrp package               Alexander Hulpke
##
##
#Y  Copyright (C)  2014-18, Alexander Hulpke
##
##  basic setup for matrix fitting free.
##

SetInfoLevel(InfoRecog,0); # recog will print status messages otherwise

# mod to recog -- rings

# newer recog has some changes to these internal APIs
if not IsBound(RIFac) and IsBound(ImageRecogNode) then
  RIFac := ImageRecogNode;
  RIKer := KernelRecogNode;
fi;

if IsBound(BindRecogMethod) then

BindRecogMethod(FindHomMethodsMatrix, "Nonfield",
"catch matrix groups defined over nonfield rings",
function(ri, G)
  if IsBound(ri!.ring) and not IsBound(ri!.field) then
    Error("hereIAm");
  fi;
  return false;
end);

AddMethod( FindHomDbMatrix, FindHomMethodsMatrix.Nonfield, 5100);


else

FindHomMethodsMatrix.Nonfield := function(ri, G)
  if IsBound(ri!.ring) and not IsBound(ri!.field) then
    Error("hereIAm");
  fi;
  return false;
end;

AddMethod( FindHomDbMatrix, FindHomMethodsMatrix.Nonfield,
  5100, "Nonfield",
          "catch matrix groups defined over nonfield rings" );

fi;

OnSubmoduleCosets:=function(cset,g)
local v;
  return [SiftedVector(cset[2],cset[1]*g),cset[2]];
end;

MakeSubmoduleCosetAction:=function(basis)
  return function(vec,g)
    return SiftedVector(basis,vec*g);
  end;
end;

MakeSubmoduleColineAction:=function(basis)
  return function(vec,g)
  local c;
    vec:=SiftedVector(basis,vec*g);
    c:=PositionNonZero(vec);
    if c<=Length(vec) then
      vec := Inverse( vec[c] ) * vec;
    fi;
    return vec;
  end;
end;

FUNCSPACEHASH:=[];
# mod to genss -- use submodules and quotients for base points

MSSFBPC:=function( grp, opt, ii, parentS ) # owf fct to call easily
local F,dim,orb,orbs,i,fct,
mo,cs,j,k,dims,bas,basc,basinv,nb,lastdim,cand,fcand,sel,limit,trysel,submodule;

  trysel:=function(recsub,recfac)
  local lgens;
    # nor the trivial action
    if ForAny(mo,x->Order(x{sel}{sel})>1) then
    Info(InfoFFMat,2,"range ",sel," have ",Length(cand.points));
      lgens:=List(mo,x->x{sel}{sel});
      fcand:=FindBasePointCandidates(Group(lgens),opt,ii,
        false:Subrecurse:=recsub,Facrecurse:=recfac);
      Info( InfoGenSS, 3, "Subfactor module of range ",sel,", ",Length(fcand.ops),
     " candidates");
      for k in [1..Length(fcand.ops)] do
 if ForAll(lgens,x->fcand.ops[k](fcand.points[k],x)=fcand.points[k]) then
   Info(InfoFFMat,2,"Ignoring fixed element for base");

 elif fcand.ops[k]=OnRight or fcand.ops[k]=OnPoints or fcand.ops[k]=OnLines then
   nb:=fcand.points[k]*bas{sel};
   if lastdim=0 then
     # proper subspace -- just vectors
     Add(cand.points,nb);
     Add(cand.ops,fcand.ops[k]);
   elif true then
     # # action on cosets
     submodule:=SemiEchelonBasis(VectorSpace(F,bas{[1..lastdim]},Zero(bas[1])));
     nb:=SiftedVector(submodule,nb);
     if fcand.ops[k]=OnLines then
       fct:=MakeSubmoduleColineAction(submodule);
       Add(FUNCSPACEHASH,[fct,submodule]);
     else
       fct:=MakeSubmoduleCosetAction(submodule);
       Add(FUNCSPACEHASH,[fct,submodule]);
     fi;
     Add(cand.points,nb);
     Add(cand.ops,fct);
   elif Length(sel)=1 then
     # TODO: 1-dim factor -- need to do cosets
     Info(InfoWarning,1,"Case not yet implemented");
   else
     # subfactor -- take subspace preimage
     nb:=OnSubspacesByCanonicalBasis(Concatenation(bas{[1..lastdim]},[nb]),
    One(grp));
     Add(cand.points,nb);
     Add(cand.ops,OnSubspacesByCanonicalBasis);
   fi;
 elif ForAny(FUNCSPACEHASH,x->x[1]=fcand.ops[k]) then
   fct:=First(FUNCSPACEHASH,x->x[1]=fcand.ops[k]);
   submodule:=SemiEchelonBasis(VectorSpace(F,
        Concatenation(bas{[1..lastdim]},
          BasisVectors(fct[2])*bas{sel})));
          Add(cand.points,fcand.points[k]*bas{sel});
   fct:=MakeSubmoduleCosetAction(submodule);
   Add(FUNCSPACEHASH,[fct,submodule]);
          Add(cand.ops,fct);
    Info(InfoFFMat,2,"ACTPOP");
 elif fcand.ops[k]=OnSubspacesByCanonicalBasis then
   nb:=fcand.points[k]*bas{sel};
   nb:=OnSubspacesByCanonicalBasis(Concatenation(bas{[1..lastdim]},nb),
  One(grp));
   Add(cand.points,nb);
   Add(cand.ops,OnSubspacesByCanonicalBasis);
 else
   Info(InfoWarning,1,"Action not recognized");
 fi;
      od;
      return true;
    else
      return false;
    fi;
  end;

  if IsBound(opt.VeryShortOrbLimit) then
    limit:=2*opt.VeryShortOrbLimit;
  else
    limit:=10^4;
  fi;

  F := DefaultFieldOfMatrixGroup(grp);

  # don't bother in small cases
  if Size(F)^Length(One(grp))<=opt.ShortOrbitsOrbLimit then
    TryNextMethod();
  fi;

  cs:=GeneratorsOfGroup(grp);
  if ForAny(cs,IsObjWithMemory) then
    cs:=Concatenation(Filtered(cs,x->not IsObjWithMemory(x)),
           List(Filtered(cs,x->IsObjWithMemory(x)),
         x->x!.el));
  fi;

  cand:=rec(ops:=[],points:=[],used:=0);
  mo:=GModuleByMats(cs,F);
  dim:=mo.dimension;
  if MTX.IsIrreducible(mo) or Size(F)^dim<=limit then
    TryNextMethod();
  fi;

  # build new basis corresponding to comp ser.
  cs:=MTX.BasesCompositionSeries(mo);
  Info(InfoFFMat,2,"dims=",List(cs,Length));
  dims:=List(cs,Length);
  bas:=[];
  basc:=[];
  for j in [2..Length(cs)] do
    nb:=BaseSteinitzVectors(cs[j],basc);
    Append(bas,nb.factorspace);
    basc:=Concatenation(nb.subspace,nb.factorspace);
    Sort(basc,function(a,b) return PositionNonZero(a)<PositionNonZero(b);end);
  od;
  basinv:=bas^-1;

  mo:=List(mo.generators,x->bas*x*basinv);

  # now step up in sizes indicated by short orbit lengths
  lastdim:=0;
  j:=2;
  if ValueOption("Subrecurse")<>false then
    while j<=Length(dims) and Length(cand.points)<=5 do
      # don't bother is the space is too small
      if (j=Length(dims) and lastdim>0) or
 (j<Length(dims) and Size(F)^(dims[j+1]-lastdim)>limit) then
 sel:=[lastdim+1..dims[j]];
 if trysel(false,true) then
   # we tried a space
   lastdim:=dims[j];
 fi;

      fi;

      j:=j+1;
    od;
  fi;

  if lastdim=0 and ValueOption("Facrecurse")<>false then

    # all but last submodule was trivial -- step down on factors
    j:=Length(dims)-1;
    while j>0 and Length(cand.points)<=5 do
      lastdim:=dims[j]-1;
      if (j>1 and Size(F)^(dim-dims[j-1])>limit) then
 sel:=[lastdim+1..dim];
 if trysel(false,false) then
   j:=0;
 fi;
      fi;
      j:=j-1;
    od;

  fi;

  if Length(cand.points)>0 then return cand; fi;

  # refer to parent
  if IsBound(opt.PCand) then
    # try which ones are short
    sel:=[];
    for i in [1..Length(opt.PCand.points)] do
      orb:=[opt.PCand.points[i]];
      mo:=opt.PCand.ops[i];
      orbs:=Set(orb); # as short, set is fine.
      j:=1;
      while j<=Length(orb) and Length(orb)<=limit do
 for k in GeneratorsOfGroup(grp) do
   cs:=mo(orb[j],k);
   if not cs in orbs then
     Add(orb,cs);
     AddSet(orbs,cs);
   fi;
 od;
 j:=j+1;
      od;
      if Length(orb)<=limit then
 Add(sel,i);
 Add(cand.points,orb[1]);
 Add(cand.ops,mo);
      fi;
    od;
    Info(InfoFFMat,2,"Selected ",Length(sel)," of ",Length(opt.PCand.points)," group basis vectors");
    if Length(cand.points)>0 then return cand; fi;
  fi;

  TryNextMethod();
end;

InstallMethod(FindBasePointCandidates,
  "for reducible matrix group over a FF, use submodules and quotients",
  [ IsGroup and IsMatrixGroup and IsFinite, IsRecord, IsInt, IsObject ], 21,
  MSSFBPC);

GetInformationFromRecog:=function(recog)
local treerecurse,n,factors,homs,leafgens,niceranges,genum,sz,leafs,g,
      minranges,mingens,permap,furtherhom,fn,extragens,extranum,extra,allgens,
      nicegp,map,stc,orbit,gd,cnt;

  # the main worker function -- traverse the tree.
  treerecurse:=function(r,h)
  local
  hom,f,k,sel,u,i,j,x,cs,nsol,xf,bigger,nicehom,ngi,stbc,opt,act,ng,dom,v;
    if IsLeaf(r) then
      f:=Length(NiceGens(r));
      Info(InfoFFMat,2,"Leaf",Size(r)," ",genum," ",f);
      k:=[genum+1..genum+f];
      if Size(r)=1 then
 Info(InfoFFMat,2,"ignoring trivial factor");
      elif Length(Set(Factors(Size(r))))<3 then
 Info(InfoFFMat,2,"ignoring solvable factor of order ",Size(r));

 # store info
 n:=n+Length(Factors(Size(r)));
 SetIsSolvableGroup(Grp(r),true);
 permap[n]:=IdentityMapping(Grp(r));
 leafs[n]:=r;
 homs[n]:=h;
 factors[n]:=false;
 sz[n]:=Size(r);
 leafgens[n]:=f;

 sel:=[1..Length(NiceGens(r))];
 mingens[n]:=sel;
 niceranges[n]:=k;
 minranges[n]:=k{sel};

      else
 nicehom:=false;
 if IsPermGroup(Grp(r)) then
   nicehom:=IdentityMapping(Grp(r));
 elif IsBound(r!.stabilizerchain) then
   #use ActionOnOrbit?
   stbc:=BaseStabilizerChain(r!.stabilizerchain);
   act:=stbc.ops[1];
   if ForAll(stbc.ops,x->x=act) then
     # all the same action -- union
     orbit:=[];
     for j in [1..Length(stbc.points)] do
       if not stbc.points[j] in orbit then
  orbit:=Union(orbit,Orbit(Grp(r),stbc.points[j],stbc.ops[j]));
       fi;
     od;
     if Length(orbit)>1 and Length(orbit)<50000 then
       nicehom:=ActionHomomorphism(Grp(r),orbit,stbc.ops[1],"surjective");
       Info(InfoFFMat,2,"Got degree ",Length(orbit));
     fi;
   fi;
 fi;


 if nicehom=false then
# Hasfhmethsel, success method: StabilizerChain

   if IsBound(r!.projective) and r!.projective then
     g:=Grp(r);
     v:=OnLines(g.1[1],One(g));
     dom:=ShallowCopy(Orbit(g,v,OnLines));
     nicehom:=ActionHomomorphism(g,dom,OnLines,"surjective");
     while Size(Image(nicehom))<Size(r) do
       cnt:=0;
       repeat
  v:=OnLines(Random(DefaultFieldOfMatrixGroup(g)^Length(One(g))),
             One(g));
                cnt:=cnt+1;
  if cnt>1000 then Error("no vector found");fi;
       until not v in dom;
       Append(dom,Orbit(g,v,OnLines));
       nicehom:=ActionHomomorphism(g,dom,OnLines,"surjective");
     od;
   else
     nicehom:=IsomorphismPermGroup(Grp(r));
   fi;
 fi;
 g:=Image(nicehom);
 if Size(g)<>Size(r) then
   Error("some discrepancy happened");
 fi;

 #test!!
 # .isknownsimple, .isknownalmostsimple
 if IsBound(r!.comment) and r!.comment[1]<>'_' then
   SetIsSimpleGroup(g,true);
   gd:=g;
 elif not IsSolvableGroup(g) then
   gd:=PerfectResiduum(g);
 else
   gd:=fail;
 fi;

 if gd<>fail then
   if NrMovedPoints(g)> SufficientlySmallDegreeSimpleGroupOrder(Size(gd))
     then
       nicehom:=nicehom*SmallerDegreePermutationRepresentation(g);
       gd:=Image(nicehom);
       Info(InfoFFMat,2,"Improved degree ",NrMovedPoints(g),"->",
         NrMovedPoints(gd));
       if HasIsSimpleGroup(g) and IsSimpleGroup(g) then
  SetIsSimpleGroup(gd,true);
  SetIsSolvableGroup(gd,false);
       fi;
       g:=gd;
   fi;
 fi;

 ## indicate unsolvable
 #nsol:=IsSimpleGroup(g) or
 #  (Length(Set(Factors(Size(r))))>2 and not IsSolvableGroup(g));


 if IsSolvableGroup(g) then
   Info(InfoFFMat,2,"Ignoring solvable factor of order ",Size(g));
     n:=n+Length(Factors(Size(g)));
   elif not IsSimpleGroup(g) then
  Info(InfoFFMat,2,"doing size",Size(g)," ",IsSimpleGroup(g));

   # not simple -- split
   cs:=CompositionSeries(g);
   ng:=List(NiceGens(r),x->ImagesRepresentative(nicehom,x));
   for i in [2..Length(cs)] do
     extra:=[];
     n:=n+1;
     # test generators
     u:=cs[i];
     sel:=[];
     for j in [1..f] do
       x:=ng[j];
       if x in cs[i-1] and not x in u then
  Add(sel,j);
  u:=ClosureSubgroup(u,x);
       fi;
     od;

     nicegp:=Group(ng);
     map:=EpimorphismFromFreeGroup(nicegp);

     if Size(u)<Size(cs[i-1]) then
       Info(InfoFFMat,2,"cannot compatibilize generators -- add extras");
       while Size(u)<Size(cs[i-1]) do
         x:=First(GeneratorsOfGroup(cs[i-1]),x->not x in u);
  u:=ClosureSubgroup(u,x);

  # decompose into word
  xf:=Factorization(nicegp,x);
  if xf=fail then Error("factorization error");fi;
  x:=MappedWord(xf,MappingGeneratorsImages(map)[1],allgens{k});

  extragens[extranum]:=x;
  Add(extra,extranum);
  extranum:=extranum+1;
       od;
     fi;
     hom:=NaturalHomomorphismByNormalSubgroup(cs[i-1],cs[i]);
     if not IsAbelian(Image(hom)) then
       permap[n]:=IsomorphismPermGroup(Image(hom));
     fi;

     fn:=fn+1;
     if Size(cs[i])=1 then
       furtherhom[fn]:=nicehom;
     else
       furtherhom[fn]:=nicehom*hom;
     fi;
     leafs[n]:=false;
     homs[n]:=Concatenation(h,[fn]);
     factors[n]:=Image(hom);
     sz[n]:=Size(Image(hom));
     leafgens[n]:=false;
     niceranges[n]:=false;
     minranges[n]:=Concatenation(k{sel},extra);
   od;

 else
   # found a simple case
   n:=n+1;

   permap[n]:=nicehom;
   # get smaller generating set
   sel:=[];
   u:=TrivialSubgroup(Image(nicehom));
   for i in [1..Length(NiceGens(r))] do
     ngi:=ImagesRepresentative(nicehom,NiceGens(r)[i]);
     if not ngi in u then
       u:=ClosureGroup(u,ngi);
       Add(sel,i);
     fi;
   od;

   leafs[n]:=r;
   homs[n]:=h;
   factors[n]:=g;
   sz[n]:=Size(r);
   leafgens[n]:=f;

   mingens[n]:=sel;
   niceranges[n]:=k;
   minranges[n]:=k{sel};

 fi;

      fi;
      genum:=genum+f;
    else
      #hom:=Homom(r);
      f:=RIFac(r);
      treerecurse(f,Concatenation(h,[1]));
      k:=RIKer(r);
      if k<>fail then
 treerecurse(k,Concatenation(h,[0]));
      fi;
    fi;

  end;

  extragens:=[];
  furtherhom:=[];
  fn:=2;
  n:=0;
  genum:=0;
  factors:=[];
  homs:=[];
  leafgens:=[];
  leafs:=[];
  niceranges:=[];
  minranges:=[];
  mingens:=[];
  sz:=[];
  permap:=[];
  allgens:=NiceGens(recog);

  extranum:=Length(allgens)+1;
  treerecurse(recog,[]);

  return rec(
    group:=Grp(recog),
    n:=n,
    genum:=Length(allgens),
    recog:=recog,
    leafs:=leafs,
    factors:=factors,
    furtherhom:=furtherhom,
    sz:=sz,
    homs:=homs,
    leafgens:=leafgens,
    minranges:=minranges,
    mingens:=mingens,
    extragens:=extragens,
    permap:=permap,
    niceranges:=niceranges);
end;

# assume that hom i can be applied
CSIImageHomNr:=function(csi,n,x)
local r,h,i;
  r:=csi.recog;
  h:=csi.homs[n];
  for i in h do
    if i=0 then
      r:=RIKer(r);
    elif i=1 then
      x:=ImageElm(Homom(r),x);
      r:=RIFac(r);
    else
      x:=ImageElm(csi.furtherhom[i],x);
    fi;
  od;
  return x;
end;

# since nice ranges can contain negatives, we cannot simply sublist
CSINiceGens:=function(csi,a)
  if IsList(a) then
    return List(a,x->CSINiceGens(csi,x));
  elif a<=csi.genum then
    return NiceGens(csi.recog)[a];
  else
    return csi.extragens[a];
  fi;
end;

CSIDepthElm:=function(csi,x)
local i;
  i:=1;
  while i<=csi.n and
   (not IsBound(csi.leafs[i]) or # early skipped multiple solvable factor
   (
   (IsBool(csi.leafs[i]) or not (IsBound(csi.leafs[i]!.projective) and csi.leafs[i]!.projective)
     or csi.leafs[i]!.projective=false)
   and Order(CSIImageHomNr(csi,i,x))=1)
     or
    (not IsBool(csi.leafs[i]) and (IsBound(csi.leafs[i]!.projective) and csi.leafs[i]!.projective) and
    Order(ImagesRepresentative(csi.permap[i],CSIImageHomNr(csi,i,x)))=1)) do
    i:=i+1;
  od;
  return i;
end;

# to test whether an element act trivially projectively, it is not enough to
# test on base, but also need to have sum of base
# elm must be an element that is already image
CSIProjectiveBases:=function(csi,i,elm)
local m;
  if not IsBound(csi.projbases) then
    csi.projbases:=[];
  fi;
  if not IsBound(csi.projbases[i]) then
    m:=ShallowCopy(One(elm));
    Add(m,Sum(m));
    csi.projbases[i]:=m;
  fi;
  return csi.projbases[i];
end;

CSIDepthElm:=function(csi,x)
local i,ximg;
  i:=1;
  while i<=csi.n do
    if not IsBound(csi.leafs[i]) or
      ((IsBool(csi.leafs[i]) or not (IsBound(csi.leafs[i]!.projective)  and csi.leafs[i]!.projective)
 or csi.leafs[i]!.projective=false)
 and Order(CSIImageHomNr(csi,i,x))=1) then
      i:=i+1;
    elif (not IsBool(csi.leafs[i]) and IsBound(csi.leafs[i]!.projective) and
 csi.leafs[i]!.projective) then
      ximg:=CSIImageHomNr(csi,i,x);
      if ForAll(CSIProjectiveBases(csi,i,ximg),z->OnLines(z,ximg)=z) then
 i:=i+1;
      else
 return i;
      fi;
    else
      return i;
    fi;
  od;
  return i;
end;

CSIAelement:=function(a,localgens,l)
local limg,rep;
  limg:=List(l,x->Image(a[2],x));
  rep:= RepresentativeAction(a[1],localgens,limg,OnTuples);
  if rep=fail then
    Error("no rep");
  fi;
  return rep;
end;

FindAct:=function(csi)
local csinice,dci,pool,
act,n,i,j,k,l,gens,lgens,c,d,genims,gp,hom,auts,isoms,pools,poolnum,a,x,
isom,diso,conj,dgp,imgdepth,perms,kn,process,ii,goodgens,conjgens,genimgs,
doesaut,biggens,wrimages,m,w,e,poolimggens,img,localgens,dfgens,wrs,dfimgs,b,perm,lims,map,aels,wrsoc,dfs;


  # get a list of generator images and construct the appropriate element of
  # a[1] inducing these generator images by conjugation
  aels:=[];

  # dci is decomposition information needed for restriction to proper
  # subgroups
  dci:=rec(csi:=csi);


  # isoms[i] An isomorphism from the first group in its pool to group i

  goodgens:=[];
  poolimggens:=[];
  genimgs:=List([1..Maximum(Union(csi.minranges))],x->[]);
  n:=csi.n;
  csinice:=NiceGens(csi.recog);
  act:=[];
  auts:=[];
  pools:=[];
  perms:=[];
  isoms:=[];
  n:=csi.n;

  doesaut:=[];

  process:=[n];
  ii:=1;
  while ii<=n do
    # do we need to feed in another layer?
    if Length(process)<ii then
      Add(process,First([n,n-1..1],x->not x in process));
    fi;
    i:=process[ii];

    if IsBound(csi.permap[i]) and not IsSolvableGroup(Image(csi.permap[i])) then

      if not IsBound(goodgens[i]) then
 # no generators set yet -- just take new ones
 #lgens:=csinice{csi.minranges[i]};
 lgens:=CSINiceGens(csi,csi.minranges[i]);
 goodgens[i]:=lgens;
      else
        lgens:=goodgens[i];
      fi;

      gp:=Image(csi.permap[i]);
      act[i]:=[];
      gens:=List(lgens,x->ImagesRepresentative(csi.permap[i],CSIImageHomNr(csi,i,x)));

#      for x in [1..Length(gens)] do
# j:=CSIImageHomNr(csi,i,csinice[csi.minranges[i][x]]);
# k:=Image(csi.permap[i],j);
# if k<>gens[x] then
#   Error("GENS");
# fi;
#      od;

      # nonsolvable factor -- Is it in pools?
      poolnum:=First([1..Length(pools)],x->i in pools[x]);
      # pools will always be joined TO the current one, so isom will not
      # have to change on the way.
      if poolnum=fail then
 Add(pools,[i]);
 poolnum:=Length(pools);
 auts[poolnum]:=[];
 isoms[i]:=false; # representative
 isom:=IdentityMapping(gp);
 Add(poolimggens,gens);
      elif i<>pools[poolnum][1] then
 isom:=isoms[i]; # iso
      else
 isom:=IdentityMapping(gp); # first one -- iso is trivial
      fi;

      #find out what the previous factors do on it
      for j in Filtered([1..i-1],x->IsBound(csi.minranges[x])) do
 Info(InfoFFMat,2,"Try ",i," mapped by ",j);

 for kn in csi.minranges[j] do
   #k:=csinice[kn];
   k:=CSINiceGens(csi,kn);
   if not IsBound(perms[kn]) then
     perms[kn]:=[];
     genimgs[kn]:=[];
     doesaut[kn]:=[];
   fi;

   conjgens:=[];
   genims:=[];
   imgdepth:=fail;
   # calculate images
   for l in lgens do
     c:=l^k; # conjugate
     Add(conjgens,c);
     d:=CSIDepthElm(csi,c);
     if imgdepth=fail then
       # new image -- isomorphism
       imgdepth:=d;
       perms[kn][i]:=d; # record permutations
     elif imgdepth<>d then
       # this cannot happen
       Error("incompatible depths");
     fi;
     Add(genims,ImagesRepresentative(csi.permap[d],CSIImageHomNr(csi,d,c)));
   od;

   dgp:=Image(csi.permap[d]);
   if AssertionLevel()>2 then
     hom:=GroupHomomorphismByImages(gp,dgp,gens,genims);
   else
     hom:=GroupHomomorphismByImagesNC(gp,dgp,gens,genims);
   fi;
   if hom=fail then Error("should not happen");fi;

   if d=i then
     # pull generator images back in original group
     genimgs[kn][i]:=List(genims,x->PreImagesRepresentativeNC(isom,x));

#if ForAny(Flat(genimgs),x->not x in Image(csi.permap[pools[poolnum][1]])) then
#  Error("imerrD");
#fi;

     # component is not moved we just need to conjugate with isom
     hom:=isom*hom*InverseGeneralMapping(isom);
   SetIsBijective(hom,true);
     if not IsInnerAutomorphism(hom) then
       Add(auts[poolnum],hom);
       AddSet(doesaut[kn],i);
     elif not IsOne(hom) then
       # not automorphism, but still acting
       AddSet(doesaut[kn],i);
     fi;
   elif d in pools[poolnum] then
     # we know already that the groups are isomorphic -- just store
     # the new automorphism

     # isomorphism is always to the first element in the pool
     if d=pools[poolnum][1] then
       # the group is the normal form -- we do not need to translate
       diso:=IdentityMapping(dgp);
     else
       # isomorphism to canonical form
       diso:=InverseGeneralMapping(isoms[d]);
     fi;
     genimgs[kn][i]:=List(genims,x->ImagesRepresentative(diso,x));

# if ForAny(Flat(genimgs),x->not x in Image(csi.permap[pools[poolnum][1]])) then
#   Error("imerrC");
# fi;
     hom:=isom*hom*diso;
   SetIsBijective(hom,true);
     if not IsInnerAutomorphism(hom) then
       Add(auts[poolnum],hom);
       AddSet(doesaut[kn],i);
     fi;
   else
     # isomorphism wasn't known yet -- we need to join pools
     # hom is the joiner, isom*hom*isoms[d]^-1 the conjugator of the
     # canonical map

     # the pool we add. We always join the image pool to the current
     # one.
     a:=First([1..Length(pools)],x->d in pools[x]);
     if a=fail then
       # we did not yet know layer d -- add it
              Info(InfoFFMat,2,"Found Layer ",d);
       Add(pools[poolnum],d);
       isoms[d]:=isom*hom;
              Assert(3,IsBijective(isoms[d]));
       # newly included component -- the generators *are* simply the
       # images
       genimgs[kn][i]:=List(genims,
         x->PreImagesRepresentativeNC(isoms[d],x));

#if ForAny(Flat(genimgs),x->not x in Image(csi.permap[pools[poolnum][1]])) then
  #Error("imerrB");
#fi;
       goodgens[d]:=conjgens;
       Add(process,d);
     else
       Error("This cannot happen??");
       # we knew the layer and join pools
       Info(InfoFFMat,2,"Join ",pools[a]," to ",pools[poolnum]);
       conj:=isom*hom;
       if not d=pools[a][1] then
  # translate to normal form
  conj:=conj*InverseGeneralMapping(isoms[d]);
       fi;

       # join pools
       for x in pools[a] do
  Add(pools[poolnum],x);
  isoms[x]:=conj*isoms[x]; # reroot isomorphism
       od;

       # translate automorphisms
       for x in auts[a] do
  Add(auts[poolnum],conj*x*InverseGeneralMapping(conj));
       od;

       # delete old
       pools[a]:=[];
       auts[a]:=[];
     fi;
   fi;
 od;
      od;
    fi;
    ii:=ii+1;
  od;

  wrs:=[];
  wrsoc:=[];
  dfgens:=[];
  dfimgs:=[];

#if ForAny(Flat(genimgs),x->not x in Image(csi.permap[pools[poolnum][1]])) then
#  Error("imerrA");
#fi;

  if Length(pools)=0 then
    # solvable
    d:=Group(());
    a:=GeneratorsOfGroup(csi.group);
    b:=List(a,x->One(d));
    RUN_IN_GGMBI:=true; # hack to skip Nice treatment
    hom:=GroupHomomorphismByImagesNC(csi.group,d,a,b);
    RUN_IN_GGMBI:=false;
    dci:=rec(isTrivial:=true);
    SetRecogDecompinfoHomomorphism(hom,dci);
    SetImagesSource(hom,Group(()));
    return hom;
  fi;

  dci.pools:=pools;
  dci.wreathemb:=[];
  dci.goodgens:=goodgens;
  dci.isoms:=isoms;
  dci.poollocalgens:=[];

  # now build each group
  for i in [1..Length(pools)] do
    pool:=pools[i];
    m:=Length(pools[i]);
    a:=Image(csi.permap[pools[i][1]]);
    a:=[a,Concatenation(auts[i],
     List(GeneratorsOfGroup(a),x->InnerAutomorphism(a,x)))];
    a:=AutomorphismRepresentingGroup(a[1],a[2]);
    aels[i]:=a;
    localgens:=List(poolimggens[i],x->Image(a[2],x));
    dci.poollocalgens[i]:=localgens;
    b:=SymmetricGroup(m);
    w:=WreathProduct(a[1],b);
    e:=List([1..m+1],x->Embedding(w,x));
    dci.wreathemb[i]:=e;
    biggens:=[];
    wrimages:=[];

    for j in Filtered([1..n],x->IsBound(csi.minranges[x])) do
      c:=csi.minranges[j];
    Info(InfoFFMat,2,"Images for ",j," ",c);

      # does any of the elements actually do something -- if so, what?

#      if true or ForAny(c,x->IsBound(doesaut[x])
#        and ForAny(pools[i],y->y in doesaut[x])) then
        Info(InfoFFMat,2,c," acts ",pools[i],j);
 for kn in c do
   #Add(biggens,csinice[kn]);
   Add(biggens,CSINiceGens(csi,kn));
   img:=One(w);
   for l in [1..Length(pools[i])] do
            if IsBound(genimgs[kn][pools[i][l]]) then
       d:=Image(e[l],CSIAelement(a,localgens,genimgs[kn][pools[i][l]]));
     else
       if pools[i][l]=j then
  d:=List(goodgens[pools[i][l]],
   x->ImagesRepresentative(csi.permap[pools[i][l]],
     CSIImageHomNr(csi,pools[i][l],x^CSINiceGens(csi,kn))));
  if isoms[j]<>false then
    d:=List(d,x->PreImagesRepresentativeNC(isoms[j],x));
  fi;
  d:=Image(e[l],CSIAelement(a,localgens,d));
       else
  # component is not acted on as it lies higher
  d:=One(a[1]);
       fi;
     fi;
     img:=img*d;
   od;
   # is it a nontrivial permutation
   if IsBound(perms[kn]) and ForAny([1..Length(perms[kn])],
     x->IsBound(perms[kn][x]) and perms[kn][x]<>x) then
     # fill up fixed points
     for d in pool do
       if not IsBound(perms[kn][d]) then perms[kn][d]:=d;fi;
     od;

     # permuting part
     d:=PermList(List(perms[kn]{pool},x->Position(pool,x)));
     img:=img*Image(e[Length(pool)+1],d);
   fi;

   Add(wrimages,img);
 od;

    od;
    Add(wrs,w);
    a:=List([1..m],x->PerfectResiduum(Image(Embedding(w,x))));
    b:=TrivialSubgroup(w);
    for l in a do
      b:=ClosureGroup(b,l);
    od;
    SetDirectFactorsFittingFreeSocle(w,a);
    Add(wrsoc,b); # socle
    Add(dfgens,biggens);
    Add(dfimgs,wrimages);
  od;

  d:=DirectProduct(wrs);
  dci.dirprod:=d;
  dci.embeddings:=List([1..Length(pools)],x->Embedding(d,x));
  dci.aels:=aels;
  a:=List([1..Length(pools)],x->List(DirectFactorsFittingFreeSocle(wrs[x]),
    y->Image(dci.embeddings[x],y)));
  dfs:=Concatenation(a);
  SetDirectFactorsFittingFreeSocle(d,dfs);
  a:=dfgens[1];
  b:=List(a,x->One(d));
  w:=TrivialSubgroup(d);
  for i in [1..Length(pools)] do
    e:=dci.embeddings[i];
    w:=ClosureGroup(w,Image(e,GeneratorsOfGroup(wrsoc[i])));
    for j in [1..Length(a)] do
      Assert(1,dfgens[i][j]=a[j]);

      b[j]:=b[j]*Image(e,dfimgs[i][j]);
    od;
  od;

  if IsPermGroup(csi.group) and AssertionLevel()>2 then
    hom:=GroupHomomorphismByImages(csi.group,d,a,b);
  else
    RUN_IN_GGMBI:=true; # hack to skip Nice treatment
    hom:=GroupHomomorphismByImagesNC(csi.group,d,a,b);
    RUN_IN_GGMBI:=false;
  fi;
  if hom=fail then
    Error("fail!");
  fi;
  b:=Subgroup(d,b);
  #SetSocle(b,w);
  dci.socle:=w;
  dfs:=Filtered(dfs,x->IsSubset(b,x));
  SetDirectFactorsFittingFreeSocle(w,dfs);
  SetDirectFactorsFittingFreeSocle(b,dfs);
  SetImagesSource(hom,b);
  SetRecogDecompinfoHomomorphism(hom,dci);
  return hom;

end;


CSIElementAct:=function(dci,elm)
local csi,pools,result,i,e,a,img,b,dp,d,kn,perm,l;
  csi:=dci.csi;
  pools:=dci.pools;
  result:=One(dci.dirprod);
  for i in [1..Length(pools)] do
    e:=dci.wreathemb[i];
    a:=dci.aels[i];
    img:=One(Image(e[1]));
    perm:=[];
    for l in [1..Length(pools[i])] do
      b:=List(dci.goodgens[pools[i][l]],x->x^elm);
      dp:=CSIDepthElm(csi,b[1]);
      Assert(2,ForAll(b,x->CSIDepthElm(csi,x)=dp));
      perm[l]:=Position(pools[i],dp);

      d:=List(dci.goodgens[pools[i][l]],
       x->ImagesRepresentative(csi.permap[dp],
  CSIImageHomNr(csi,dp,x^elm)));
      if dci.isoms[dp]<>false then
 d:=List(d,x->PreImagesRepresentativeNC(dci.isoms[dp],x));
      fi;
      d:=Image(e[l],CSIAelement(a,dci.poollocalgens[i],d));
      img:=img*d;
    od;

    # permuting part
    d:=PermList(perm);
    img:=img*Image(e[Length(pools[i])+1],d);
    result:=result*Image(dci.embeddings[i],img);

  od;
  return result;
end;

#############################################################################
##
#M  ImagesRepresentative(<hom>,<x>)
##
InstallMethod(ImagesRepresentative,"for recognition mappings",
        FamSourceEqFamElm,
  [ IsGroupGeneralMapping and
  HasRecogDecompinfoHomomorphism,IsMultiplicativeElementWithInverse], 0,
function(hom, x)
local d;
  d:=RecogDecompinfoHomomorphism(hom);
  if IsBound(d.isTrivial) then return ();fi;
  if IsBound(d.fct) then
    return d.fct(x);
  else
    return CSIElementAct(RecogDecompinfoHomomorphism(hom),x);
  fi;
end);

#############################################################################
##
#M  PreImagesSetNC(<hom>,<x>)
##
InstallMethod(PreImagesSetNC,"for recognition mappings", CollFamRangeEqFamElms,
  [ IsGroupGeneralMapping and
  HasRecogDecompinfoHomomorphism,IsGroup], 0,
function(hom, U)
local gens,pre;
  gens:=SmallGeneratingSet(U);
  pre:=List(gens,x->PreImagesRepresentativeNC(hom,x));
  U:=RecogDecompinfoHomomorphism(hom).LiftSetup;
  U:=SubgroupByFittingFreeData(Source(hom),pre,gens,U.pcgs);
  return U;
end);


#TODO: Detect Nonsolvable permuters (via perms) and leave out of pool

BasePointsActionsOrbitLengthsStabilizerChain:=function(c)
local l,o;
  l:=[];
  while c<>false do
    o:=c!.orb;
    Add(l,[o!.orbit[1],o!.op,Length(o!.orbit)]);
    c:=c!.stab;
  od;
  return l;
end;


FactorspaceActfun:=function(field,bas)
local heads;
  bas:=TriangulizedMat(bas);
  heads:=HeadsInfoOfSemiEchelonizedMat(bas,Length(bas[1]));
  return function(v,g)
    local c;
    v:=v*g;
    v:=SiftedVectorForGaussianRowSpace(field,bas, heads, v );
    c:=PositionNonZero(v);
    if c<=Length(v) then
      v:=Inverse(v[c])*v;
    fi;
    MakeImmutable(v);
    return v;
  end;
end;

INVTRANSPCACHE:=[];
AsInverseTranspose:=function(x,g)
local a,p;
  a:=fail;
  p:=0;
  while a=fail and p<Length(INVTRANSPCACHE) do
    p:=p+1;
    if IsIdenticalObj(INVTRANSPCACHE[p][1],g) then
      a:=INVTRANSPCACHE[p][2];
      if p>50 then
 p:=Concatenation([p],[1..p-1],[p+1..Length(INVTRANSPCACHE)]);
        INVTRANSPCACHE:=INVTRANSPCACHE{p};
      fi;
    fi;
  od;
  if a=fail then
    a:=TransposedMat(Inverse(g));
    if Length(INVTRANSPCACHE)>100 then
      # clean out old
      INVTRANSPCACHE:=Concatenation([[g,a]],INVTRANSPCACHE{[1..90]});
    else
      INVTRANSPCACHE:=Concatenation([[g,a]],INVTRANSPCACHE);
    fi;
  fi;
  return OnRight(x,a);
end;


ModuleStructureBase:=function(mats)
local orbtranslimit,f,total,gens,mo,bas,basn,dims,a,p,vec,orb,t,dict,use,fct,
    new,alt,g,pnt,limit,whole,siftchain,sub,b,trymultipleorbits;

  orbtranslimit:=function(vec,fct,limit)
  local dict,orb,t,pnt,g,img,p,coinc;
    dict:=NewDictionary(vec,true,f^Length(vec));
    orb:=[vec];
    AddDictionary(dict,vec,1);
    t:=[One(gens[1])];
    pnt:=1;
    coinc:=true;
    while pnt<=Length(orb) do
      for g in gens do
 img:=fct(orb[pnt],g);
 p:=LookupDictionary(dict,img);
 if p=fail then
   Add(orb,img);
   if Length(orb)>limit then
     return fail;
   fi;
   AddDictionary(dict,img,Length(orb));
   Add(t,t[pnt]*g);
 elif coinc then
   coinc:=false;
 fi;
      od;
      pnt:=pnt+1;
    od;
    return [dict,orb,t];
  end;

  trymultipleorbits:=function(seeds,fct,limit)
  local best,bestl,bestc,i,orb;
    best:=fail;
    bestl:=0;
    bestc:=0;
    for i in seeds do
      # form orbit with possible initial canonization
      orb:=orbtranslimit(fct(i,One(gens[1])),fct,limit);
      if orb<>fail and Length(orb[2])>1 then
        if Length(orb[2])>bestl then
   best:=orb;
   bestl:=Length(orb[2]);
   bestc:=1;
   if bestl>100 then
     return best;
   fi;
        else
   bestc:=bestc+1;
   # if we got 30 times the same length then use it.
   if bestc>30 then
     return best;
   fi;
 fi;
      elif bestl>0 then
 # we found at least one and others failed
        return best;
      fi;
    od;
    return best;
  end;

  siftchain:=function(use,x)
  local i,img,u;
    i:=1;
    for u in use do
      img:=u.fct(u.vec,x);
      img:=LookupDictionary(u.dict,img);
      if img=fail then
        return [fail,i,x];
      fi;
      x:=x/u.t[img];
      i:=i+1;
    od;
    return x;
  end;

  limit:=1000;

  whole:=Group(mats);
  f:=FieldOfMatrixList(mats);
  total:=1;
  gens:=mats;
  mo:=GModuleByMats(gens,f);
  bas:=MTX.BasesCompositionSeries(mo);
  dims:=List(bas,Length);
  if ForAll([2..Length(bas)],x->IsSubset(bas[x],bas[x-1])) then
    basn:=List([2..Length(bas)],x->Filtered(bas[x],y->not y in bas[x-1]));
    bas:=Concatenation(basn);
  else
    a:=ShallowCopy(bas[2]); # 1 is empty
    p:=3;
    while p<=Length(bas) do
      t:=Difference(bas[p],a);
      t:=Difference(t,bas[p-1]);
      repeat
        vec:=List([1..Length(bas[p])-Length(bas[p-1])],x->Random(t));
      until RankMat(Concatenation(a,vec))=Length(bas[p]);
      a:=Concatenation(a,vec);
      p:=p+1;
    od;
    bas:=a;
  fi;
  use:=[];

  while Length(gens)>0 do
    basn:=List(bas,x->OnLines(x,One(gens[1])));
    p:=PositionProperty(basn,x->ForAny(gens,y->OnLines(x,y)<>x));
    if p=fail then
      p:=PositionProperty(bas,x->ForAny(gens,y->x*y<>x));
      vec:=bas{[p..Minimum(p+10,Length(bas))]};
      fct:=OnRight;
    elif Size(f)^p<limit then
      p:=PositionProperty(dims,x->Size(f)^x>limit);
      if p=fail then
        p:=Length(dims);
      else
        p:=p-1;
      fi;
      orb:=OrbitsDomain(Group(gens),NormedRowVectors(VectorSpace(f,bas{[1..dims[p]]},Zero(bas[1]))),OnLines);
      orb:=Filtered(orb,x->Length(x)>1);
      Sort(orb,function(a,b) return Length(a)>Length(b);end);
      vec:=List(orb,x->x[1]);
      fct:=OnLines;
    else
      vec:=bas{[p..Minimum(p+10,Length(bas))]};
      fct:=OnLines;
    fi;

    # nontrivial orbit
    orb:=trymultipleorbits(vec,fct,limit);
    if orb=fail then
      b:=p;

      a:=Reversed(Filtered(dims,x->x<b));
      p:=fail;
      while p=fail and a[1]<>0 do
 sub:=a[1];
 fct:=FactorspaceActfun(f,bas{[1..sub]});
 basn:=List(bas,x->fct(x,One(gens[1])));
 p:=Filtered([a[1]+1..Minimum(a[1]+10,Length(bas))],
       x->ForAny(gens,y->fct(basn[x],y)<>basn[x]));
 if p=[] then
   p:=Filtered([a[1]+10..Length(bas)],
         x->ForAny(gens,y->fct(basn[x],y)<>basn[x]));
 fi;
 if p=[] then
   p:=fail;
 else
   # try to find one with orbit not just length p but also not too
   # large
   p:=Reversed(p);
   while Length(p)>1 and Size(f)^(p[1]-a[1])/(Size(f)-1)>limit do
     p:=p{[2..Length(p)]};
   od;
   p:=p[1];
 fi;
 a:=a{[2..Length(a)]};
      od;
      if p<>fail then
 orb:=trymultipleorbits(bas{[p..Minimum(p+10,Length(bas))]},fct,limit);
 if orb=fail then
   # try dual action
   fct:=AsInverseTranspose;
   p:=First([b..Length(bas)],x->ForAny(gens,y->fct(bas[x],y)<>bas[x]));
   if p<>fail then
     p:=[p];
     for orb in [1..5] do
       Add(p,p[1]+orb);
       Add(p,p[1]-orb);
     od;
     p:=Filtered(p,x->x>0 and x<Length(bas));
     orb:=trymultipleorbits(bas{p},fct,limit);
   fi;
   if orb=fail then
     Info(InfoFFMat,2,"even too long in dual");
     return rec(points:=[],ops:=[]);
   else
     Info(InfoFFMat,2,"dual ");
   fi;
 else
   Info(InfoFFMat,2,"factor space ");
 fi;
      else
 return rec(points:=[],ops:=[]);
 Error("p=fail -- should not happen");
      fi;

    fi;

    dict:=orb[1];
    t:=orb[3];
    orb:=orb[2];
    vec:=orb[1];
    Info(InfoFFMat,2,"got Length ",Length(orb),":",
      Collected(Factors(total*Length(orb))));

    Add(use,rec(vec:=vec,fct:=fct,orb:=orb,dict:=dict,t:=t,gens:=gens));

    #sift 20 random elements
    new:=[];
    p:=Maximum(Minimum(1000,Length(orb)*Length(gens)),10);
    alt:=0;
    a:=fail;
    while a=fail and Length(new)<20 and alt<p do
      a:=PseudoRandom(whole);
      a:=siftchain(use,a);
      alt:=alt+1;
      if a[1]<>fail then
 if fct(vec,a)<>vec then
   Error("not stab");
 fi;
        if not IsOne(a) and not a in new then
   Add(new,a);
   alt:=0;
 fi;
        a:=fail; # sifted through
      fi;
    od;

    if a<>fail then
      gens:=ShallowCopy(use[a[2]].gens);
      Add(gens,a[3]);
      use:=use{[1..a[2]-1]};
      total:=Product(List(use,x->Length(x.orb)));
      Info(InfoFFMat,2,"construction fail on level ",a[2]," of ",Length(use),
        " -- redo ",total);
    else
      total:=total*Length(orb);
      gens:=new;
    fi;

  od;
  return rec(points:=List(use,x->x.vec),ops:=List(use,x->x.fct),
             order:=total);
end;

MATGRP_AddGeneratorToStabilizerChain:="2bdefined";

MATGRP_StabilizerChainInner:=
  function( gens, size, layer, cand, opt, parentS )
    # Computes a stabilizer chain for the group generated by gens
    # with known size size (can be false if not known). This will be
    # layer layer in the final stabilizer chain. cand is a (shared)
    # record for base point candidates and opt the (shared) option
    # record. This is called in StabilizerChain and calls itself.
    # It also can be called if a new layer is needed.
    local base,gen,S,i,merk,merk2,next,pr,r,stabgens,x;

    Info(InfoGenSS,4,"Entering MATGRP_StabilizerChainInner layer=",layer);
    next:=rec(point:=cand.points[1],op:=cand.ops[1]);
    #next := GENSS_NextBasePoint(gens,cand,opt,parentS);
    #cand := next.cand;   # This could have changed

    S := GENSS_CreateStabChainRecord(parentS,gens,size,
                                     next.point,next.op,cand,opt);
    base := S!.base;

    Info( InfoGenSS, 3, "Entering orbit enumeration layer ",layer,"..." );
    repeat
        Enumerate(S!.orb,opt.OrbitLengthLimit);
        if not(IsClosed(S!.orb)) then
            if opt.FailInsteadOfError then
                return "Orbit too long, increase opt.OrbitLengthLimit";
            else
                Error("Orbit too long, increase opt.OrbitLengthLimit");
            fi;
        fi;
    until IsClosed(S!.orb);
    Info(InfoGenSS, 2, "Layer ", layer, ": Orbit length is ", Length(S!.orb));

    if layer > 1 then
        parentS!.stab := S;   # such that from now on random element
                              # generation works!
    else
        if (Length(S!.orb) > 50 or S!.orb!.depth > 5) and
           S!.opt.OrbitsWithLog then
            Error("ARGH!");
            Info(InfoGenSS, 3, "Trying to make Schreier tree shallower (depth=",
                 S!.orb!.depth,")...");
            merk := Length(S!.orb!.gens);
            merk2 := Length(S!.stronggens);
            MakeSchreierTreeShallow(S!.orb);
            Append(S!.stronggens,S!.orb!.gens{[merk+1..Length(S!.orb!.gens)]});
            Append(S!.layergens,[merk2+1..Length(S!.stronggens)]);
            Info(InfoGenSS, 3, "Depth is now ",S!.orb!.depth);
        fi;
    fi;
    S!.orb!.gensi := List(S!.orb!.gens,x->x^-1);

    # as we add normalizing, we are done
    return S;

    # Are we done?
    if size <> false and Length(S!.orb) = size then
        S!.proof := true;
        Info(InfoGenSS,4,"Leaving MATGRP_StabilizerChainInner layer=",layer);
        return S;
    fi;

    # Now create a few random stabilizer elements:
    stabgens := EmptyPlist(opt.RandomStabGens);
    for i in [1..opt.RandomStabGens] do
        x := GENSS_RandomElementFromAbove(S,layer);
        if not(S!.IsOne(x)) then
            Add(stabgens,x);
        fi;
    od;
    Info(InfoGenSS,3,"Created ",opt.RandomStabGens,
         " random stab els, ",
         Length(stabgens)," non-trivial.");

    if Length(stabgens) > 0 then   # there is a non-trivial stabiliser
        Info(InfoGenSS,3,"Found ",Length(stabgens)," non-trivial ones.");
        if size <> false then
            S!.stab := MATGRP_StabilizerChainInner(stabgens,size/Length(S!.orb),
                                                   layer+1,cand,opt,S);
        else
            S!.stab := MATGRP_StabilizerChainInner(stabgens,false,
                                                   layer+1,cand,opt,S);
        fi;
        if IsString(S!.stab) then return S!.stab; fi;
        if opt.ImmediateVerificationElements > 0 then
            Info(InfoGenSS,2,"Doing immediate verification in layer ",
                 S!.layer," (",opt.ImmediateVerificationElements,
                 " elements)...");
            i := 0;
            while i < opt.ImmediateVerificationElements do
                i := i + 1;
                x := GENSS_RandomElementFromAbove(S,layer);
                if MATGRP_AddGeneratorToStabilizerChain(S!.topS,x) then
                    Info( InfoGenSS, 2, "Immediate verification found error ",
                          "(layer ",S!.layer,")..." );
                    i := 0;
                fi;
            od;
        fi;

        S!.proof := S!.stab!.proof;   # hand up information
    else
        # We are not sure that the next stabiliser is trivial, but we believe!
        Info(InfoGenSS,3,"Found no non-trivial ones.");
        S!.proof := false;
    fi;

    Info(InfoGenSS,4,"Leaving MATGRP_StabilizerChainInner layer=",layer);
    return S;
  end;


MATGRP_AddGeneratorToStabilizerChain:=
  function( S, el,pt,op )
    # Increases the set represented by S by the generator el.
    local SS, r, n, pr, i, newstrongnr;
    if IsBound(S!.trivialgroup) and S!.trivialgroup then
        if S!.IsOne(el) then
            return false;
        fi;
        #SS := StabilizerChain(Group(el),S!.opt);
 SS:=StabilizerChain(Group(el),rec(Cand:=rec(ops:=[op],points:=[pt]),Reduced:=false,StrictlyUseCandidates:=true));

        if IsString(SS) then return SS; fi;
        for n in NamesOfComponents(SS) do
            S!.(n) := SS!.(n);
        od;
        Unbind(S!.trivialgroup);
        return true;
    fi;

    r := SiftGroupElement( S, el );
    # if this is one then el is already contained in the stabilizer chain
    if r.isone then     # already in the group!
        return false;
    fi;
    # Now there remain two cases:
    #  (1) the sift stopped somewhere and we have to add a generator there
    #  (2) the sift ran all through the chain and the element still was not
    #      the identity, then we have to prolong the chain
    if r.S <> false then   # case (1)
        SS := r.S;
        Info( InfoGenSS, 2, "Adding new generator to stab. chain ",
              "in layer ", SS!.layer, " from ",Length(SS!.stronggens) );
        Add(SS!.stronggens,r.rem);
        Add(SS!.layergens,Length(SS!.stronggens));
        AddGeneratorsToOrbit(SS!.orb,[r.rem]);
        Add(SS!.orb!.gensi,r.rem^-1);
        newstrongnr := Length(SS!.stronggens);
        Info( InfoGenSS, 4, "Entering orbit enumeration layer ",SS!.layer,
              "..." );
        repeat
            Enumerate(SS!.orb,S!.opt.OrbitLengthLimit);
            if not(IsClosed(SS!.orb)) then
                if S!.opt.FailInsteadOfError then
                    return "Orbit too long, increase S!.opt.OrbitLengthLimit";
                else
                    Error("Orbit too long, increase S!.opt.OrbitLengthLimit!");
                fi;
            fi;
        until IsClosed(SS!.orb);
        Info( InfoGenSS, 4, "Done orbit enumeration layer ",SS!.layer,"..." );
        SS!.proof := false;
    else   # case (2)
        # Note that we do not create a pr instance here for one
        # generator, this will be done later on as needed...
        SS := r.preS;
        newstrongnr := Length(SS!.stronggens)+1;  # r.rem will end up there !
        SS!.stab := MATGRP_StabilizerChainInner([r.rem],false,
                           SS!.layer+1,rec(points:=[pt],ops:=[op]), SS!.opt, SS );
        if IsString(SS!.stab) then return SS!.stab; fi;
        SS := SS!.stab;
    fi;
    # Now we have added a new generator (or a new layer) at layer SS,
    # the new gen came from layer S (we were called here, after all),
    # thus we have to check, whether all the orbits between S (inclusively)
    # and SS (exclusively) are also closed under the new generator r.rem,
    # we add it to all these orbits, thereby also making the Schreier trees
    # shallower:
    while S!.layer < SS!.layer do
        Info(InfoGenSS,2,"Adding new generator to orbit in layer ",S!.layer);
        Add(S!.layergens,newstrongnr);
        AddGeneratorsToOrbit(S!.orb,[r.rem]);
        Add(S!.orb!.gensi,r.rem^-1);
        S := S!.stab;
    od;
    # Finally, we have to add it to the product replacer!
    AddGeneratorToProductReplacer(S!.opt!.pr,r.rem);
    return true;
  end;


SolvableBSGS:=function(arg)
local CBase, normalizingGenerator,df,ops,firstmoved,i,
solvNC,S,pcgs,x,r,c,w,a,bound,U,xp,depths,oldsz,prime,relord,gens,acter,ogens,stabs,n,strongs,stronglevs,laynums,slvec,layerzero,p,laynum,layers,sel,vals,stronglayers,layervecs,slpval,slp,baspts,levp,blocksz,lstrongs,lstrongsinv,bl,opt,check,primes,shortlim,orb,orbs,j,sz,goodbase,CHAINTEST,orblens;

  goodbase:=[];
  CHAINTEST:=function(X,str)
    while X<>false do
      #if IsBound(X!.stronggens) and
      #  Length(X!.layergens)>Length(Factors(Size(X))) then
      #  Error("UGH");
      #fi;
      if not X!.orb!.orbit[1] in goodbase.points then
 Error("new point!");
      fi;
      #if Length(X!.orb!.gens)<>Length(Set(X!.orb!.gens)) then
      #  Error("duplicate!");
      #fi;
      #if IsBound(X!.opt) and IsBound(X!.opt.StrictlyUseCandidates) and
      #  X!.opt.StrictlyUseCandidates=false then Error("eh5!"); fi;

      if IsBound(X!.orb!.gens) and Length(X!.orb!.gens)<>Length(Factors(Size(X))) then
        Error("length!");
      fi;

      if IsBound(X!.orb!.gens) and Length(Difference(X!.orb!.gens,strongs))>0 then
        Error("XTRA!");
      fi;

      if IsBound(X!.orb!.gensi) and List(X!.orb!.gens,Inverse)<>X!.orb!.gensi then
 Error(str,"inverse!");
      fi;
      if IsBound(X!.orb!.gensi) and ForAny(X!.orb!.schreiergen,IsInt)  and
 Maximum(Filtered(X!.orb!.schreiergen,IsInt))>Length(X!.orb!.gensi)
 then
 Error("length!");
      fi;
      X:=X!.stab;
    od;
  end;

  gens:=arg[Minimum(2,Length(arg))];
  if IsGroup(gens) then
    a:=gens;
    gens:=GeneratorsOfGroup(gens);
  else
    a:=Group(gens);
  fi;
  if false and Length(arg)>2 and Length(gens)>5+Length(Factors(arg[3])) then
    gens:=List([1..5+Length(Factors(arg[3]))],x->PseudoRandom(a));
    gens:=Set(gens);
    a:=Group(gens);
    check:=true;
    #SetSize(a,sz);
  else
    check:=false;
  fi;
  if IsBound(arg[3]) then
    sz:=arg[3];
    #SetSize(a,sz);
  else
    sz:=fail;
  fi;
  SetIsSolvableGroup(a,true);

  if Length(arg)=1 then
    acter:=gens;
  else
    acter:=arg[1];
    if IsGroup(acter) then
      acter:=GeneratorsOfGroup(acter);
    fi;
  fi;

  shortlim:=Size(DefaultFieldOfMatrixGroup(a))*3000;

  df:=DefaultFieldOfMatrixGroup(a);
  if false then
    # try vectors from big group
    w:=BasisVectorsForMatrixAction(Group(acter));
    w:=ImmutableMatrix(df,w);
    if Size(df)=2 then
      ops:=List(w,x->OnRight);
    else
      ops:=List(w,x->OnLines);
    fi;
  fi;
  w:=ModuleStructureBase(gens);
  if IsBound(arg[3]) and IsBound(w.order) and w.order<arg[3] then
    for i in gens[1] do
      Add(w.points,i);
      Add(w.ops,OnRight);
    od;
  fi;

  opt:=rec(RandomStabGens:=10,
         Cand:=rec(points:=w.points,ops:=w.ops),
      #TODO XXX Find better strategy for limit iof field is larger
         VeryShortOrbLimit:=shortlim
        );
  FUNCSPACEHASH:=[]; # needed in base point selection code
  CBase:=StabilizerChain(a,opt);
  if sz<>fail and Size(CBase)<sz then
    Info(InfoWarning,1,"Wrong size -- redo with `doall' option");
    return fail;
  fi;

  primes:=Set(Factors(Size(CBase)));
  FUNCSPACEHASH:=[];
  w:=BasePointsActionsOrbitLengthsStabilizerChain(CBase);
  Info(InfoGenSS,2,"Suggested Base Points",List(w,x->Position(opt.Cand.points,x[1])),
                   " Lengths ",List(w,x->x[3]));

  goodbase:=BaseStabilizerChain(CBase);
  w:=1;
  opt:=1;

  # Dixon's (1968 - the solvable length of a solvable linear group) bounds
  if IsPerm(gens[1]) then
    a:=Length(MovedPoints(gens));
    bound := Int( LogInt( Maximum(1,a ^ 5), 3 ) / 2 );
  elif IsMatrixOrMatrixObj(gens[1]) then
    a:=NrRows(gens[1]); # dimension

    # we would need proper log
    #bound := Int( (8.55*Log(a+1,10)+0.36 );
    # since it does not exist, replace 8.55 by 9 and simplify rounded up.
    # this anyhow only matters for catching wrong input, so its harmless
    bound := Log((a+1)^9,10)+1;
  else
    # no bound known
    bound:=infinity;
  fi;

  normalizingGenerator:=function(g)
  local oldstrong,oldsz,phq,pbp,pba;
    oldsz:=Size(S);
    oldstrong:=ShallowCopy(StrongGenerators(S));
    # work around the ommission of prior redundant base points
    pba:=Filtered([1..Length(goodbase.points)],x->goodbase.ops[x](goodbase.points[x],g)<>goodbase.points[x]);
    pbp:=pba[1];

    #Print("\n");
    #View(S);
    #Print("\n use ",pba,"\n");

    MATGRP_AddGeneratorToStabilizerChain(S,g,goodbase.points[pbp],goodbase.ops[pbp]);

    while Size(S)=oldsz do
      Error("orderr BUG !!!\n");
      MATGRP_AddGeneratorToStabilizerChain(S,g);
    od;
    return Difference(StrongGenerators(S),oldstrong);
  end;

  solvNC:=function()
  local N,process,layergens,U,g,h,r,V,x,comm,pow,wp,sift;
    N:=StabilizerChain(Group(StrongGenerators(S)),rec(Base:=CBase,Size:=Size(S),Reduced:=false,StrictlyUseCandidates:=true)); # really should be copy

    # determine relative order
    pow:=2;
    wp:=w*w;
    while not SiftGroupElement(N,wp).isone do
      wp:=wp*w;
      pow:=pow+1;
    od;
    if not IsPrimeInt(pow) then
      prime:=Factors(pow)[1];
      w:=w^(pow/prime);
    else
      prime:=pow;
    fi;
    Info(InfoFFMat,2,"Relative order ",pow," prime ",prime);

    process:=[w];
    layergens:=[];
    U:=[];
    for g in process do
      sift:=SiftGroupElement(S,g);
      if not sift.isone then
        Info(InfoFFMat,2,"SS=",Size(S)," ",Length(U));

        for h in layergens do
   comm:=Comm(g,h);
  #Print(Order(comm),"\n");
   if not SiftGroupElement(N,comm).isone then
     # wrong element -- get new generator for layer below
     a:=false;
     w:=comm;
     S:=N; # don't we want to forget what we added?
     return false;
   fi;
 od;

 # the sifted element will be as good as generator, but allows for
 # cleaner decomposition.
 g:=sift.rem;

 V:=normalizingGenerator(g);
 #g:=V[1];
  if g in U then Error("duplicate");fi;
 U:=Concatenation([g],U);
 Add(layergens,g);
 for x in acter do
   Add(process,g^x);
 od;

      fi;
    od;
    a:=true;
    return U;

  end;

  S:=StabilizerChain(Group(One(gens[1])),rec(Base:=CBase,Reduced:=false,StrictlyUseCandidates:=true));

  pcgs:=[];
  depths:=[];
  relord:=[];
  xp:=1;
  while xp<=Length(gens) do
    Info(InfoFFMat,2,"Processing ",xp);
    x:=gens[xp];
    # feed through derived series if necessary
    while not SiftGroupElement(S,x).isone do
      c:=0;
      w:=x;
      a:=false;
      oldsz:=Size(S);
      while not a do
        c:=c+1;
  if c>bound then
    # not solvable
    Error("not solvable");
  fi;

 U:=solvNC(); # will change a,w

      od;
Info(InfoFFMat,2,"Found Layer ",Size(S)/oldsz);
#View(S);
Info(InfoFFMat,2,"n");
      if prime^Length(U)<>Size(S)/oldsz then Error("layerlen"); fi;
      pcgs:=Concatenation(U,pcgs);
      Add(depths,Length(pcgs));
      Append(relord,ListWithIdenticalEntries(Length(U),prime));

    od;
    xp:=xp+1;
  od;
  n:=Length(pcgs);
  depths:=Reversed(List(depths,x->n+1-x));
  relord:=Reversed(relord);
  Add(depths,n+1);

  w:=BasePointsActionsOrbitLengthsStabilizerChain(S);
  Info(InfoGenSS,2,"USED Base Points",List(w,x->Position(goodbase.points,x[1])),
                   " Lengths ",List(w,x->x[3]));


  # now build the chain once more with memory so we can decompose

  blocksz:=[];

  Info(InfoFFMat,2,"NOW",Size(S)," ",Length(pcgs));
  if Length(Factors(Size(S)))<>Length(pcgs) then Error("redundancies");fi;

  # now sift the generators through so that the strong generators *ARE* a pcgs
  gens:=Reversed(pcgs); # start with low level gens again
  pcgs:=[];
  acter:=[];
  #S:=StabilizerChain(Group(One(gens[1])),rec(Base:=CBase,Reduced:=false,StrictlyUseCandidates:=true));
  #S := GENSS_CreateStabChainRecord(false,
#        [],1,
#        goodbase.points[1],
#        goodbase.ops[1],goodbase,
#        rec(Base:=CBase,Reduced:=false,StrictlyUseCandidates:=true,InitialHashSize:=10));
  S:=false; # work around special treatment for trivial group.
  oldsz:=1;
  stabs:=[];
  xp:=1;
  strongs:=[];
  stronglevs:=[];
  while xp<=Length(gens) do


    if S<>false then
      #CHAINTEST(S,"E");
      oldsz:=Size(S);
      Info(InfoFFMat,2,"ProcessiNg ",xp," ",Size(S));


#if Length(StrongGenerators(S))>Length(Factors(Size(S))) then Error("more2\n");fi;
      x:=gens[xp];
      x:=SiftGroupElement(S,x).rem;
      #SiftGroupElement(S,x);

      if not IsOne(x) then
 normalizingGenerator(x);
      fi;
    else
      x:=gens[1];
      # OrbitsWithLog will add powers as strong generators to make the tree shallower.
      # This messes with the correspondence of strong generators and pcgs elements

      S:=StabilizerChain(Group(x),rec(Base:=CBase,Reduced:=false,StrictlyUseCandidates:=true,
        OrbitsWithLog := false,RandomStabGens:=1,Size:=Order(x)));

      # Remove those ~!@#$ extra generators (powers of x) that are added
      # to make the tree shallower, but cause problems here.
      strongs:=[x];

      a:=S;

      while a<>false do
        a!.stronggens:=ShallowCopy(strongs);
        a!.layergens:=[1];
        if Length(a!.orb!.gens)>0 then
          if a!.orb!.gens<>strongs then
            a!.orb:=Orb(ShallowCopy(strongs),a!.orb[1],a!.orb!.op,rec(schreier:=true));
            a!.orb!.gensi:=List(a!.orb!.gens,Inverse);
            repeat
              Enumerate(a!.orb);
            until IsClosed(a!.orb);
            a!.orb!.depth:=Size(a!.orb)-1;
            #if Length(a!.orb)=1 then
            #  a!.orb!.schreiergen:=ShallowCopy(strongs);
            #else
            #  a!.orb!.schreiergen:=[];
            #fi;
          fi;
        fi;
        a:=a!.stab;
      od;

      #CHAINTEST(S,"F2");

      strongs:=[];

    fi;

    if Size(S)=oldsz then Error("no change!");fi;

    Add(pcgs,x);
    a:=Set(Filtered(StrongGenerators(S),x->not x in strongs));
    a:=Difference(a,List([0..Order(x)],y->x^y));
    if Length(a)>0 then
      # redo
      Info(InfoFFMat,1,"nanu-redo");
      #Error("nanu");
      return SolvableBSGS(arg[1],arg[2],arg[3]);
    fi;
    Append(strongs,[x]);

    #CHAINTEST(S,"F");


    Append(stronglevs,ListWithIdenticalEntries(1,n+1-xp));
    #if n+1-xp in depths then
    #  Add(stabs,StructuralCopy(S));
    #fi;
    xp:=xp+1;
  od;

  pcgs:=Reversed(pcgs);

  CBase:=BaseStabilizerChain(S);
  w:=BasePointsActionsOrbitLengthsStabilizerChain(S);
  Info(InfoGenSS,2,"Used Base Points",List(w,x->Position(goodbase.points,x[1])),
                   " Lengths ",List(w,x->x[3]));

  baspts:=[];
  levp:=[];
  xp:=[1..Length(pcgs)];
  a:=S;
  for i in [1..Length(CBase.points)] do
    p:=List(xp,x->Position(a!.orb!.orbit,CBase.ops[i](CBase.points[i],pcgs[x])));
    sel:=Filtered([1..Length(xp)],x->p[x]<>1);
    baspts{xp{sel}}:=ListWithIdenticalEntries(Length(sel),i);
    levp[i]:=xp{sel};
    blocksz{xp{sel}}:=p{sel}-1;
    xp:=Difference(xp,xp{sel});
    a:=a!.stab;
  od;

  slpval:=function(w)
  local a,i;
    a:=w[2]*vals[w[1]];
    for i in [3,5..Length(w)-1] do
      a:=(a+w[i+1]*vals[w[i]]) mod p;
    od;
    return a;
  end;

  layerzero:=[];
  laynum:=Length(depths)-1;
  layers:=List([1..n],x->First([laynum,laynum-1..1],y->x>=depths[y]));
  stronglayers:=layers{stronglevs};
  # get vectors for strong generators (b/c we decompose into these)
  slvec:=[];
  for i in [1..laynum] do
    p:=relord[depths[i]];
    a:=IdentityMat(depths[i+1]-depths[i]);
    layerzero[i]:=Zero(a[1]);
    sel:=Positions(stronglayers,i);
    slvec{sel}:=a{List(strongs{sel},x->Position(pcgs,x))-depths[i]+1};

#    layervecs:=ListWithIdenticalEntries(n,fail); # this will trap use of
#    # higher gens
#    layervecs{[depths[i]..depths[i+1]-1]}:=a;
#
#    for j in [depths[i+1]..n] do
#      layervecs[j]:=Zero(a[1]);
#    od;
#    slp:=LinesOfStraightLineProgram(SLPOfElms(strongs{sel}));
#    vals:=Reversed(layervecs);
#    for j in slp do
#      if ForAll(j,IsList) then
# #last line
# slvec{sel}:=List(j,x->slpval(x));
#      elif IsList(j[1]) then
# Error("reassign syntax?");
#      else
# Add(vals,slpval(j));
#      fi;
#    od;
  od;
  ForgetMemory(strongs);
  ForgetMemory(gens);
  ForgetMemory(S);

  S!.pcgs:=pcgs;
  S!.layerzero:=layerzero;
  S!.layerprimes:=relord{depths{[1..laynum]}};
  S!.strongvecs:=slvec;
  S!.layranges:=List([1..laynum],x->[depths[x]..depths[x+1]-1]);
  S!.revranges:=List([1..laynum],x->Reversed([1..Length(S!.layranges[x])]));

  # reindexing
  a:=S;
  while a<>false do
    p:=List(a!.orb!.gensi,x->Position(strongs,x^-1));
    if fail in p then
      Error("not found!");
    fi;
    a!.gensistrongpos:=p;
    a!.gensilayers:=stronglayers{p};
    a:=a!.stab;
  od;

  #TODO: Use chain for decomposition -- at the moment it uses subgroups
  a:=pcgs;
  pcgs:=PcgsByPcSequenceCons(IsPcgsDefaultRep,
    IsPcgsMatGroupByStabChainRep and IsPcgs and IsPrimeOrdersPcgs,
    FamilyObj(gens[1]),pcgs,[]);
  pcgs!.stabilizerChain:=S;
  #pcgs!.stabs:=Reversed(stabs);
  pcgs!.laynums:=[1..laynum];
  pcgs!.layranges:=S!.layranges;
  pcgs!.baspts:=baspts;
  pcgs!.blocksz:=blocksz;
  pcgs!.levp:=levp;
  pcgs!.invpows:=
    List([1..Length(pcgs)],x->List([1..relord[x]-1],y->a[x]^(-y)));
  SetRelativeOrders(pcgs,relord);
  SetIndicesEANormalSteps(pcgs,depths);

  return rec(
    pcgs:=pcgs,
    depths:=depths,
    relord:=relord,
    baspts:=baspts,
    blocksz:=blocksz);
end;

# old ersion of exponent routines, allowing for arbitrary orbit arrangemnts
MatPcgsSift:=function( S, x,l )
local o,p,po,preS,r,v,vecs,prime;
  v:=S!.layerzero[l];
  prime:=S!.layerprimes[l];
  vecs:=S!.strongvecs;
  preS := false;
  while S <> false do
      o := S!.orb;
      if IsObjWithMemory(x) then
        p := o!.op(o[1],x!.el);
      else
 p := o!.op(o[1],x);
      fi;
      po := Position(o,p);
      if po = fail then   # not in current stabilizer
   Error("element not in group");
   return rec( v:=v,rem := x, S := S );
      fi;
      # Now sift through Schreier tree:
      while po > 1 do
 r:=o!.schreiergen[po];
 x := x * S!.orb!.gensi[r];
 po := o!.schreierpos[po];
 if S!.gensilayers[r]=l then
   # generator on the desired layer -- add up vectors
   v:=(v+vecs[S!.gensistrongpos[r]]) mod prime;
 fi;
      od;
      S := S!.stab;
  od;
  return v;
end ;

MatPcgsExponentsOld:=function(S,laynums,x)
local a,j,i,v;
  v:=[];
  for i in [1..Length(laynums)] do
    #S:=stabs[laynums[i]];
    a:=MatPcgsSift(S,x,laynums[i]);
    Append(v,a);
    if i<Length(laynums) then
      # need to divide off what is given by the vector
      for j in [1..Length(a)] do
        if a[j]<>0 then
   x:=LeftQuotient(S!.pcgs[S!.layranges[laynums[i]][j]]^a[j],x);
 fi;
      od;
    fi;
  od;
  return v;
end;


# new routine, using orbit positions
#decomposition as product, but not in canonical order, thus in multi stages
#TODO compare cost matrix multiplication vs. collection
MatPcgsExponents:=function(arg)
local pcgs,laynums,ox,o,p,po,preS,r,isone,ind,i,prd,S,q,rem,bs,pS,x,dep,e,layer,delta,
      z,prime,curran,seli,md,pos,sel,deponly;

  pcgs:=arg[1];
  laynums:=arg[2];
  ox:=arg[3];
  deponly:=Length(arg)>3 and arg[4];

  dep:=IndicesEANormalSteps(pcgs);
  md:=laynums[Length(laynums)]; #the layer depth which we ignore.

  z:=ListWithIdenticalEntries(dep[Length(dep)]-1,0);
  e:=ShallowCopy(z);
  pS:=pcgs!.stabilizerChain;

  repeat
    # factor the element using orbit positions  -- this is correct only for
    # the topmost layer used
    x:=ox;
    S:=pS;
    prd:=[];
    pos:=[];
    preS := false;
    ind:=1;
    layer:=md; # Maximal layer we do
    delta:=ShallowCopy(z); # we need to forget all in the previous layer
    curran:=pcgs!.layranges[layer];
    prime:=RelativeOrders(pcgs)[curran[1]];
    while S <> false do
      sel:=pcgs!.levp[ind];
      bs:=pcgs!.blocksz{sel};

      o := S!.orb;
      if IsObjWithMemory(x) then
 p := o!.op(o[1],x!.el);
      else
 p := o!.op(o[1],x);
      fi;
      po := Position(o,p)-1;

      # decompose
      for i in [1..Length(sel)] do
 seli:=sel[i];

 q:=QuoInt(po,bs[i]);
 rem:=po-q*bs[i];
 if q>0 then
   if seli<dep[layer] then
     # decrease layer in which we decompose
     layer:=layer-1;
     while seli<dep[layer] do
       layer:=layer-1;
     od;
     delta:=ShallowCopy(z); # we need to forget all in the previous layer
     prime:=RelativeOrders(pcgs)[seli];
     curran:=pcgs!.layranges[layer];
   fi;
   #Add(prd,[sel[i],q]);;

   # remember exponent entry if right layer
   if seli<dep[layer+1] then
     delta[seli]:=delta[seli]+q mod prime;
   fi;

   #x:=x/(pcgs[sel[i]]^q);
   x:=x*pcgs!.invpows[seli][q]; # use stored inverse powers

 fi;
 po:=rem;
      od;

      #if o[1]<>o!.op(o[1],x) then Error("not all off!");fi;

      S := S!.stab;
      ind:=ind+1;
    od;

    if delta<>fail then
      # now the affected (topmost) layer is correct
      e:=e+delta;

      # we don't need to correct the last layer we use
      if deponly and not IsZero(delta) then
 delta:=fail; # pop out.
      elif layer<laynums[Length(laynums)] then
 # we have d describe a the highest level. So we want x=d*newx
 for i in curran do
   if delta[i]>0 then
     ox:=pcgs!.invpows[i][delta[i]]*ox;
   fi;
 od;
      fi;

    fi;

  # stop when we've set the lowest layer or if the remainder is the identity
  until layer=laynums[Length(laynums)] or delta=fail;

  # do we only want some?
  if laynums=pcgs!.laynums then
    return e;
  else
    return e{Concatenation(pcgs!.layranges{laynums})};
  fi;

end;

InstallMethod(ExponentsOfPcElement,"matrix pcgs",IsCollsElms,
  [IsPcgsMatGroupByStabChainRep and IsPcgs and IsPrimeOrdersPcgs,
   IsMatrixOrMatrixObj],
function(pcgs,x)
  return MatPcgsExponents(pcgs,pcgs!.laynums,x);
end);

InstallOtherMethod(ExponentsOfPcElement,"matrix pcgs,indices",IsCollsElmsX,
  [IsPcgsMatGroupByStabChainRep and IsPcgs and IsPrimeOrdersPcgs,
   IsMatrixOrMatrixObj,IsList],
function(pcgs,x,inds)
local i,j,sel,lay,ip,sl,r,use;
  # is it a layer?
  for i in pcgs!.laynums do
    if inds=pcgs!.layranges[i] then
      # only this layer
      return MatPcgsExponents(pcgs,[i],x);
    fi;
  od;
  # which layers do we need?
  if not IsSortedList(inds) then
    # perverse case -- old
    return MatPcgsExponents(pcgs,pcgs!.laynums,x){inds};
  fi;
  sel:=[];
  lay:=[];
  ip:=1;
  sl:=0;
  for i in pcgs!.laynums do
    r:=pcgs!.layranges[i];
    use:=false;
    for j in [1..Length(r)] do
      if ip<=Length(inds) and  r[j]=inds[ip] then
 Add(sel,j+sl);
 use:=true;
        ip:=ip+1;
      fi;
    od;
    if use then
      AddSet(lay,i);
      sl:=sl+Length(r);
    fi;
  od;
  return MatPcgsExponents(pcgs,lay,x){sel};
end);

InstallMethod(DepthOfPcElement,"matrix pcgs",IsCollsElms,
  [IsPcgsMatGroupByStabChainRep and IsPcgs and IsPrimeOrdersPcgs,
  IsMatrixOrMatrixObj],
function(pcgs,x)
local e;
  e:=MatPcgsExponents(pcgs,pcgs!.laynums,x,true);
  return PositionNonZero(e);
end);

BindGlobal("TFDepthLeadExp",function(pcgs,x)
local p;
  x:=MatPcgsExponents(pcgs,pcgs!.laynums,x,true); # first nonzero
  p:=PositionNonZero(x);
  if p>Length(x) then
    # identity
    return [p,0];
  else
    return [p,x[p]];
  fi;
end);

InstallMethod(FittingFreeLiftSetup,"fields, using recognition",true,
  [IsMatrixGroup],0,
function(G)
local csi,r,factorhom,sbs,k,pc,hom,rad,it,i,sz,x,stop;
  r:=DefaultFieldOfMatrixGroup(G);
  if not IsField(r) then
    TryNextMethod();
  fi;

  r:=RecognizeGroup(G);
  SetSize(G,Size(r));
  csi:=GetInformationFromRecog(r);
  G!.storedrecog:=csi;
  factorhom:=FindAct(csi);


  #TODO: Better kernel gens by random selection
  sz:=Size(G)/Size(Image(factorhom));
  if Size(Image(factorhom))=1 then
    # solvable
    k:=GeneratorsOfGroup(G);
  else
    it:=CoKernelGensIterator(InverseGeneralMapping(factorhom));
    k:=Filtered(List([1..csi.genum],x->CSINiceGens(csi,x)),x->IsOne(ImagesRepresentative(factorhom,x)));
    if sz>1 then
      stop:=true;
      repeat
 for i in [1..3*Length(Factors(sz))] do
   if not IsDoneIterator(it) then
     x:=NextIterator(it);
     if not IsOne(x) and not x in k then
       Add(k,x);
     fi;
   fi;
 od;
 if sz>1 and Length(k)<Length(Factors(sz)) then stop:=false; fi; # work around issue
 if ValueOption("doall")=true then stop:=false;fi;
      until stop or IsDoneIterator(it);
    fi;
  fi;

  Info(InfoGenSS,3,"|k|=",Length(k));
  # TODO: Proper test

  if ForAll(k,IsOne) then
    rad:=TrivialSubgroup(G);
    sbs:=rec(pcgs:=[],depths:=[1],relord:=[],pcisom:=IsomorphismPcGroup(rad),radical:=rad);
  else
    sbs:=SolvableBSGS(G,k,sz);
    while sbs=fail do
      sbs:=SolvableBSGS(G,k,sz:doall);
    od;
    rad:=SubgroupNC(G,sbs.pcgs);
    SetSize(rad,Product(RelativeOrders(sbs.pcgs)));
    sbs.radical:=rad;
    pc:=PcGroupWithPcgs(sbs.pcgs);
    RUN_IN_GGMBI:=true; # hack to skip Nice treatment
    hom:=GroupHomomorphismByImagesNC(rad,pc,sbs.pcgs,FamilyPcgs(pc));
    RUN_IN_GGMBI:=false;
    SetIsBijective(hom,true);
    sbs.pcisom:=hom;
  fi;
  sbs.csi:=csi;
  SetKernelOfMultiplicativeGeneralMapping(factorhom,rad);
  sbs.factorhom:=factorhom;
  RecogDecompinfoHomomorphism(factorhom)!.LiftSetup:=sbs;

  return sbs;
end);

FFStats:=function(g)
local start,f;
  start:=Runtime();
  f:=FittingFreeLiftSetup(g);
  Print("Time:",Runtime()-start,"\n");
  Print("Factordegree ",NrMovedPoints(Range(f.factorhom)),"\n");
  Print("PcgsDegrees ",Maximum(List(
    BasePointsActionsOrbitLengthsStabilizerChain(f.pcgs!.stabilizerChain),
    x->x[3])),"\n");

end;

# work over residue class rings

MyZmodnZObj:=function(a,b)
  if IsPrimeInt(b) and b<65536 then
    return Z(b)^0*a;
  else
    return ZmodnZObj(a,b);
  fi;
end;

ReduceModM:=function(a,m)
  local b,r,i,j;
  if IsList(a) then
    if IsList(a[1]) then
      # matrix
      b:=[];
      for i in a do
 r:=[];
 for j in i do
   if IsZmodnZObjNonprime(j) then
     Add(r,MyZmodnZObj(j![1],m));
   else
     Add(r,MyZmodnZObj(j,m));
   fi;
 od;
 Add(b,r);
      od;
      if IsPrimeInt(m) then
 b:=ImmutableMatrix(m,b);
      fi;
      return b;
    else
      # vector
      b:=[];
      for j in a do
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.41 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge