1#############################################################################
2##
3##  This file is part of GAP, a system for computational discrete algebra.
4##  This file's authors include Alexander Hulpke.
5##
6##  Copyright of GAP belongs to its developers, whose names are too numerous
7##  to list here. Please refer to the COPYRIGHT file for details.
8##
9##  SPDX-License-Identifier: GPL-2.0-or-later
10##
11##  This file contains functions that deal with action on chief factors or
12##  composition factors and the representation of such groups in a nice way
13##  as permutation groups.
14##
15
16InstallMethod( FittingFreeLiftSetup, "permutation", true, [ IsPermGroup ],0,
17function( G )
18local   pcgs,r,hom,A,iso,p,i,depths,ords,b,mo,pc,limit,good,new,start,np;
19
20  r:=RadicalGroup(G);
21  if Size(r)=1 then
22    hom:=IdentityMapping(G);
23  else
24    hom:=NaturalHomomorphismByNormalSubgroup(G,r);
25  fi;
26
27  A:=Image(hom);
28  if IsPermGroup(A) and NrMovedPoints(A)/Size(A)*Size(Socle(A))
29      >SufficientlySmallDegreeSimpleGroupOrder(Size(A)) then
30    A:=SmallerDegreePermutationRepresentation(A:cheap);
31    Info(InfoGroup,3,"Radical factor degree reduced ",NrMovedPoints(Image(hom)),
32         " -> ",NrMovedPoints(Image(A)));
33    hom:=hom*A;
34  fi;
35
36  pcgs := TryPcgsPermGroup( G,r, false, false, true );
37  if not IsPcgs( pcgs )  then
38    return fail;
39  fi;
40
41  # do we have huge steps? Refine.
42  limit:=10^5;
43  depths:=IndicesEANormalSteps(pcgs);
44  ords:=RelativeOrders(pcgs);
45
46  # can we simply use the existing Pcgs?
47  A:=List([2..Length(depths)],x->Product(ords{[depths[x-1]..depths[x]-1]}));
48  good:=true;
49  while Length(A)>0 and Maximum(A)>limit and good do
50    A:=depths[Position(A,Maximum(A))];
51    p:=Filtered([A+1..Length(pcgs)],x->IsNormal(G,SubgroupNC(G,pcgs{[x..Length(pcgs)]})));
52    # maximal split in middle
53    if Length(p)>0 then
54      i:=List(p,x->[(x-A)*(18-x),x]);
55      Sort(i);
56      p:=i[Length(i)][2]; # best split
57      if not p in depths then
58        depths:=Concatenation(Filtered(depths,x->x<=A),[p],
59                  Filtered(depths,x->x>A));
60      else
61        good:=false;
62      fi;
63    else
64      good:=false;
65    fi;
66    A:=List([2..Length(depths)],x->Product(ords{[depths[x-1]..depths[x]-1]}));
67  od;
68
69  # still bad?
70  good:=true;
71  if Length(A)>0 and Maximum(A)>limit and good then
72    A:=depths[Position(A,Maximum(A))];
73    p:=ords[A];
74    A:=[A..depths[Position(depths,A)+1]-1];
75    pc:=InducedPcgsByPcSequence(pcgs,pcgs{[A[1]..Length(pcgs)]}) mod
76        InducedPcgsByPcSequence(pcgs,pcgs{[A[Length(A)]+1..Length(pcgs)]});
77    mo:=LinearActionLayer(G,pc);
78    mo:=GModuleByMats(mo,GF(p));
79    b:=MTX.BasesCompositionSeries(mo);
80    if Length(b)>2 then
81      new:=[1];
82      start:=1;
83      for i in [2..Length(b)] do
84        if p^Length(b[i])/start>limit then
85          if i-1 in new then
86            Add(new,i);
87            start:=p^Length(b[i]);
88          else
89            Add(new,i-1);
90            start:=p^Length(b[i-1]);
91          fi;
92        fi;
93      od;
94      if not Length(b) in new then
95        Add(new,Length(b));
96      fi;
97
98      # now form pc elements
99      np:=[];
100      for i in [2..Length(new)] do
101        start:=BaseSteinitzVectors(b[new[i]],b[new[i-1]]).factorspace;
102        start:=List(start,x->PcElementByExponents(pc,List(x,Int)));
103        Add(np,start);
104      od;
105      np:=Reversed(np);
106      b:=A[1];
107      pc:=Concatenation(pcgs{[1..b-1]},
108           Concatenation(np),
109           pcgs{[A[Length(A)]+1..Length(pcgs)]});
110
111      pcgs:=PermgroupSuggestPcgs(G,pc);
112      #depths:=Concatenation(Filtered(depths,x->x<=b),
113#              List([1..Length(np)-1],x->b+Sum(List(np{[1..x]},Length))),
114#              Filtered(depths,x->x>A[Length(A)]));
115      depths:=IndicesEANormalSteps(pcgs);
116      ords:=RelativeOrders(pcgs);
117    else
118      good:=false;
119    fi;
120    A:=List([2..Length(depths)],x->Product(ords{[depths[x-1]..depths[x]-1]}));
121  fi;
122
123  if not HasPcgsElementaryAbelianSeries(r) then
124    SetPcgsElementaryAbelianSeries(r,pcgs);
125  fi;
126
127  A:=CreateIsomorphicPcGroup(pcgs,true,false);
128
129  iso := GroupHomomorphismByImagesNC( r, A, pcgs, GeneratorsOfGroup( A ));
130  SetIsBijective( iso, true );
131  return rec(pcgs:=pcgs,
132             depths:=depths,
133             radical:=r,
134             pcisom:=iso,
135             factorhom:=hom);
136
137end );
138
139
140#testfunction for AutomorphismRepresentingGroup
141#test:=function(start)
142#local it,g,a,r;
143#  it:=SimpleGroupsIterator(start:NOPSL2);
144#  repeat
145#    g:=NextIterator(it);
146#    Print("@ Trying ",g," ",Size(g),"\n");
147#    a:=AutomorphismGroup(g);
148#    r:=AutomorphismRepresentingGroup(g,GeneratorsOfGroup(a));
149#    Print("@ Got ",NrMovedPoints(r[1])," from ",NrMovedPoints(g),"\n");
150#  until false;
151#end;
152InstallGlobalFunction(AutomorphismRepresentingGroup,function(G,autos)
153local G0,a0,tryrep,sel,selin,a,s,dom,iso,stabs,outs,map,i,j,p,found,seln,
154  sub,d;
155
156  tryrep:=function(rep,bound)
157  local Gi,repi,maps,v,w,cen,hom;
158     Gi:=Image(rep,G);
159     if not IsSubset(MovedPoints(Gi),[1..LargestMovedPoint(Gi)]) then
160       rep:=rep*ActionHomomorphism(Gi,MovedPoints(Gi),"surjective");
161       Gi:=Image(rep,G);
162     fi;
163     Info(InfoGroup,2,"Trying degree ",NrMovedPoints(Gi));
164     maps:=List(sel,x->InducedAutomorphism(rep,autos[x]));
165     #for v in maps do SetIsBijective(v,true); od;
166     if ForAll(maps,x->IsConjugatorAutomorphism(x:cheap)) then
167        # the representation extends
168        v:=List( maps, ConjugatorOfConjugatorIsomorphism );
169        w:=ClosureGroup(Gi,v);
170        Info(InfoGroup,1,"all conjugator degree ",NrMovedPoints(w));
171
172        maps:=[];
173        maps{sel}:=v;
174        maps{selin}:=List(selin,x->
175          Image(rep,
176            ConjugatorOfConjugatorIsomorphism(autos[x])));
177
178        cen:=Centralizer(w,Gi);
179        if Size(cen)=1 then
180          return [w,rep,maps];
181        else
182          Info(InfoGroup,2,"but centre");
183          hom:=NaturalHomomorphismByNormalSubgroupNC(w,cen);
184          if IsPermGroup(Image(hom)) and
185            NrMovedPoints(Image(hom))<=bound then
186
187            #Print("QQQ\n");
188            return [Image(hom,w),rep*hom,List(maps,x->Image(hom,x))];
189          fi;
190
191        fi;
192     else
193       Info(InfoGroup,2,"Does not work");
194     fi;
195     return fail;
196  end;
197
198  selin:=Filtered([1..Length(autos)],x->IsInnerAutomorphism(autos[x]));
199  sel:=Difference([1..Length(autos)],selin);
200
201  # first try given rep
202  if NrMovedPoints(G)^3>Size(G) then
203    # likely too high degree. Try to reduce first
204    a:=SmallerDegreePermutationRepresentation(G:cheap);
205    a:=tryrep(a,4*NrMovedPoints(Image(a)));
206  elif not IsSubset(MovedPoints(G),[1..LargestMovedPoint(G)]) then
207    a:=tryrep(ActionHomomorphism(G,MovedPoints(G),"surjective"),
208                4*NrMovedPoints(G));
209  else
210    a:=tryrep(IdentityMapping(G),4*NrMovedPoints(G));
211    if a=fail and ForAll(autos,x->IsConjugatorAutomorphism(x:cheap)) then
212      a:=tryrep(SmallerDegreePermutationRepresentation(G:cheap),4*NrMovedPoints(G));
213    fi;
214  fi;
215  if a<>fail then return a;fi;
216
217  # then (assuming G simple) try transitive action of small degree
218  dom:=Set(Orbit(G,LargestMovedPoint(G)));
219  s:=Blocks(G,dom);
220  if Length(s)=1 then
221    if Set(dom)=[1..Length(dom)] then
222      Info(InfoGroup,2,"reduction is equal to G");
223      iso:=fail;
224    else
225      Info(InfoHomClass,2,"point action");
226      iso:=ActionHomomorphism(G,dom,"surjective");
227    fi;
228  else
229    Info(InfoHomClass,2,"block refinement");
230    iso:=ActionHomomorphism(G,s,OnSets,"surjective");
231  fi;
232
233  if iso<>fail then
234    # try the new rep
235    a:=tryrep(iso,4*NrMovedPoints(G));
236    if a<>fail then return a;fi;
237
238    # otherwise go to new small deg rep
239    G:=Image(iso,G);
240    autos:=List(autos,x->InducedAutomorphism(iso,x));
241  fi;
242
243  # test the automorphisms that are not inner. (The conjugator automorphisms
244  # have no reason to be normal in all automoirphisms, so this will not
245  # work.)
246  seln:=Filtered(sel,x->not IsInnerAutomorphism(autos[x]));
247
248  # autos{seln} generates the non-perm automorphism group. Enumerate
249  # use that automorphism is conjugator is stabilizer is conjugate
250  stabs:=[Stabilizer(G,1)];
251  outs:=[IdentityMapping(G)];
252  i:=1;
253  while i<=Length(stabs) do
254    for j in seln do
255      sub:=Image(autos[j],stabs[i]);
256      p:=0;
257      found:=fail;
258      while found=fail and p<Length(stabs) do
259        p:=p+1;
260        found:=RepresentativeAction(G,sub,stabs[p]);
261        #Print(j," maps ",i," to ",p,"\n");
262      od;
263
264      if found=fail then
265        # new copy
266        Add(stabs,sub);
267        map:=outs[i]*autos[j];
268        Add(outs,map);
269      fi;
270
271    od;
272    i:=i+1;
273  od;
274  Info(InfoGroup,1,"Build ",Length(outs)," copies");
275  if Length(stabs)=1 then
276    # the group is given in a representation in which there is a centralizer
277    # in Sn
278    a:=tryrep(IdentityMapping(G),infinity);
279    return a;
280
281    Error("why only one -- should have been found before");
282  fi;
283
284  d:=DirectProduct(List(stabs,x->G));
285  p:=[];
286  for i in GeneratorsOfGroup(G) do
287    a:=One(d);
288    for j in [1..Length(stabs)] do
289      a:=a*Image(Embedding(d,j),PreImagesRepresentative(outs[j],i));
290    od;
291    Add(p,a);
292  od;
293
294  a:=Subgroup(d,p);
295  SetSize(a,Size(G));
296  p:=GroupHomomorphismByImagesNC(G,a,GeneratorsOfGroup(G),p);
297
298  a:=tryrep(p,4*NrMovedPoints(G));
299  if a<>fail then
300    if iso<>fail then
301      a[2]:=iso*a[2];
302    fi;
303    return a;
304  fi;
305
306  Info(InfoGroup,1,"Wreath embedding failed");
307  Error("This should never happen");
308
309end);
310
311InstallGlobalFunction(EmbedAutomorphisms,function(arg)
312local G,H,tg,th,hom, tga, Gemb, C, outs, auts, ar, Hemb;
313
314  G:=arg[1];
315  H:=arg[2];
316  tg:=arg[3];
317  th:=arg[4];
318  if Length(arg)>4 then
319    outs:=arg[4];
320  else
321    outs:=fail;
322  fi;
323  if th=tg then
324    hom:=IdentityMapping(tg);
325  else
326    hom:=IsomorphismGroups(th,tg);
327  fi;
328  if hom=fail then
329    Error("nonisomorphic simple groups!");
330  fi;
331  tga:=List(GeneratorsOfGroup(H),
332            i->GroupHomomorphismByImagesNC(tg,tg,
333               GeneratorsOfGroup(tg),
334               List(GeneratorsOfGroup(tg),
335                    j->Image(hom,PreImagesRepresentative(hom,j)^i))));
336
337  Gemb:=fail;
338  if ForAll(tga,IsConjugatorAutomorphism) then
339    Info(InfoHomClass,4,"All automorphism are conjugator");
340    C:=ClosureGroup(G,List(tga,ConjugatorInnerAutomorphism));
341    #reco:=ConstructiveRecognitionAlmostSimpleGroupTom(tg);
342    if outs=fail then
343      outs:=Size(AutomorphismGroup(tg))/Size(tg);
344    fi;
345    if Size(C)/Size(tg)=outs then
346      Info(InfoHomClass,2,"Automorphisms realize full automorphism group");
347      Gemb:=IdentityMapping(G);
348      G:=C;
349      tga:=List(tga,ConjugatorInnerAutomorphism);
350    fi;
351  fi;
352
353  if Gemb=fail then
354    # not all realizable or too small -> build new group
355    Info(InfoHomClass,2,"Compute full automorphism group");
356    auts:=AutomorphismGroup(tg);
357    auts:=GeneratorsOfGroup(auts);
358    ar:=AutomorphismRepresentingGroup(tg,Concatenation(
359           auts,
360           List(GeneratorsOfGroup(G),i->ConjugatorAutomorphism(tg,i)),
361           tga));
362
363    tga:=ar[3]{[Length(ar[3])-Length(tga)+1..Length(ar[3])]};
364    Gemb:=GroupHomomorphismByImagesNC(G,ar[1],GeneratorsOfGroup(G),
365          ar[3]{[Length(auts)+1..Length(auts)+Length(GeneratorsOfGroup(G))]});
366    G:=ar[1];
367  else
368    Gemb:=IdentityMapping(G);
369  fi;
370  Hemb:=GroupHomomorphismByImagesNC(H,Group(tga),GeneratorsOfGroup(H),tga);
371  return [G,Gemb,Hemb];
372end);
373
374InstallGlobalFunction(WreathActionChiefFactor,
375function(G,M,N)
376local cs,i,k,u,o,norm,T,Thom,autos,ng,a,Qhom,Q,E,Ehom,genimages,
377      n,w,embs,reps,act,img,gimg,gens;
378
379  # get the simple factor(s)
380  cs:=CompositionSeries(M);
381  # the cs with N gives a cs for M/N.
382  # take the first subnormal subgroup that is not  in N. This will be the
383  # subgroup
384  u:=fail;
385  if Size(N)=1 then
386    if Length(cs)=2 and Size(Centralizer(G,M))=1 then
387      return [G,IdentityMapping(G),G,M,1];
388    fi;
389    u:=cs[2];
390  else
391    i:=2;
392    u:=ClosureGroup(N,cs[i]);
393    while Size(u)=Size(M) do
394      i:=i+1;
395      u:=ClosureGroup(N,cs[i]);
396    od;
397  fi;
398
399  o:=OrbitStabilizer(G,u);
400  norm:=o.stabilizer;
401  o:=o.orbit;
402  n:=Length(o);
403  Info(InfoHomClass,1,"Factor: ",Index(u,N),"^",n);
404  Qhom:=ActionHomomorphism(G,o,"surjective");
405  Q:=Image(Qhom,G);
406  Thom:=NaturalHomomorphismByNormalSubgroup(M,u);
407  T:=Image(Thom);
408  if IsSubset(M,norm) then
409    # nothing outer possible
410    a:=Image(Thom);
411  else
412    # get the induced automorphism action of elements
413    ng:=SmallGeneratingSet(norm);
414    autos:=List(ng,i->GroupHomomorphismByImagesNC(T,T,
415                        GeneratorsOfGroup(T),
416                        List(GeneratorsOfGroup(T),
417                          j->Image(Thom,PreImagesRepresentative(Thom,j)^i))));
418    a:=AutomorphismRepresentingGroup(T,autos);
419    Thom:=GroupHomomorphismByImagesNC(norm,a[1],ng,a[3]);
420    a:=a[1];
421  fi;
422
423  # now embed into wreath
424  w:=WreathProduct(a,Q);
425
426  embs:=List([1..n+1],i->Embedding(w,i));
427
428  # define isomorphisms between the components
429  reps:=List([1..n],i->
430          PreImagesRepresentative(Qhom,RepresentativeAction(Q,1,i)));
431
432  genimages:=[];
433  for i in GeneratorsOfGroup(G) do
434    img:=Image(Qhom,i);
435    gimg:=Image(embs[n+1],img);
436    for k in [1..n] do
437      # look at part of i's action on the k-th factor.
438      # we get this by looking at the action of
439      #   reps[k] *   i    *   reps[k^img]^-1
440      # 1   ->    k  ->  k^img    ->           1
441      # on the first component.
442      act:=reps[k]*i*(reps[k^img]^-1);
443      # this must be multiplied *before* permuting
444      gimg:=ImageElm(embs[k],ImageElm(Thom,act))*gimg;
445    od;
446    #gimg:=RestrictedPermNC(gimg,MovedPoints(w));
447    Add(genimages,gimg);
448  od;
449
450  E:=Subgroup(w,genimages);
451  # allow also mapping of `a' by enlarging
452  gens:=GeneratorsOfGroup(G);
453
454  if AssertionLevel()>1 then
455    Ehom:=GroupHomomorphismByImages(G,w,gens,genimages);
456    Assert(1,fail<>Ehom);
457  else
458    Ehom:=GroupHomomorphismByImagesNC(G,w,gens,genimages);
459  fi;
460
461  return [w,Ehom,a,Image(Thom,M),n];
462end);
463
464#############################################################################
465##
466#F  PermliftSeries( <G> )
467##
468InstallGlobalFunction(PermliftSeries,function(G)
469local limit, r, pcgs, ser, ind, m, p, l, l2, good, i, j,nser,hom;
470
471  # Do we limit factor size?
472  limit:=ValueOption("limit");
473
474  if HasStoredPermliftSeries(G) then
475    ser:=StoredPermliftSeries(G);
476    if limit=fail or ForAll([2..Length(ser[1])],
477      i->Size(ser[1][i-1])/Size(ser[1][i])<=limit) then
478      return ser;
479    fi;
480  fi;
481
482  # it seems to be cleaner (and avoids deferring abelian factors) if we
483  # factor out the radical first. (Note: The radical method for perm groups
484  # stores the nat hom.!)
485  r:=RadicalGroup(G);
486
487  if Size(r)=1 then
488    return [[r],false];
489  fi;
490
491  # try to improve the representation of G/r
492  hom:=NaturalHomomorphismByNormalSubgroup(G,r);
493  if IsPermGroup(Range(hom)) then
494    hom:=hom*SmallerDegreePermutationRepresentation(Range(hom):cheap);
495  fi;
496  AddNaturalHomomorphismsPool(G,r,hom);
497
498  # first try whether the pcgs found
499  # is good enough
500  pcgs:=PcgsElementaryAbelianSeries(r);
501  ser:=EANormalSeriesByPcgs(pcgs);
502  if not ForAll(ser,i->IsNormal(G,i)) then
503    # we have to get a better series
504
505    # do we want to reduce the degree?
506    m:=fail;
507    if IsPermGroup(r) then
508      m:=ReducedPermdegree(r);
509    fi;
510    if m<>fail then
511      p:=Image(m);
512      ser:=InvariantElementaryAbelianSeries(p, List( GeneratorsOfGroup( G ),
513              i -> GroupHomomorphismByImagesNC(p,p,GeneratorsOfGroup(p),
514                     List(GeneratorsOfGroup(p),
515                          j->Image(m,PreImagesRepresentative(m,j)^i)))),
516              TrivialSubgroup(p),true);
517      ser:=List(ser,i->PreImage(m,i));
518    else
519      ser:=InvariantElementaryAbelianSeries(r, List( GeneratorsOfGroup( G ),
520              i -> ConjugatorAutomorphismNC( r, i ) ),
521              TrivialSubgroup(G),true);
522    fi;
523
524    # remember there is no universal parent pcgs
525    pcgs:=false;
526    ind:=false;
527  else
528    ind:=IndicesEANormalSteps(pcgs);
529    pcgs:=List([1..Length(ind)],
530      i->InducedPcgsByPcSequenceNC(pcgs,pcgs{[ind[i]..Length(pcgs)]}));
531  fi;
532
533  if limit<>fail then
534    nser:=[ser[1]];
535    for i in [2..Length(ser)] do
536      if Size(ser[i-1])/Size(ser[i])>limit then
537        m:=ModuloPcgs(ser[i-1],ser[i]);
538        p:=RelativeOrders(m)[1];
539        l:=GModuleByMats(LinearActionLayer(G,m),GF(p));
540        l:=MTX.BasesCompositionSeries(l);
541        l2:=[[]];
542        good:=false;
543        for j in [1..Length(l)] do
544          if p^(Length(l[j])-Length(l2[Length(l2)]))>limit then
545            if Length(good)>0 then
546              Add(l2,good);
547            fi;
548          fi;
549          good:=l[j];
550        od;
551        l2:=List(l2,i->List(i,j->PcElementByExponentsNC(m,j)));
552        l2:=List(l2,j->ClosureGroup(ser[i],j));
553        pcgs:=false; # if there was a pcgs is it wrong now
554        Append(nser,Reversed(l2));
555      else
556        Add(nser,ser[i]);
557      fi;
558    od;
559    if nser<>ser then
560      ser:=nser;
561    fi;
562  fi;
563
564  ser:=[ser,pcgs];
565  if not HasStoredPermliftSeries(G) then
566    SetStoredPermliftSeries(G,ser);
567  fi;
568  return ser;
569end);
570
571InstallMethod(StoredPermliftSeries,true,[IsGroup],0,PermliftSeries);
572
573InstallGlobalFunction(EmbeddingWreathInWreath,function(wnew,w,emb,start)
574local info, a, ai, n, gens, imgs, e, e2, shift, hom, i, j;
575  info:=WreathProductInfo(w);
576  a:=GeneratorsOfGroup(info.groups[1]);
577  ai:=List(a,i->Image(emb,i));
578  n:=Length(info.components);
579  gens:=[];
580  imgs:=[];
581  # base
582  for i in [1..n] do
583    e:=Embedding(w,i);
584    e2:=Embedding(wnew,i+start-1);
585    for j in [1..Length(a)] do
586      Add(gens,Image(e,a[j]));
587      Add(imgs,Image(e2,ai[j]));
588    od;
589  od;
590  # complement embeddings
591  e:=Embedding(w,n+1);
592  e2:=Embedding(wnew,Length(WreathProductInfo(wnew).components)+1);
593  shift:=MappingPermListList([1..n],[start..start+n-1]);
594  for j in GeneratorsOfGroup(info.groups[2]) do
595    Add(gens,Image(e,j)); # component permutation in w
596    Add(imgs,Image(e2,j^shift));
597  od;
598  hom:=GroupHomomorphismByImages(w,wnew,gens,imgs);
599  return hom;
600end);
601
602InstallGlobalFunction(EmbedFullAutomorphismWreath,function(w,a,t,n)
603local au, agens, agau, a2, w2, ogens, ngens, oe, ne, emb, i, j;
604  IsNaturalAlternatingGroup(t);
605  au:=AutomorphismGroup(t);
606  agens:=GeneratorsOfGroup(a);
607  agau:=List(agens,i->ConjugatorAutomorphism(t,i));
608  a2:=AutomorphismRepresentingGroup(t,
609       # this way we get the images easily
610       Concatenation(agau,GeneratorsOfGroup(au)));
611  agau:=a2[3]{[1..Length(agau)]};
612  if Index(a,t)=1 then
613    agau:=a2[2];
614  else
615    agau:=GroupHomomorphismByImagesNC(a,a2[1],agens,agau);
616  fi;
617  w2:=WreathProduct(a2[1],Image(Projection(w)));
618  ogens:=[];
619  ngens:=[];
620  # for all w-generators take the corresponding w2 generators
621  for i in [1..n+1] do
622    oe:=Embedding(w,i);
623    ne:=Embedding(w2,i);
624    for j in GeneratorsOfGroup(Source(oe)) do
625      Add(ogens,Image(oe,j));
626      if i<=n then
627        Add(ngens,Image(ne,Image(agau,j)));
628      else
629        Add(ngens,Image(ne,j));
630      fi;
631    od;
632  od;
633  emb:=GroupHomomorphismByImagesNC(w,w2,ogens,ngens);
634  return [emb,w2,a2[1],Image(a2[2])];
635end);
636