Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/recog/gap/projective/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 22.0.2025 mit Größe 27 kB image not shown  

Quelle  c6.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

#############################################################################
##
##  This file is part of recog, a package for the GAP computer algebra system
##  which provides a collection of methods for the constructive recognition
##  of groups.
##
##  This files's authors include Max Neunhöffer, Ákos Seress.
##
##  Copyright of recog belongs to its developers whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-3.0-or-later
##
##
## TODO: This implementation is probably based on the paper [BNS06].
##
##  Find a subgroup of the normaliser of a symplectic type r group
##
#############################################################################


#    functions related to coordinatization of a group R,
#    where R/Z(R) is a vector space

#    basis(r,n,q,gr)
#    the input gr is the extraspecial group or a subgroup corresponding
#    to a NONSINGULAR subspace (important, otherwise fails), plus possibly
#    scalar matrices
#    output: a list of 4k matrices; the first 2k are generators for gr
#    corresponding to a basis e_1,f_1,...,e_k,f_k of hyperbolic pairs for odd r,
#    and noncommuting pairs for r=2 (in the full extraspecial group k=n);
#    the other 2k matrices contain
#    basis vectors for the eigenspaces of the generators
#
#    exponents(r,n,q,list,x)
#    list must be the output of ``basis''
#    x is an arbitrary element of the extraspecial
#    output: a list of 2k numbers, containing the exponents in the
#    decomposition x=e_1^(a_1) f_1^(b_1) e_2^(a_2) ... f_k^(b_k) z^l
#    (here z is a scalar; its exponent is not computed because we do not
#    need it)
#
#    rewriteones(r,n,q,list,x)
#    list must be the output of ``basis''
#    x is an element of the normalizer of the extraspecial in GL(r^n,q)
#    output: 2k x 2k matrix over GF(r), corresponding to the action of x
#    on the symplectic space, in the basis e_1,f_1,...,f_k




# given the eigenspaces of a hyperbolic pair of group elements
# (or a noncommuting pair in the case r=2) from a basis and
# another group element x, it finds the powers of the basis elements in x
RECOG.whichpower:=function(r,n,q,spa,spb,x)
    local v,w,i,j;

    v:=spa[1]*x;
    w:=SolutionMat(spa,v);
    j:=Position(List(w,y->y<>0*Z(q)),true);
    j:=Int( (j-1)/r ^(n-1));

    v:=spb[1]*x;
    w:=SolutionMat(spb,v);
    i:=Position(List(w,y->y<>0*Z(q)),true);
    i:=Int( (i-1)/r ^(n-1));

    return [i,j];
end;

# blocks is a block system of r subspaces, basis for subspaces listed
# in one big list; x permutes the subspaces
# computes the permutation action of x
# ell is the number of blocks
RECOG.ActionOnBlocks := function(r,n,q,blks,x)

    local w,i,j,perm, ell, blocks;

    ell := blks.ell;
    blocks := blks.blocks * x * blks.blocks^-1;
    perm:=[];
    for i in [1..ell] do
      w:=blocks[1+(i-1)*(Length(blocks)/ell)];
      j:=Position(List(w,y->y<>0*Z(q)),true);
      j:=1+Int( (j-1)/(Length(blocks)/ell));
      perm[i]:=j;
    od;

    return PermList(perm);
end;

RECOG.HomFuncActionOnBlocks := function(data,el)
  return RECOG.ActionOnBlocks(data.r,data.n,data.q,data.blks,el);
end;


RECOG.CommonDiagonal2:=function(r,n,q,rad)
    local xxx,newq,es,nicebasis,blocksizes,i,mat,sum,newblocksizes,newnicebasis,
          x,y,size;

    Info(InfoRecog,3,"C6: enter new diagonalization");
    xxx:=Runtime();

    if r=2 and (q mod 4) =3 then
       newq:=q^2;
    else
       newq:=q;
    fi;
    es:=Eigenspaces(GF(newq),rad[1]);
    nicebasis:=Concatenation(List(es,x->GeneratorsOfVectorSpace(x)));
    MakeImmutable(nicebasis);
    blocksizes:=List(es,x->Dimension(x));
    for i in [2..Length(rad)] do
      if Length(blocksizes) < r^n then
        mat:=nicebasis*rad[i]/nicebasis;
        sum:=0;
        newblocksizes:=[];
        newnicebasis:=[];
        for size in blocksizes do
          if size = 1 then
            Add(newnicebasis,Concatenation(List([1..sum],x->Zero(GF(newq))),
              [One(GF(newq))],List([sum+2..r^n],x->Zero(GF(newq)))));
            sum:=sum+1;
            Add(newblocksizes,1);
          else
            es:=Eigenspaces(GF(newq),mat{[sum+1..sum+size]}{[sum+1..sum+size]});
            for x in es do
              for y in GeneratorsOfVectorSpace(x) do
                Add(newnicebasis,Concatenation(List([1..sum],x->Zero(GF(newq))),
                    y,List([sum+size+1..r^n],x->Zero(GF(newq)))));
              od;
            od;
            Append(newblocksizes,List(es,x->Dimension(x)));
            sum:=sum+size;
          fi;
        od;
        MakeImmutable(newnicebasis);
        nicebasis:=newnicebasis*nicebasis;
        blocksizes:=newblocksizes;
      fi;
    od;

    Info(InfoRecog,3,Runtime()-xxx,"exit new diagonalization");

    return nicebasis;
end;


#for a list of commuting, noncentral elements of the extraspecial group
#times scalars, computes a basis of the vectorspace generated by them
#nicebasis is an r^n x r^n matrix, conjugating the input into diagonal form
#the vector space is a subspace of GF(r)^(r^n)
RECOG.RadBasis:=function(r,n,q,rad)
    local s, i, nicebasis, niceinv, diagrad,  action, blocks, f, xxx, xxy;

    Info(InfoRecog,3,"Reached Radbasis");
    if Length(rad)=0 then
       return [ [],[],[],[] ];
    fi;

    nicebasis := RECOG.CommonDiagonal2(r,n,q,rad);
    niceinv := nicebasis^(-1);
    Info(InfoRecog,3,"checking diagonalization:  ",
         Collected(List(rad,x->IsDiagonalMat(nicebasis*x*niceinv))));
    diagrad:=List(rad,x->DiagonalOfMat(nicebasis*x*niceinv));

    #write each vector in diagrad as scalar times a vector over GF(r)
    action:= [];
    for i in [1..Length(diagrad)] do
        action[i]:=List(diagrad[i],x-> x/diagrad[i][1]);
    od;
        action := TransposedMatMutable(action);

if Length(action) <> Length(nicebasis) then
    ErrorNoReturn("what's wrong?");
fi;

    # The identical rows of action correspond to vectors in
    # a  homogeneous component
    s := Set( action );

if Length(nicebasis) mod Length(s)  <> 0 then
    ErrorNoReturn("what's wrong2?");
fi;
    # all vectors in nicebasis whose rows in action are
    # identical form a block
    f := function (a, b) return Position(s,a) <= Position(s,b); end;
    blocks := ShallowCopy(nicebasis);
    SortParallel( action, blocks, f );

    Info(InfoRecog,3,"Radbasis end");

    return rec( ell := Length(s) , blocks := blocks );

end;


#creates a basis for a subgroup g of the extraspecial group
RECOG.basis2:=function(r,n,q,g)
    local xxx,
    a,b,spa,i,j,k,len,gens,list,list2,spb,ainv,binv,powers,posa,rad,
          posb,newq;

    xxx:=Runtime();
    Info(InfoRecog,3,"enter basis2");

    #need a field where characteristic polynomials split into linear factors
    if r=2 and (q mod 4) = 3 then
       newq:=q^2;
    else
       newq:=q;
    fi;

    list  := []; # will contain the generators for the nonsingular part
    list2 := []; # will contain the eigenspace bases for the generators
    rad   := []; # will contain generators for the radical
    len   := Length(GeneratorsOfGroup(g));
    gens  := [];
    for i in [1..len] do
      Add(gens,GeneratorsOfGroup(g)[i]);
    od;

    repeat
       posa:=0;
       posb:=0;
       k:=1;

       repeat
          if IsBound(gens[k]) then
             if gens[k]<>gens[k][1,1]*One(g) then
                a:=gens[k];
                posa:=k;
             else
                k:=k+1;
             fi;
             Unbind(gens[k]);
          else
             k:=k+1;
          fi;
       until posa > 0 or k > len;
       if posa > 0 then
          k:=k+1;
          repeat
            if IsBound(gens[k]) then
               if gens[k] = gens[k][1,1]*One(g) then
                  Unbind(gens[k]);
                  k:=k+1;
               elif gens[k]*a <> a*gens[k] then
                  b:=gens[k];
                  Unbind(gens[k]);
                  posb:=k;
               else
                  k:=k+1;
               fi;
            else
                k:=k+1;
            fi;
          until posb > 0 or k > len;

          if posb > 0 then # found a hyperbolic pair
             Add(list,a);
             Add(list,b);
             spa := Eigenspaces(GF(newq),a)[1];
             spa := List(GeneratorsOfVectorSpace(spa),z->ShallowCopy(z));
             #list bases for other eigenspaces, in the order b permutes them
                     for i in [1..r-1] do
                        for j in [1..r^(n-1)] do
                           spa[i*r^(n-1)+j]:=spa[(i-1)*r^(n-1)+j]*b;
                        od;
                     od;
                     MakeImmutable(spa);
                     Add(list2,spa);

             spb := Eigenspaces(GF(newq),b)[1];
             spb := List(GeneratorsOfVectorSpace(spb),z->ShallowCopy(z));
             for i in [1..r-1] do
                for j in [1..r^(n-1)] do
                   spb[i*r^(n-1)+j]:=spb[(i-1)*r^(n-1)+j]*a;
                od;
             od;
             MakeImmutable(spb);
             Add(list2,spb);

             ainv:=a^(-1);
             binv:=b^(-1);

             for j in [1..len] do
                if IsBound(gens[j]) then
                   powers:=RECOG.whichpower(r,n,q,spa,spb,gens[j]);
                   gens[j]:=gens[j]*(ainv^powers[1])*(binv^powers[2]);
                fi;
             od;
          else # a commutes with everybody
             Add(rad,a);
          fi;
      fi; # posa > 0
    until posa=0;

    Info(InfoRecog,3,"exit basis2");

    if Length(rad) > 0 then
        return rec( basis := rec(), blocks := RECOG.RadBasis(r,n,q,rad) );
    else
        return rec( basis := rec(sympl:=list,es:=list2), blocks := [] );
    fi;

end;


# given the symplectic basis and a group element x, it finds the
# exponents of the symplectic basis elements in the decomposition of x
RECOG.exponents:=function(r,n,q,list2,x)
    local i,len,exp,pair;

    exp:=[];
    len:=Length(list2)/2;
    for i in [1..len] do
      pair:=RECOG.whichpower(r,n,q,list2[2*i-1],list2[2*i],x);
      Add(exp,pair[1]);
      Add(exp,pair[2]);
    od;

    return exp;
end;

# divides out the hyperbolic pair part of the bottom group
# should return something in the radical
RECOG.check:=function(r,n,q,list,x,exp)
    local y,i;

    #Print(exp, "\n");

    y:=One(x);
    for i in [1..Length(list)] do
      y:=y*list[i]^exp[i];
    od;

    return (x/y);
end;

#divides out the radical part of the bottom group
#should return a scalar matrix
RECOG.check2 := function(r,n,q,rad,x,coeffs)

    local y,i;

    #Print(List( coeffs, i-> IntFFE(i)), "\n" );

    y := One(x);
    for i in [1..Length(rad)] do
      y := y*rad[i]^IntFFE(coeffs[i]);
    od;

    return (x/y);
end;


# rewrite an element of the normalizer of the extraspecial group
# as 2n x 2n matrix over GF(r) (or as smaller matrix, if the
# extraspecial group is just a subgroup of r^(1+2n) )

RECOG.rewriteones := function(r,n,q,data,blocks,x)

    local list,rad, mat, i, xx, exp, remain, remain2, coeffs;

    if blocks = [] then
        list  := data.sympl;
        mat   := [];
        for i in [1..Length(list)] do
            xx := list[i]^x;
            exp := RECOG.exponents(r,n,q,data.es,xx);
            remain := RECOG.check(r,n,q,list,xx,exp);
            if remain <> remain[1,1]*One(remain) then
                return fail;
            fi;
            Add(mat, Z(r)^0*exp);
        od;
        ConvertToMatrixRep(mat, r);
        return mat;
    else #we are in type 3 output
        return RECOG.ActionOnBlocks(r,n,q,blocks,x);
    fi;
end;

RECOG.HomFuncrewriteones := function(da,el)
  return RECOG.rewriteones(da.r,da.n,da.q,da.data,[],el);
end;


#   these functions were added by me to help test when
#   an element of the normaliser powers up to a noncentral
#   element of R.

#finds the multiplicity of x-1 in x^n-1 factored over GF(p)
RECOG.multiplicity:=function(p,n)
    local  f, one, x, facs, l, i;

   f:=GF(p);
   one:=One(f);
   x:=X(f);
   facs:=Collected( Factors(x^n-one) );
   l:=Length(facs);
   i:=0;
   repeat
      i:=i+1;
   until facs[i][1]=x-one;

   return facs[i][2];
end;

# decompose a vector space into a sum of common eigenspaces
# rad is generator list for an abelian matrix group
RECOG.commondiagonal:=function(q,rad)
    local int, es, int2, vs, nicebasis, i, j, k;

    Info(InfoRecog,3,"enter diagonalization");

    int:=Eigenspaces(GF(q^2),rad[1]);
    for i in [2..Length(rad)] do
        es:=Eigenspaces(GF(q^2),rad[i]);
        int2:=[];
        for j in [1..Length(int)] do
            for k in [1..Length(es)] do
                vs:=Intersection(int[j],es[k]);
                if Dimension(vs)>0 then
                   Add(int2,vs);
                fi;
            od;
        od;
        int:=int2;
    od;
    nicebasis:=Concatenation(List(int,x->GeneratorsOfVectorSpace(x)));
    MakeImmutable(nicebasis);

    Info(InfoRecog,3,"exit diagonalization");
    return nicebasis;
end;

#creates a basis for a subgroup g of the extraspecial group
RECOG.basis:=function(r,n,q,g)
    local xxx,
    a,b,spa,i,j,k,len,gens,list,list2,spb,ainv,binv,powers,posa,rad,
          radoutput;

    Info(InfoRecog,3,"enter basis");


    list:=[]; #this will contain the generators for the nonsingular part
    list2:=[]; #this will contain the eigenspace bases for the generators
    rad:=[]; #this will contain generators for the radical
    len:=Length(GeneratorsOfGroup(g));
    gens:=[];
    for i in [1..len] do
      Add(gens,GeneratorsOfGroup(g)[i]);
    od;
    Add(gens,One(gens[1]));
    len:=len+1;

    repeat
      k:=0;

      repeat
        k:=k+1;
        a:=gens[k];
      until a<>a[1,1]*One(a) or k=len;
      posa:=k;
      if k<len then
        repeat
           k:=k+1;
           b:=gens[k];
        until a*b <> b*a or k=len;
      fi;
      if k<len then #we found a hyperbolic pair
        Add(list,a);
        Add(list,b);

        spa:=Eigenspaces(GF(q^2),a)[1];
        spa:=List(GeneratorsOfVectorSpace(spa),z->ShallowCopy(z));
        #list bases for other eigenspaces, in the order b permutes them
        for i in [1..r-1] do
          for j in [1..r^(n-1)] do
            spa[i*r^(n-1)+j]:=spa[(i-1)*r^(n-1)+j]*b;
          od;
        od;
        MakeImmutable(spa);
        Add(list2,spa);

        spb:=Eigenspaces(GF(q^2),b)[1];
        spb:=List(GeneratorsOfVectorSpace(spb),z->ShallowCopy(z));
        for i in [1..r-1] do
          for j in [1..r^(n-1)] do
            spb[i*r^(n-1)+j]:=spb[(i-1)*r^(n-1)+j]*a;
          od;
        od;
        MakeImmutable(spb);
        Add(list2,spb);

        ainv:=a^(-1);
        binv:=b^(-1);

        for j in [1..len] do
          powers:=RECOG.whichpower(r,n,q,spa,spb,gens[j]);
          gens[j]:=gens[j]*(ainv^powers[1])*(binv^powers[2]);
        od;
      fi;
      if k=len and posa<k then #a is in the center, but not scalar
         Add(rad,a);
         for i in [posa..len-1] do
             gens[i]:=gens[i+1];
         od;
         len:=len-1;
         k:=0;
      fi;
    until k>=len;

    radoutput := RECOG.RadBasis(r,n,q,rad);

    Info(InfoRecog,3,"exit basis");

    return rec(sympl:=list,es:=list2,nicebasis:=radoutput[1],
       niceinv:=radoutput[2], vs:=radoutput[3], rad:=radoutput[4]);

end;



# RECOG.TestAbelianOld := function (n,grp,u)

#     local list, x, y, limu, randlist, randgens;

#         list := [u];
#         if Length(GeneratorsOfGroup(grp)) > 3 then
#             limu := 16 * n;
#     else
#         limu := 13 * n;
#         fi;

#     while limu > 0 do
#             limu := limu - 1;
#             x  := RandomSubproduct(list);
#             y  := RandomSubproduct(list);
#         x  := Comm(x,y);
#         if x <> x[1,1] * One(x) then
#         return [false,x];
#         fi;
#             randlist:= RandomSubproduct(list);
#             if randlist <> One(grp) then
#                 if Length(GeneratorsOfGroup(grp)) > 3 then
#                     randgens:= RandomSubproduct(grp);
#                     if randgens <> One(grp) then
#                         Add(list,randlist^randgens);
#                     fi;
#                 else # for short generator lists, conjugate with all gens
#                     for randgens in GeneratorsOfGroup(grp) do
#                         Add(list, randlist^randgens);
#                     od;
#                 fi;
#             fi;
#     od;

#     return [true,u,list];

# end;


#############################################################################
##
#F  TestAbelian(n,grp,u) . . . . . . . . . . . . . . . .
##

RECOG.TestAbelian := function (n,grp,u)

    local list, x, y, h, g, pos, limu, randlist, randgens;

    list := [u];
    limu := Maximum(16,6*n);

    while limu > 0 do
        limu := limu - 1;
        y  := RandomSubproduct(list);
        # check whether y commutes with the element computed
        # in the previous iteration
        x := list[Length(list)];
        h := x * y; g := y * x;
        pos := PositionNonZero( h[1] );
        if g <> g[1][pos]/h[1][pos]   * h then
            # x and y do not commute
             return [ false, g/h ];
        fi;

        x := y^PseudoRandom(grp);
        h := x * y; g := y * x;
        pos := PositionNonZero( h[1] );
        if g <> g[1][pos]/h[1][pos]   * h then
            # x and y do not commute
             return [ false, g/h ];
        fi;
        Add( list, x );

    od;

    return [true,u,list];

 end;



#############################################################################
##
##  fast randomised routine for testing whether <w^grp> is
##  a vector space modulo scalars
##  the input MUST have projective order r
##  2 means <w^grp>/Z(R) is a vector space of dimension > 0
##  3 means Z(R)-coset of w is fixed by grp

#############################################################################
##
#F  BlindDescent() . . . . . . . . . . . . . . . .
##

RECOG.BlindDescent := function(r,n,grp,limit)

    local x, ox, y, oy, z,  p, abel;

    x := PseudoRandom(grp);

    while limit > 0 do
        limit := limit - 1;
        y := PseudoRandom(grp);
        oy := ProjectiveOrder(y)[1];
        if oy mod r = 0  then
            abel := RECOG.TestAbelian(n,grp,y^(oy/r));
            if  abel[1] = true  then
                return [y^(oy/r),abel[3]];
            fi;
        fi;
        for p in Union(List( Collected(Factors(oy)), i->i[1]),[1]) do
            z :=Comm(x,y^(oy/p));
            if z <> z[1,1] * One(z) then
                x := z;
            fi;
        od;
        ox := ProjectiveOrder(x)[1];
        if ox  mod r = 0 then
            abel := RECOG.TestAbelian(n,grp,x^(ox/r));
            if abel[1] = true  then
                return [x^(ox/r),abel[3]];
            else
               x := abel[2];
            fi;
        else
            x :=  RECOG.TestAbelian(n,grp,x)[2];
        fi;
    od;
    return fail;
end;


#############################################################################
##
#F  RecogniseC6() . . . . . . . . . . . . . . . .
## the algorithm to recognise, constructively, when <grp> is a subgroup
## of the normaliser of symplectic type r-group.
## the output is a record having the following fields:
##  .<igens> = the image of the given gens for <grp> in the classical group
##  .<basis> = 2n gens for the r-group that <grp> normalises,
##             and a standard basis for corresponding classical module
##  .<r>     = the r for the symplectic type r-group
##  .<n>     = r^n is the dimension of <grp>
##  .<q>     = field size of given representation
## or fail to indicate (possibly temporary) failure or false to indicate
## that it failed forever, so there is no point to call it again.
RECOG.New2RecogniseC6 := function(grp)

    local   type, blocks, spaces, xxx, d, b, ppi,
            r, n, q, u, rgrp, grpbasis, igens, list, i, grp1;

    d := DimensionOfMatrixGroup(grp);
    q := Size(FieldOfMatrixGroup(grp));
    ppi := PrimePowersInt(d);
    r := ppi[1];
    n := ppi[2];
    if not Length(ppi) = 2 then
        return NeverApplicable;
    fi;
    if (q-1) mod r <> 0 then
        return NeverApplicable;
    fi;

    ## first find a non-central element of the <r>-core of <grp>
    b := RECOG.BlindDescent(r,n,grp,100);
    if b = fail then
        return TemporaryFailure;
    fi;
    Info(InfoRecog,3,"Finished blind descent");

    u := b[1];

    ## take enough conjugates to generate the <r>-core
    rgrp := Group(b[2]);
    ## try to find a set of standard gens for <rgrp>
    grpbasis := RECOG.basis2(r,n,q,rgrp);

    ## construct image of <grp> in classical group
    Info(InfoRecog,3,"enter image computation");
    igens := List(GeneratorsOfGroup(grp),
               x->RECOG.rewriteones(r,n,q,grpbasis.basis,grpbasis.blocks,x));
    Info(InfoRecog,3,"exit image computation");
    if Position(igens,fail) = fail then
        return rec( igens := igens, basis := grpbasis,
                    r := r, n := n, q := q );
    else
        return TemporaryFailure;
    fi;

end;

#! @BeginChunk C6
#! This method is designed for the handling of the Aschbacher class C6
#! (normaliser of an extraspecial group). If the input <A>G</A><M>\le PGL(d,q)</M>
#! does not satisfy <M>d=r^n</M> and <M>r|q-1</M> for some prime <M>r</M>
#! and integer <M>n</M> then the method
#! returns <K>NeverApplicable</K>. Otherwise, it returns either a homomorphism of
#! <A>G</A> into <M>Sp(2n,r)</M>, or a homomorphism into the C2 permutation
#! action of <A>G</A> on a decomposition of <M>GF(q)^d</M>, or <K>fail</K>.
#! @EndChunk
BindRecogMethod(FindHomMethodsProjective, "C6",
"find either an (imprimitive) action or a symplectic one",
function(ri, G)
    local r,re,hom;

    RECOG.SetPseudoRandomStamp(G,"C6");

    re := RECOG.New2RecogniseC6(G);
    if re = TemporaryFailure or re = NeverApplicable then
        return re;
    fi;

    if re.basis.basis = rec() then
        Info(InfoRecog,2,"C6: Found block system.");
        hom := GroupHomByFuncWithData(G,GroupWithGenerators(re.igens),
                 RECOG.HomFuncActionOnBlocks,
                 rec(r := re.r,n := re.n,q := re.q,blks := re.basis.blocks));
        InitialDataForKernelRecogNode(ri).t := re.basis.blocks.blocks;
        InitialDataForKernelRecogNode(ri).blocksize := ri!.dimension / re.basis.blocks.ell;
        AddMethod(InitialDataForKernelRecogNode(ri).hints,
                  FindHomMethodsProjective.DoBaseChangeForBlocks,
                  2000);
        Setimmediateverification(ri,true);
        findgensNmeth(ri).args[1] := re.basis.blocks.ell + 3;
        findgensNmeth(ri).args[2] := 5;
        Setmethodsforimage(ri,FindHomDbPerm);
    else
        Info(InfoRecog,2,"C6: Found homomorphism.");
        hom := GroupHomByFuncWithData(G,GroupWithGenerators(re.igens),
                 RECOG.HomFuncrewriteones,
                 rec(r := re.r,n := re.n,q := re.q,data := re.basis.basis));
        findgensNmeth(ri).args[1] := 3 + re.n;
        findgensNmeth(ri).args[2] := 5;
        Setimmediateverification(ri,true);
        Setmethodsforimage(ri,FindHomDbMatrix);
    fi;
    SetHomom(ri,hom);

    return Success;
end);

#
# Inputs are g a group of matrices preserving a symplectic form
#            over another group of matrices preserving the same symplectic form
#                 and acting absolutely irreducibly
#            p a prime
#
#            Suppose g <= over <= Sp(2k,r) this function will return a
#            group of r^k x r^k matrices in characteristic p with a
#            normal subgroup R of type r^{1+2k} preserving the set of
#            one-spaces generated by the basis and quotient isomorphic
#            to g
#
#            over is needed when g does not act absolutely
#            irreducibly, as a convenient way to specify the symplectic
#            form in question
#
#      The algorithm is based on the technique used by Walsh in
#      the construction of the Monster
#

RECOG.MakeC6Group := function(g,over,p)
    local   f,  r,  gm,  M,  k,  chis,  ws,  space,  i,  chi,  w,  x,
            basis,  newgens,  labels,  q,  zeta,  Ts,  Ds,  result,
            us,  vs,  o,  vmos,  allvs,  toprow, b, m;
    #
    # preliminaries
    #
    f := DefaultFieldOfMatrixGroup(g);
    r := Characteristic(f);
    if Size(f) <> r then
        ErrorNoReturn("Must be over prime field");
    fi;
    if p = r then
        ErrorNoReturn("Must be another characteristic");
    fi;
    if p =2 or r =2 then
        ErrorNoReturn("Odd characteristics only please");
    fi;
    q := p;
    while (q-1) mod r <> 0 do
        q := q*p;
    od;
    if q > 65536 then
        ErrorNoReturn("field too big");
    fi;
    zeta := Z(q)^((q-1)/r);
    #
    # Find the form
    #
    gm := GModuleByMats(GeneratorsOfGroup(over),f);
    M := MTX.InvariantBilinearForm(gm);
    if TransposedMat(M) <> -M then
        ErrorNoReturn("form not symplectic");
    fi;
    #
    # Now convert that into the "standard" symplectic form
    #
    # ( 0 I)
    # (-I 0)
    #
    #  where I is a k x k identity matrix
    #
    #  chis are the basis of the first part of the space
    #  ws the basis of the second part
    #
    k := DimensionOfMatrixGroup(g)/2;
    chis := [];
    ws := [];
    #
    # space will the space orthogonal to all the chis and ws
    #
    space := FullRowSpace(f,2*k);
    for i in [1..k] do
        repeat
            chi := Random(space);
        until not IsZero(chi);
        repeat
            w := Random(space);
        until not IsZero(w) and not IsZero(chi*M*w);
        x := chi*M*w;
        if not IsOne(x) then
            w := w/x;
        fi;
        Add(chis,chi);
        Add(ws,w);
        if i <> k then
            b := GeneratorsOfLeftModule(space);
            space := Submodule(space,NullspaceMat(b*M*TransposedMat([chi,w]))*b);
        fi;
    od;
    #
    # OK, now rewrite the group so that it preserves our favourite
    # symplectic form
    #
    basis := Concatenation(chis,ws);
    newgens := List(GeneratorsOfGroup(g), x->basis*x*basis^-1);
    #
    # Now thw basis will be in bijection with F_r^k
    #
    labels := Elements(FullRowSpace(f,k));
    basis := CanonicalBasis(FullRowSpace(f,k));
    #
    # Make the 2k generators of the extra-special group, which will be
    # in bijection with our favourite symplectic basis
    #
    Ts := List([1..k], i->
                  PermutationMat(PermListList(labels, List(labels,l->l+basis[i])),r^k,GF(q)));
    Ds :=  List([1..k], i->
                DiagonalMat(List(labels,l->zeta^IntFFE(basis [i]*l))));
    MakeImmutable(Ts);
    MakeImmutable(Ds);
    result := Concatenation(Ts,Ds);
    for m in result do
        ConvertToMatrixRep(m,q);
    od;

    #
    # Finally, lift the generators of g, see the Monster paper for
    #  explanation of this
    #
    for x in newgens do
        #
        # The us and vs are the images of the Ts and Ds under x
        #
        us := List([1..k], i->
                   Product([1..k], j-> Ts[j]^IntFFE(x[i,j]))*
                   Product([1..k], j-> Ds[j]^IntFFE(x[i,j+k])));
        vs := List([1..k], i->
                   Product([1..k], j-> Ts[j]^IntFFE(x[i+k,j]))*
                   Product([1..k], j-> Ds[j]^IntFFE(x[i+k,j+k])));
        #
        # Now we want the vector fixed by the all the vs
        #
        o := One(vs[1]);
        vmos := List(vs, v->v-o);
        allvs := List([1..r^k], i->Concatenation(vmos{[1..k]}[i]));
        toprow := NullspaceMat(allvs)[1];
        #
        # Finally we make the rest of the matrix using the action of
        # the us -- this could be done more economically
        #
        Add( result, List(labels, l -> toprow*Product([1..k],j-> us[j]^IntFFE(l[j]))));
    od;
    return [Group(result), SubgroupNC(~[1],result{[1..2*k]})];
end;

[ Dauer der Verarbeitung: 0.61 Sekunden  ]