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 60 kB image not shown  

Quelle  almostsimple.gi   Sprache: unbekannt

 
#############################################################################
##
##  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
##
##
##  Code to recognise (simple) groups by their two largest element orders.
##  At least recognise the "natural" characteristic.
##
#############################################################################

# parses certain strings and numbers into a number
RECOG.ParseNumber := function( number, d, default )
  if IsInt(number) then
      return number;
  elif number = "logd" then
      return LogInt(d, 2);
  elif IsString(number) and EndsWith(number, "d") then
      return d * Int(number{[1..Length(number)-1]});
  fi;
  return default;
end;

# RECOG.MakeStabChainHint := function( chain, stdgens )
#   local b,bb,choice,dims,f,gens,grpnum,grps,i,j,lens,llens,m,name,names,nams,nrs,o,orblens,pts,r,size,slps;
#   f := FieldOfMatrixList(stdgens);
#   name := chain[1].name;
#   size := chain[1].order;
#   slps := [];
#   names := [];
#   dims := [];
#   orblens := [];
#   pts := [];
#   gens := stdgens;
#   repeat
#       Print("Working on ",name,"\n");
#       grps := [];
#       nams := [];
#       nrs := [];
#       for i in [1..Length(chain)] do
#           r := chain[i];
#           if IsBound(r.parent) and r.parent = name then
#               Add(grps,ResultOfStraightLineProgram(r.generators,gens));
#               Add(nams,r.name);
#               Add(nrs,i);
#           fi;
#       od;
#       if Length(grps) = 0 then break; fi;
#       Print("Considering subgroups: ",nams,"\n");
#       bb := [];
#       llens := [];
#       grpnum := [];
#       for i in [1..Length(grps)] do
#           # will be left by break in case of success
#           Print("  Considering ",nams[i],"\n");
#           m := GModuleByMats(grps[i],f);
#           if not MTX.IsIrreducible(m) then
#               b := List(MTX.BasesMinimalSubmodules(m),MutableCopyMat);
#               Sort(b,function(a,b) return Length(a) < Length(b); end );
#               Print("    Dimensions: ",List(b,Length),"\n");
#               lens := [];
#               for j in [1..Length(b)] do
#                   TriangulizeMat(b[j]);
#                   if Length(b[j]) = 1 then
#                       o := Orb(gens,b[j][1],OnLines,rec( report := 10000,
#                              treehashsize := 1000, storenumbers := true ));
#                   else
#                       o := Orb(gens,b[j],OnSubspacesByCanonicalBasis,
#                          rec( report := 10000, treehashsize := 1000,
#                               storenumbers := true ));
#                   fi;
#                   Enumerate(o);
#                   Print("    Found orbit of length ",Length(o),"\n");
#                   lens[j] := Length(o);
#               od;
#               Append(bb,b);
#               Append(llens,lens);
#               Append(grpnum,ListWithIdenticalEntries(Length(b),i));
#           else
#               Print("    Restriction is irreducible!\n");
#           fi;
#       od;
#       choice := 1;
#       Print("Dimensions: ",List(bb,Length),"\n");
#       Print("Orbit lengths: ",llens,"\n");
#       Error("now decide which orbit to take, set choice");
#       if choice > 0 then
#           i := grpnum[choice];
#           Add(names,nams[i]);
#           Add(dims,Length(bb[choice]));
#           name := nams[i];
#           gens := grps[i];
#           size := size / llens[choice];
#           Add(orblens,llens[choice]);
#           Add(slps,chain[nrs[i]].generators);
#           Add(pts,bb[choice]);
#       fi;
#   until size = 1 or choice = 0;
#   return rec( slps := slps, names := names, dims := dims, orblens := orblens,
#               pts := pts );
# end;

InstallGlobalFunction( DoHintedStabChain, function(ri,G,hint)
    local S,b,bra,c,cf,elm,finder,fu,gm,homs,m,max,maxes,maxgens,opt,s,stdgens;
    finder := AtlasProgram(hint.name,"find");
    if finder = fail then
        Info(InfoRecog,1,"Expected BBox finder for stdgens of ",hint.name,
             " not availabe!");
        Info(InfoRecog,1,"Check your AtlasRep installation!");
        return fail;
    fi;
    gm := Group(ri!.gensHmem);
    gm!.pseudorandomfunc := [rec(
       func := function(ri) return RandomElm(ri,"StdGens",true).el; end,
       args := [ri])];
    Info(InfoRecog,2,"Finding standard generators with bbox program...");
    stdgens := RunBBoxProgram(finder.program,gm,ri!.gensHmem,
                              rec( orderfunction := RECOG.ProjectiveOrder ) );
    if stdgens = fail or stdgens = "timeout" then
        Info(InfoRecog,2,"Stdgens finder did not succeed for ",hint.name);
        return fail;
    fi;
    stdgens := stdgens.gens;
    #Setslptostd(ri,SLPOfElms(stdgens));
    #SetStdGens(ri,StripMemory(stdgens));
    if IsBound(hint.usemax) then
        if IsBound(hint.brauercharelm) then
            elm := ResultOfStraightLineProgram(hint.brauercharelm,stdgens);
            bra := BrauerCharacterValue(elm!.el);
            maxes := hint.usemax{Filtered([1..Length(hint.usemax)],
                                          i->hint.brauercharvals[i] = bra)};
        else
            maxes := hint.usemax;
        fi;
        for max in maxes do
            s := AtlasProgram(hint.name,max);
            if s = fail then
                Info(InfoRecog,1,"Expected maximal subgroup slp of ",hint.name,
                     " not available!");
                Info(InfoRecog,1,"Check your AtlasRep installation!");
                return fail;
            fi;
            maxgens := ResultOfStraightLineProgram(s.program,
                                                   StripMemory(stdgens));
            m := GModuleByMats(maxgens,ri!.field);
            if MTX.IsIrreducible(m) then
                Info(InfoRecog,2,"Found irreducible submodule!");
                continue;
            fi;
            cf := List(MTX.CollectedFactors(m),x->x[1]);
            Sort(cf,function(a,b) return a.dimension < b.dimension; end);
            for c in cf do
                homs := MTX.Homomorphisms(c,m);
                if Length(homs) > 0 then
                    ConvertToMatrixRep(homs[1],ri!.field);
                    b := MutableCopyMat(homs[1]);
                    break;
                fi;
                # Some must be in the socle, so this terminates with break!
            od;
            TriangulizeMat(b);
            fu := function() return RandomElm(ri,"StabChain",true).el; end;
            opt := rec( Projective := true, RandomElmFunc := fu );
            if Length(b) = 1 then
                opt.Cand := rec( points := [b[1]], ops := [OnLines] );
            else
                opt.Cand := rec( points := [b],
                                 ops := [OnSubspacesByCanonicalBasis] );
            fi;
            gm := GroupWithGenerators(stdgens);
            opt.Size := hint.size;
            Info(InfoRecog,2,"Computing hinted stabilizer chain for ",
                 hint.name," ...");
            S := StabilizerChain(gm,opt);
            # Verify correctness by sifting original gens:
            # Actually, genss does not terminate if no group of this
            # size is found!
            ri!.stabilizerchain := S;
            Setslptonice(ri,SLPOfElms(StrongGenerators(S)));
            SetSize(ri,hint.size);
            ForgetMemory(S);
            Unbind(S!.opt.RandomElmFunc);
            Setslpforelement(ri,SLPforElementFuncsProjective.StabilizerChainProj);
            SetFilterObj(ri,IsLeaf);
            if IsBound(hint.issimple) then
                SetIsRecogInfoForSimpleGroup(ri,hint.issimple);
            fi;
            SetIsRecogInfoForAlmostSimpleGroup(ri,true);
            ri!.comment := hint.name;
            return true;
        od;
    fi;
    Info( InfoRecog, 2, "Got stab chain hint, not yet implemented!" );
    return fail;
  end );

InstallGlobalFunction( DoHintedLowIndex, function(ri,G,hint)
  local bas,d,fld,gens,hm,hom,i,numberrandgens,orb,orblenlimit,s,
        tries,triesinner,triesinnerlimit,trieslimit,x,y;

  Info(InfoRecog,2,"Got hint for group, trying LowIndex...");

  fld := ri!.field;
  d := ri!.dimension;
  if IsBound(hint.elordersstart) then
      i := 0;
      repeat
          i := i + 1;
          if i > 10000 then
              ErrorNoReturn("possible infinite loop in DoHintedLowIndex, ",
                            "wrong hints?");
          fi;
          x := PseudoRandom(G);
      until Order(x) in hint.elordersstart;
      x := [x];
  else
      x := [];
  fi;

  tries := 0;
  numberrandgens := RECOG.ParseNumber(hint.numberrandgens,d,2);
  triesinnerlimit := RECOG.ParseNumber(hint.triesforgens,d,"1d");
  trieslimit := RECOG.ParseNumber(hint.tries,d,10);
  orblenlimit := RECOG.ParseNumber(hint.orblenlimit,d,"4d");
  Info(InfoRecog,3,"Using numberrandgens=",numberrandgens,
       " triesinnerlimit=",triesinnerlimit," trieslimit=",trieslimit,
       " orblenlimit=",orblenlimit);

  repeat
      gens := ShallowCopy(x);
      triesinner := 0;
      if numberrandgens = Length(gens) then   # we have to make the hm module
          hm := GModuleByMats(gens,fld);
          if MTX.IsIrreducible(hm) then
              tries := tries + 1;
              continue;
          fi;
      else
          while Length(gens) < numberrandgens and
                triesinner < triesinnerlimit do
              y := PseudoRandom(G);
              Add(gens,y);
              triesinner := triesinner + 1;
              hm := GModuleByMats(gens,fld);
              if MTX.IsIrreducible(hm) then
                  Unbind(gens[Length(gens)]);
              fi;
          od;
      fi;
      if Length(gens) = numberrandgens then
          # We hope to have the maximal subgroup!
          bas := [MTX.ProperSubmoduleBasis(hm)];
          s := bas[1];
          while s <> fail do
              hm := MTX.InducedActionSubmodule(hm,s);
              s := MTX.ProperSubmoduleBasis(hm);
              Add(bas,s);
          od;
          Unbind(bas[Length(bas)]);
          s := bas[Length(bas)];
          for i in [Length(bas)-1,Length(bas)-2..1] do
              s := s * bas[i];
          od;
          # Now s is the basis of a minimal submodule, permute that:
          s := MutableCopyMat(s);
          TriangulizeMat(s);
          # FIXME: this will be unnecessary:
          ConvertToMatrixRep(s);
          Info(InfoRecog,2,"Found invariant subspace of dimension ",
               Length(s),", enumerating orbit...");
          if not IsBound(hint.subspacedims) or
             Length(s) in hint.subspacedims then
              #orb := RECOG.OrbitSubspaceWithLimit(G,s,orblenlimit);
              orb := Orb(G,s,OnSubspacesByCanonicalBasis,
                         rec(storenumbers := true,
                             hashlen := NextPrimeInt(2*orblenlimit)));
              Enumerate(orb,orblenlimit);
              if IsClosed(orb) then
                  hom := OrbActionHomomorphism(G,orb);
                  if Length(s) * Length(orb) = d then
                      # A block system!
                      InitialDataForKernelRecogNode(ri).t := Concatenation(orb);
                      InitialDataForKernelRecogNode(ri).blocksize := Length(s);
                      AddMethod(InitialDataForKernelRecogNode(ri).hints,
                                FindHomMethodsProjective.DoBaseChangeForBlocks,
                                2000);
                      Setimmediateverification(ri,true);
                      findgensNmeth(ri).args[1] := Length(orb)+3;
                      findgensNmeth(ri).args[2] := 5;
                      Info(InfoRecog,2,"Found block system with ",
                           Length(orb)," blocks.");
                  else
                      Info(InfoRecog,2,"Found orbit of length ",
                           Length(orb)," - not a block system.");
                  fi;
                  SetHomom(ri,hom);
                  Setmethodsforimage(ri,FindHomDbPerm);
                  return true;
              fi;
          else
              Info(InfoRecog,2,"Subspace dimension not as expected, ",
                   "not enumerating orbit.");
          fi;
      fi;
      tries := tries + 1;
  until tries > trieslimit;
  return fail;
end );

# We start a database of hints, whenever we discover a certain group, we
# can ask this database what to do:

RECOG.AlmostSimpleHints := rec();

# is called in almostsimple/hints.gi to create a database in
# RECOG.AlmostSimpleHints to store hints about almost simple groups.
# Currently just sporadic simple groups are contained.
InstallGlobalFunction( InstallAlmostSimpleHint,
  function( name, type, re )
    if not IsBound(RECOG.AlmostSimpleHints.(name)) then
        RECOG.AlmostSimpleHints.(name) := [];
    fi;
    re.type := type;
    Add( RECOG.AlmostSimpleHints.(name),re );
  end );

# FIXME: unused?
# TODO: this was likely used to generate the hints in almostsimple/hints.gi.
# Document this, and how to replicate the hints; move the code to a separate file.
# Indeed, ideally a user should be able to trivially regenerate the list of hints
# by running a script. Note that for that, we need to also explain how the arguments
# "reps" and "maxes" are chosen...
# Perhaps a full script is not possible; but then we should still explain how
# the hints where generated.
RECOG.ProduceTrivialStabChainHint := function(name,reps,maxes)
  local bad,f,g,gens,hint,list,m,o,prevdim,prevfield,r,range,res,ri,
        size,success,t,values,x;
  PrintTo(Concatenation("NEWHINTS.",name),"# Hints for ",name,":\n");
  prevdim := fail;
  prevfield := fail;
  for r in reps do
      Print("\nDoing representation #",r,"\n");
      gens := AtlasGenerators(name,r);
      g := Group(gens.generators);
      f := gens.ring;
      values := [];
      success := false;
      size := Size(CharacterTable(name));
      for m in [1..Length(maxes)] do
          Print("Doing maximal subgroup #",m,"\n");
          hint := rec( name := name, size := size, usemax := [m] );
          ri := RecogNode(rec(),g,true);
          t := Runtime();
          res := DoHintedStabChain(ri,g,hint);
          t := Runtime() - t;
          if res = true then
              o := ri!.stabilizerchain!.orb;
              x := o[1];
              if IsMatrix(x) then
                  Add(values,[Length(x)*QuoInt(Length(o)+99,100),Length(o)]);
              else
                  Add(values,[QuoInt(Length(o)+99,100),Length(o)]);
              fi;
              Print("value=",values[Length(values)]," time=",t," orblen=",
                    Length(o)," subspace=");
              ViewObj(x);
              Print("\n");
              success := true;
          else
              Add(values,[infinity,infinity]);
              Print("failure\n");
          fi;
      od;
      if success then
          if Size(f) = prevfield and Length(gens.generators[1]) = prevdim then
              AppendTo(Concatenation("NEWHINTS.",name),
                       ">>>SAME FIELD AND DIM\n");
          fi;
          list := ShallowCopy(maxes);
          SortParallel(values,list);
          bad := First([1..Length(values)],i->values[i][1] = infinity);
          if bad = fail or bad > 3 then
              if Length(values) > 3 then
                  range := [1..3];
              else
                  range := [1..Length(values)];
              fi;
          else
              range := [1..bad-1];
          fi;
          AppendTo(Concatenation("NEWHINTS.",name),
                "InstallAlmostSimpleHint( \"",name,"\", \"StabChainHint\",\n",
                "  rec( name := \"",name,"\", fields := [",
                Size(f),"], dimensions := [",Length(gens.generators[1]),
                "], \n       usemax := ",list{range},
                ", \n       size := ", size,
                ", atlasrepnrs := [",r,"], \n       values := ",
                values{range},"\n  ));\n");
      fi;
      prevfield := Size(f);
      prevdim := Length(gens.generators[1]);
  od;
end;

# FIXME: unused?
RECOG.DistinguishAtlasReps := function(name,rep1,rep2)
  local br1,br2,classes,gens1,gens2,guck1,guck2,l,lens,slps;
  classes := AtlasProgram(name,"cyclic").program;
  gens1 := GeneratorsWithMemory(AtlasGenerators(name,rep1).generators);
  gens2 := AtlasGenerators(name,rep2).generators;
  guck1 := ResultOfStraightLineProgram(classes,gens1);
  guck2 := ResultOfStraightLineProgram(classes,gens2);
  br1 := List(guck1,x->BrauerCharacterValue(x!.el));
  br2 := List(guck2,BrauerCharacterValue);
  l := Filtered([1..Length(br1)],i->br1[i]<>br2[i]);
  slps := List(guck1,SLPOfElm);
  lens := List(l,x->Length(LinesOfStraightLineProgram(slps[x])));
  SortParallel(lens,l);
  Print("brauercharelm := ",slps[l[1]],", brauercharvals := ",
        [br1[l[1]],br2[l[1]]],",\n");
end;


# This is for the released AtlasRep package:
if not IsBound(AGR_TablesOfContents) then
    AGR_TablesOfContents := fail;
    AGR_InfoForName := fail;
fi;

# FIXME: unused?
RECOG.PrintGenericStabChainHint := function ( n )
    local S,g,gens,nn,toc,tocs;
    tocs := AGR_TablesOfContents( "all" );
    nn := AGR_InfoForName( n )[2];
    toc := tocs[1].(nn);
    gens := AtlasGenerators( n, 1 ).generators;
    g := Group( gens );
    S := StabilizerChain( g );
    Print( "InstallAlmostSimpleHint( \"", n, "\", \"StabChainHint\",\n" );
    Print( "  rec( name := \"", n, "\", usemax := " );
    Print( Set( List( toc.maxes, x->x[2] ) ) );
    Print( ",\n       size := ", Size( S ), ",\n  ));\n" );
end;

# dimensions optionally
# subspacedims there or not
# elordersstart unbound ==> start with empty generator list
# if numberrandgens = "logd" then it will use LogInt(d,2)
# if triesforgens = "Xd" then it will use X * d (X a number as a string)
# if orblenlimit = "Xd" then it will use X * d (X a number as a string)
# L2 hint with doing the decision on the fly
#   depending on the ppd-Properties of L2(p)
# This means:
#   rec( numberrandgens := "logd", tries := 10, triesforgens := "1d",
#        orblenlimit := "4d" )
# is the standard low index.

# BUG: The following hint was added a long time ago, but it
# can lead to an infinite loop in DoHintedLowIndex, because
# elordersstart suggests searching for elements of order 31,
#  but no such elements are found.
# See also https://github.com/gap-system/recog/issues/6
# InstallAlmostSimpleHint( "L2(31)", "LowIndexHint",
#   rec( characteristics := [31], dimensions := [1,2,3],
#        elordersstart := [31], numberrandgens := 2, tries := 1,
#        triesforgens := 100, orblenlimit := 32, issimple := true ) );

# if hint in AlmostSimpleHints exists appropriate function is executed
InstallGlobalFunction( LookupHintForSimple,
  function(ri,G,name)
    local dim,f,hi,j,p,q;
    Info(InfoRecog,2,"Looking up hints for ",name,"...");
    if IsBound(RECOG.AlmostSimpleHints.(name)) then
        j := 1;
        hi := RECOG.AlmostSimpleHints.(name);
        f := ri!.field;
        p := Characteristic(f);
        q := Size(f);
        dim := ri!.dimension;
        while j <= Length(hi) do
            if (not IsBound(hi[j].characteristics) or
                p in hi[j].characteristics) and
               (not IsBound(hi[j].fields) or
                q in hi[j].fields) and
               (not IsBound(hi[j].dimensiondivs) or
                ForAny(hi[j].dimensiondivs,d->dim mod d = 0)) and
               (not IsBound(hi[j].dimensions) or
                dim in hi[j].dimensions) then
                # This hint is applicable!
                if hi[j].type = "LowIndexHint" then
                    return DoHintedLowIndex(ri,G,hi[j]);
                elif hi[j].type = "StabChainHint" then
                    return DoHintedStabChain(ri,G,hi[j]);
                # Put other hint types here!
                fi;
            fi;
            j := j + 1;
        od;
    fi;
    Info(InfoRecog,2,"No hint worked, giving up.");
    return fail;
end );


# checks whether the orbit of <vec> under g is not longer than bound
RECOG.shortorbit := function(vec,g,bound)
    local v, i, pos;
    v := StructuralCopy(vec);
    pos := PositionNonZero(vec);
    vec := vec / vec[pos];
    for i in [1..bound] do
        v := v * g;
        if v = v[pos] * vec then
            break;
        fi;
    od;
    return i;
end;


# Under the assumption that G is an almost simple group,
# attempt to guess the "natural" characteristic of the
# group based on the two or three maximal orders of group elements.
#
# Used by FindHomMethodsProjective.ThreeLargeElOrders.
RECOG.findchar:=function(ri,G,randelfunc)
    # randelfunc must be a function taking ri as one argument and returning
    # uniformly distributed random elements in G together with its
    # projective order (as for example below), or fail.
    local mat,vs,vec,bound,count,m1,m2,m3,g,order,list,last,r,p,d,pr;

    if randelfunc = fail then
        pr := ProductReplacer(GeneratorsOfGroup(G));
        randelfunc := function(ri)
          local el;
          el := Next(pr);
          return rec( el := el, order := ProjectiveOrder(el)[1] );
        end;
    fi;

    p := Characteristic(ri!.field);
    d := ri!.dimension;
    mat:=One(G);
    vs:=VectorSpace(GF(p),mat);
    repeat
        vec:=Random(vs);
    until not IsZero(vec);

    if RECOG.shortorbit(vec,Product(GeneratorsOfGroup(G)), 3*d) = 3*d then
        return p;
    fi;

    #find three largest element orders m1, m2, m3
    bound:=32*(LogInt(d,2))^2*6*4;
    count:=0;
    m1:=0;
    m2:=0;
    m3:=0;
    last:=0;
    repeat
        count:=count+1;
        r := randelfunc(ri);
        g := r.el;
        order:=r.order;
        if order >= 3*d then
            return p;
        elif order > m1 then
            m3:=m2;
            m2:=m1;
            m1:=order;
            last:=count;
        elif order<m1 and order>m2 then
            m3:=m2;
            m2:=order;
            last:=count;
        elif order<m2 and order>m3 then
            m3:=order;
            last:=count;
        fi;
    until count=bound or count>=2*last+50;

    #handle ambiguous cases
    if [m1,m2,m3] = [13,7,5] then
        return [[13,7, ["2B2",8]]];
    elif [m1,m2] = [13,8] then
        return [[13,8, ["l",3,3]]];
    elif [m1,m2,m3] = [13,7,6] then
        return [[13,7, ["l",2,13]]];
    elif [m1,m2,m3] = [13,12,6] then
        return [[13,12,["l",2,5]]];
    elif [m1,m2,m3] = [13,12,9] then
        return [[13,12,["G2",3]]];
    elif [m1,m2,m3] = [12,9,6] then
        return [[12,9,["u",4,2]]];
    elif [m1,m2,m3] = [12,9,8] then
        return [[12,9,["u",4,3]]];
    elif [m1,m2] = [5,3] then
        return [[ 5,3,["l",2,4]]];
    elif [m1,m2] = [5,4] then
        return [[5,4,["l",2,9]]];
    elif [m1,m2] = [7,4] then
        return [[7,4,["l",2,7]]];
    elif [m1,m2] = [15,13] then
        return [[15,13,["u",3,4]]];
    elif [m1,m2] = [30,20] then
        return [[30,20,["s",4,5]]];
    elif [m1,m2] = [30,24] then
        return [[30,24,["s",8,2]]];
    elif [m1,m2] = [63,60] then
        return [[63,60,["u",4,5]]];
    elif [m1,m2] = [91,85] then
        return [[91,85,["l",3,16]]];
    fi;

    list:=Filtered(RECOG.grouplist, x->x[1]=m1 and x[2]=m2);
    #one more ambiguous case
    if  Length(list) >=2 and (
        (list[1][3]{[1,2]}=["l",2] and list[2][3][1]="G2") or
        (list[2][3]{[1,2]}=["l",2] and list[1][3][1]="G2")) then
       if m3>m1/2 then
           return Filtered(list,x->x[3][1]="G2");
       else
           return Filtered(list,x->x[3][1]="l");
       fi;
    else
        return list;
    fi;

end;

# just called for PSL (in FindHomMethodsProjective.ThreeLargeElOrders),
# gives hints
RECOG.MakePSL2Hint := function( name, G )
  local d,defchar,f,p,q;
  f := DefaultFieldOfMatrixGroup(G);
  q := Size(f);
  p := Characteristic(f);
  d := DimensionOfMatrixGroup(G);
  defchar := Factors(name[3])[1];
  if p = defchar then
      return fail;
  fi;
  Info(InfoRecog,2,"Making hint for group ",name,"...");
  # we are in cross characteristic.
  # to be made better...
  return rec( elordersstart := [defchar], numberrandgens := 1, tries := 10,
              triesforgens := 3*(name[3]+1),
              orblenlimit := 3*(name[3]+1) );
end;

# is used in FindHomMethodsProjective.ComputeSimpleSocle
# it computes the non-abelian simple socle randomly (it might
# underestimates it)
# if called for an abelian group (even a group with nilpotence class smaller
# than 3?) it runs in an infinite loop
RECOG.simplesocle := function(ri,g)
  local x,y,comm,comm2,comm3,gensH;

  repeat
    x:=RandomElm(ri,"simplesocle",true).el;
  until not ri!.isone(x);

  repeat
    y:=RandomElm(ri,"simplesocle",true).el;
    comm:=Comm(x,y);
  until not ri!.isone(comm);

  repeat
    y:=RandomElm(ri,"simplesocle",true).el;
    comm2:=Comm(comm,comm^y);
  until not ri!.isone(comm2);

  repeat
    y:=RandomElm(ri,"simplesocle",true).el;
    comm3:=Comm(comm2,comm2^y);
  until not ri!.isone(comm3);

  gensH:=FastNormalClosure(g,[comm3],20);

  return gensH;
end;

#! @BeginChunk ComputeSimpleSocle
#! This method randomly computes the non-abelian simple socle and
#! stores it along with additional information if it is called for
#! an almost simple group. Once the non-abelian simple socle is
#! computed the function does not need to be called again for this
#! node and therefore returns <K>NeverApplicable</K>.
#! @EndChunk
BindRecogMethod(FindHomMethodsProjective, "ComputeSimpleSocle",
"compute simple socle of almost simple group",
function(ri,G)
  local x;
  RECOG.SetPseudoRandomStamp(G,"ComputeSimpleSocle");
  ri!.simplesocle := Group(RECOG.simplesocle(ri,G));
  ri!.simplesoclepr := ProductReplacer(ri!.simplesocle);
  ri!.simplesoclerand := EmptyPlist(100);
  Append(ri!.simplesoclerand,GeneratorsOfGroup(ri!.simplesocle));
  ri!.simplesoclerando := EmptyPlist(100);
  for x in ri!.simplesoclerand do
      Add(ri!.simplesoclerando,ProjectiveOrder(x)[1]);
  od;
  ri!.simplesoclerandp := 0;
  ri!.simplesocle!.pseudorandomfunc :=
       [rec( func := Next, args := [ri!.simplesoclepr] )];
  return NeverApplicable;
end);

# computes a random element in the non-abelian simple socle
# and its projective order
# first uses the random generator and afterwards generate
# a new random element
RECOG.RandElFuncSimpleSocle := function(ri)
  local el,ord;
  ri!.simplesoclerandp := ri!.simplesoclerandp + 1;
  if not IsBound(ri!.simplesoclerand[ri!.simplesoclerandp]) then
      el := Next(ri!.simplesoclepr);
      ri!.simplesoclerand[ri!.simplesoclerandp] := el;
      ord := ProjectiveOrder(el)[1];
      ri!.simplesoclerando[ri!.simplesoclerandp] := ord;
  else
      el := ri!.simplesoclerand[ri!.simplesoclerandp];
      ord := ri!.simplesoclerando[ri!.simplesoclerandp];
  fi;
  return rec( el := el, order := ord );
end;

#! @BeginChunk ThreeLargeElOrders
#! In the case when the input group <A>G</A><M> \le PGL(d,p^e)</M> is
#! suspected to be
#! simple but not alternating, this method takes the three
#! largest element orders from a sample of pseudorandom elements of
#! <A>G</A>. From these element orders, it tries to determine whether <A>G</A>
#! is of Lie type and the characteristic of <A>G</A> if it is of
#! Lie type. In the case when <A>G</A> is of Lie type of characteristic
#! different from <M>p</M>, the method also provides
#! a short list of the possible isomorphism types of <A>G</A>.
#!
#! This method assumes that its input is neither alternating nor sporadic and
#! that <Ref Func="ComputeSimpleSocle"/> has already been called.
#!
#! This recognition method is based on the paper <Cite Key="KS09"/>.
#! @EndChunk
BindRecogMethod(FindHomMethodsProjective, "ThreeLargeElOrders",
"recognise Lie type groups and get its characteristic",
function(ri,G)
  local hint,name,namecat,p,res;
  RECOG.SetPseudoRandomStamp(G,"ThreeLargeElOrders");
  ri!.simplesoclerandp := 0;
  p := RECOG.findchar(ri,ri!.simplesocle,RECOG.RandElFuncSimpleSocle);
  if p = Characteristic(ri!.field) then
      Info(InfoRecog,2,"ThreeLargeElOrders: defining characteristic p=",p);
      return false; # FIXME: false = NeverApplicable here really correct?
  fi;
  # Try all possibilities:
  Info(InfoRecog,2,"ThreeLargeElOrders: found ",p);
  for hint in p do
      Info(InfoRecog,2,"Trying ",hint);
      name := hint[3];
      if name[1] = "l" then  # Handle PSL specially
          if name[2] = 2 then
              hint := RECOG.MakePSL2Hint(name,G);
              if hint <> fail then
                  res := DoHintedLowIndex(ri,G,hint);
              else   # we use Pete Brooksbank's methods
                  return SLCR.FindHom(ri,G,2,name[3]);
              fi;
          else
              return SLCR.FindHom(ri,G,name[2],name[3]);
          fi;
      else
          if Length(name) = 3 then
              namecat := Concatenation(UppercaseString(name[1]),
                                       String(name[2]),
                                       "(",String(name[3]),")");
          else
              namecat := name[1];
          fi;
          res := LookupHintForSimple(ri,G,namecat);
      fi;
      if res = true then
          return Success;
      fi;
  od;
  Info(InfoRecog,2,"Did not succeed with hints, giving up...");
  return fail; # FIXME: fail = TemporaryFailure here really correct?
end);

# RECOG.DegreeAlternating := function (orders)
#     local   degs,  prims,  m,  f,  n;
#     degs := [];
#     prims := [];
#     for m in orders do
#         if m > 1 then
#             f := Collected(Factors(m));
#             Sort(f);
#             n := Sum(f, x->x[1]^x[2]);
#             if f[1][1] = 2 then n := n+2; fi;
#             AddSet(degs,n);
#             UniteSet(prims,Set(f,x->x[1]));
#         fi;
#     od;
#     return [degs, prims];
# end;

# RECOG.RecognizeAlternating := function (orders)
#     local   tmp,  degs,  prims,  mindeg,  p1,  p2,  i;
#    tmp := RECOG.DegreeAlternating (orders);
#    degs := tmp[1];
#    prims := tmp[2];
#    if Length(degs) = 0 then
#        return "Unknown";
#    fi;
#    mindeg := Maximum (degs);  # minimal possible degree

#    p1 := PrevPrimeInt (mindeg + 1);
#    p2 := PrevPrimeInt (p1);
#    if not p1 in prims or not p2 in prims then
#        return 0;
#    fi;
#    if mindeg mod 2 = 1 then
#        if not (mindeg in orders and  mindeg - 2 in orders) then
#            return 0;
#        fi;
#    else
#        if not mindeg - 1 in orders then
#            return 0;
#        fi;
#    fi;

#    for i in [3..Minimum (QuoInt(mindeg,2) - 1, 6)] do
#        if IsPrime (i) and IsPrime (mindeg - i) then
#            if not i * (mindeg - i) in orders then
#                return 0;
#            fi;
#        elif IsPrime (i) and IsPrime (mindeg - i -1) then
#            if not i * (mindeg - i - 1) in orders then
#                return 0;
#            fi;
#        fi;
#    od;
#    return mindeg;
# end;
#
# SLPforElementFuncsProjective.Alternating := function(ri,x)
#   local y,slp;
#   RecSnAnIsOne := IsOneProjective;
#   RecSnAnEq := IsEqualProjective;
#   y := FindImageAn(ri!.recogSnAnDeg,x,
#                    ri!.recogSnAnRec[2][1], ri!.recogSnAnRec[2][2],
#                    ri!.recogSnAnRec[3][1], ri!.recogSnAnRec[3][2]);
#   RecSnAnIsOne := IsOne;
#   RecSnAnEq := EQ;
#   if y = fail then return fail; fi;
#   slp := SLPforAn(ri!.recogSnAnDeg,y);
#   return slp;
# end;
#
# SLPforElementFuncsProjective.Symmetric := function(ri,x)
#   local y,slp;
#   RecSnAnIsOne := IsOneProjective;
#   RecSnAnEq := IsEqualProjective;
#   y := FindImageSn(ri!.recogSnAnDeg,x,
#                    ri!.recogSnAnRec[2][1], ri!.recogSnAnRec[2][2],
#                    ri!.recogSnAnRec[3][1], ri!.recogSnAnRec[3][2]);
#   RecSnAnIsOne := IsOne;
#   RecSnAnEq := EQ;
#   if y = fail then return fail; fi;
#   slp := SLPforSn(ri!.recogSnAnDeg,y);
#   return slp;
# end;
#
# FindHomMethodsProjective.AlternatingBBByOrders := function(ri,G)
#   local Gm,RecSnAnEq,RecSnAnIsOne,deg,limit,ordersseen,r;
#   if IsBound(ri!.projordersseen) then
#       ordersseen := ri!.projordersseen;
#   else
#       ordersseen := [];
#   fi;
#   limit := QuoInt(3*ri!.dimension,2);
#   while Length(ordersseen) <= limit do
#       Add(ordersseen,RECOG.ProjectiveOrder(PseudoRandom(G)));
#       if Length(ordersseen) mod 20 = 0 or
#          Length(ordersseen) = limit then
#           deg := RECOG.RecognizeAlternating(ordersseen);
#           Info(InfoRecog,2,ordersseen);
#           if deg > 0 then  # we strongly suspect Alt(deg):
#               # Switch blackbox recognition to projective:
#               Info(InfoRecog,2,"Suspect alternating or symmetric group of ",
#                    "degree ",deg,"...");
#               RecSnAnIsOne := IsOneProjective;
#               RecSnAnEq := IsEqualProjective;
#               Gm := GroupWithMemory(G);
#               r := RecogniseSnAn(deg,Gm,1/100);
#               RecSnAnIsOne := IsOne;
#               RecSnAnEq := EQ;
#               if r = fail or r[1] <> "An" then
#                   Info(InfoRecog,2,"AltByOrders: Did not find generators.");
#                   continue;
#               fi;
#               Info(InfoRecog,2,"Found Alt(",deg,")!");
#               ri!.recogSnAnRec := r;
#               ri!.recogSnAnDeg := deg;
#               SetSize(ri,Factorial(deg)/2);
#               Setslpforelement(ri,SLPforElementFuncsProjective.Alternating);
#               Setslptonice(ri,SLPOfElms(Reversed(r[2])));
#               ForgetMemory(r[2]);
#               ForgetMemory(r[3][1]);
#               SetFilterObj(ri,IsLeaf);
#               SetIsRecogInfoForSimpleGroup(ri,true);
#               return Success;
#           fi;
#       fi;
#   od;
#   return fail; # FIXME: fail = TemporaryFailure here really correct?
# end;

# abbreviation stands for "homomorphism fully deleted permutation module";
# returns a permutation
RECOG.HomFDPM := function(data,x)
  local r;
  r := RECOG.FindPermutation(data.cob*x*data.cobi,data.fdpm);
  if r = fail then
      return fail;
  fi;
  return r[2];
end;

#! @BeginChunk AltSymBBByDegree
#! This method is a black box constructive (?) recognition of alternating
#! and symmetric groups.
#! 
#! This algorithm is probably based on the paper <Cite Key="BLGN+05"/>.
#! @EndChunk
# subroutines are in AnSnOnFDPM.gi and also paper reference
BindRecogMethod(FindHomMethodsProjective, "AltSymBBByDegree",
"try BB recognition for dim+1 and/or dim+2 if sensible",
function(ri,G)
  local GG,Gm,RecSnAnEq,RecSnAnIsOne,d,deg,f,fact,hom,newgens,o,orders,p,primes,
        r,totry;
  RECOG.SetPseudoRandomStamp(G,"AltSymBBByDegree");
  d := ri!.dimension;
  orders := RandomOrdersSeen(ri);
  if Length(orders) = 0 then
      orders := [RandomElmOrd(ri,"AltSym",false).order];
  fi;
  primes := Filtered(Primes,x->x <= d+2);
  for o in orders do
      fact := FactorsTD(o,primes);
      if Length(fact[2]) <> 0 then
          Info(InfoRecog,2,"AltSym: prime factor of order excludes A_n");
          return NeverApplicable;
      fi;
  od;
  f := ri!.field;
  # We first try the deleted permutation module method:
  if d >= 6 then
      Info(InfoRecog,3,"Trying deleted permutation module method...");
      r := RECOG.RecogniseFDPM(G,f,1/10);
      if r <> fail and IsRecord(r) then
          # Now make a homomorphism object:
          newgens := List(GeneratorsOfGroup(G),
                          x->RECOG.HomFDPM(r,x));
          if not fail in newgens then
              GG := GroupWithGenerators(newgens);
              hom := GroupHomByFuncWithData(G,GG,RECOG.HomFDPM,r);

              SetHomom(ri,hom);
              Setmethodsforimage(ri,FindHomDbPerm);

              ri!.comment := "FDPM";
              return Success;
          fi;
      fi;
      Info(InfoRecog,3,"Deleted permutation module method failed.");
  fi;

  return TemporaryFailure;    # do not try any more now


# TODO: try out an example that should need this;
#  e.g. start with A_n on k-subsets, k >= 2, then go to perm mats...
#

# FIXME: there is dead code below...

#   p := Characteristic(f);
#   totry := EmptyPlist(2);
#   if (d+1) mod p <> 0 and d+1 > 10 then
#       Add(totry,d+1);
#   fi;
#   if (d+2) mod p = 0 and d+2 > 10 then
#       Add(totry,d+2);
#   fi;

#   for deg in totry do
#       Info(InfoRecog,3,"Looking for Alt/Sym(",deg,")...");
#       RecSnAnIsOne := IsOneProjective;
#       RecSnAnEq := IsEqualProjective;
#       Gm := GroupWithMemory(G);
#       r := RecogniseSnAn(deg,Gm,1/100);
#       RecSnAnIsOne := IsOne;
#       RecSnAnEq := EQ;
#       if r = fail then
#           Info(InfoRecog,2,"AltSym: deg=",deg,": did not find generators.");
#           continue;
#       fi;
#       if r[1] = "An" then
#           Info(InfoRecog,2,"Found Alt(",deg,")!");
#           ri!.recogSnAnRec := r;
#           ri!.recogSnAnDeg := deg;
#           SetSize(ri,Factorial(deg)/2);
#           Setslpforelement(ri,SLPforElementFuncsProjective.Alternating);
#           Setslptonice(ri,SLPOfElms(Reversed(r[2])));
#           ForgetMemory(r[2]);
#           ForgetMemory(r[3][1]);
#           SetFilterObj(ri,IsLeaf);
#           SetIsRecogInfoForSimpleGroup(ri,true);
#           ri!.comment := "Alt";
#           return Success;
#       else   # r[1] = "Sn"
#           Info(InfoRecog,2,"Found Sym(",deg,")!");
#           ri!.recogSnAnRec := r;
#           ri!.recogSnAnDeg := deg;
#           SetSize(ri,Factorial(deg));
#           Setslpforelement(ri,SLPforElementFuncsProjective.Symmetric);
#           Setslptonice(ri,SLPOfElms(Reversed(r[2])));
#           ForgetMemory(r[2]);
#           ForgetMemory(r[3][1]);
#           SetFilterObj(ri,IsLeaf);
#           SetIsRecogInfoForAlmostSimpleGroup(ri,true);
#           ri!.comment := "Sym";
#           return Success;
#       fi;
#   od;
#   return TemporaryFailure;
end);

# Looking at element orders to determine which sporadic it could be:

# The following may have been generated by RECOG.MakeSporadicsInfo.
# RECOG.SporadicsElementOrders[i] contains all appearing element orders
# in the sporadic simple group RECOG.SporadicsNames[i].
# RECOG.SporadicsElementOrders[i][j] contains an element order of the
# sporadic simple group RECOG.SporadicsNames[i] with
# probability RECOG.SporadicsProbabilities[i][j].
# RECOG.SporadicsSizes[i] is the size of the sporadic simple group
# RECOG.SporadicsNames[i].
# RECOG.SporadicsKillers contain orders that appear relatively often.
RECOG.SporadicsElementOrders :=
[ [ 1,2,3,5,6,7,10,11,15,19 ],[ 1,2,3,4,5,6,8,11 ],
  [ 1,2,3,4,5,6,8,10,11 ],
  [ 1,2,3,4,5,6,8,9,10,12,15,17,19 ],
  [ 1,2,3,4,5,6,7,8,11,14,15,23 ],[ 1,2,3,4,5,6,7,8,11 ],
  [ 1,2,3,4,5,6,7,8,10,12,15 ],
  [ 1,2,3,4,5,6,7,8,10,12,14,15,17,21,28 ],
  [ 1,2,3,4,5,6,7,8,10,12,13,14,15,16,20,24,26,29 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,15,20 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,14,15,21,23 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,14,15,16,20,21,22,23,24,28,
      29,30,31,33,35,37,40,42,43,44,66 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,14,15,16,19,20,28,31 ],
  [ 1,2,3,4,5,6,7,8,9,10,12,13,14,15,18,19,20,21,24,27,
      28,30,31,36,39 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,30 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,19,20,21,22,25,30, 35,40 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,18,20,21,22,24,25,
      28,30,31,33,37,40,42,67 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,18,20,21,22,23,24,30
     ],[ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,18,20,23,24,28,30 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,18,20,21,24 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,21,22,24,30 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,21,22,
      23,24,26,28,30,33,35,36,39,40,42,60 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,21,
      22,23,24,26,27,28,30,35,36,39,42,60 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,21,
      22,23,24,26,27,28,29,30,33,35,36,39,42,45,60 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
      21,22,23,24,25,26,27,28,30,31,32,33,34,35,36,38,39,40,
      42,44,46,47,48,52,55,56,60,66,70 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
      21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,38,39,
      40,41,42,44,45,46,47,48,50,51,52,54,55,56,57,59,60,62,
      66,68,69,70,71,78,84,87,88,92,93,94,95,104,105,110,119 ]
    ,[ 1,2,3,4,5,6,8,10,11,12 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,14 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,14,15,20,30 ],
  [ 1,2,3,4,5,6,7,8,10,12,14,15,24 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,20,22,24,30 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,21,22,24,28,30,40 ],
  [ 1,2,3,4,5,6,7,8,10,12,14,15,16,17,20,21,24,28,30,42 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,14,15,18,19,20,21,22,24,
      25,28,30,35,40,42,44,60 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,21,22,24,30,36,42 ],
  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,21,
      22,23,24,26,27,28,29,30,33,34,35,36,39,40,42,45,46,54,60,66,70,78,84 ],
  [ 1,2,3,4,5,6,7,8,10,11,12,14,15,16,19,20,22,24,28,30,
      31,38,56 ],[ 1,2,3,4,5,6,8,9,10,12,15,17,18,19,24,34 ]
    ,[ 1,2,3,4,5,6,8,10,12,13,16 ],
  [ 1,2,3,4,5,6,8,10,12,13,16,20 ] ];
RECOG.SporadicsProbabilities :=
[ [ 1/175560,1/120,1/30,1/15,1/6,1/7,1/5,1/11,2/15,3/19 ],
  [ 1/7920,1/48,1/18,1/8,1/5,1/6,1/4,2/11 ],
  [ 1/95040,3/320,5/108,1/16,1/10,1/4,1/4,1/10,2/11 ],
  [ 1/50232960,1/1920,49/9720,1/96,1/15,1/24,1/8,1/9,1/5,1/12,2/15,
      2/17,2/19 ],
  [ 1/10200960,1/2688,1/180,1/32,1/15,1/12,1/7,1/8,2/11,1/7,2/15,
      2/23 ],[ 1/443520,1/384,1/36,3/32,1/5,1/12,2/7,1/8,2/11 ],
  [ 1/604800,3/640,31/1080,1/96,7/150,1/8,1/7,1/8,3/10,1/12,2/15 ],
  [ 1/4030387200,17/322560,2/945,1/84,1/300,1/18,95/4116,1/16,1/20,
      1/6,5/28,1/15,2/17,4/21,1/14 ],
  [ 1/145926144000,283/22364160,1/2160,17/5120,13/3000,1/48,1/28,
      11/192,3/40,1/8,1/52,3/28,1/15,1/8,3/20,1/12,3/52,2/29 ],
  [ 1/44352000,11/23040,1/360,19/960,17/375,5/72,1/7,3/16,1/10,2/11,
      1/12,1/15,1/10 ],
  [ 1/244823040,19/107520,11/3780,1/48,1/60,1/12,1/21,1/16,1/20,
      1/11,1/6,1/7,2/15,2/21,2/23 ],
  [ 1/86775571046077562880,13/21799895040,1/2661120,53/1576960,1/6720,
      2311/2661120,1/420,31/7680,13/960,133/31944,1/32,5/84,1/30,
      1/32,1/80,1/21,13/264,1/23,1/24,1/14,1/29,1/30,3/31,1/33,
      2/35,3/37,1/20,1/21,3/43,1/44,1/33 ],
  [ 1/460815505920,1/161280,1/3240,79/20160,1/180,1/72,29/1372,1/16,
      1/20,1/11,1/36,1/28,2/45,1/4,3/19,1/10,1/14,2/31 ],
  [ 1/90745943887872000,1/92897280,13603/1719506880,257/1935360,1/3000,
      67/25920,1/1176,5/384,5/648,1/120,25/432,1/39,1/56,1/15,5/72,
      1/19,1/20,1/21,1/6,1/9,1/28,1/15,2/31,1/12,2/39 ],
  [ 1/898128000,1/40320,31/29160,1/96,31/750,11/360,1/7,1/8,2/27,
      1/30,2/11,1/12,1/7,1/15,1/15 ],
  [ 1/273030912000000,131/473088000,59/1632960,23/46080,16913/31500000,
      1/192,1/420,9/320,1/27,431/12000,1/22,17/144,1/28,13/180,2/19,
      3/20,1/21,1/22,2/25,1/12,2/35,1/20 ],
  [ 1/51765179004000000,1/39916800,15401/2694384000,1/20160,601/2250000,
      1291/362880,1/168,1/80,1/54,73/3600,1/33,5/288,1/168,28/1125,
      1/18,1/40,1/21,1/11,1/8,1/25,1/28,1/45,5/31,2/33,2/37,1/20,
      1/21,3/67 ],
  [ 1/495766656000,179/31933440,631/2449440,1/1440,1/250,373/12960,
      1/42,1/24,1/54,1/15,1/11,1/18,1/14,1/10,1/18,1/10,1/21,1/11,
      2/23,1/12,1/30 ],
  [ 1/42305421312000,523/743178240,1/116640,139/120960,1/500,79/12960,
      1/56,5/192,1/54,1/20,1/11,2/27,5/56,1/10,1/16,1/18,1/10,
      2/23,1/12,1/28,1/10 ],
  [ 1/448345497600,151/23224320,661/1959552,103/23040,7/1800,187/10368,
      1/84,5/96,1/27,3/40,1/11,31/288,2/13,1/28,1/9,1/9,1/20,2/21,
      1/24 ],
  [ 1/64561751654400,4297/7357464576,11419/176359680,181/276480,1/600,
      9121/933120,1/42,17/384,5/108,1/24,1/11,79/864,2/13,1/14,1/30,
      1/16,7/108,1/20,1/21,1/11,1/24,1/30 ],
  [ 1/4157776806543360000,39239/12752938598400,7802083/4035109478400,
      1061/11612160,1433/15120000,198391/69672960,2/2205,79/23040,1/216,
      109/9600,1/66,10949/207360,1/156,1/42,277/5400,1/32,1/24,
      37/480,17/252,1/22,2/23,25/288,1/52,1/14,13/120,1/33,1/35,
      1/36,2/39,1/40,1/84,1/60 ],
  [ 1/4089470473293004800,407161/129123503308800,161281/148565394432,
      239/5806080,1/25200,1036823/705438720,1/840,1/128,127/17496,
      11/1200,1/44,529/12960,1/39,5/168,1/72,1/16,1/17,13/216,1/30,
      1/42,3/44,2/23,1/16,1/13,1/27,1/28,7/120,1/35,1/18,2/39,
      1/42,1/60 ],
  [ 1/1255205709190661721292800,6439/1032988026470400,144613199/
        4412392214630400,25/6967296,1/907200,159797/564350976,67/123480,
      11/4608,1189/1049760,7/4800,1/132,4741/311040,1/234,5/168,
      103/16200,1/32,1/17,11/288,1/48,17/252,1/44,2/23,7/72,1/26,
      1/27,1/28,2/29,1/24,2/33,1/35,1/24,4/117,5/84,2/45,1/60 ],
  [ 1/4154781481226426191177580544000000,
      34727139371/281639525236291462496256000,160187/10459003768012800,
      56445211/3060705263616000,1873/11088000000,7216687/1418939596800,
      1/564480,18983/123863040,5/34992,667/2688000,1/1320,12629/3732480,
      1/312,871/564480,31/3600,1/96,1/68,7/432,1/38,323/12000,1/252,
      5/264,1/23,19/432,1/25,3/104,1/27,5/224,67/1200,2/31,1/32,
      1/66,3/68,1/70,5/108,1/38,1/39,1/20,1/36,1/44,1/23,2/47,
      1/48,1/52,1/55,1/56,1/30,1/66,1/70 ],
  [ 1/808017424794512875886459904961710757005754368000000000,
      952987291/132953007399245638117682577408000000,
      1309301528411/299423045898886400305790976000,
      228177889/1608412858851262464000,361177/34128864000000000,
      352968797/83672030144102400,16369/1382422809600,80467/177124147200,
      7/18895680,1270627/532224000000,1/1045440,20669/313528320,
      31/949104,9/250880,8611/40824000,1/3072,1/2856,91/139968,1/1140,
      2323/1152000,907/370440,3/3520,1/276,167/13824,1/250,1/208,
      1/162,3/392,1/87,529/43200,1/93,1/64,5/1188,1/136,31/2100,
      1/48,1/76,25/702,49/1600,1/41,1/56,1/176,1/135,3/92,1/47,
      1/96,1/50,1/51,3/104,1/54,1/110,5/112,1/57,2/59,41/720,1/31,
      1/44,1/68,2/69,3/140,2/71,1/26,1/28,2/87,1/44,1/46,2/93,
      1/47,2/95,1/52,1/105,1/110,2/119 ],
  [ 1/190080,17/1920,5/216,3/32,1/20,5/24,1/8,3/20,1/11,1/4 ],
  [ 1/887040,29/8960,1/72,7/96,1/10,1/8,1/7,1/8,1/10,1/11,1/12,1/7
     ],[ 1/88704000,11/21504,1/720,7/240,17/750,17/240,1/14,1/8,1/6,
      1/11,1/12,1/14,1/30,1/5,1/30 ],
  [ 1/1209600,103/26880,31/2160,11/192,7/300,7/48,1/14,5/48,3/20,
      5/24,1/14,1/15,1/12 ],
  [ 1/1796256000,67/887040,31/58320,17/2880,31/1500,31/720,1/14,5/48,
      1/27,7/60,1/11,7/72,1/14,1/30,1/10,1/11,1/12,1/30 ],
  [ 1/896690995200,16081/2554675200,661/3919104,1031/322560,7/3600,
      2879/103680,1/168,53/1440,1/54,89/1200,1/22,65/576,1/13,3/56,
      1/18,1/16,1/18,1/40,1/21,1/22,19/144,1/28,1/30,1/20 ],
  [ 1/8060774400,23/387072,1/945,9/1120,1/600,473/7560,95/8232,7/96,
      1/24,1/8,19/168,1/30,1/8,1/17,1/20,2/21,1/12,1/28,1/30,1/21 ]
    ,[ 1/546061824000000,7057/25546752000,59/3265920,119351/177408000,
      16913/63000000,2497/362880,1/840,21/640,1/54,691/24000,1/44,
      101/1440,5/168,13/360,1/18,1/19,743/6000,1/42,1/44,1/8,1/25,
      1/28,7/120,1/35,1/10,1/42,1/22,1/60 ],
  [ 1/129123503308800,10781/17517772800,11419/352719360,329/414720,
      1/1200,46757/4354560,1/84,1/32,5/216,17/400,1/22,295/2592,1/13,
      1/12,1/60,1/16,29/216,1/20,1/42,1/22,1/8,1/20,1/36,1/42 ],
  [ 1/2510411418381323442585600,352149857/65431527572688076800,
      144613199/8824784429260800,12091/4180377600,1/1814400,
      20115929623/65368773550080,67/246960,13/7680,1189/2099520,97/67200,
      1/264,282547/13063680,1/468,31/1680,103/32400,1/32,1/34,
      4153/139968,41/2400,17/504,7/264,1/23,7/96,5/156,1/54,2/21,
      1/29,11/240,1/33,1/34,1/70,31/432,2/117,1/40,11/168,1/45,
      1/23,1/54,1/60,1/33,1/70,1/39,1/84 ],
  [ 1/921631011840,401/67415040,1/6480,79/40320,1/360,17/720,29/2744,
      43/672,7/120,1/22,1/72,5/56,1/45,1/8,3/38,1/20,1/22,1/12,
      1/28,1/15,1/31,3/38,1/14 ],
  [ 1/100465920,91/195840,49/19440,1/64,1/30,11/144,5/48,1/18,1/10,
      1/8,1/15,1/17,1/6,1/19,1/12,1/17 ],
  [ 1/17971200,23/30720,1/108,11/384,1/50,1/12,3/16,1/10,1/6,2/13,
      1/4 ],
  [ 1/35942400,23/61440,1/216,37/1280,1/100,1/24,3/16,1/20,
      1/4,1/13,1/4,1/10 ] ];
RECOG.SporadicsNames :=
[ "J1","M11","M12","J3","M23","M22","J2","He","Ru","HS","M24",
  "J4","ON","Th","McL","HN","Ly","Co3","Co2","Suz","Fi22","Co1",
  "Fi23","Fi24'","B","M","M12.2","M22.2","HS.2","J2.2","McL.2","Suz.2",
  "He.2","HN.2","Fi22.2","Fi24'.2","ON.2","J3.2","2F4(2)'","2F4(2)'.2"];
RECOG.SporadicsSizes :=
[ 175560,7920,95040,50232960,10200960,443520,604800,4030387200,
  145926144000,44352000,244823040,86775571046077562880,460815505920,
  90745943887872000,898128000,273030912000000,51765179004000000,
  495766656000,42305421312000,448345497600,64561751654400,
  4157776806543360000,4089470473293004800,1255205709190661721292800,
  4154781481226426191177580544000000,
  808017424794512875886459904961710757005754368000000000,190080,887040,
  88704000,1209600,1796256000,896690995200,8060774400,546061824000000,
  129123503308800,2510411418381323442585600,921631011840,100465920,
  17971200,35942400 ];
RECOG.SporadicsKillers :=
[ [[ 5,7 ]],[[ 5,7 ]],[[ 6,7 ]],[[ 11,9 ]],[[ 10,9 ]],[[ 5,7 ]],[[ 7,9 ]],
  [[ 11,14 ]],[[ 14,15 ]],[[ 10,8 ]],[[ 12,11 ]],[[ 29,20,26,23 ]],
  [[ 15,14 ]],[[ 20,19 ]],[[ 13,11 ]],[[ 12,16 ]],[[ 19,23 ]],[[ 11,14,16 ]],
  [[ 17,14,21 ]],[[ 15,13 ]],[ [ 18 .. 22 ] ],
  [ [ 26 .. 32 ],[ 25 .. 32 ] ],[ [ 28 .. 32 ],[ 27 .. 32 ] ],
  [ [ 27 .. 35 ],[ 29 .. 35 ],[ 27,29,34 ] ],  # the latter is for Fi23
  [ [ 31 .. 49 ],[ 40,41,42,43,44,45,46,48,49 ] ], # the latter is agains Fi23
  [ [ 32 .. 73 ],[ 61 .. 73 ] ],[[ 6,10 ]],[[ 7,12 ]],[[ 9,14 ]],[[ 9,10 ]],
  [[ 15,8,10 ]],[[ 13,12,21 ]],[[ 11,13,10 ]],[[ 25,17,20 ]],
  [[ 21,17 ],[23,24]],   # the latter is to distinguish Fi22.2 and Fi22
  [[ 35,32,23,26 ],[ 36,37,38,40,41,42,43 ]], # the latter is for Fi23
  [[ 18,12,14 ]],[[ 10,13 ]],[[ 7,11 ]],[[ 9,11 ]] ];
RECOG.SporadicsWorkers := [];
# Removed to avoid dependency on unpublished package gensift:
#RECOG.SporadicsWorkers[2] := SporadicsWorkerGenSift;   # M11
# and same for: M12, M22, J2, HS, Ly, Co3, Co2

# RECOG.MakeSporadicsInfo := function(name)
#   local ct,i,index,killers,o,orders,p,pos,prob,probs,probscopy,sum;
#   ct := CharacterTable(name);
#   orders := Set(OrdersClassRepresentatives(ct));
#   probs := [];
#   for o in orders do
#       prob := 0;
#       pos := Positions(OrdersClassRepresentatives(ct),o);
#       for p in pos do
#           prob := prob + 1/SizesCentralizers(ct)[p];
#       od;
#       Add(probs,prob);
#   od;
#   index := [1..Length(orders)];
#   probscopy := ShallowCopy(probs);
#   SortParallel(probscopy,index);
#   sum := probscopy[Length(orders)];
#   i := Length(orders);
#   repeat
#       i := i - 1;
#       sum := sum + probscopy[i];
#   until sum > 1/4;
#   killers := index{[i..Length(orders)]};
#   return rec( size := Size(ct), orders := orders,
#               probabilities := probs, killers := killers, name := name );
# end;

# returns a number (the projective order of <m>?) if the order is smaller than
# 120 otherwise fail
RECOG.RuleOutSmallProjOrder := function(m)
  local l,o,v;
  if IsPerm(m) then
      o := Order(m);
      if o > 119 then
          return fail;
      fi;
      return o;
  fi;
  v := ShallowCopy(m[1]);
  Randomize(v);
  ORB_NormalizeVector(v);
  o := Orb([m],v,OnLines,rec( hashlen := 300, report := 0 ));
  Enumerate(o,121);
  if not IsClosed(o) then
      return fail;
  fi;
  l := Length(o);
  Randomize(v);
  ORB_NormalizeVector(v);
  o := Orb([m],v,OnLines,rec( hashlen := 300, report := 0 ));
  Enumerate(o,121);
  if not IsClosed(o) then
      return fail;
  fi;
  l := Lcm(l,Length(o));
  if l > 119 then
      return fail;
  fi;
  return l;
end;

#! @BeginChunk SporadicsByOrders
#! This method returns a list of sporadic simple groups that <A>G</A>
#! possibly could be. Therefore it checks whether
#! <A>G</A> has elements of orders that do not appear in sporadic
#! groups and otherwise checks whether the most common ("killer") orders
#! of the sporadic groups appear.
#! Afterwards it creates hints that come out of a table for the sporadic
#! simple groups.
#! @EndChunk
BindRecogMethod(FindHomMethodsProjective, "SporadicsByOrders",
"generate a few random elements and compute the proj. orders",
function(ri,G)
  local count,gens,i,j,jj,k,killers,l,limit,o,ordersseen,pp,r,raus,res,x;

  RECOG.SetPseudoRandomStamp(G,"SporadicsByOrders");

  l := [1..Length(RECOG.SporadicsNames)];
  pp := 0*l;
  ordersseen := [];
  count := 0;
  gens := GeneratorsOfGroup(G);
  limit := 120+Length(gens);
  for i in [1..limit] do
      if i <= Length(gens) then
          r := rec( el := gens[i] );
      else
          r := RandomElm(ri,"SporadicsByOrders",false);
      fi;
      o := RECOG.RuleOutSmallProjOrder(r.el);
      if o = fail then
          Info(InfoRecog,2,"Ruled out all sporadic groups.");
          return NeverApplicable;
      elif i <= Length(gens) then
          r.order := OrderFunc(ri)(r.el);
      else
          GetElmOrd(ri,r);
      fi;
      o := r.order;
      x := r.el;
      AddSet(ordersseen,o);
      Info(InfoRecog,3,"Found order: ",String(o,3)," (element #",i,")");
      l := Filtered(l,i->o in RECOG.SporadicsElementOrders[i]);
      if l = [] then
          Info(InfoRecog,2,"Ruled out all sporadic groups.");
          return NeverApplicable;
      fi;
      # Throw out improbable ones:
      j := 1;
      while j <= Length(l) do
          if Length(l) = 1 then
              limit := 1/1000;
          else
              limit := 1/400;
          fi;
          jj := l[j];
          raus := false;
          # check whether orders appear in killers
          for k in [1..Length(RECOG.SporadicsElementOrders[jj])] do
              if not RECOG.SporadicsElementOrders[jj][k] in ordersseen and
                 (1-RECOG.SporadicsProbabilities[jj][k])^i < limit then
                  Info(InfoRecog,3,"Have thrown out ",RECOG.SporadicsNames[jj],
                       " (did not see order ",
                       RECOG.SporadicsElementOrders[jj][k],")");
                  raus := true;
                  break;
              fi;
          od;
          if not raus and IsBound(RECOG.SporadicsKillers[jj]) then
            for killers in RECOG.SporadicsKillers[jj] do
              if Intersection(ordersseen,
                              RECOG.SporadicsElementOrders[jj]{killers})=[]
                 and (1-Sum(RECOG.SporadicsProbabilities[jj]{killers}))^i
                     < 10^-3 then
                  raus := true;
                  break;
                  Info(InfoRecog,3,"Have thrown out ",RECOG.SporadicsNames[jj],
                       " (did not see orders in ",
                       RECOG.SporadicsElementOrders[jj]{killers},")");
              fi;
            od;
          fi;
          if raus then
              Remove(l,j);
          else
              j := j + 1;
          fi;
      od;
      if l = [] then
          Info(InfoRecog,2,"Ruled out all sporadic groups.");
          return NeverApplicable;
      elif Length(l) = 1 then
        count := count + 1;
        if count >= 9 then
          Info(InfoRecog,2,"I guess that this is the sporadic simple group ",
               RECOG.SporadicsNames[l[1]],".");
          break;
        fi;
      fi;
      if Length(l) < 6 then
          Info(InfoRecog,2,"Possible sporadics left: ",
               RECOG.SporadicsNames{l}," i=",i);
      else
          Info(InfoRecog,2,"Possible sporadics left: ",Length(l)," i=",i);
      fi;
  od;
  if ValueOption("DEBUGRECOGSPORADICS") <> fail then
      return RECOG.SporadicsNames{l};
  fi;
  for i in [1..Length(l)] do
      Info(InfoRecog,2,"Trying hint for ",RECOG.SporadicsNames[l[i]],"...");
      res := LookupHintForSimple(ri,G,RECOG.SporadicsNames[l[i]]);
      if res = true then
          return Success;
      fi;
      if IsBound(RECOG.SporadicsWorkers[l[i]]) then
          Info(InfoRecog,2,"Calling its installed worker...");
          res := RECOG.SporadicsWorkers[l[1]](RECOG.SporadicsNames[l[i]],
                                        RECOG.SporadicsSizes[l[i]],ri,G);
          if res = true then
              return Success;
          fi;
      fi;
      Info(InfoRecog,2,"This did not work.");
  od;
  return false; # FIXME: false = NeverApplicable here really correct?
end);

# Data for the function NameSporadic
RECOG.NameSporadicData := MakeImmutable([
    rec(name := "M11",
        maximalOrdersOverset := [5, 6, 8, 11],
        maximalOrdersSubset := [],
        length := 4),
    rec(name := "M12",
        maximalOrdersOverset := [6, 8, 10, 11],
        maximalOrdersSubset := [],
        length := 4),
    rec(name := "M22",
        maximalOrdersOverset := [5, 6, 7, 8, 11],
        maximalOrdersSubset := [],
        length := 5),
    rec(name := "M23",
        maximalOrdersOverset := [6, 8, 11, 14, 15, 23],
        maximalOrdersSubset := [11, 14, 15, 23]),
    rec(name := "M24",
        maximalOrdersOverset := [8, 10, 11, 12, 14, 15, 21, 23],
        maximalOrdersSubset := [11, 21, 23]),
    rec(name := "J1",
        maximalOrdersOverset := [6, 7, 10, 11, 15, 19],
        maximalOrdersSubset := [11, 15, 19]),
    rec(name := "J2",
        maximalOrdersOverset := [7, 8, 10, 12, 15],
        maximalOrdersSubset := [7, 12, 15]),
    rec(name := "J3",
        maximalOrdersOverset := [8, 9, 10, 12, 15, 17, 19],
        maximalOrdersSubset := [15, 17, 19]),
    rec(name := "HS",
        maximalOrdersOverset := [7, 8, 10, 11, 12, 15, 20],
        maximalOrdersSubset := [11, 20]),
    rec(name := "McL",
        maximalOrdersOverset := [8, 9, 11, 12, 14, 30],
        maximalOrdersSubset := [11, 14, 30]),
    rec(name := "Suz",
        maximalOrdersOverset := [11, 13, 14, 15, 18, 20, 21, 24],
        maximalOrdersSubset := [11, 13]),
    rec(name := "Ru",
        maximalOrdersOverset := [14, 15, 16, 20, 24, 26, 29],
        maximalOrdersSubset := [26, 29]),
    rec(name := "Co3",
        maximalOrdersOverset := [14, 18, 20, 21, 22, 23, 24, 30],
        maximalOrdersSubset := [22, 23, 24, 30]),
    rec(name := "Co2",
        maximalOrdersOverset := [11, 16, 18, 20, 23, 24, 28, 30],
        maximalOrdersSubset := [16, 23, 28, 30]),
    rec(name := "Co1",
        maximalOrdersOverset := [16, 22, 23, 24, 26, 28, 33, 35, 36, 39, 40, 42, 60],
        maximalOrdersSubset := [33, 42]),
    rec(name := "ON",
        maximalOrdersOverset := [11, 12, 15, 16, 19, 20, 28, 31],
        maximalOrdersSubset := [19, 28, 31]),
    rec(name := "Fi22",
        maximalOrdersOverset := [13, 14, 16, 18, 20, 21, 22, 24, 30],
        maximalOrdersSubset := [13, 24, 30]),
    rec(name := "He",
        maximalOrdersOverset := [8, 10, 12, 15, 17, 21, 28],
        maximalOrdersSubset := [17, 28]),
    rec(name := "Ly",
        maximalOrdersOverset := [18, 22, 24, 25, 28, 30, 31, 33, 37, 40, 42, 67],
        maximalOrdersSubset := [31, 67]),
    rec(name := "J4",
        maximalOrdersOverset := [16, 23, 24, 28, 29, 30, 31, 33, 35, 37, 40, 42, 43, 44, 66],
        maximalOrdersSubset := [37, 43]),
    rec(name := "Fi23",
        maximalOrdersOverset := [13, 14, 16, 17, 22, 23, 24, 26, 27, 28, 35, 36, 39, 42, 60],
        maximalOrdersSubset := [17, 23]),
    rec(name := "Fi24'",
        maximalOrdersOverset := [16, 17, 22, 23, 24, 26, 27, 28, 29, 33, 35, 36, 39, 42, 45, 60],
        maximalOrdersSubset := [17, 29]),
    rec(name := "Th",
        maximalOrdersOverset := [19, 20, 21, 24, 27, 28, 30, 31, 36, 39],
        maximalOrdersSubset := [19, 31, 39]),
]);
#! @BeginChunk NameSporadic
#! This method returns a list of sporadic simple groups that the group
#! underlying <A>ri</A> could be. It does not recognise extensions of sporadic
#! simple groups nor the Monster and the Baby Monster group. It is based on the
#! Magma v2.24.10 function <C>RecognizeSporadic</C>.
#! @EndChunk
# TODO G is unused
BindRecogMethod(FindHomMethodsProjective, "NameSporadic",
"generate maximal orders",
function(ri, G)
    local orders, setOfOrders, maximalOrders, isMaximal,
        namesOfPossibleSporadics, res, i, j, data, name;
    orders := [];
    #do we need SetPseudoRandomStamp?
    for i in [1 .. 500] do
        Add(orders, RandomElmOrd(ri, "NameSporadic", false).order);
    od;
    # Compute maximal orders. Maximal in the sense that it does not divide the
    # order of another group element.
    setOfOrders := AsSet(orders);
    # All orders we look for are <= 66.
    if setOfOrders[Length(setOfOrders)] > 67 then
        return NeverApplicable;
    fi;
    maximalOrders := [];
    for i in [1..Length(setOfOrders)] do
        isMaximal := true;
        for j in [i+1..Length(setOfOrders)] do
            if setOfOrders[j] mod setOfOrders[i] = 0 then
                isMaximal := false;
                break;
            fi;
        od;
        if isMaximal then
            Add(maximalOrders, setOfOrders[i]);
        fi;
    od;
    namesOfPossibleSporadics := [];
    for data in RECOG.NameSporadicData do
        if IsBound(data.length) and not Length(maximalOrders) = data.length then
            continue;
        fi;
        if IsSubset(maximalOrders, data.maximalOrdersSubset)
                and IsSubset(data.maximalOrdersOverset, maximalOrders) then
            Add(namesOfPossibleSporadics, data.name);
        fi;
    od;
    # HN works a bit differently
    if IsSubset([9, 12, 14, 19, 21, 22, 25, 30, 35, 40], maximalOrders)
            and (IsSubset(maximalOrders, [19]) or IsSubset(maximalOrders, [21]))
    then
        Add(namesOfPossibleSporadics, "HN");
    fi;
    if ValueOption("DEBUGRECOGSPORADICS") <> fail then
        return namesOfPossibleSporadics;
    fi;
    for name in namesOfPossibleSporadics do
        Info(InfoRecog, 2, "Trying hint for ", name,
             "...");
        res := LookupHintForSimple(ri, Grp(ri), name);
        if res = true then return Success; fi;
        Info(InfoRecog, 2, "This did not work.");
    od;
    return NeverApplicable;
end);

[ Dauer der Verarbeitung: 0.38 Sekunden  (vorverarbeitet)  ]