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

Quelle  giant.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 Maska Law, Á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
##
##
##  This file provides code for recognising whether a permutation group
##  on n points is isomorphic to A_n or S_n acting naturally.
##
#############################################################################

DeclareInfoClass( "InfoGiants" );
SetInfoLevel( InfoGiants, 1 );


#######################################################################
##
#F  NiceGeneratorsSn(<n>,<grp>,<N>) ...... find n-cycle, transposition
##
##

RECOG.NiceGeneratorsSn := function ( mp, grp, N )

    local t, cyclen, g, y, h, i, x, supp, n;

    n := Length(mp);
    while N > 0 do
        N := N - 1;
        t := PseudoRandom( grp );
        # was: cyclen := Collected( CycleLengths( t, [1..n] ) );
        cyclen := CycleStructurePerm(t);

        # was: if IsBound(g) = false and [n,1] in cyclen then
        if IsBound(g) = false and IsBound(cyclen[n-1]) then
            # we found an $n$-cycle
            g := t;
        fi;

        if IsBound(y) = false and IsBound(cyclen[1]) and cyclen[1] = 1 and
               ForAll([1..QuoInt(n,2)-1],i->not IsBound(cyclen[2*i+1]))
               # was: Filtered( cyclen, x -> x[1] mod 2 = 0 ) = [ [ 2,1 ] ]
        then
            # we can get a transposition
            y := t^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/2);
        fi;

        if IsBound(g) and IsBound(y) then
            i := 10*n;
            supp := MovedPoints( y );
            while i > 0 do  # take up to i conjugates,
                            # check if they match the $n$-cycle
                i := i-1;
                x := PseudoRandom( grp );
                if (supp[1]^x)^g = supp[2]^x or (supp[2]^x)^g = supp[1]^x
                    then h := y^x;
                    return [ g, h ];
                fi;
            od;
            return fail;
        fi;

    od; # loop over random elements

    return fail;

end;


######################################################################
##
#F  ConjEltSn(<n>,<g>,<h>) . . . element c s.t. g^c=(1..n), h^c=(1,2)
##
##

RECOG.ConjEltSn :=  function( mp, g, h )

    local c,i,la,n,oo,pos,supp;

    n := Length(mp);
    la := mp[n];   # this is the largest moved point

    supp := MovedPoints( h );

    if supp[1]^g = supp[2] then pos := supp[1];
    else pos := supp[2];
    fi;

    c := [];
    for i in [ 1 .. n ] do
        c[pos] := i;
        pos := pos^g;
    od;
    oo := Difference([1..la],mp);
    for i in [1..Length(oo)] do
        c[oo[i]] := i+n;
    od;

    return PermList( c );

end;


######################################################################
##
#F  RecogniseSn(<n>, <grp>, <N>) . . . . . . recognition function
##
##

RECOG.RecogniseSn :=  function( mp, grp, eps )

    local le, N, gens, c, n;

    n := Length(mp);

    le := 0;
    while 2^le < eps^-1 do
        le := le + 1;
    od;

    N := Int(24 * (4/3)^3 * le * 6 * n);

    gens := RECOG.NiceGeneratorsSn( mp, grp, N );
    if gens = fail then
        Info(InfoGiants,1,"couldn't find nice generators for Sn");
        return fail;
    fi;

    c := RECOG.ConjEltSn( mp, gens[1], gens[2] );

    return rec( stamp := "Sn", degree := n,
                gens := Reversed(gens),  conjperm := c );

end;


########################################################################
##
#F  NiceGeneratorsAnEven(<n>,<grp>,<N>) . . find (2,n-2)-cycle, 3-cycle
##
##

RECOG.NiceGeneratorsAnEven := function ( mp, grp, N )

    local l, t, cyclen, a, b, c, i, fp, suppb, others, g, h, n;

    n := Length(mp);
    l := One(grp);

    while N > 0 do
        N := N - 1;
        t := PseudoRandom( grp );
        # was: cyclen := Collected( CycleLengths( t, [1..n] ) );
        cyclen := CycleStructurePerm(t);

        # was: if IsBound(a) = false and [n-1,1] in cyclen then
        if IsBound(a) = false and IsBound(cyclen[n-2]) then
            # we found an $n-1$-cycle
            a := t;
        fi;

        if IsBound(b) = false and IsBound(cyclen[2]) and cyclen[2] = 1 and
               # Filtered( cyclen, x -> x[1] mod 3 = 0 ) = [ [ 3,1 ] ]
               ForAll( [2..QuoInt(n,3)], x->not IsBound(cyclen[3*x-1]) )
        then
            # we can get a $3$-cycle
            #b := t^(Lcm(List(cyclen,x->x[1]))/3);
            b := t^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/3);
        fi;

        if IsBound(a) and IsBound(b) then
            i := 10*n;
            fp := Difference( mp, MovedPoints(a) )[1];
            suppb:= MovedPoints( b );
            while i > 0 do
                i := i-1;
                t := PseudoRandom( grp );
                if fp in List( suppb, x -> x^t ) then
                    c := b^t;
                    others := [ fp^c, (fp^c)^c ];
                    if others[1]^a = others[2] then
                        h := c;
                    elif others[2]^a = others[1] then
                        h := c^2;
                    else
                        h := Comm(c^a,c);   # h = (1,i,i+1)
                    fi;
                    g := a * h;
                    return [ g, h ];
                fi;
            od; # while

            return fail;
        fi;

    od; # loop over random elements

    return fail;

end;


#########################################################################
##
#F  NiceGeneratorsAnOdd(<n>,<grp>,<N>) . . . . find (n-2)-cycle, 3-cycle
##
##

RECOG.NiceGeneratorsAnOdd := function ( mp, grp, N )

    local l, t, cyclen, a, b, i, suppb, suppc, suppca, imc, h, g, n;

    n := Length(mp);
    l := One(grp);

    while N > 0 do
        N := N - 1;
        t := PseudoRandom( grp );
        # was: cyclen := Collected( CycleLengths( t, [1..n] ) );
        cyclen := CycleStructurePerm(t);

        if IsBound(a) = false and IsBound(cyclen[n-1]) then
            # we found an $n$-cycle
            a := t;
        fi;

        if IsBound(b) = false and IsBound(cyclen[2]) and cyclen[2] = 1 and
               # was: Filtered( cyclen, x -> x[1] mod 3 = 0 ) = [ [ 3,1 ] ]
               ForAll( [2..QuoInt(n,3)], x->not IsBound(cyclen[3*x-1]) )
        then
            # we can get a $3$-cycle
            #b := t^(Lcm(List(cyclen,x->x[1]))/3);
            b := t^(Lcm(Filtered([2..n],x->IsBound(cyclen[x-1])))/3);
        fi;

        if IsBound(a) and IsBound(b) then
            i := 10*n;
            suppb := MovedPoints( b );
            while i > 0 do
                i := i-1;
                t := PseudoRandom( grp );

                suppc := List( suppb, x -> x^t );
                # support of c=b^t, say [i,j,k]

                suppca := List( suppc, x -> x^a );
                # support of c^a, so [i^a,j^a,k^a]

                imc := List( suppc, x -> ((x^(t^-1))^b)^t );
                # [i^c,j^c,k^c]

                if Length( Intersection( suppc, suppca ) ) = 2 then
                    # so c=b^t moves three consecutive points of a
                    if  suppca[1] = imc[1] or
                        suppca[2] = imc[2] or
                        suppca[3] = imc[3] then
                        # so c moves points in same order as a
                        h := b^t;
                    else
                        # so c moves points in opposite order to a
                        h := (b^2)^t;
                    fi;
                elif Length( Intersection( suppc, suppca ) ) = 1 then
                    # so c=b^t moves only two consecutive points of a
                    if suppca[1] = imc[1] or
                       suppca[2] = imc[2] or
                       suppca[3] = imc[3] then
                        # so c moves points in same order as a
                        h := b^t;
                        h := Comm( h^2, h^a );
                    else
                        # so c moves points in opposite order to a
                        h := b^t;
                        h := Comm( h, (h^a)^2 );
                    fi;
                fi;

                if IsBound( h ) then
                    g := a * h^2;
                    return [ g, h ];
                fi;

            od; # while

            return fail;
        fi;

    od; # loop over random elements

    return fail;

end;


#########################################################################
##
#F  ConjEltAnEven(<n>,<g>,<h>) . . . c s.t. g^c=(1,2)(3..n), h^c=(1,2,3)
##
##

RECOG.ConjEltAnEven := function( mp, g, h )
    local c,i,la,n,oo,pos,s1,s1g,supp;

    n := Length(mp);
    la := mp[n];    # this is the largest moved point

    supp := MovedPoints(h);  # {i,j,k} where h=(i,j,k), i^g=j, j^g=i
    s1 := supp[1];
    s1g := s1^g;

    c := [];
    if s1g in supp then      # {s1,s1g} = {i,j}
        if s1^h = s1g then   # [s1,s1g] = [i,j]
            c[s1] := 1;
            c[s1g] := 2;
        else
            c[s1g] := 1;
            c[s1] := 2;
        fi;
        pos := Difference(supp,Set([s1,s1g]))[1];
        for i in [3..n] do
            c[pos] := i;
            pos := pos^g;
        od;
        oo := Difference([1..la],mp);
        for i in [1..Length(oo)] do
            c[oo[i]] := i+n;
        od;

    else   # s1 = k
        if supp[2]^h = supp[2]^g then
            c[supp[2]] := 1;
            c[supp[3]] := 2;
        else
            c[supp[3]] := 1;
            c[supp[2]] := 2;
        fi;
        pos := s1;
        for i in [3..n] do
            c[pos] := i;
            pos := pos^g;
        od;
        oo := Difference([1..la],mp);
        for i in [1..Length(oo)] do
            c[oo[i]] := i+n;
        od;
    fi;

    return PermList( c );

end;


######################################################################
##
#F  ConjEltAnOdd(<n>,<g>,<h>) . . . . c s.t. g^c=(3..n), h^c=(1,2,3)
##
##

RECOG.ConjEltAnOdd := function( mp, g, h )
    local c,compt,i,la,n,oo,pos;

    n := Length(mp);
    la := mp[n];   # this is the largest moved point

    compt := Intersection( MovedPoints( g ), MovedPoints( h ) )[1];
    # compt is the common point moved by both g and h : so becomes 3

    c := [];
    c[ compt^h ] := 1;
    c[ (compt^h)^h ] := 2;

    pos := compt;

    for i in [3..n] do
        c[pos] := i;
        pos := pos^g;
    od;

    oo := Difference([1..la],mp);
    for i in [1..Length(oo)] do
        c[oo[i]] := i+n;
    od;

    return PermList(c);

end;


######################################################################
##
#F  RecogniseAn(<n>, <grp>, <N>) . . . . . . recognition function
##
##

RECOG.RecogniseAn :=  function( mp, grp, eps )

        local le, N, gens, c, n;

        n := Length(mp);

        le := 0;
        while 2^le < eps^-1 do
            le := le + 1;
        od;

        N := Int(24 * (4/3)^3 * le * 6 * n);

        if n mod 2 = 0 then
            gens := RECOG.NiceGeneratorsAnEven( mp, grp, N );
        else
            gens := RECOG.NiceGeneratorsAnOdd( mp, grp, N );
        fi;

        if gens = fail then
            Info(InfoGiants,1,"couldn't find nice generators for An");
            return fail;
        fi;

        if n mod 2 = 0 then
            c := RECOG.ConjEltAnEven( mp, gens[1], gens[2] );
        else
            c := RECOG.ConjEltAnOdd( mp, gens[1], gens[2] );
        fi;

        return rec( stamp := "An", degree := n,
                    gens := Reversed(gens), conjperm := c );
end;


######################################################################
##
#F  RecogniseGiant(<n>, <grp>, <N>) . . . . . . recognition function
##
##
##  This is the main function.
##

RECOG.RecogniseGiant :=  function( mp, grp, eps )

    if ForAny(GeneratorsOfGroup( grp ), x -> SignPerm(x) = -1) then
        return RECOG.RecogniseSn( mp, grp, eps );
    else
        return RECOG.RecogniseAn( mp, grp, eps );
    fi;

end;


########################################################################
##
#F  FindHomomorphismMethods.Giant
##

# See Corollary 10.2.2 in [Ser03].
RECOG.IsGiant:=function(g,mp)
  local bound, i, p, cycles, l, x, n;
  n := Length(mp);
  bound:=20*LogInt(n,2);
  i:=0;
  repeat
    i:=i+1;
    p:=PseudoRandom(g);
    x:=Random(mp);
    l:=CycleLength(p,x);
  until (i>bound) or (l> n/2 and l<n-2 and IsPrime(l));
  if i>bound then
    return fail;
  else
    return true;
  fi;
end;

##  SLP for pi from (1,2), (1,...,n)

RECOG.SLPforSn :=  function( n, pi )

    local cycles, initpts, c, newc, i, R, ci, cycslp, k ;

    if IsOne(pi) then
        return StraightLineProgramNC( [[1,0]], 2 );
    fi;
    if LargestMovedPoint(pi) > n then
        return fail;
    fi;

    # we need the cycles of pi of length > 1 to be written such
    # that the minimum point is the initial point of the cycle
    initpts := [ ];
    cycles := [ ];
    for c in Filtered( Cycles( pi, [ 1 .. n ] ), c -> Length(c) > 1 ) do
        i := Minimum( c );
        Add( initpts, i );
        if i = c[1] then
            Add( cycles, c );
        else
            newc := [ i ];
            for k in [ 2 .. Length(c) ] do
                Add( newc, newc[k-1]^pi );
            od;
            Add( cycles, newc );
        fi;
    od;

    # R will be a straight line program from tau_1, sigma_1
    # we update cycle product, tau_i+1, sigma_i+2
    # and then overwrite the updates into positions 1,2,3
    R := [ [1,0], [3,1], [1,1], [2,1,1,1],
                    [[4,1],1], [[5,1],2], [[6,1],3] ];
    i := 1;
    repeat
        if i in initpts then
            # ci is the cycle of pi beginning with i
            ci := cycles[ Position( initpts, i ) ];
            # cycslp is the SLP for ci from tau_i and sigma_i+1
            cycslp := [ 1,1, 3,1+ci[1]-ci[2] ];
            for k in [ 2 .. Length(ci)-1 ] do
                Append( cycslp, [ 2,1, 3,ci[k]-ci[k+1] ] );
            od;
            Append( cycslp, [ 2,1, 3,ci[Length(ci)]-ci[1]-1 ] );
            Append( R, [ [cycslp,4] ]);
        else    # we carry forward cycle product computed so far
            Append( R, [ [[1,1],4] ] );
        fi;
                # we update tau_i+1 and sigma_i+2
        Append( R, [ [[2,1,3,-1,2,1,3,1,2,1],5],
                 [[3,1,2,1,3,-1,2,1,3,1,2,1],6],
                [[4,1],1], [[5,1],2], [[6,1],3] ]);
        i := i + 1;
    until i > Maximum( initpts );

    # the return value
    Add(R,[ [1,1],1 ]);

    # R is a straight line program with 2 inputs
    R:=StraightLineProgramNC( R, 2 );

    return R;

end;


##  SLP for pi from (1,2,3), sigma

RECOG.SLPforAn :=  function( n, pi )

    local cycles, initpts, c, newc,  R, i, nexttrpn, ci, cycslp, k, j,
          nexttau, nextsigma ;

    if IsOne(pi) then
        return StraightLineProgramNC( [[1,0]], 2 );
    fi;
    if SignPerm( pi ) = -1 then
        return fail;
    fi;
    if LargestMovedPoint(pi) > n then
        return fail;
    fi;

    # we need the cycles of pi of length > 1 to be written such
    # that the minimum point is the initial point of the cycle
    initpts := [ ];
    cycles := [ ];
    for c in Filtered( Cycles( pi, [ 1 .. n ] ), c -> Length(c) > 1 ) do
        i := Minimum( c );
        Add( initpts, i );
        if i = c[1] then
            Add( cycles, c );
        else
            newc := [ i ];
            for k in [ 2 .. Length(c) ] do
                Add( newc, newc[k-1]^pi );
            od;
            Add( cycles, newc );
        fi;
    od;

    # R will be a straight line program from tau_1, sigma_1
    # we update cycle product, tau_i+1, sigma_i+1
    # and then overwrite the updates into positions 1,2,3
    R := [ [1,0], [3,1], [1,1], [2,1],
                  [[4,1],1], [[5,1],2], [[6,1],3] ];
    i := 1;

    # we keep track of which transposition of pi we must compute next
    nexttrpn := 1;

    repeat
      if i in initpts then
        # ci is the cycle of pi beginning with i
        ci := cycles[ Position( initpts, i ) ];
        # cycslp is the SLP for ci from tau_i and sigma_i
        # we carry forward the cycle product computed so far
        cycslp := [ 1,1 ];
        for k in [ 2 .. Length(ci) ] do
            j := ci[k];  # so (i,j)=(ci[1],ci[k])
            if j < n-1 then
                # NB: if i < j < n-1 then (i,j)(n-1,n) = (n-1,n)(i,j)
                if j = i+1 then
                    if IsEvenInt( n-i ) then
                        Append( cycslp, [ 3,i+2-n, 2,2, 3,1, 2,1,
                                          3,-1, 2,2, 3,n-i-2 ] );
                    else
                        Append( cycslp, [ 3,i+2-n, 2,1, 3,1, 2,1,
                                          3,-1, 2,1, 3,n-i-2 ] );
                    fi;
                else
                    if IsEvenInt( n-i ) then
                        Append( cycslp, [ 3,i+2-j, 2,1, 3,j-n,
                                          2,2, 3,1, 2,1, 3,-1, 2,2,
                                          3,n-j, 2,2, 3,j-i-2 ] );
                    elif IsOddInt( n-i ) and IsEvenInt( j-i-2 ) then
                        Append( cycslp, [ 3,i+2-j, 2,1, 3,j-n,
                                          2,1, 3,1, 2,1, 3,-1, 2,1,
                                          3,n-j, 2,2, 3,j-i-2 ] );
                    else
                        Append( cycslp, [ 3,i+2-j, 2,2, 3,j-n,
                                          2,1, 3,1, 2,1, 3,-1, 2,1,
                                          3,n-j, 2,1, 3,j-i-2 ] );
                    fi;
                fi;
            elif ( j = n-1 or j = n ) and i < n-1 then
                if ( j = n-1 and IsOddInt( nexttrpn ) ) or
                   ( j = n and IsEvenInt( nexttrpn ) ) then
                    if IsEvenInt( n-i ) then
                        if n-i>2 then
                           Append( cycslp,
                                [ 3,i+2-n, 2,2, 3,1, 2,1, 3,n-i-3  ] );
                        else
                           Append( cycslp, [ 2,2 ] );
                        fi;
                    else
                        Append( cycslp,
                                [ 3,i+2-n, 2,1, 3,1, 2,1, 3,n-i-3  ] );
                    fi;
                elif ( j = n and IsOddInt( nexttrpn ) ) or
                     ( j = n-1 and IsEvenInt( nexttrpn ) ) then
                    if IsEvenInt( n-i ) then
                        if n-i>2 then
                           Append( cycslp,
                                [ 3,i+3-n, 2,2, 3,-1, 2,1, 3,n-i-2  ] );
                        else
                           Append( cycslp, [ 2,1 ] );
                        fi;
                    else
                        Append( cycslp,
                                [ 3,i+3-n, 2,2, 3,-1, 2,2, 3,n-i-2  ] );
                    fi;
                fi;
            else   # (i,j) = (n-1,n)
                Append( cycslp, [ ] );
            fi;

            nexttrpn := nexttrpn + 1;
        od;
        Append( R, [ [cycslp,4] ] );

      else  # not (i in initpts)
        # we carry forward cycle product computed so far
        Append( R, [ [[1,1],4] ] );
      fi;

      # we update tau_i+1 and sigma_i+1
      if IsEvenInt(n-i) then
          nexttau   := [ 2,-1,3,-1,2,1,3,1,2,1 ];
          nextsigma := [ 3,1,5,1 ];
      else
          nexttau   := [ 2,-1,3,-1,2,2,3,1,2,1 ];
          nextsigma := [ 3,1,2,2,5,-1 ];
      fi;

      Append( R, [ [nexttau,5], [nextsigma,6],
                     [[4,1],1], [[5,1],2], [[6,1],3] ]);
      i := i + 1;

    until i > Maximum( initpts );

    # the return value
    Add(R,[ [1,1],1 ]);

    # R is a straight line program with 2 inputs
    R:=StraightLineProgramNC( R, 2 );

    return R;

end;


RECOG.GiantEpsilon := 1/1024;

#! @BeginChunk Giant
#! The method tries to determine whether the input group <A>G</A> is
#! a giant (that is, <M>A_n</M> or <M>S_n</M> in its natural action on
#! <M>n</M> points). The output is either a data structure <M>D</M> containing
#! nice generators for <A>G</A> and a procedure to write an SLP for arbitrary
#! elements of <A>G</A> from the nice generators; or <K>NeverApplicable</K> if
#! <A>G</A> is not transitive; or <K>fail</K>, in the case that no
#! evidence was found that <A>G</A> is a giant, or evidence was found, but
#! the construction of <M>D</M> was unsuccessful.
#! If the method constructs <M>D</M> then the calling node becomes a leaf.
#! @EndChunk
BindRecogMethod(FindHomMethodsPerm, "Giant",
"tries to find Sn and An in their natural actions",
rec(validatesOrAlwaysValidInput := true),
function(ri, grp)
    local grpmem,mp,res;
    if not IsPermGroup(grp) then
        return NeverApplicable;
    fi;
    if not IsTransitive(grp) then
        return NeverApplicable;
    fi;
    mp := MovedPoints(grp);
    # Decide whether group is a giant
    if RECOG.IsGiant(grp,mp) = fail then
        return TemporaryFailure;
    fi;
    grpmem := Group(ri!.gensHmem);
    grpmem!.pseudorandomfunc := [rec(
       func := function(ri) return RandomElm(ri,"Giant",true).el; end,
       args := [ri])];

    # Do constructive recognition for giants
    res := RECOG.RecogniseGiant(mp,grpmem,RECOG.GiantEpsilon);
    if res = fail then
        return TemporaryFailure;
    fi;
    Setslptonice(ri, SLPOfElms(res.gens));
    # Note that when putting the generators into the record, we reverse
    # their order, such that it fits to the SLPforSn/SLPforAn function!
    Setslpforelement(ri,SLPforElementFuncsPerm.Giant);
    ri!.giantinfo := res;
    SetFilterObj(ri,IsLeaf);
    if res.stamp = "An" then
        SetSize(ri,Factorial(Length(mp))/2);
        SetIsRecogInfoForSimpleGroup(ri,true);
    else
        SetSize(ri,Factorial(Length(mp)));
        SetIsRecogInfoForAlmostSimpleGroup(ri,true);
    fi;
    SetNiceGens(ri,StripMemory(res.gens));
    return Success;
end);

SLPforElementFuncsPerm.Giant :=
  function(ri,g)
    local gg;
    gg := g^ri!.giantinfo.conjperm;
    # Note that when putting the generators into the record, we reverse
    # their order, such that it fits to the SLPforSn/SLPforAn function!
    if ri!.giantinfo.stamp = "An" then
        return RECOG.SLPforAn(ri!.giantinfo.degree,gg);
    else   # Sn
        return RECOG.SLPforSn(ri!.giantinfo.degree,gg);
    fi;
  end;

[ Dauer der Verarbeitung: 0.58 Sekunden  ]