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


SSL factgrp.gi   Sprache: unbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include 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 declarations of operations for factor group maps
##

#############################################################################
##
#M  NaturalHomomorphismsPool(G) . . . . . . . . . . . . . . initialize method
##
InstallMethod(NaturalHomomorphismsPool,true,[IsGroup],0,
  G->rec(GopDone:=false,ker:=[],ops:=[],cost:=[],group:=G,lock:=[],
         intersects:=[],blocksdone:=[],in_code:=false,dotriv:=false));

#############################################################################
##
#F  EraseNaturalHomomorphismsPool(G) . . . . . . . . . . . . initialize
##
InstallGlobalFunction(EraseNaturalHomomorphismsPool,function(G)
local r;
  r:=NaturalHomomorphismsPool(G);
  if r.in_code=true then return;fi;
  r.GopDone:=false;
  r.ker:=[];
  r.ops:=[];
  r.cost:=[];
  r.group:=G;
  r.lock:=[];
  r.intersects:=[];
  r.blocksdone:=[];
  r.in_code:=false;
  r.dotriv:=false;
  r:=NaturalHomomorphismsPool(G);
end);

#############################################################################
##
#F  AddNaturalHomomorphismsPool(G,N,op[,cost[,blocksdone]]) . Store operation
##       op for kernel N if there is not already a cheaper one
##       returns false if nothing had been added and 'fail' if adding was
##       forbidden
##
InstallGlobalFunction(AddNaturalHomomorphismsPool,function(arg)
local G, N, op, pool, p, c, perm, ch, diff, nch, nd, involved, i;
  G:=arg[1];
  N:=arg[2];
  op:=arg[3];

  # don't store trivial cases
  if Size(N)=Size(G) then
    Info(InfoFactor,4,"full group");
    return false;
  elif Size(N)=1 then
    # do we really want the trivial subgroup?
    if not (HasNaturalHomomorphismsPool(G) and
      NaturalHomomorphismsPool(G).dotriv=true) then
      Info(InfoFactor,4,"trivial sub: ignore");
      return false;
    fi;
    Info(InfoFactor,4,"trivial sub: OK");
  fi;

  pool:=NaturalHomomorphismsPool(G);

  # split lists in their components
  if IsList(op) and not IsInt(op[1]) then
    p:=[];
    for i in op do
      if IsMapping(i) then
        c:=Intersection(G,KernelOfMultiplicativeGeneralMapping(i));
      else
        c:=Core(G,i);
      fi;
      Add(p,c);
      AddNaturalHomomorphismsPool(G,c,i);
    od;
    # transfer in numbers list
    op:=List(p,i->PositionSet(pool.ker,i));
    if Length(arg)<4 then
      # add the prices
      c:=Sum(pool.cost{op});
    fi;
  # compute/get costs
  elif Length(arg)>3 then
    c:=arg[4];
  else
    if IsGroup(op) then
      c:=IndexNC(G,op);
    elif IsMapping(op) then
      c:=Image(op);
      if IsPcGroup(c) then
        c:=1;
      elif IsPermGroup(c) then
        c:=NrMovedPoints(c);
      else
        c:=Size(c);
      fi;
    fi;
  fi;

  # check whether we have already a better operation (or whether this normal
  # subgroup is locked)

  p:=PositionSet(pool.ker,N);
  if p=fail then
    if pool.in_code then
      return fail;
    fi;
    p:=PositionSorted(pool.ker,N);
    # compute the permutation we have to apply finally
    perm:=PermList(Concatenation([1..p-1],[Length(pool.ker)+1],
                   [p..Length(pool.ker)]))^-1;

    # first add at the end
    p:=Length(pool.ker)+1;
    pool.ker[p]:=N;
    Info(InfoFactor,2,"Added price ",c," for size ",IndexNC(G,N),
         " in group of size ",Size(G));
  elif c>=pool.cost[p] then
    Info(InfoFactor,4,"bad price");
    return false; # nothing added
  elif pool.lock[p]=true then
    return fail; # nothing added
  else
    Info(InfoFactor,2,"Changed price ",c," for size ",IndexNC(G,N));
    perm:=();
    # update dependent costs
    ch:=[p];
    diff:=[pool.cost[p]-c];
    while Length(ch)>0 do
      nch:=[];
      nd:=[];
      for i in [1..Length(pool.ops)] do
        if IsList(pool.ops[i]) then
          involved:=Intersection(pool.ops[i],ch);
          if Length(involved)>0 then
            involved:=Sum(diff{List(involved,x->Position(ch,x))});
            pool.cost[i]:=pool.cost[i]-involved;
            Add(nch,i);
            Add(nd,involved);
          fi;
        fi;
      od;
      ch:=nch;
      diff:=nd;
    od;
  fi;

  if IsMapping(op) and not HasKernelOfMultiplicativeGeneralMapping(op) then
    SetKernelOfMultiplicativeGeneralMapping(op,N);
  fi;
  pool.ops[p]:=op;
  pool.cost[p]:=c;
  pool.lock[p]:=false;

  # update the costs of all intersections that are affected
  for i in [1..Length(pool.ker)] do
    if IsList(pool.ops[i]) and IsInt(pool.ops[i][1]) and p in pool.ops[i] then
      pool.cost[i]:=Sum(pool.cost{pool.ops[i]});
    fi;
  od;

  if Length(arg)>4 then
    pool.blocksdone[p]:=arg[5];
  else
    pool.blocksdone[p]:=false;
  fi;

  if perm<>() then
    # sort the kernels anew
    pool.ker:=Permuted(pool.ker,perm);
    # sort/modify the other components accordingly
    pool.ops:=Permuted(pool.ops,perm);
    for i in [1..Length(pool.ops)] do
      # if entries are lists of integers
      if IsList(pool.ops[i]) and IsInt(pool.ops[i][1]) then
        pool.ops[i]:=List(pool.ops[i],i->i^perm);
      fi;
    od;
    pool.cost:=Permuted(pool.cost,perm);
    pool.lock:=Permuted(pool.lock,perm);
    pool.blocksdone:=Permuted(pool.blocksdone,perm);
    pool.intersects:=Set(pool.intersects,i->List(i,j->j^perm));
  fi;

  return perm; # if anyone wants to keep the permutation
end);


#############################################################################
##
#F  LockNaturalHomomorphismsPool(G,N)  . .  store flag to prohibit changes of
##                                                               the map to N
##
InstallGlobalFunction(LockNaturalHomomorphismsPool,function(G,N)
local pool;
  pool:=NaturalHomomorphismsPool(G);
  N:=PositionSet(pool.ker,N);
  if N<>fail then
    pool.lock[N]:=true;
  fi;
end);


#############################################################################
##
#F  UnlockNaturalHomomorphismsPool(G,N) . . .  clear flag to allow changes of
##                                                               the map to N
##
InstallGlobalFunction(UnlockNaturalHomomorphismsPool,function(G,N)
local pool;
  pool:=NaturalHomomorphismsPool(G);
  N:=PositionSet(pool.ker,N);
  if N<>fail then
    pool.lock[N]:=false;
  fi;
end);


#############################################################################
##
#F  KnownNaturalHomomorphismsPool(G,N) . . . . .  check whether Hom is stored
##                                                               (or obvious)
##
InstallGlobalFunction(KnownNaturalHomomorphismsPool,function(G,N)
  return N=G or Size(N)=1
      or PositionSet(NaturalHomomorphismsPool(G).ker,N)<>fail;
end);


#############################################################################
##
#F  GetNaturalHomomorphismsPool(G,N)  . . . .  get operation for G/N if known
##
InstallGlobalFunction(GetNaturalHomomorphismsPool,function(G,N)
local pool,p,h,ise,emb,i,j;
  if not HasNaturalHomomorphismsPool(G) then
    return fail;
  fi;
  pool:=NaturalHomomorphismsPool(G);
  p:=PositionSet(pool.ker,N);
  if p<>fail then
    h:=pool.ops[p];
    if IsList(h) then
      # just stored as intersection. Construct the mapping!
      # join intersections
      ise:=ShallowCopy(h);
      for i in ise do
        if IsList(pool.ops[i]) and IsInt(pool.ops[i][1]) then
          for j in Filtered(pool.ops[i],j-> not j in ise) do
            Add(ise,j);
          od;
        elif not pool.blocksdone[i] then
          h:=GetNaturalHomomorphismsPool(G,pool.ker[i]);
          pool.in_code:=true; # don't add any new kernel here
          # (which would mess up the numbering)
          ImproveActionDegreeByBlocks(G,pool.ker[i],h);
          pool.in_code:=false;
        fi;
      od;
      ise:=List(ise,i->GetNaturalHomomorphismsPool(G,pool.ker[i]));
      if not (ForAll(ise,IsPcGroup) or ForAll(ise,IsPermGroup)) then
        ise:=List(ise,x->x*IsomorphismPermGroup(Image(x)));
      fi;

      h:=CallFuncList(DirectProduct,List(ise,Image));
      emb:=List([1..Length(ise)],i->Embedding(h,i));
      emb:=List(GeneratorsOfGroup(G),
           i->Product([1..Length(ise)],j->Image(emb[j],Image(ise[j],i))));
      ise:=SubgroupNC(h,emb);

      h:=GroupHomomorphismByImagesNC(G,ise,GeneratorsOfGroup(G),emb);
      SetKernelOfMultiplicativeGeneralMapping(h,N);
      pool.ops[p]:=h;
    elif IsGroup(h) then
      h:=FactorCosetAction(G,h,N); # will implicitly store
    fi;
    p:=h;
  fi;
  return p;
end);


#############################################################################
##
#F  DegreeNaturalHomomorphismsPool(G,N) degree for operation for G/N if known
##
InstallGlobalFunction(DegreeNaturalHomomorphismsPool,function(G,N)
local p,pool;
  pool:=NaturalHomomorphismsPool(G);
  p:=First([1..Length(pool.ker)],i->IsIdenticalObj(pool.ker[i],N));
  if p=fail then
    p:=PositionSet(pool.ker,N);
  fi;
  if p<>fail then
    p:=pool.cost[p];
  fi;
  return p;
end);


#############################################################################
##
#F  CloseNaturalHomomorphismsPool(<G>[,<N>]) . . calc intersections of known
##         operation kernels, don't continue anything which is smaller than N
##
InstallGlobalFunction(CloseNaturalHomomorphismsPool,function(arg)
local G,pool,p,comb,i,c,perm,isi,N,discard,Npos,psub,pder,new,co,pos,j,k;

  G:=arg[1];
  pool:=NaturalHomomorphismsPool(G);
  p:=[1..Length(pool.ker)];

  Npos:=fail;
  if Length(arg)>1 then
    # get those p that lie above N
    N:=arg[2];
    p:=Filtered(p,i->IsSubset(pool.ker[i],N));
    if Length(p)=0 then
      return;
    fi;
    SortParallel(List(pool.ker{p},Size),p);
    if Size(pool.ker[p[1]])=Size(N) then
      # N in pool
      Npos:=p[1];
      c:=pool.cost[Npos];
      p:=Filtered(p,x->pool.cost[x]<c);
    fi;
  else
    SortParallel(List(pool.ker{p},Size),p);
    N:=fail;
  fi;

  if Size(Intersection(pool.ker{p}))>Size(N) then
    # cannot reach N
    return;
  fi;

  # determine inclusion, derived
  psub:=List(pool.ker,x->0);
  pder:=List(pool.ker,x->0);
  discard:=[];
  for i in [1..Length(p)] do
    c:=Filtered(p{[1..i-1]},x->IsSubset(pool.ker[p[i]],pool.ker[x]));
    psub[p[i]]:=Set(c);
    if ForAny(c,x->pool.cost[x]<=pool.cost[p[i]]) then
      AddSet(discard,p[i]);
    fi;
    c:=DerivedSubgroup(pool.ker[p[i]]);
    if N<>fail then c:=ClosureGroup(N,c);fi;
    pder[p[i]]:=Position(pool.ker,c);
  od;
#if Length(discard)>0 then Error(discard);fi;
#discard:=[];
  p:=Filtered(p,x->not x in discard);
  for i in discard do psub[i]:=0;od;

  new:=p;
  repeat
    # now intersect, staring from top
    if new=p then
      comb:=Combinations(new,2);
    else
      comb:=List(Cartesian(p,new),Set);
    fi;
    comb:=Filtered(comb,i->not i in pool.intersects and Length(i)>1);
    Info(InfoFactor,2,"CloseNaturalHomomorphismsPool: ",Length(comb));
    new:=[];
    discard:=[];
    i:=1;
    while i<=Length(comb) do
      co:=comb[i];
      # unless they contained in each other
      if not (co[1] in psub[co[2]] or co[2] in psub[co[1]]
        # or there a subgroup below both that is already at least as cheap
        or ForAny(Intersection(psub[co[1]],psub[co[2]]),
          x->pool.cost[x]<=pool.cost[co[1]]+pool.cost[co[2]])
        # or both intersect in an abelian factor?
        or (N<>fail and pder[co[1]]<>fail and pder[co[1]]=pder[co[2]]
            and pder[co[1]]<>Npos)) then
        c:=Intersection(pool.ker[co[1]],pool.ker[co[2]]);

        pos:=Position(pool.ker,c);
        if pos=fail or pool.cost[pos]>pool.cost[co[1]]+pool.cost[co[2]] then
          Info(InfoFactor,3,"Intersect ",co,": ",
              Size(pool.ker[co[1]])," ",Size(pool.ker[co[2]]),
                " yields ",Size(c));
          isi:=ShallowCopy(co);

          # unpack 'iterated' lists
          if IsList(pool.ops[co[2]]) and IsInt(pool.ops[co[2]][1]) then
            isi:=Concatenation(isi{[1]},pool.ops[co[2]]);
          fi;
          if IsList(pool.ops[co[1]]) and IsInt(pool.ops[co[1]][1]) then
            isi:=Concatenation(isi{[2..Length(isi)]},pool.ops[co[1]]);
          fi;
          isi:=Set(isi);

          perm:=AddNaturalHomomorphismsPool(G,c,isi,Sum(pool.cost{co}));
          if pos=fail then
            pos:=Position(pool.ker,c);
            p:=List(p,i->i^perm);
            new:=List(new,i->i^perm);
            discard:=OnSets(discard,perm);
            #pder:=Permuted(List(pder,x->x^perm),perm);
            for k in [1..Length(pder)] do
              if IsPosInt(pder[k]) then pder[k]:=pder[k]^perm;fi;
            od;
            Add(pder,0);
            pder:=Permuted(pder,perm);
            #psub:=Permuted(List(psub,x->OnTuples(x,perm)));
            for k in [1..Length(psub)] do
              if IsList(psub[k]) then psub[k]:=OnSets(psub[k],perm);fi;
            od;
            Add(psub,0);
            psub:=Permuted(psub,perm);

            Apply(comb,j->OnSets(j,perm));

            # add new c if needed
            for j in p do
              if IsSubset(pool.ker[j],c) then
                AddSet(psub[j],pos);
                if pool.cost[j]>=pool.cost[pos] then
                  AddSet(discard,j);
                fi;
              fi;
            od;
            psub[pos]:=Set(Filtered(p,x->IsSubset(c,pool.ker[x])));
            pder[pos]:=fail;

          else
            if perm<>() then Error("why perm here?");fi;
            psub[pos]:=Set(Filtered(p,x->IsSubset(c,pool.ker[x])));

          fi;
          AddSet(new,pos);
          if ForAny(psub[pos],x->pool.cost[x]<=pool.cost[pos]) then
            AddSet(discard,pos);
          fi;
          pder[pos]:=fail;
          if c=N and pool.cost[pos]^3<=IndexNC(G,N) then
            return; # we found something plausible
          fi;

        else
          Info(InfoFactor,5,"Intersect ",co,": ",
              Size(pool.ker[co[1]])," ",Size(pool.ker[co[2]]),
                " yields ",Size(c));
        fi;

      fi;
      i:=i+1;
    od;
#discard:=[];
    for i in discard do psub[i]:=0;od;
    p:=Difference(Union(p,new),discard);
    new:=Difference(new,discard);
    SortParallel(List(pool.ker{p},Size),p);
    SortParallel(List(pool.ker{new},Size),new);
  until Length(new)=0;

end);


#############################################################################
##
#F  FactorCosetAction( <G>, <U>, [<N>] )  operation on the right cosets Ug
##                                        with possibility to indicate kernel
##
InstallGlobalFunction("DoFactorCosetAction",function(arg)
local G,u,op,h,N,rt;
  G:=arg[1];
  u:=arg[2];
  if Length(arg)>2 then
    N:=arg[3];
  else
    N:=false;
  fi;
  if IsList(u) and Length(u)=0 then
    u:=G;
    Error("only trivial operation ?  I Set u:=G;");
  fi;
  if N=false then
    N:=Core(G,u);
  fi;
  rt:=RightTransversal(G,u);
  if not IsRightTransversalRep(rt) then
    # the right transversal has no special `PositionCanonical' method.
    rt:=List(rt,i->RightCoset(u,i));
  fi;
  h:=ActionHomomorphism(G,rt,OnRight,"surjective");
  op:=Image(h,G);
  SetSize(op,IndexNC(G,N));

  # and note our knowledge
  SetKernelOfMultiplicativeGeneralMapping(h,N);
  AddNaturalHomomorphismsPool(G,N,h);
  return h;
end);

InstallMethod(FactorCosetAction,"by right transversal operation",
  IsIdenticalObj,[IsGroup,IsGroup],0,
function(G,U)
  return DoFactorCosetAction(G,U);
end);

InstallOtherMethod(FactorCosetAction,
  "by right transversal operation, given kernel",IsFamFamFam,
  [IsGroup,IsGroup,IsGroup],0,
function(G,U,N)
  return DoFactorCosetAction(G,U,N);
end);

InstallMethod(FactorCosetAction,"by right transversal operation, Niceo",
  IsIdenticalObj,[IsGroup and IsHandledByNiceMonomorphism,IsGroup],0,
function(G,U)
local hom;
  hom:=RestrictedNiceMonomorphism(NiceMonomorphism(G),G);
  return hom*DoFactorCosetAction(NiceObject(G),Image(hom,U));
end);

InstallOtherMethod(FactorCosetAction,
  "by right transversal operation, given kernel, Niceo",IsFamFamFam,
  [IsGroup and IsHandledByNiceMonomorphism,IsGroup,IsGroup],0,
function(G,U,N)
local hom;
  hom:=RestrictedNiceMonomorphism(NiceMonomorphism(G),G);
  return hom*DoFactorCosetAction(NiceObject(G),Image(hom,U),Image(hom,N));
end);

# action on lists of subgroups
InstallOtherMethod(FactorCosetAction,
  "On cosets of list of groups",IsElmsColls,
  [IsGroup,IsList],0,
function(G,L)
local q,i,gens,imgs,d;
  if Length(L)=0 or not ForAll(L,x->IsGroup(x) and IsSubset(G,x)) then
    TryNextMethod();
  fi;
  q:=List(L,x->FactorCosetAction(G,x));
  gens:=MappingGeneratorsImages(q[1])[1];
  imgs:=List(q,x->List(gens,y->ImagesRepresentative(x,y)));
  d:=imgs[1];
  for i in [2..Length(imgs)] do
    d:=SubdirectDiagonalPerms(d,imgs[i]);
  od;
  imgs:=Group(d);
  q:=GroupHomomorphismByImagesNC(G,imgs,gens,d);
  return q;
end);


#############################################################################
##
#M  DoCheapActionImages(G) . . . . . . . . . . All cheap operations for G
##
InstallMethod(DoCheapActionImages,"generic",true,[IsGroup],0,Ignore);

InstallMethod(DoCheapActionImages,"permutation",true,[IsPermGroup],0,
function(G)
local pool, dom, o, op, Go, j, b, i,allb,newb,mov,allbold,onlykernel,k,
  found,type;

  onlykernel:=ValueOption("onlykernel");
  found:=NrMovedPoints(G);
  pool:=NaturalHomomorphismsPool(G);
  if pool.GopDone=false then

    dom:=MovedPoints(G);
    # orbits
    o:=OrbitsDomain(G,dom);
    o:=Set(o,Set);

    # do orbits and test for blocks
    for i in o do
      if Length(i)<>Length(dom) or
        # only works if domain are the first n points
        not (1 in dom and 2 in dom and IsRange(dom)) then
        op:=ActionHomomorphism(G,i,"surjective");
        Range(op:onlyimage); #`onlyimage' forces same generators
        AddNaturalHomomorphismsPool(G,Stabilizer(G,i,OnTuples),
                            op,Length(i));
        type:=1;
      else
        op:=IdentityMapping(G);
        type:=2;
      fi;

      Go:=Image(op,G);
      # all minimal and maximal blocks
      mov:=MovedPoints(Go);
      allb:=ShallowCopy(RepresentativesMinimalBlocks(Go,mov));
      allbold:=[];
      SortBy(allb,Length);
      while Length(allb)>0 do
        j:=Remove(allb);
        Add(allbold,j);
        # even if generic spread, <found, since blocks are always of size
        # >1.
        if Length(i)/Length(j)<found then
          b:=List(Orbit(G,i{j},OnSets),Immutable);

          #Add(bl,Immutable(Set(b)));
          op:=ActionHomomorphism(G,Set(b),OnSets,"surjective");
          ImagesSource(op:onlyimage); #`onlyimage' forces same generators
          k:=KernelOfMultiplicativeGeneralMapping(op);
          if onlykernel<>fail and k=onlykernel and Length(b)<found then
            found:=Length(b);
          fi;
          AddNaturalHomomorphismsPool(G,k,op);

          # also one finer blocks (to make up for iterating only once)
          if type=2 then
            newb:=Blocks(G,b,OnSets);
          else
            newb:=Blocks(Go,Blocks(Go,mov,j),OnSets);
          fi;

          if Length(newb)>1 then
            newb:=Union(newb[1]);
            if not (newb in allb or newb in allbold) then
              Add(allb,newb);
              SortBy(allb,Length);
            fi;
          fi;

        fi;

      od;

      #if Length(i)<500 and Size(Go)>10*Length(i) then
      #else
#        # one block system
#        b:=Blocks(G,i);
#        if Length(b)>1 then
#          Add(bl,Immutable(Set(b)));
#        fi;
#      fi;
    od;

    pool.GopDone:=true;
  fi;

end);

BindGlobal("DoActionBlocksForKernel",
function(G,mustfaithful)
local dom, o, bl, j, b, allb,newb;

  dom:=MovedPoints(G);
  # orbits
  o:=OrbitsDomain(G,dom);
  o:=Set(o,Set);


  # all good blocks
  bl:=dom;
  allb:=ShallowCopy(RepresentativesMinimalBlocks(G,dom));
  for j in allb do
    if Length(dom)/Length(j)<Length(bl) and
      Size(Core(mustfaithful,Stabilizer(mustfaithful,j,OnSets)))=1
      then
        b:=Orbit(G,j,OnSets);
        bl:=b;
        # also one finer blocks (as we iterate only once)
        newb:=Blocks(G,b,OnSets);
        if Length(newb)>1 then
          newb:=Union(newb[1]);
          if not newb in allb then
            Add(allb,newb);
          fi;
        fi;
    fi;
  od;
  if Length(bl)<Length(dom) then
    return bl;
  else
    return fail;
  fi;

end);


#############################################################################
##
#F  GenericFindActionKernel  random search for subgroup with faithful core
##
BADINDEX:=1000; # the index that is too big
BindGlobal( "GenericFindActionKernel", function(arg)
local G, N, knowi, goodi, simple, uc, zen, cnt, pool, ise, v, badi,
totalcnt, interrupt, u, nu, cor, zzz,bigperm,perm,badcores,max,i,hard;

  G:=arg[1];
  N:=arg[2];
  if Length(arg)>2 then
    knowi:=arg[3];
  else
    knowi:=IndexNC(G,N);
  fi;

  # special treatment for solvable groups. This will never be triggered for
  # perm groups or nice groups
  if Size(N)>1 and HasSolvableFactorGroup(G,N) then
    perm:=ActionHomomorphism(G,RightCosets(G,N),OnRight,"surjective");
    perm:=perm*IsomorphismPcGroup(Image(perm));
    return perm;
  fi;

  # special treatment for abelian factor
  if HasAbelianFactorGroup(G,N) then
    if IsPermGroup(G) and Size(N)=1 then
      return IdentityMapping(G);
    else
      perm:=ActionHomomorphism(G,RightCosets(G,N),OnRight,"surjective");
    fi;
    return perm;
  fi;

  bigperm:=IsPermGroup(G) and NrMovedPoints(G)>10000;

  # what is a good degree:
  goodi:=Minimum(Int(knowi*9/10),LogInt(IndexNC(G,N),2)^2);

  simple:=HasIsNonabelianSimpleGroup(G) and IsNonabelianSimpleGroup(G) and Size(N)=2;
  uc:=TrivialSubgroup(G);
  # look if it is worth to look at action on N
  # if not abelian: later replace by abelian Normal subgroup
  if IsAbelian(N) and (Size(N)>50 or IndexNC(G,N)<Factorial(Size(N)))
      and Size(N)<50000 then
    zen:=Centralizer(G,N);
    if Size(zen)=Size(N) then
      cnt:=0;
      repeat
        cnt:=cnt+1;
        zen:=Centralizer(G,Random(N));
        if (simple or Size(Core(G,zen))=Size(N)) and
            IndexNC(G,zen)<IndexNC(G,uc) then
          uc:=zen;
        fi;
      # until enough searched or just one orbit
      until cnt=9 or (IndexNC(G,zen)+1=Size(N));
      AddNaturalHomomorphismsPool(G,N,uc,IndexNC(G,uc));
    else
      Info(InfoFactor,3,"centralizer too big");
    fi;
  fi;

  pool:=NaturalHomomorphismsPool(G);
  pool.dotriv:=true;
  CloseNaturalHomomorphismsPool(G,N);
  pool.dotriv:=false;
  ise:=Filtered(pool.ker,x->IsSubset(x,N));
  if Length(ise)=0 then
    ise:=G;
  else
    ise:=Intersection(ise);
  fi;

  # try a random extension step
  # (We might always first add a random element and get something bigger)
  v:=N;

  #if Length(arg)=3 then
    ## in one example 512->90, ca. 40 tries
    #cnt:=Int(arg[3]/10);
  #else
    #cnt:=25;
  #fi;

  badcores:=[];
  badi:=BADINDEX;
  hard:=ValueOption("hard");
  if hard=fail then
    hard:=100000;
  elif hard=true then
    hard:=10000;
  fi;
  totalcnt:=0;
  interrupt:=false;
  cnt:=20;
  repeat
    u:=v;
    repeat
      repeat
        if Length(arg)<4 or Random(1,2)=1 then
          if IsCyclic(u) and Random(1,4)=1 then
            # avoid being stuck with a bad first element
            u:=Subgroup(G,[Random(G)]);
          fi;
          if Length(GeneratorsOfGroup(u))<2 then
            # closing might cost a big stabilizer chain calculation -- just
            # recreate
            nu:=Group(Concatenation(GeneratorsOfGroup(u),[Random(G)]));
          else
            nu:=ClosureGroup(u,Random(G));
          fi;
        else
          if Length(GeneratorsOfGroup(u))<2 then
            # closing might cost a big stabilizer chain calculation -- just
            # recreate
            nu:=Group(Concatenation(GeneratorsOfGroup(u),[Random(arg[4])]));
          else
            nu:=ClosureGroup(u,Random(arg[4]));
          fi;
        fi;
        SetParent(nu,G);
        totalcnt:=totalcnt+1;
        if KnownNaturalHomomorphismsPool(G,N) and
          Minimum(IndexNC(G,v),knowi)<hard
             and 5*totalcnt>Minimum(IndexNC(G,v),knowi,1000) then
          # interrupt if we're already quite good
          interrupt:=true;
        fi;
        if ForAny(badcores,x->IsSubset(nu,x)) then
          nu:=u;
        fi;
        # Abbruchkriterium: Bis kein Normalteiler, es sei denn, es ist N selber
        # (das brauchen wir, um in einigen trivialen F"allen abbrechen zu
        # k"onnen)
#Print("nu=",Length(GeneratorsOfGroup(nu))," : ",Size(nu),"\n");
      until

        # der Index ist nicht so klein, da"s wir keine Chance haben
        ((not bigperm or
        Length(Orbit(nu,MovedPoints(G)[1]))<NrMovedPoints(G)) and
        (IndexNC(G,nu)>50 or Factorial(IndexNC(G,nu))>=IndexNC(G,N)) and
        not IsNormal(G,nu)) or IsSubset(u,nu) or interrupt;

      Info(InfoFactor,4,"Index ",IndexNC(G,nu));
      u:=nu;

    until totalcnt>300 or
      # und die Gruppe ist nicht zuviel schlechter als der
      # beste bekannte Index. Daf"ur brauchen wir aber wom"oglich mehrfache
      # Erweiterungen.
      interrupt or (((Length(arg)=2 or IndexNC(G,u)<knowi)));

    if IndexNC(G,u)<knowi then

      #Print("Index:",IndexNC(G,u),"\n");

      if simple and u<>G then
        cor:=TrivialSubgroup(G);
      else
        cor:=Core(G,u);
      fi;
      if Size(cor)>Size(N) and IsSubset(cor,N) and not cor in badcores then
        Add(badcores,cor);
      fi;
      # store known information(we do't act, just store the subgroup).
      # Thus this is fairly cheap
      pool.dotriv:=true;
      zzz:=AddNaturalHomomorphismsPool(G,cor,u,IndexNC(G,u));

      if IsPerm(zzz) and zzz<>() then
        CloseNaturalHomomorphismsPool(G,N);
      fi;
      pool.dotriv:=false;

      zzz:=DegreeNaturalHomomorphismsPool(G,N);

      Info(InfoFactor,3,"  ext ",cnt,": ",IndexNC(G,u)," best degree:",zzz);

      if cnt<10 and Size(cor)>Size(N) and IndexNC(G,u)*2<knowi and
        ValueOption("inmax")=fail then
        if IsSubset(SolvableRadical(u),N) and Size(N)<Size(SolvableRadical(u)) then
          # only affine ones are needed, rest will have wrong kernel
          max:=DoMaxesTF(u,["1"]:inmax,cheap);
        else
          max:=TryMaximalSubgroupClassReps(u:inmax,cheap);
        fi;
        max:=Filtered(max,x->IndexNC(G,x)<knowi and IsSubset(x,N));
        for i in max do
          cor:=Core(G,i);
          AddNaturalHomomorphismsPool(G,cor,i,IndexNC(G,i));
        od;
        zzz:=DegreeNaturalHomomorphismsPool(G,N);
        Info(InfoFactor,3,"  Maxes: ",Length(max)," best degree:",zzz);
      fi;
    else
      zzz:=DegreeNaturalHomomorphismsPool(G,N);
    fi;
    if IsInt(zzz) then
      knowi:=zzz;
    fi;

    cnt:=cnt-1;

    if cnt=0 and zzz>badi then
      badi:=Int(badi*12/10);
      Info(InfoWarning+InfoFactor,2,
        "index unreasonably large, iterating ",badi);
      cnt:=20;
      totalcnt:=0;
      interrupt:=false;
      v:=N; # all new
    fi;
  until interrupt or cnt<=0 or zzz<=goodi;
  Info(InfoFactor,1,zzz," vs ",badi);

  return GetNaturalHomomorphismsPool(G,N);

end );

#############################################################################
##
#F  SmallerDegreePermutationRepresentation( <G> )
##
InstallGlobalFunction(SmallerDegreePermutationRepresentation,function(G)
local o, s, k, gut, erg, H, hom, b, ihom, improve, map, loop,bl,
  i,cheap,k2,change;

  change:=false;
  Info(InfoFactor,1,"Smaller degree for order ",Size(G),", deg: ",NrMovedPoints(G));
  cheap:=ValueOption("cheap");
  if cheap="skip" then
    return IdentityMapping(G);
  fi;

  cheap:=cheap=true;

  if Length(GeneratorsOfGroup(G))>7 then
    s:=SmallGeneratingSet(G);
    if Length(s)=0 then s:=[One(G)];fi;
    if Length(s)<Length(GeneratorsOfGroup(G))-1 then
      Info(InfoFactor,1,"reduced to ",Length(s)," generators");
      H:=Group(s);
      change:=true;
      SetSize(H,Size(G));
      return SmallerDegreePermutationRepresentation(H);
    fi;
  fi;


  # deal with large abelian components first (which could be direct)
  if cheap<>true then
    hom:=MaximalAbelianQuotient(G);
    i:=IndependentGeneratorsOfAbelianGroup(Image(hom));
    o:=List(i,Order);
    if ValueOption("norecurse")<>true and
      Product(o)>20 and Sum(o)*4<NrMovedPoints(G) then
      Info(InfoFactor,2,"append abelian rep");
      s:=AbelianGroup(IsPermGroup,o);
      ihom:=GroupHomomorphismByImagesNC(Image(hom),s,i,GeneratorsOfGroup(s));
      erg:=SubdirectDiagonalPerms(
            List(GeneratorsOfGroup(G),x->Image(ihom,Image(hom,x))),
            GeneratorsOfGroup(G));
      k:=Group(erg);SetSize(k,Size(G));
      hom:=GroupHomomorphismByImagesNC(G,k,GeneratorsOfGroup(G),erg);
      return hom*SmallerDegreePermutationRepresentation(k:norecurse);
    fi;
  fi;

  # known simple?
  if HasIsSimpleGroup(G) and IsSimpleGroup(G)
      and NrMovedPoints(G)>=SufficientlySmallDegreeSimpleGroupOrder(Size(G))
        then return IdentityMapping(G);
  fi;

  if not IsTransitive(G,MovedPoints(G)) then
    o:=ShallowCopy(OrbitsDomain(G,MovedPoints(G)));
    SortBy(o, Length);

    for loop in [1..2] do
      s:=[];
      # Try subdirect product
      k:=G;
      gut:=[];
      for i in [1..Length(o)] do
        s:=Stabilizer(k,o[i],OnTuples);
        if Size(s)<Size(k) then
          k:=s;
          Add(gut,i);
        fi;
      od;
      # reduce each orbit separately
      o:=o{gut};
      # second run: now take the big orbits first
      Sort(o,function(a,b)return Length(a)>Length(b);end);
    od;

    SortBy(o, Length);

    erg:=List(GeneratorsOfGroup(G),i->());
    k:=G;
    for i in [1..Length(o)] do
      Info(InfoFactor,1,"Try to shorten orbit ",i," Length ",Length(o[i]));
      s:=ActionHomomorphism(G,o[i],OnPoints,"surjective");
      k2:=Image(s,k);
      k:=Stabilizer(k,o[i],OnTuples);
      H:=Range(s);

      # is there an action that is good enough for improving the overall
      # kernel, even if it is not faithful? If so use the best of them.
      b:=DoActionBlocksForKernel(H,k2);
      if b<>fail then
        Info(InfoFactor,2,"Blocks for kernel reduce to ",Length(b));
        b:=ActionHomomorphism(H,b,OnSets,"surjective");
        s:=s*b;
      fi;

      s:=s*SmallerDegreePermutationRepresentation(Image(s));
      Info(InfoFactor,1,"Shortened to ",NrMovedPoints(Range(s)));
      erg:=SubdirectDiagonalPerms(erg,List(GeneratorsOfGroup(G),i->Image(s,i)));
    od;
    if NrMovedPoints(erg)<NrMovedPoints(G) then
      s:=Group(erg,());  # `erg' arose from `SubdirectDiagonalPerms'
      SetSize(s,Size(G));
      s:=GroupHomomorphismByImagesNC(G,s,GeneratorsOfGroup(G),erg);
      SetIsBijective(s,true);
      return s;
    fi;
    return IdentityMapping(G);
  fi; # intransitive treatment



  # if the original group has no stabchain we probably do not want to keep
  # it (or a homomorphisms pool) there -- make a copy for working
  # intermediately with it.
  if not HasStabChainMutable(G) then
    H:= GroupWithGenerators( GeneratorsOfGroup( G ),One(G) );
    change:=true;
    if HasSize(G) then
      SetSize(H,Size(G));
    fi;
    if HasBaseOfGroup(G) then
      SetBaseOfGroup(H,BaseOfGroup(G));
    fi;
  else
    H:=G;
  fi;
  hom:=IdentityMapping(H);
  b:=NaturalHomomorphismsPool(H);
  b.dotriv:=true;
  AddNaturalHomomorphismsPool(H,TrivialSubgroup(H),hom,NrMovedPoints(H));
  b.dotriv:=false;

  # cheap initial block reduction?
  if IsTransitive(H,MovedPoints(H)) then
    improve:=true;
    while improve and (cheap or NrMovedPoints(H)*5>Size(H)) do
      improve:=false;
      bl:=Blocks(H,MovedPoints(H));
      map:=ActionHomomorphism(G,bl,OnSets,"surjective");
      ImagesSource(map:onlyimage); #`onlyimage' forces same generators
      bl:=KernelOfMultiplicativeGeneralMapping(map);
      AddNaturalHomomorphismsPool(G,bl,map);
      if Size(bl)=1 then
        hom:=hom*map;
        H:=Image(map);
        change:=true;
        Info(InfoFactor,2," quickblocks improved to degree ",NrMovedPoints(H));
      fi;
    od;
  fi;

  b:=NaturalHomomorphismsPool(H);
  b.dotriv:=true;
  if change then
    DoCheapActionImages(H:onlykernel:=TrivialSubgroup(H));
  else
    DoCheapActionImages(H);
  fi;
  CloseNaturalHomomorphismsPool(H,TrivialSubgroup(H));
  b.dotriv:=false;
  map:=GetNaturalHomomorphismsPool(H,TrivialSubgroup(H));
  if map<>fail and Image(map)<>H then
    Info(InfoFactor,2,"cheap actions improved to degree ",NrMovedPoints(H));
    hom:=hom*map;
    H:=Image(map);
  fi;

  o:=DegreeNaturalHomomorphismsPool(H,TrivialSubgroup(H));
  if cheap<>true and (IsBool(o) or o*2>=NrMovedPoints(H)) then
    s:=GenericFindActionKernel(H,TrivialSubgroup(H),NrMovedPoints(H));
    if s<>fail then
      hom:=hom*s;
    fi;
  fi;

  return hom;
end);

#############################################################################
##
#F  ImproveActionDegreeByBlocks( <G>, <N> , hom )
##  extension of <U> in <G> such that   \bigcap U^g=N remains valid
##
InstallGlobalFunction(ImproveActionDegreeByBlocks,function(G,N,oh)
local gimg,img,dom,b,improve,bp,bb,i,k,bestdeg,subo,op,bc,bestblock,bdom,
      bestop,sto,subomax;
  Info(InfoFactor,1,"try to find block systems");

  # remember that we computed the blocks
  b:=NaturalHomomorphismsPool(G);

  # special case to use it for improving a permutation representation
  if Size(N)=1 then
    Info(InfoFactor,1,"special case for trivial subgroup");
    b.ker:=[N];
    b.ops:=[oh];
    b.cost:=[Length(MovedPoints(Range(oh)))];
    b.lock:=[false];
    b.blocksdone:=[false];
    subomax:=20;
  else
    subomax:=500;
  fi;

  i:=PositionSet(b.ker,N);
  if b.blocksdone[i] then
    return DegreeNaturalHomomorphismsPool(G,N); # we have done it already
  fi;
  b.blocksdone[i]:=true;

  if not IsPermGroup(Range(oh)) then
    return 1;
  fi;

  gimg:=Image(oh,G);
  img:=gimg;
  dom:=MovedPoints(img);
  bdom:=fail;

  if IsTransitive(img,dom) then
    # one orbit: Blocks
    repeat
      b:=Blocks(img,dom);
      improve:=false;
      if Length(b)>1 then
        if Length(dom)<40000 then
          subo:=ApproximateSuborbitsStabilizerPermGroup(img,dom[1]);
          subo:=Difference(List(subo,i->i[1]),dom{[1]});
        else
          subo:=fail;
        fi;
        bc:=First(b,i->dom[1] in i);
        if subo<>fail and (Length(subo)<=subomax) then
          Info(InfoFactor,2,"try all seeds");
          # if the degree is not too big or if we are desperate then go for
          # all blocks
          # greedy approach: take always locally best one (otherwise there
          # might be too much work to do)
          bestdeg:=Length(dom);
          bp:=[]; #Blocks pool
          i:=1;
          while i<=Length(subo) do
            if subo[i] in bc then
              bb:=b;
            else
              bb:=Blocks(img,dom,[dom[1],subo[i]]);
            fi;
            if Length(bb)>1 and not (bb[1] in bp or Length(bb)>bestdeg) then
              Info(InfoFactor,3,"found block system ",Length(bb));
              # new nontriv. system found
              AddSet(bp,bb[1]);
              # store action
              op:=1;# remove old homomorphism to free memory
              if bdom<>fail then
                bb:=Set(bb,i->Immutable(Union(bdom{i})));
              fi;

              op:=ActionHomomorphism(gimg,bb,OnSets,"surjective");
              if HasSize(gimg) and not HasStabChainMutable(gimg) then
                sto:=StabChainOptions(Range(op));
                sto.limit:=Size(gimg);
                # try only with random (will exclude some chances, but is
                # quicker. If the size is OK we have a proof anyhow).
                sto.random:=100;
#                if gimgbas<>false then
#                  SetBaseOfGroup(Range(op),
#                    List(gimgbas,i->PositionProperty(bb,j->i in j)));
#                fi;
                if Size(Range(op))=Size(gimg) then
                  sto.random:=1000;
                  k:=TrivialSubgroup(gimg);
                  op:=oh*op;
                  SetKernelOfMultiplicativeGeneralMapping(op,PreImage(oh,k));
                  AddNaturalHomomorphismsPool(G,
                      KernelOfMultiplicativeGeneralMapping(op),
                                              op,Length(bb));
                else
                  k:=[]; # do not trigger improvement
                fi;
              else
                k:=KernelOfMultiplicativeGeneralMapping(op);
                SetSize(Range(op),IndexNC(gimg,k));
                op:=oh*op;
                SetKernelOfMultiplicativeGeneralMapping(op,PreImage(oh,k));
                AddNaturalHomomorphismsPool(G,
                    KernelOfMultiplicativeGeneralMapping(op),
                                            op,Length(bb));

              fi;
              # and note whether we got better
              #improve:=improve or (Size(k)=1);
              if Size(k)=1 and Length(bb)<bestdeg then
                improve:=true;
                bestdeg:=Length(bb);
                bestblock:=bb;
                bestop:=op;
              fi;
            fi;
            # break the test loop if we found a fairly small block system
            # (iterate greedily immediately)
            if improve and bestdeg<i then
              i:=Length(dom);
            fi;
            i:=i+1;
          od;
        else
          Info(InfoFactor,2,"try only one system");
          op:=1;# remove old homomorphism to free memory
          if bdom<>fail then
            b:=Set(b,i->Immutable(Union(bdom{i})));
          fi;
          op:=ActionHomomorphism(gimg,b,OnSets,"surjective");
          if HasSize(gimg) and not HasStabChainMutable(gimg) then
            sto:=StabChainOptions(Range(op));
            sto.limit:=Size(gimg);
            # try only with random (will exclude some chances, but is
            # quicker. If the size is OK we have a proof anyhow).
            sto.random:=100;
#            if gimgbas<>false then
#              SetBaseOfGroup(Range(op),
#                 List(gimgbas,i->PositionProperty(b,j->i in j)));
#            fi;
            if Size(Range(op))=Size(gimg) then
              sto.random:=1000;
              k:=TrivialSubgroup(gimg);
              op:=oh*op;
              SetKernelOfMultiplicativeGeneralMapping(op,PreImage(oh,k));
              AddNaturalHomomorphismsPool(G,
                  KernelOfMultiplicativeGeneralMapping(op),
                                          op,Length(b));
            else
              k:=[]; # do not trigger improvement
            fi;
          else
            k:=KernelOfMultiplicativeGeneralMapping(op);
            SetSize(Range(op),IndexNC(gimg,k));
            # keep action knowledge
            op:=oh*op;
            SetKernelOfMultiplicativeGeneralMapping(op,PreImage(oh,k));
            AddNaturalHomomorphismsPool(G,
                KernelOfMultiplicativeGeneralMapping(op),
                                        op,Length(b));
          fi;

          if Size(k)=1 then
            improve:=true;
            bestblock:=b;
            bestop:=op;
          fi;
        fi;
        if improve then
          # update mapping
          bdom:=bestblock;
          img:=Image(bestop,G);
          dom:=MovedPoints(img);
        fi;
      fi;
    until improve=false;
  fi;
  Info(InfoFactor,1,"end of blocks search");
  return DegreeNaturalHomomorphismsPool(G,N);
end);

#############################################################################
##
#M  FindActionKernel(<G>)  . . . . . . . . . . . . . . . . . . . . generic
##
InstallMethod(FindActionKernel,"generic for finite groups",IsIdenticalObj,
  [IsGroup and IsFinite,IsGroup],0,GenericFindActionKernel);

RedispatchOnCondition(FindActionKernel,IsIdenticalObj,[IsGroup,IsGroup],
  [IsGroup and IsFinite,IsGroup],0);

InstallMethod(FindActionKernel,"general case: can't do",IsIdenticalObj,
  [IsGroup,IsGroup],0,ReturnFail);

BindGlobal("FactPermRepMaxDesc",function(g,n,maxlev)
local lim,deg,all,c,recurse,use,start;
  if ValueOption("infactorpermrep")=true then return false;fi;
  deg:=DegreeNaturalHomomorphismsPool(g,n);
  if deg=fail then deg:=infinity;fi;
  all:=[];
  start:=ClosureGroup(DerivedSubgroup(g),n);
  lim:=RootInt(IndexNC(g,n),3)*Maximum(1,LogInt(IndexNC(g,start),2));
  c:=start;
  Info(InfoFactor,1,"Try maximals for limit ",lim," from ",deg);

  recurse:=function(a,lev)
  local m,ma,nm,i,j,co,wait,use;
    Info(InfoFactor,3,"pop in ",lev);
    m:=[a];
    while Length(m)>0 do
      wait:=[];
      ma:=[];
      for i in m do
        if ForAll(all,y->RepresentativeAction(g,i,y)=fail) then
          Add(all,i);
          Info(InfoFactor,2,"Maximals of index ",IndexNC(g,i));
          nm:=TryMaximalSubgroupClassReps(i:inmax,infactorpermrep,cheap);
          nm:=Filtered(nm,x->IndexNC(g,x)<=lim and IsSubset(x,n) and not
          IsNormal(g,x));
          for j in nm do
            if IsSubset(j,c) then
              use:=ClosureGroup(n,DerivedSubgroup(j));
              if not IsSubset(use,c) then
                j:=use;
                use:=true;
              else
                Add(wait,j);
                use:=false;
              fi;
            else
              use:=true;
            fi;
            if use then
              co:=Core(g,j);
              AddNaturalHomomorphismsPool(g,co,j,IndexNC(g,j));
              c:=Intersection(co,c);
              Add(ma,j);
            fi;
          od;
        else
          Info(InfoFactor,2,"discard conjugate");
        fi;
      od;
      if Length(ma)>0 then
        CloseNaturalHomomorphismsPool(g,n);
        i:=DegreeNaturalHomomorphismsPool(g,n);
        if i<deg then
          deg:=i;
          Info(InfoFactor,1,"Itmax improves to degree ",deg);
          if lev>1 or deg<lim then return true;fi;
        fi;
        m:=ma;
        SortBy(m,x->-Size(x));
      elif lev<maxlev then
        # no improvement. Go down
        wait:=Filtered(wait,x->IndexNC(g,x)*10<=lim);
        for i in wait do
          if recurse(i,lev+1) then return true;fi;
        od;
        m:=[];
      else
        m:=[];
      fi;
    od;
    if Size(c)>Size(n) then
      Info(InfoFactor,3,"pop up failure ",Size(c));
    else
      Info(InfoFactor,3,"pop up found ",Size(c));
    fi;
    return false;
  end;

  return recurse(start,1);

end);


#############################################################################
##
#M  FindActionKernel(<G>)  . . . . . . . . . . . . . . . . . . . . permgrp
##
InstallMethod(FindActionKernel,"perm",IsIdenticalObj,
  [IsPermGroup,IsPermGroup],0,
function(G,N)
local pool, dom, bestdeg, blocksdone, o, s, badnormals, cnt, v, u, oo, m,
      badcomb, idx, i, comb,act,k,j;

  if IndexNC(G,N)<50 then
    # small index, anything is OK
    return GenericFindActionKernel(G,N);
  else
    # get the known ones, including blocks &c. which might be of use
    DoCheapActionImages(G);

    # find smallish layer actions
    oo:=ClosureGroup(SolvableRadical(G),N);
    dom:=ChiefSeriesThrough(G,[oo,N]);
    dom:=Filtered(dom,x->IsSubset(oo,x) and IsSubset(x,N));

    i:=2;
    while i<=Length(dom) do
      j:=i;
      while j<Length(dom)
        #and HasElementaryAbelianFactorGroup(dom[i-1],dom[j+1])
        and IndexNC(dom[i-1],dom[j+1])<=2000 do
        j:=j+1;
      od;
      if IndexNC(dom[i-1],dom[j])<=2000 then
        v:=RightTransversal(dom[i-1],dom[j]);
        oo:=OrbitsDomain(G,v,function(rep,g)
          return v[PositionCanonical(v,rep^g)];
          end);
        for k in oo do
          if Length(k)>1 then
            u:=Stabilizer(G,k[1],function(x,g)
              return v[PositionCanonical(v,x^g)];
            end);
            repeat
              if not IsNormal(G,u) then
                AddNaturalHomomorphismsPool(G,Core(G,u),u,IndexNC(G,u));
              fi;
              m:=u;
              u:=ClosureGroup(N,DerivedSubgroup(u));
            until m=u;
          fi;
        od;
      fi;
      i:=j+1;
    od;

    pool:=NaturalHomomorphismsPool(G);
    dom:=MovedPoints(G);

    # store regular to have one anyway
    bestdeg:=IndexNC(G,N);
    AddNaturalHomomorphismsPool(G,N,N,bestdeg);

    # check if there are multiple orbits
    o:=Orbits(G,MovedPoints(G));
    s:=List(o,i->Stabilizer(G,i,OnTuples));
    if not ForAny(s,i->IsSubset(N,i)) then
      Info(InfoFactor,2,"Try reduction to orbits");
      s:=List(s,i->ClosureGroup(i,N));
      if Intersection(s)=N then
        Info(InfoFactor,1,"Reduction to orbits will do");
        List(s,i->NaturalHomomorphismByNormalSubgroup(G,i));
      fi;
    fi;

    CloseNaturalHomomorphismsPool(G,N);

    # action in orbit image -- sometimes helps
    if Length(o)>1 then
      for i in o do

        act:=ActionHomomorphism(G,i,OnPoints,"surjective");
        k:=KernelOfMultiplicativeGeneralMapping(act);
        k:=ClosureGroup(k,N); # pre-image of (image of normal subgroup under act)
        u:=Image(act,N);
        v:=NaturalHomomorphismByNormalSubgroupNC(Image(act),u);

        o:=DegreeNaturalHomomorphismsPool(Image(act),u);
        if IsInt(o) then # otherwise its solvable factor we do differently
          AddNaturalHomomorphismsPool(G,k,act*v,o);
        fi;
      od;
      CloseNaturalHomomorphismsPool(G,N);
    fi;

    bestdeg:=DegreeNaturalHomomorphismsPool(G,N);

    Info(InfoFactor,1,"Orbits and known, best Index ",bestdeg);

    blocksdone:=false;
    # use subgroup that fixes a base of N
    # get orbits of a suitable stabilizer.
    o:=BaseOfGroup(N);
    s:=Stabilizer(G,o,OnTuples);
    badnormals:=Filtered(pool.ker,i->IsSubset(i,N) and Size(i)>Size(N));
    if Size(s)>1 and IndexNC(G,s)/Size(N)<2000 and bestdeg>IndexNC(G,s) then
      cnt:=Filtered(OrbitsDomain(s,dom),i->Length(i)>1);
      for i in cnt do
        v:=ClosureGroup(N,Stabilizer(s,i[1]));
        if Size(v)>Size(N) and IndexNC(G,v)<2000
          and not ForAny(badnormals,j->IsSubset(v,j)) then
          u:=Core(G,v);
          if Size(u)>Size(N) and IsSubset(u,N) and not u in badnormals then
            Add(badnormals,u);
          fi;
          AddNaturalHomomorphismsPool(G,u,v,IndexNC(G,v));
        fi;
      od;

      # try also intersections
      CloseNaturalHomomorphismsPool(G,N);

      bestdeg:=DegreeNaturalHomomorphismsPool(G,N);

      Info(InfoFactor,1,"Base Stabilizer and known, best Index ",bestdeg);

      if bestdeg<500 and bestdeg<IndexNC(G,N) then
        # should be better...
        bestdeg:=ImproveActionDegreeByBlocks(G,N,
          GetNaturalHomomorphismsPool(G,N));
        blocksdone:=true;
        Info(InfoFactor,2,"Blocks improve to ",bestdeg);
      fi;
    fi;

    # then we should look at the orbits of the normal subgroup to see,
    # whether anything stabilizing can be of use
    o:=Filtered(OrbitsDomain(N,dom),i->Length(Orbit(G,i[1]))>Length(i));
    Apply(o,Set);
    oo:=OrbitsDomain(G,o,OnSets);
    s:=G;
    for i in oo do
      s:=StabilizerOfBlockNC(s,i[1]);
    od;
    Info(InfoFactor,2,"stabilizer of index ",IndexNC(G,s));

    if not ForAny(badnormals,j->IsSubset(s,j)) then
      m:=Core(G,s); # the normal subgroup we get this way.
      if Size(m)>Size(N) and IsSubset(m,N) and not m in badnormals then
        Add(badnormals,m);
      fi;
      AddNaturalHomomorphismsPool(G,m,s,IndexNC(G,s));
    else
      m:=G; # guaranteed fail
    fi;

    if Size(m)=Size(N) and IndexNC(G,s)<bestdeg then
      bestdeg:=IndexNC(G,s);
      blocksdone:=false;
      Info(InfoFactor,2,"Orbits Stabilizer improves to index ",bestdeg);
    elif Size(m)>Size(N) then
      # no hard work for trivial cases
      if 2*IndexNC(G,N)>Length(o) then
        # try to find a subgroup, which does not contain any part of m
        # For wreath products (the initial aim), the following method works
        # fairly well
        v:=Subgroup(G,Filtered(GeneratorsOfGroup(G),i->not i in m));
        v:=SmallGeneratingSet(v);

        cnt:=1;
        badcomb:=[];
        repeat
          Info(InfoFactor,3,"Trying",cnt);
          for comb in Combinations([1..Length(v)],cnt) do
    #Print(">",comb,"\n");
            if not ForAny(badcomb,j->IsSubset(comb,j)) then
              u:=SubgroupNC(G,v{comb});
              o:=ClosureGroup(N,u);
              idx:=Size(G)/Size(o);
              if idx<10 and Factorial(idx)*Size(N)<Size(G) then
                # the permimage won't be sufficiently large
                AddSet(badcomb,Immutable(comb));
              fi;
              if idx<bestdeg and Size(G)>Size(o)
              and not ForAny(badnormals,i->IsSubset(o,i)) then
                m:=Core(G,o);
                if Size(m)>Size(N) and IsSubset(m,N) then
                  Info(InfoFactor,3,"Core ",comb," failed");
                  AddSet(badcomb,Immutable(comb));
                  if not m in badnormals then
                    Add(badnormals,m);
                  fi;
                fi;
                if idx<bestdeg and Size(m)=Size(N) then
                  Info(InfoFactor,3,"Core ",comb," succeeded");
                  bestdeg:=idx;
                  AddNaturalHomomorphismsPool(G,N,o,bestdeg);
                  blocksdone:=false;
                  cnt:=0;
                fi;
              fi;
            fi;
          od;
          cnt:=cnt+1;
        until cnt>Length(v);
      fi;
    fi;

    Info(InfoFactor,2,"Orbits Stabilizer, Best Index ",bestdeg);
    # first force blocks
    if (not blocksdone) and bestdeg<200 and bestdeg<IndexNC(G,N) then
      Info(InfoFactor,3,"force blocks");
      bestdeg:=ImproveActionDegreeByBlocks(G,N,
        GetNaturalHomomorphismsPool(G,N));
      blocksdone:=true;
      Info(InfoFactor,2,"Blocks improve to ",bestdeg);
    fi;

    if bestdeg=IndexNC(G,N) or
      (bestdeg>400 and not(bestdeg<=2*NrMovedPoints(G))) then
      if GenericFindActionKernel(G,N,bestdeg,s)<>fail then
        blocksdone:=true;
      fi;
      bestdeg:=DegreeNaturalHomomorphismsPool(G,N);
      Info(InfoFactor,1,"  Random search found ",bestdeg);
    fi;

    if bestdeg>10000 and bestdeg^2>IndexNC(G,N) then
      cnt:=bestdeg;
      FactPermRepMaxDesc(G,N,5);
      bestdeg:=DegreeNaturalHomomorphismsPool(G,N);
      if bestdeg<cnt then blocksdone:=false;fi;
      Info(InfoFactor,1,"Iterated maximals found ",bestdeg);
    fi;

    if not blocksdone then
      ImproveActionDegreeByBlocks(G,N,GetNaturalHomomorphismsPool(G,N));
    fi;

    Info(InfoFactor,3,"return hom");
    return GetNaturalHomomorphismsPool(G,N);
    return o;
  fi;

end);

#############################################################################
##
#M  FindActionKernel(<G>)  . . . . . . . . . . . . . . . . . . . . generic
##
InstallMethod(FindActionKernel,"Niceo",IsIdenticalObj,
  [IsGroup and IsHandledByNiceMonomorphism,IsGroup],0,
function(G,N)
local hom,hom2;
  hom:=NiceMonomorphism(G);
  hom2:=GenericFindActionKernel(NiceObject(G),Image(hom,N));
  if hom2<>fail then
    return hom*hom2;
  else
    return hom;
  fi;
end);

BindGlobal("FACTGRP_TRIV",Group([],()));

#############################################################################
##
#M  NaturalHomomorphismByNormalSubgroup( <G>, <N> )  . .  mapping G ->> G/N
##                             this function returns an epimorphism from G
##  with kernel N. The range of this mapping is a suitable (isomorphic)
##  permutation group (with which we can compute much easier).
InstallMethod(NaturalHomomorphismByNormalSubgroupOp,
  "search for operation",IsIdenticalObj,[IsGroup,IsGroup],0,
function(G,N)
local proj,h,pool;

  # catch the trivial case N=G
  if CanComputeIndex(G,N) and IndexNC(G,N)=1 then
    h:=FACTGRP_TRIV;  # a new group is created
    h:=GroupHomomorphismByImagesNC( G, h, GeneratorsOfGroup( G ),
           List( GeneratorsOfGroup( G ), i -> () ));  # a new group is created
    SetKernelOfMultiplicativeGeneralMapping( h, G );
    return h;
  fi;

  # catch trivial case N=1 (IsTrivial might not be set)
  if (HasSize(N) and Size(N)=1) or (HasGeneratorsOfGroup(N) and
    ForAll(GeneratorsOfGroup(N),IsOne)) then
    return IdentityMapping(G);
  fi;

  # check, whether we already know a factormap
  pool:=NaturalHomomorphismsPool(G);
  h:=PositionSet(pool.ker,N);
  if h<>fail and IsGeneralMapping(pool.ops[h]) then
    return GetNaturalHomomorphismsPool(G,N);
  fi;

  DoCheapActionImages(G);
  if HasSolvableRadical(G) and N=SolvableRadical(G) then
    h:=GetNaturalHomomorphismsPool(G,N);
  fi;

  if HasDirectProductInfo(G) and DegreeNaturalHomomorphismsPool(G,N)=fail then
    for proj in [1..Length(DirectProductInfo(G).groups)] do
      proj:=Projection(G,proj);
      h:=NaturalHomomorphismByNormalSubgroup(Image(proj,G),Image(proj,N));
      AddNaturalHomomorphismsPool(G,
        ClosureGroup(KernelOfMultiplicativeGeneralMapping(proj),N),proj*h);
    od;
  fi;
  CloseNaturalHomomorphismsPool(G,N);

  h:=DegreeNaturalHomomorphismsPool(G,N);
  if h<>fail and RootInt(h^3,2)<IndexNC(G,N) then
    h:=GetNaturalHomomorphismsPool(G,N);
  else
    h:=fail;
  fi;

  if h=fail then
    # now we try to find a suitable operation

    # redispatch upon finiteness test, as following will fail in infinite case
    if not HasIsFinite(G) and IsFinite(G) then
      return NaturalHomomorphismByNormalSubgroupOp(G,N);
    fi;

    h:=FindActionKernel(G,N);
    if h<>fail then
      Info(InfoFactor,1,"Action of degree ",
        Length(MovedPoints(Range(h)))," found");
    else
      Error("I don't know how to find a natural homomorphism for <N> in <G>");
      # nothing had been found, Desperately one could try again, but that
      # would create a possible infinite loop.
      h:= NaturalHomomorphismByNormalSubgroup( G, N );
    fi;
  fi;
  # return the map
  return h;
end);

RedispatchOnCondition(NaturalHomomorphismByNormalSubgroupNCOrig,IsIdenticalObj,
  [IsGroup,IsGroup],[IsGroup and IsFinite,IsGroup],0);

RedispatchOnCondition(NaturalHomomorphismByNormalSubgroupInParent,true,
  [IsGroup],[IsGroup and IsFinite],0);

RedispatchOnCondition(FactorGroupNC,IsIdenticalObj,
  [IsGroup,IsGroup],[IsGroup and IsFinite,IsGroup],0);

#############################################################################
##
#M  NaturalHomomorphismByNormalSubgroup( <G>, <N> ) . .  for solvable factors
##
NH_TRYPCGS_LIMIT:=30000;
InstallMethod( NaturalHomomorphismByNormalSubgroupOp,
  "test if known/try solvable factor for permutation groups",
  IsIdenticalObj, [ IsPermGroup, IsPermGroup ], 0,
function( G, N )
local   map,  pcgs, A, filter;

  if KnownNaturalHomomorphismsPool(G,N) then
    A:=DegreeNaturalHomomorphismsPool(G,N);
    if A<50 or (IsInt(A) and A<IndexNC(G,N)/LogInt(IndexNC(G,N),2)^2) then
      map:=GetNaturalHomomorphismsPool(G,N);
      if map<>fail then
        Info(InfoFactor,2,"use stored map");
        return map;
      fi;
    fi;
  fi;

  if IndexNC(G,N)=1 or Size(N)=1
    or Minimum(IndexNC(G,N),NrMovedPoints(G))>NH_TRYPCGS_LIMIT then
    TryNextMethod();
  fi;

  # Make  a pcgs   based on  an  elementary   abelian series (good  for  ag
  # routines).
  pcgs := TryPcgsPermGroup( [ G, N ], false, false, true );
  if not IsModuloPcgs( pcgs )  then
      TryNextMethod();
  fi;

  # Construct or look up the pcp group <A>.
  A:=CreateIsomorphicPcGroup(pcgs,false,false);

  UseFactorRelation( G, N, A );

  # Construct the epimorphism from <G> onto <A>.
  map := rec();
  filter := IsPermGroupGeneralMappingByImages and
            IsToPcGroupGeneralMappingByImages and
            IsGroupGeneralMappingByPcgs and
            IsMapping and IsSurjective and
            HasSource and HasRange and
            HasPreImagesRange and HasImagesSource and
            HasKernelOfMultiplicativeGeneralMapping;

  map.sourcePcgs       := pcgs;
  map.sourcePcgsImages := GeneratorsOfGroup( A );

  ObjectifyWithAttributes( map,
  NewType( GeneralMappingsFamily
          ( ElementsFamily( FamilyObj( G ) ),
            ElementsFamily( FamilyObj( A ) ) ), filter ),
            Source,G,
            Range,A,
            PreImagesRange,G,
            ImagesSource,A,
            KernelOfMultiplicativeGeneralMapping,N
            );

  return map;
end );

#############################################################################
##
#F  PullBackNaturalHomomorphismsPool( <hom> )
##
InstallGlobalFunction(PullBackNaturalHomomorphismsPool,function(hom)
local s,r,nat,k;
  s:=Source(hom);
  r:=Range(hom);
  for k in NaturalHomomorphismsPool(r).ker do
    nat:=hom*NaturalHomomorphismByNormalSubgroup(r,k);
    AddNaturalHomomorphismsPool(s,PreImage(hom,k),nat);
  od;
end);

#############################################################################
##
#F  TryQuotientsFromFactorSubgroups(<hom>,<ker>,<bound>)
##
InstallGlobalFunction(TryQuotientsFromFactorSubgroups,function(hom,ker,bound)
local s,p,k,it,u,v,d,ma,mak,lev,sub,low;
  s:=Source(hom);
  p:=Image(hom);
  k:=KernelOfMultiplicativeGeneralMapping(hom);
  it:=DescSubgroupIterator(p:skip:=4);
  repeat
    u:=NextIterator(it);
    Info(InfoExtReps,2,"Factor subgroup index ",Index(p,u));
    v:=PreImage(hom,u);
    d:=DerivedSubgroup(v);
    if not IsSubset(d,k) then
      d:=ClosureGroup(ker,d);
      if not IsSubset(d,k) then
        ma:=NaturalHomomorphismByNormalSubgroup(v,d);
        mak:=Image(ma,k);
        lev:=0;
        sub:=fail;
        while sub=fail do
          lev:=lev+1;
          low:=ShallowCopy(LowLayerSubgroups(Range(ma),lev));
          SortBy(low,x->-Size(x));
          sub:=First(low,x->not IsSubset(x,mak));
        od;
        sub:=PreImage(ma,sub);
        Info(InfoExtReps,2,"Found factor permrep ",IndexNC(s,sub));
        d:=Core(s,sub);
        AddNaturalHomomorphismsPool(s,d,sub);
        k:=Intersection(k,d);
        if Size(k)=Size(ker) then return;fi;
      fi;
    fi;
  until IndexNC(p,u)>=bound;
end);

#############################################################################
##
#M  UseFactorRelation( <num>, <den>, <fac> )  . . . .  for perm group factors
##
InstallMethod( UseFactorRelation,
   [ IsGroup and HasSize, IsObject, IsPermGroup ],
   function( num, den, fac )
   local limit;
   if not HasSize( fac ) then
     if HasSize(den) then
       SetSize( fac, Size( num ) / Size( den ) );
     else
       limit := Size( num );
       if IsBound( StabChainOptions(fac).limit ) then
         limit := Minimum( limit, StabChainOptions(fac).limit );
       fi;
       StabChainOptions(fac).limit:=limit;
     fi;
   fi;
   TryNextMethod();
   end );

[ Verzeichnis aufwärts0.52unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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