diff --git a/doc/recog.bib b/doc/recog.bib index e553080a1..20ffe346b 100644 --- a/doc/recog.bib +++ b/doc/recog.bib @@ -387,6 +387,18 @@ @article {KK15 NOTE = {https://doi.org/10.1016/j.jalgebra.2014.08.014}, } +@book{KL90, + AUTHOR = {Kleidman, Peter B. and Liebeck, Martin W.}, + TITLE = {The Subgroup Structure of the Finite Classical Groups}, + SERIES = {London Mathematical Society Lecture Note Series}, + YEAR = {1990}, + PUBLISHER = {Cambridge University Press}, + PLACE = {Cambridge}, + DOI = {10.1017/CBO9780511629235}, +COLLECTION = {London Mathematical Society Lecture Note Series} +} + + @article {LO16, AUTHOR = {Liebeck, Martin W. and O'Brien, E. A.}, TITLE = {Recognition of finite exceptional groups of {L}ie type}, @@ -421,6 +433,19 @@ @article {LO07 NOTE = {https://doi.org/10.1112/jlms/jdm028}, } +@article{L84, + AUTHOR = {Liebeck, Martin W.}, + TITLE = {On minimal degrees and base sizes of primitive permutation groups}, + JOURNAL = {Archiv der Mathematik}, + VOLUME = {43}, + NUMBER = {1}, + PAGES = {11--15}, + YEAR = {1984}, + PUBLISHER = {Springer}, + DOI = {10.1007/BF01193603}, +} + + @article {HLO+08, AUTHOR = {Holmes, P. E. and Linton, S. A. and O'Brien, E. A. and Ryba, A. J. E. and Wilson, R. A.}, diff --git a/gap/SnAnBB.gi b/gap/SnAnBB.gi index 9c63ef047..9faff0f10 100644 --- a/gap/SnAnBB.gi +++ b/gap/SnAnBB.gi @@ -18,100 +18,906 @@ ## The code is based upon the algorithm presented in the paper [BLGN+03]. ## ## -# DeclareInfoClass( "InfoRecSnAn" ); -# SetInfoLevel( InfoRecSnAn, 0 ); -# -# # The following are used for comparisons: -# -# # FIXME: Get rid of these globals. -# # However, it seems to me this whole file is dead code anyway.. -# RecSnAnIsOne := IsOne; -# RecSnAnEq := EQ; -# -# ## is in S_n -# -# SatisfiesSnPresentation := function( n, r, s ) -# -# local j, t; +RECOG.SatisfiesSnPresentation := function(ri, n, r, s) + local j, t; + if not isone(ri)((r * s)^(n-1)) then + return false; + fi; + j := 2; + t := r; + while j <= n/2 do + t := t * r; + if not isone(ri)(Comm(s,t)^2) then + return false; + fi; + j := j + 1; + od; + return true; +end; + +RECOG.SatisfiesAnPresentation := function(ri, s, t, n) + local j, r, ti, tr; + + if not isone(ri)(s^(n-2)) or not isone(ri)(t^3) then + return false; + fi; + + if IsOddInt(n) then + # we already know s^(n-2) = t^3 = 1 + if not isone(ri)((s * t)^n) then + return false; + fi; + tr := t; + for j in [1..(n-3)/2] do + tr := tr ^ s; # equal to t^(s^j) + if not isone(ri)((t * tr)^2) then + return false; + fi; + od; + return true; + else + # we already know s^(n-2) = t^3 = 1 + if not isone(ri)((s * t)^(n-1)) then + return false; + fi; + j := 1; + r := s^0; + ti := t^-1; + while j <= (n-2)/2 do + r := r * s; + if (IsEvenInt(j) and not isone(ri)((t *(t^r))^2)) or + (IsOddInt(j) and not isone(ri)((ti *(t^r))^2)) then + return false; + fi; + j := j + 1; + od; + return true; + fi; +end; + +RECOG.Binary := function( i, m ) + local j, bin, le; + bin := []; + for j in [ 1 .. m ] do + Add( bin, i mod 2 ); + i := QuoInt(i,2); + od; + for j in [m+1 .. 2 * m ] do + bin[j] := 1 - bin[j-m]; + od; + return bin; +end; + +RECOG.ConstructXiSn := function( n, g, h ) + local a, c, xis, xisl, k, m, b, i, j, q, q2, q4, g2, g4, conj, pow; + + k := QuoInt( n, 3 ); + a := h^g * h; # a := (1,2,3); + c := g^3; + q := (g^(-1)*h); + q2 := q^2; + q4 := q2^2; + conj := g^2; + g2 := conj; + g4 := g2^2; + pow := g^(-1); + + # m = Ceil( log_2 (k+1) ) + m := 0; + while 2^m < k+1 do + m := m + 1; + od; + + if (n mod 3) = 0 then + xis := List( [1..2*m+4], i -> h^0 ); + xisl := List( [1..2*m+4], i -> [ ] ); + for i in [ 1 .. k ] do + if ((i mod 2) = 1) and (i < k) then + xis[m+2] := xis[m+2]*a^(conj*pow); + Add(xisl[m+2],[3*i-1..3*i+1]); + xis[m+1] := xis[m+1]*a^((conj*pow)^2); + Add(xisl[m+1],[3*i..3*i+2]); + conj := conj * q; + pow := pow * g; + xis[2*m+4] := xis[2*m+4]*a^((conj*pow)^3); + Add(xisl[2*m+4],[3*i-2,3*i+2,3*i+3]); + conj := conj *q; + pow := pow *g; + xis[2*m+3] := xis[2*m+3]*a^((conj*pow)^3); + Add(xisl[2*m+3],[3*i-2,3*i-1,3*i+3]); + conj := conj * q4; + pow := pow * g4; + fi; + b := RECOG.Binary(i, m); + for j in [1 .. m] do + if b[j] = 1 then + xis[j] := xis[j] * a; + Add(xisl[j],[3*i-2..3*i] ); # al; + fi; + if b[j+m] = 1 then + xis[j+m+2] := xis[j+m+2] * a; + Add(xisl[j+m+2],[3*i-2..3*i] ); # al; + fi; + od; + a := a^c; + od; + else # n mod 3 > 0 + xis := List( [1..2*m+6], i -> h^0 ); + xisl := List( [1..2*m+6], i -> [ ] ); + for i in [ 1 .. k ] do + if ((i mod 2) = 1) and (i < k) then + xis[m+2] := xis[m+2]*a^(conj*pow); + Add(xisl[m+2],[3*i-1..3*i+1]); + xis[m+1] := xis[m+1]*a^((conj*pow)^2); + Add(xisl[m+1],[3*i..3*i+2]); + conj := conj * q; + pow := pow * g; + xis[2*m+5] := xis[2*m+5]*a^((conj*pow)^3); + Add(xisl[2*m+5],[3*i-2,3*i+2,3*i+3]); + conj := conj *q; + pow := pow *g; + xis[2*m+4] := xis[2*m+4]*a^((conj*pow)^3); + Add(xisl[2*m+4],[3*i-2,3*i-1,3*i+3]); + conj := conj * q4; + pow := pow * g4; + fi; + b := RECOG.Binary(i, m); + for j in [1 .. m] do + if b[j] = 1 then + xis[j] := xis[j] * a; + Add(xisl[j],[3*i-2..3*i] ); # al; + fi; + if b[j+m] = 1 then + xis[j+m+3] := xis[j+m+3] * a; + Add(xisl[j+m+3],[3*i-2..3*i] ); # al; + fi; + od; + a := a^c; + od; + if (n mod 3) =1 then + xis[m+3] := a; + xisl[m+3] := [[1,2,n]]; + elif (n mod 3) =2 then + xis[m+3] := a; + xisl[m+3] := [[1,n-1,n]]; + fi; + fi; + + xisl:=List(xisl,z->Union(z)); + + return [xis, xisl]; + +end; + +## Test whether i^z = j +RECOG.IsImagePointSn := function(ri, n, z, g, h, j, t1z, t2z) + local s, k, cnt, gj; + + gj := g^(j-3); + s := []; + s[1] := (h^(h^g))^gj; + s[2] := h^(gj*g); + s[3] := s[2]^g; + s[4] := s[1]^(g^2); + + cnt := 0; + for k in [ 1 .. 4 ] do + if not isequal(ri)(t1z*s[k],s[k]*t1z) then + cnt := cnt + 1; + fi; + od; + if cnt < 3 then return false; fi; + + cnt := 0; + for k in [ 1 .. 4 ] do + if not isequal(ri)(t2z*s[k],s[k]*t2z) then + cnt := cnt + 1; + fi; + od; + if cnt < 3 then return false; fi; + + return true; + +end; + +## Determine the image of z under lambda +RECOG.FindImageSn := function(ri, n, z, g, h, xis, xisl) + local i, j, l, t, tz, k, sup, m, rest, lp1, mxj, mxjpm, zim, OrderSup; + + m := Length(xisl)/2; + t := [h,h^g]; + t[3] := h^(t[2]); + k := g^3; + zim := []; + + # compute images of i, i+1 and i+2 + i := 1; + while i <= n-2 do + tz := List( t, x->x^z ); + sup := [ [1..n], [1..n], [1..n] ]; + for j in [1 .. m] do # loop over xis + l := 1; + mxj := xisl[j]; + mxjpm := xisl[j+m]; + while l <= 3 do # limit support of i+l-1 + lp1 := l mod 3 + 1; + if isequal(ri)(tz[l]*xis[j],xis[j]*tz[l]) then + sup[l] := Difference( sup[l], mxj); + sup[lp1] := Difference( sup[lp1], mxj); + if isequal(ri)(tz[lp1]*xis[j],xis[j]*tz[lp1]) then + sup[lp1 mod 3 + 1] := + Difference( sup[lp1 mod 3 + 1], mxj); + else + sup[lp1 mod 3 + 1] := + Difference( sup[lp1 mod 3 + 1], mxjpm); + fi; + l := 4; # exit loop over l + elif isequal(ri)(tz[l]*xis[j+m],xis[j+m]*tz[l]) then + sup[l] := Difference( sup[l], mxjpm); + sup[lp1] := Difference( sup[lp1], mxjpm); + if isequal(ri)(tz[lp1]*xis[j+m],xis[j+m]*tz[lp1]) then + sup[(lp1) mod 3 + 1] := + Difference( sup[lp1 mod 3 + 1], mxjpm); + else + sup[lp1 mod 3 + 1] := + Difference( sup[lp1 mod 3 + 1], mxj); + fi; + l := 4; # exit loop over l + fi; + l := l + 1; + od; + od; + + # now the images of i,i+1,i+2 should be determined up to 5 points + for l in [ 1 .. 3 ] do + lp1 := l mod 3 + 1; + for j in sup[l] do + if not IsBound(zim[i+l-1]) then + if Length(sup[l]) = 1 then + zim[i+l-1] := sup[l][1]; + elif RECOG.IsImagePointSn(ri,n,z,g,h,j,t[l]^z,t[lp1 mod 3+1]^z) + then zim[i+l-1] := j; + fi; + fi; + od; + od; + + i := i + 3; + t[1] := t[1]^k; + t[2] := t[1]^g; + t[3] := t[1]^t[2]; + + od; # while + + if RemInt(n,3) = 1 then + zim[n] := Difference([1..n],zim)[1]; + fi; + + if RemInt(n,3) = 2 then + sup := Difference([1..n],zim); + if RECOG.IsImagePointSn(ri, n,z,g,h,sup[1],(h^(g^(-1)))^z, + (h^(g^(-2)))^z ) then + zim[n] := sup[1]; + else + zim[n] := sup[2]; + fi; + zim[n-1] := Difference(sup,[zim[n]])[1]; + fi; + + if Length(Set(zim)) <> n then return fail; fi; + + return PermList(zim); +end; + +RECOG.ConstructXiAn := function( n, g, h ) + local a, c, xis, xisl, k, m, b, i, j, cyc5, cyc, cyc10, + a1, b1, a2, b2, aux, a3, b3, anew; + + k := QuoInt( n, 5 ); + # m = Ceil( log_2 (k+1) ) + m := 0; + while 2^m < k+1 do + m := m + 1; + od; + + c := g^5; + + if (n mod 2) = 1 then + if (n mod 5) = 0 then + a := h * (h^g)^(-1) * h^(g^2); # (1,2,3,4,5) + cyc := g*h; # (1,2,3,...,n) + cyc5 := cyc^5; + cyc10 := cyc5^2; + a1 := a^(cyc^2); # (3,4,5,6,7) + b1 := a^c; # (1,2,8,9,10) + anew := a^(cyc^5); # (6,7,8,9,10) + a2 := (b1^h)^anew; # (2,3,9,10,6) + b2 := (a1^h)^anew; # (1,4,5,7,8) + aux := a1^(g^2); # (5,6,7,8,9) + a3 := a1^(aux^2); # (3,4,7,8,9) + b3 := ((a^aux)^(anew^2))^(g^2); # (1,2,5,6,10) + + xis := [a]; + xisl := [ [ [1 .. 5] ] ]; + + for j in [ 2 .. m] do + xis[j] := g^0; + xisl[j] := [ ]; + od; + + xis[m+1] := a1; + xisl[m+1] := [ [3..7] ]; + xis[m+2] := a2; + xisl[m+2] := [ [2,3,6,9,10] ]; + xis[m+3] := a3; + xisl[m+3] := [ [3,4,7,8,9] ]; + xis[m+4] := g^0; + xisl[m+4] := []; + + for j in [m+5 .. 2*m+3 ] do + xis[j] := a; + xisl[j] := [ [1 .. 5] ]; + od; + + xis[2*m+4] := b1; + xisl[2*m+4] := [ [1,2,8,9,10] ]; + xis[2*m+5] := b2; + xisl[2*m+5] := [ [1,4,5,7,8] ]; + xis[2*m+6] := b3; + xisl[2*m+6] := [ [1,2,5,6,10] ]; + + for i in [ 2 .. k ] do + if ((i mod 2) = 1) and (i 0 + a := h * (h^g)^(-1) * h^(g^2); # (1,2,3,4,5) + cyc := g*h; # (1,2,3,...,n) + cyc5 := cyc^5; + cyc10 := cyc5^2; + a1 := a^(cyc^2); # (3,4,5,6,7) + b1 := a^c; # (1,2,8,9,10) + anew := a^(cyc^5); # (6,7,8,9,10) + a2 := (b1^h)^anew; # (2,3,9,10,6) + b2 := (a1^h)^anew; # (1,4,5,7,8) + aux := a1^(g^2); # (5,6,7,8,9) + a3 := a1^(aux^2); # (3,4,7,8,9) + b3 := ((a^aux)^(anew^2))^(g^2); # (1,2,5,6,10) + + xis := [a]; + xisl := [ [ [1 .. 5] ] ]; + + for j in [ 2 .. m] do + xis[j] := g^0; + xisl[j] := [ ]; + od; + + xis[m+1] := a1; + xisl[m+1] := [ [3..7] ]; + xis[m+2] := a2; + xisl[m+2] := [ [2,3,6,9,10] ]; + xis[m+3] := a3; + xisl[m+3] := [ [3,4,7,8,9] ]; + xis[m+5] := g^0; + xisl[m+5] := []; + + for j in [m+6 .. 2*m+4 ] do + xis[j] := a; + xisl[j] := [ [1 .. 5] ]; + od; + + xis[2*m+5] := b1; + xisl[2*m+5] := [ [1,2,8,9,10] ]; + xis[2*m+6] := b2; + xisl[2*m+6] := [ [1,4,5,7,8] ]; + xis[2*m+7] := b3; + xisl[2*m+7] := [ [1,2,5,6,10] ]; + + for i in [ 2 .. k ] do + if ((i mod 2) = 1) and (i 0 + cyc := g*h^2; # (2,3,...,n) + cyc5 := cyc^5; + cyc10 := cyc5^2; + a1 := (a^(cyc^2))^(h^2); # (3,4,5,6,7) + b1 := a^c; # (2,1,8,9,10) + a2 := (b1^h)^anew; # (3,2,9,10,6) + b2 := (a1^h)^anew; # (1,4,5,7,8) + aux := a1^(g^2); # (5,6,7,8,9) + a3 := a1^(aux^2); # (3,4,7,8,9) + b3 := ((a^aux)^(anew^2))^(g^2); # (1,2,5,6,10) + + xis := [a]; + xisl := [ [ [1 .. 5] ] ]; + + for j in [ 2 .. m] do + xis[j] := g^0; + xisl[j] := [ ]; + od; + + xis[m+1] := a1; + xisl[m+1] := [ [3..7] ]; + xis[m+2] := a2; + xisl[m+2] := [ [2,3,6,9,10] ]; + xis[m+3] := a3; + xisl[m+3] := [ [3,4,7,8,9] ]; + xis[m+5] := g^0; + xisl[m+5] := []; + + for j in [m+6 .. 2*m+4 ] do + xis[j] := a; + xisl[j] := [ [1 .. 5] ]; + od; + + xis[2*m+5] := b1; + xisl[2*m+5] := [ [1,2,8,9,10] ]; + xis[2*m+6] := b2; + xisl[2*m+6] := [ [1,4,5,7,8] ]; + xis[2*m+7] := b3; + xisl[2*m+7] := [ [1,2,5,6,10] ]; + + a1 := a1^cyc10; + b1 := ((b1^(cyc^2))^(h^2))^(cyc^8); + a2 := a2^cyc10; + b2 := ((b2^(cyc^2))^(h^2))^(cyc^8); + a3 := a3^cyc10; + b3 := ((b3^(cyc^2))^(h^2))^(cyc^8); + + for i in [ 2 .. k ] do + if ((i mod 2) = 1) and (iUnion(z)); + + return [xis,xisl]; +end; + +# Test whether i^z = j +RECOG.IsImagePointAn := function(ri, n, z, g, h, j, s, a, b, t1z, t2z) + local sc, k, cnt, bj; + + sc := ShallowCopy(s); + + if n mod 2 = 0 and j-1 = 1 then + for k in [ 1 .. 5 ] do sc[k] := sc[k]^a; od; + elif n mod 2 = 0 and j > 1 then + bj := b^(j-2); + for k in [ 1 .. 5 ] do sc[k] := sc[k]^bj; od; + else + bj := b^(j-1); + for k in [ 1 .. 5 ] do sc[k] := sc[k]^bj; od; + fi; + + cnt := 0; + for k in [ 1 .. 5 ] do + if not isequal(ri)(t1z*sc[k],sc[k]*t1z) then + cnt := cnt + 1; + fi; + od; + if cnt < 4 then return false; fi; + + cnt := 0; + for k in [ 1 .. 5 ] do + if not isequal(ri)(t2z*sc[k],sc[k]*t2z) then + cnt := cnt + 1; + fi; + od; + if cnt < 4 then return false; fi; + return true; +end; + +## Determine the image of z under lambda +RECOG.FindImageAn := function(ri, n, z, g, h, xis, xisl) + local i, j, jj, d, dd, t, k, ind, indices, sup, m, rest, lp1, + findp, mxj, mxjpm, zim, l, inds, a, b, c, tim, tc, tdz, s; + + m := Length(xisl)/2; + # list of pairs of 3-cycles intersecting in i is in ith entry + findp := [[1,7], [1,8], [1,5], [2,5], [4,7] ]; + ## Find two 3-cycles which have the other two points in common + ## with the d-th 3-cycle, e.g. + ## if t[d] = (1,2,3) then we want (1,2,4) and (1,2,5) + tc := [[2,4],[1,7],[1,4],[1,3],[3,6],[1,5],[2,5],[2,3],[1,2],[1,5]]; + rest := [ 5*QuoInt(n,5)+1 .. 5*QuoInt(n,5) + RemInt(n,5) ]; + + # first we have to construct 10 elements such that + # their supports are all 3-subsets of {i, .., i+4} + if n mod 2 <> 0 then + b := g * h; # the n-cycle + c := (h^(b^2))*h; # (1,2,3,4,5) + t := []; + for i in [ 0 .. 4 ] do + Add(t,h^(c^i)); + Add(t,(h^(c*h^(-1)))^(c^i)); + od; + a := b^0; + tim := [[1,2,3], [1,2,4], [2,3,4], [2,3,5], [3,4,5], + [1,3,4], [1,4,5], [2,4,5], [1,2,5], [1,3,5] ]; + else + b := g * h; # the (n-1)-cycle without 2 + c := (h^2*((h^2)^(b^2)) * h^2); # (1,2,3,4,5) + t := []; + for i in [ 0 .. 4 ] do + Add(t,h^(c^i)); + Add(t,((h^g)^(-1))^(c^i)); + od; + tim := [[1,2,3], [1,2,4], [2,3,4], [2,3,5], [3,4,5], + [1,3,4], [1,4,5], [2,4,5], [1,2,5], [1,3,5] ]; + a := c * (t[6]^(g^3) * t[6]^(g^5) * t[6]^(g^7))^(h^2); + # (1,2,3,4,5,6,7,8,9,10,11) + fi; + + s := []; + s[1] := h; + s[2] := s[1]^(c^3); + s[3] := s[2]^(g^2); + s[4] := s[3]^(g^2); + s[5] := s[4]^(g^2); + zim := []; + + # compute images of i, .., i+4 + i := 1; + while i <= n-4 do + tdz := List(t, x->x^z); + sup := [ [1..n], [1..n], [1..n], [1..n], [1..n] ]; + for j in [1 .. m] do + d := 1; + mxj := xisl[j]; + mxjpm := xisl[j+m]; + while d <= 10 do + if isequal(ri)(tdz[d]*xis[j],xis[j]*tdz[d]) then + sup[tim[d][1]] := Difference( sup[tim[d][1]], mxj); + sup[tim[d][2]] := Difference( sup[tim[d][2]], mxj); + sup[tim[d][3]] := Difference( sup[tim[d][3]], mxj); + k := tc[d]; + for jj in [ 1 .. 2 ] do + dd := Difference(tim[k[jj]], tim[d])[1]; + if isequal(ri)(tdz[k[jj]]*xis[j],xis[j]*tdz[k[jj]]) then + sup[dd] := Difference( sup[dd], mxj); + else + sup[dd] := Difference( sup[dd], mxjpm); + fi; + od; + d := 11; + elif isequal(ri)(tdz[d]*xis[j+m],xis[j+m]*tdz[d]) then + sup[tim[d][1]] := Difference(sup[tim[d][1]], mxjpm); + sup[tim[d][2]] := Difference(sup[tim[d][2]], mxjpm); + sup[tim[d][3]] := Difference(sup[tim[d][3]], mxjpm); + k := tc[d]; + for jj in [ 1 .. 2 ] do + dd := Difference(tim[k[jj]], tim[d])[1]; + if isequal(ri)(tdz[k[jj]]*xis[j+m],xis[j+m]*tdz[k[jj]]) then + sup[dd] := Difference( sup[dd], mxjpm); + else + sup[dd] := Difference( sup[dd], mxj); + fi; + od; + d := 11; + fi; + d := d + 1; + od; + od; + + # Now determine the images of these 5 points + for l in [ 1 .. 5 ] do + if Length(sup[l]) = 1 + then zim[i+l-1] := sup[l][1]; + else + for j in [1..Length(sup[l])] do + if not IsBound(zim[i+l-1]) then + if RECOG.IsImagePointAn(ri,n,z,g,h,sup[l][j],s,a,b, + t[findp[l][1]]^z, t[findp[l][2]]^z ) then + zim[i+l-1] := sup[l][j]; + fi; + fi; + od; + fi; + od; + + if i = 1 and (n mod 2 = 0) then + t := List( t, j -> j^(a^5)); + else + t := List( t, j -> j^(b^5)); + fi; + + i := i + 5; + od; + + if RemInt(n,5) = 1 then + zim[n] := Difference([1..n],zim)[1]; + elif RemInt(n,5) > 1 then + t := List( t, j -> j^(b^(-5+RemInt(n,5)))); + for k in [ 1 .. RemInt(n,5)-1 ] do + sup := Difference([1..n],zim); + for j in sup do + if not IsBound(zim[n+1-k]) then + if RECOG.IsImagePointAn(ri,n,z,g,h,j,s,a,b, + t[findp[6-k][1]]^z, t[findp[6-k][2]]^z ) then + zim[n+1-k] := j; + sup := Difference(sup,[j]); + fi; + fi; + od; + od; + zim[n+1-RemInt(n,5)] := sup[1]; + fi; + + if Length(Set(zim)) <> n then return fail; fi; + + return PermList(zim); +end; + + +# ###################################################################### +# ## +# #F RecogniseSnAn(, , ) . . . . . . recognition function +# ## +# ## The main function. # -# Info( InfoRecSnAn, 1, "calling Satisfies Sn Presentation"); +# # FIXME: dead code? (it's callers are all dead) +# RecogniseSnAn := function( n, grp, eps ) # -# if not(RecSnAnIsOne((r * s)^(n-1))) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation -1"); -# return false; -# fi; +# local N, gens, le, g, h, slp, gl, b, eval, xis; # -# j := 2; -# t := r; -# while j <= n/2 do -# t := t * r; -# if not RecSnAnIsOne(Comm(s,t)^2) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation"); -# return false; -# fi; -# j := j + 1; +# le := 0; +# while 2^le < eps^-1 do +# le := le + 1; # od; # -# Info( InfoRecSnAn, 1, "satisfies Sn presentation"); -# return true; -# -# end; -# -# -# ## is in A_n -# -# SatisfiesAnPresentation := function( n, s, t ) -# -# local j, r, ti; -# -# Info( InfoRecSnAn, 1, "calling Satisfies An Presentation"); +# #N := Int(24 * (4/3)^3 * le * 6 * n); +# N := 20 * n; # -# if not(RecSnAnIsOne(s^(n-2))) or not(RecSnAnIsOne(t^3)) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation-1"); -# return false; -# fi; +# gens := NiceGeneratorsSnAn( n, grp, N ); +# if gens = fail then return fail; fi; # -# if n mod 2 <> 0 then -# # we already know s^(n-2) = t^3 = 1 -# if not(RecSnAnIsOne((s * t)^n)) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation"); -# return false; -# fi; -# j := 1; -# r := s^0; -# while j <= (n-3)/2 do -# r := r * s; -# if not(RecSnAnIsOne((t *(t^r))^2)) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation"); -# return false; -# fi; -# j := j + 1; +# if gens[3] = "Sn" then +# xis := RECOG.ConstructXiSn( n, gens[1], gens[2] ); +# for g in GeneratorsOfGroup(grp) do +# gl := RECOG.FindImageSn( n, g, gens[1], gens[2], xis[1], xis[2] ); +# if gl = fail then return fail; fi; +# slp := RECOG.SLPforSn( n, gl ); +# eval := ResultOfStraightLineProgram(slp, [gens[2],gens[1]]); +# if not isequal(ri)(eval,g) then return fail; fi; # od; -# return true; +# return [ "Sn", [gens[1],gens[2]], xis ]; # else -# # we already know s^(n-2) = t^3 = 1 -# if not(RecSnAnIsOne((s * t)^(n-1))) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation"); -# return false; -# fi; -# j := 1; -# r := s^0; -# while j <= (n-2)/2 do -# r := r * s; -# ti := t^-1; -# if (IsEvenInt(j) and not(RecSnAnIsOne((t *(t^r))^2))) or -# (IsOddInt(j) and not(RecSnAnIsOne((ti *(t^r))^2))) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation"); -# return false; +# xis := RECOG.ConstructXiAn( n, gens[1], gens[2] ); +# for g in GeneratorsOfGroup(grp) do +# gl := RECOG.FindImageAn( n, g, gens[1], gens[2], xis[1], xis[2] ); +# if gl = fail then return fail; fi; +# if SignPerm(gl) = -1 then +# # we found an odd permutation, +# # so the group cannot be An +# slp := RECOG.SLPforAn( n, (1,2)*gl ); +# eval:=ResultOfStraightLineProgram(slp,[gens[2],gens[1]]); +# h := eval * g^-1; +# if n mod 2 <> 0 then +# b := gens[1] * gens[2]; +# else +# b := h * gens[1] * gens[2]; +# fi; +# if RECOG.SatisfiesSnPresentation( n, b, h ) then +# xis := RECOG.ConstructXiSn( n, b, h ); +# for g in GeneratorsOfGroup(grp) do +# gl := RECOG.FindImageSn(n,g,b,h,xis[1],xis[2] ); +# if gl = fail then return fail; fi; +# slp := RECOG.SLPforSn(n, gl); +# eval := ResultOfStraightLineProgram(slp,[h,b]); +# if not isequal(ri)(eval,g) then return fail; fi; +# od; +# return [ "Sn", [b,h] ,xis ]; +# else +# return fail; +# fi; +# else +# slp := RECOG.SLPforAn( n, gl ); +# eval:=ResultOfStraightLineProgram(slp,[gens[2],gens[1]]); +# if not isequal(ri)(eval,g) then return fail; fi; # fi; -# j := j + 1; # od; -# return true; +# +# return ["An", [gens[1],gens[2]], xis]; # fi; # # end; # -# # NiceGeneratorsSnAn := function ( n, grp, N ) # # local AddStack, g1, g2, g3, g4, g, h, a, b, c, t, i, k, l, @@ -154,8 +960,8 @@ # # use this random element to check the transpositions # for a in g2 do # x := a * a^t; -# if not(RecSnAnIsOne(x)) and not(RecSnAnIsOne(x^2)) and -# not(RecSnAnIsOne(x^3)) then +# if not(isone(ri)(x)) and not(isone(ri)(x^2)) and +# not(isone(ri)(x^3)) then # # a is not a transposition # Info( InfoRecSnAn, 2, "a is not a transposition"); # RemoveElmList(g2,Position(g2,a)); @@ -166,8 +972,8 @@ # # use this random element to check the 3-cycle # for a in g4 do # x := a * a^t; -# if not(RecSnAnIsOne(x)) and not(RecSnAnIsOne(x^2)) and -# not(RecSnAnIsOne(x^3)) and not(RecSnAnIsOne(x^5)) then +# if not(isone(ri)(x)) and not(isone(ri)(x^2)) and +# not(isone(ri)(x^3)) and not(isone(ri)(x^5)) then # # a is not a 3-cycle # Info( InfoRecSnAn, 2, "a is not a 3-cycle"); # RemoveElmList(g4,Position(g4,a)); @@ -175,7 +981,7 @@ # fi; # od; # -# if not(RecSnAnIsOne(t)) and RecSnAnIsOne(t^n) then +# if not(isone(ri)(t)) and isone(ri)(t^n) then # # we hope we found an n-cycle # AddStack(g1,t); # elfound[1] := true; @@ -187,14 +993,14 @@ # fi; # # b := t^(n-2-delta); -# if not(RecSnAnIsOne(b)) and RecSnAnIsOne(b^2) then +# if not(isone(ri)(b)) and isone(ri)(b^2) then # # we hope we found a 2(n-2)-cycle # AddStack(g2,b); # elfound[2] := true; # Info( InfoRecSnAn, 2, "found transposition"); # fi; # -# if delta = 1 and not(RecSnAnIsOne(t)) and RecSnAnIsOne(t^(n-1)) then +# if delta = 1 and not(isone(ri)(t)) and isone(ri)(t^(n-1)) then # # we hope we found an n or (n-1)-cycle # AddStack(g3,t); # elfound[3] := true; @@ -202,7 +1008,7 @@ # fi; # # b := t^(n-k); -# if not(RecSnAnIsOne(b)) and RecSnAnIsOne(b^3) then +# if not(isone(ri)(b)) and isone(ri)(b^3) then # # we hope we found a 3(n-k)-element # AddStack(g4,b); # elfound[4] := true; @@ -221,8 +1027,8 @@ # # use this opportunity again to check that # # a really is a transposition # x := a*h; -# if not(RecSnAnIsOne(x)) and not(RecSnAnIsOne(x^2)) and -# not(RecSnAnIsOne(x^3)) then +# if not(isone(ri)(x)) and not(isone(ri)(x^2)) and +# not(isone(ri)(x^3)) then # # a is not a transposition # Info(InfoRecSnAn,2,"a is not a transposition"); # RemoveElmList(g2,Position(g2,a)); @@ -231,10 +1037,10 @@ # else # for b in g1 do # y := Comm(h, h^b); -# if not(RecSnAnIsOne(y)) and -# not(RecSnAnIsOne(y^2)) and RecSnAnIsOne(y^3) then +# if not(isone(ri)(y)) and +# not(isone(ri)(y^2)) and isone(ri)(y^3) then # Info(InfoRecSnAn,1,"found good transposition"); -# if SatisfiesSnPresentation( n, b, h ) then +# if RECOG.SatisfiesSnPresentation( n, b, h ) then # Info( InfoRecSnAn, 1, # "Group satisfies presentation for Sn ",N); # return [ b, h, "Sn" ]; @@ -259,8 +1065,8 @@ # # use this opportunity again to check that # # a really is a 3-cycle # x := a * c; -# if not(RecSnAnIsOne(x)) and not(RecSnAnIsOne(x^2)) and -# not(RecSnAnIsOne(x^3)) and not(RecSnAnIsOne(x^5)) then +# if not(isone(ri)(x)) and not(isone(ri)(x^2)) and +# not(isone(ri)(x^3)) and not(isone(ri)(x^5)) then # # a is not a 3-cycle # Info( InfoRecSnAn, 2, "a is not a 3-cycle"); # RemoveElmList(g4,Position(g4,a)); @@ -268,25 +1074,25 @@ # i := 0; # else # for b in g3 do # choose an n- or (n-1)-cycle -# if not(RecSnAnIsOne(Comm(c,c^b))) then +# if not(isone(ri)(Comm(c,c^b))) then # # hope: supp (c) = {1,2,k} # t := c*c^b; -# if RecSnAnEq(t^2,t) then +# if isequal(ri)(t^2,t) then # # k = 3 # x := c^(b^2); # y := c^x; -# if RecSnAnIsOne(Comm(y, y^(b^2))) then +# if isone(ri)(Comm(y, y^(b^2))) then # # y\lambda = (1,5,2) # h := c^2; # else # # y\lambda = (1,2,4) # h := c; # fi; -# elif RecSnAnIsOne(Comm(c, c^(b^2))) then +# elif isone(ri)(Comm(c, c^(b^2))) then # # 5 <= k <= n -2 # x := c^b; # y := c^x; -# if RecSnAnIsOne(Comm(y,y^b)) then +# if isone(ri)(Comm(y,y^b)) then # # y = (1,3,k) hence c = (1,2,k) # h := Comm(c^2, x); # else @@ -296,13 +1102,13 @@ # # k= 4, n-1 # x := c^b; # y := c^x; -# if RecSnAnIsOne(Comm(y,y^b)) then +# if isone(ri)(Comm(y,y^b)) then # # y = (n-1, 1, 3), c = (1,2,n-1) # h := Comm(c^2,x); -# elif RecSnAnIsOne(Comm(y,y^(b^2))) then +# elif isone(ri)(Comm(y,y^(b^2))) then # # y = (1,4,5) c = (1,4,2) # h := Comm(c,x^2); -# elif RecSnAnIsOne((y*y^b)^2) then +# elif isone(ri)((y*y^b)^2) then # # y = (1, n-1, n) c = (1, n-1, 2) # h := Comm(c,x^2); # else @@ -313,7 +1119,7 @@ # # g := b * h^2; # -# if SatisfiesAnPresentation( n, g, h ) then +# if RECOG.SatisfiesAnPresentation( n, g, h ) then # Info( InfoRecSnAn, 1, # "Group satisfies presentation for An ",N); # return [ g, h, "An" ]; @@ -338,8 +1144,8 @@ # # use this opportunity again to check that # # a really is a 3-cycle # x := a * c; -# if not(RecSnAnIsOne(x)) and not(RecSnAnIsOne(x^2)) and -# not(RecSnAnIsOne(x^3)) and not(RecSnAnIsOne(x^5)) then +# if not(isone(ri)(x)) and not(isone(ri)(x^2)) and +# not(isone(ri)(x^3)) and not(isone(ri)(x^5)) then # # a is not a 3-cycle # Info( InfoRecSnAn, 2, "a is not a 3-cycle"); # RemoveElmList(g4,Position(g4,a)); @@ -347,14 +1153,14 @@ # i := 0; # else # for b in g3 do -# if not(RecSnAnIsOne(Comm(c,c^b))) and -# not(RecSnAnIsOne(Comm(c,c^(b^2)))) and -# not(RecSnAnIsOne(Comm(c,c^(b^4)))) then +# if not(isone(ri)(Comm(c,c^b))) and +# not(isone(ri)(Comm(c,c^(b^2)))) and +# not(isone(ri)(Comm(c,c^(b^4)))) then # # hope: supp (c) = {1,i,j} # h := Comm(c^b,c); # # h = (1,i,i+1) # g := b * h; -# if SatisfiesAnPresentation( n, g, h ) then +# if RECOG.SatisfiesAnPresentation( n, g, h ) then # Info( InfoRecSnAn, 1, # "Group satisfies presentation for An ", N); # return [ g, h, "An" ]; @@ -374,1071 +1180,3 @@ # return fail; # # end; -# -# -# Binary := function( i, m ) -# local j, bin, le; -# bin := []; -# for j in [ 1 .. m ] do -# Add( bin, i mod 2 ); -# i := QuoInt(i,2); -# od; -# for j in [m+1 .. 2 * m ] do -# bin[j] := 1 - bin[j-m]; -# od; -# return bin; -# end; -# -# -# ConstructXiSn := function( n, g, h ) -# -# local a, c, xis, xisl, k, m, b, i, j, q, q2, q4, g2, g4, conj, pow; -# -# k := QuoInt( n, 3 ); -# a := h^g * h; # a := (1,2,3); -# c := g^3; -# q := (g^(-1)*h); -# q2 := q^2; -# q4 := q2^2; -# conj := g^2; -# g2 := conj; -# g4 := g2^2; -# pow := g^(-1); -# -# # m = Ceil( log_2 (k+1) ) -# m := 0; -# while 2^m < k+1 do -# m := m + 1; -# od; -# -# if (n mod 3) = 0 then -# xis := List( [1..2*m+4], i -> h^0 ); -# xisl := List( [1..2*m+4], i -> [ ] ); -# for i in [ 1 .. k ] do -# if ((i mod 2) = 1) and (i < k) then -# xis[m+2] := xis[m+2]*a^(conj*pow); -# Add(xisl[m+2],[3*i-1..3*i+1]); -# xis[m+1] := xis[m+1]*a^((conj*pow)^2); -# Add(xisl[m+1],[3*i..3*i+2]); -# conj := conj * q; -# pow := pow * g; -# xis[2*m+4] := xis[2*m+4]*a^((conj*pow)^3); -# Add(xisl[2*m+4],[3*i-2,3*i+2,3*i+3]); -# conj := conj *q; -# pow := pow *g; -# xis[2*m+3] := xis[2*m+3]*a^((conj*pow)^3); -# Add(xisl[2*m+3],[3*i-2,3*i-1,3*i+3]); -# conj := conj * q4; -# pow := pow * g4; -# fi; -# b := Binary(i, m); -# for j in [1 .. m] do -# if b[j] = 1 then -# xis[j] := xis[j] * a; -# Add(xisl[j],[3*i-2..3*i] ); # al; -# fi; -# if b[j+m] = 1 then -# xis[j+m+2] := xis[j+m+2] * a; -# Add(xisl[j+m+2],[3*i-2..3*i] ); # al; -# fi; -# od; -# a := a^c; -# od; -# else # n mod 3 > 0 -# xis := List( [1..2*m+6], i -> h^0 ); -# xisl := List( [1..2*m+6], i -> [ ] ); -# for i in [ 1 .. k ] do -# if ((i mod 2) = 1) and (i < k) then -# xis[m+2] := xis[m+2]*a^(conj*pow); -# Add(xisl[m+2],[3*i-1..3*i+1]); -# xis[m+1] := xis[m+1]*a^((conj*pow)^2); -# Add(xisl[m+1],[3*i..3*i+2]); -# conj := conj * q; -# pow := pow * g; -# xis[2*m+5] := xis[2*m+5]*a^((conj*pow)^3); -# Add(xisl[2*m+5],[3*i-2,3*i+2,3*i+3]); -# conj := conj *q; -# pow := pow *g; -# xis[2*m+4] := xis[2*m+4]*a^((conj*pow)^3); -# Add(xisl[2*m+4],[3*i-2,3*i-1,3*i+3]); -# conj := conj * q4; -# pow := pow * g4; -# fi; -# b := Binary(i, m); -# for j in [1 .. m] do -# if b[j] = 1 then -# xis[j] := xis[j] * a; -# Add(xisl[j],[3*i-2..3*i] ); # al; -# fi; -# if b[j+m] = 1 then -# xis[j+m+3] := xis[j+m+3] * a; -# Add(xisl[j+m+3],[3*i-2..3*i] ); # al; -# fi; -# od; -# a := a^c; -# od; -# if (n mod 3) =1 then -# xis[m+3] := a; -# xisl[m+3] := [[1,2,n]]; -# elif (n mod 3) =2 then -# xis[m+3] := a; -# xisl[m+3] := [[1,n-1,n]]; -# fi; -# fi; -# -# xisl:=List(xisl,z->Union(z)); -# -# return [xis, xisl]; -# -# end; -# -# -# ## Test whether i^z = j -# -# IsImagePoint := function ( n, z, g, h, j, t1z, t2z ) -# -# local s, k, cnt, gj; -# -# gj := g^(j-3); -# s := []; -# s[1] := (h^(h^g))^gj; -# s[2] := h^(gj*g); -# s[3] := s[2]^g; -# s[4] := s[1]^(g^2); -# -# cnt := 0; -# for k in [ 1 .. 4 ] do -# if not RecSnAnEq(t1z*s[k],s[k]*t1z) then -# cnt := cnt + 1; -# fi; -# od; -# if cnt < 3 then return false; fi; -# -# cnt := 0; -# for k in [ 1 .. 4 ] do -# if not RecSnAnEq(t2z*s[k],s[k]*t2z) then -# cnt := cnt + 1; -# fi; -# od; -# if cnt < 3 then return false; fi; -# -# return true; -# -# end; -# -# -# ## Determine the image of z under lambda -# -# # FIXME: dead code? (it's callers are all dead) -# FindImageSn := function( n, z, g, h, xis, xisl ) -# -# local i, j, l, t, tz, k, sup, m, rest, lp1, mxj, mxjpm, zim, OrderSup; -# -# m := Length(xisl)/2; -# t := [h,h^g]; -# t[3] := h^(t[2]); -# k := g^3; -# zim := []; -# -# # compute images of i, i+1 and i+2 -# i := 1; -# while i <= n-2 do -# tz := List( t, x->x^z ); -# sup := [ [1..n], [1..n], [1..n] ]; -# for j in [1 .. m] do # loop over xis -# l := 1; -# mxj := xisl[j]; -# mxjpm := xisl[j+m]; -# while l <= 3 do # limit support of i+l-1 -# lp1 := l mod 3 + 1; -# if RecSnAnEq(tz[l]*xis[j],xis[j]*tz[l]) then -# sup[l] := Difference( sup[l], mxj); -# sup[lp1] := Difference( sup[lp1], mxj); -# if RecSnAnEq(tz[lp1]*xis[j],xis[j]*tz[lp1]) then -# sup[lp1 mod 3 + 1] := -# Difference( sup[lp1 mod 3 + 1], mxj); -# else -# sup[lp1 mod 3 + 1] := -# Difference( sup[lp1 mod 3 + 1], mxjpm); -# fi; -# l := 4; # exit loop over l -# elif RecSnAnEq(tz[l]*xis[j+m],xis[j+m]*tz[l]) then -# sup[l] := Difference( sup[l], mxjpm); -# sup[lp1] := Difference( sup[lp1], mxjpm); -# if RecSnAnEq(tz[lp1]*xis[j+m],xis[j+m]*tz[lp1]) then -# sup[(lp1) mod 3 + 1] := -# Difference( sup[lp1 mod 3 + 1], mxjpm); -# else -# sup[lp1 mod 3 + 1] := -# Difference( sup[lp1 mod 3 + 1], mxj); -# fi; -# l := 4; # exit loop over l -# fi; -# l := l + 1; -# od; -# od; -# -# # now the images of i,i+1,i+2 should be determined up to 5 points -# for l in [ 1 .. 3 ] do -# lp1 := l mod 3 + 1; -# for j in sup[l] do -# if not IsBound(zim[i+l-1]) then -# if Length(sup[l]) = 1 then -# zim[i+l-1] := sup[l][1]; -# elif IsImagePoint(n,z,g,h,j,t[l]^z,t[lp1 mod 3+1]^z) -# then zim[i+l-1] := j; -# fi; -# fi; -# od; -# od; -# -# i := i + 3; -# t[1] := t[1]^k; -# t[2] := t[1]^g; -# t[3] := t[1]^t[2]; -# -# od; # while -# -# if RemInt(n,3) = 1 then -# zim[n] := Difference([1..n],zim)[1]; -# fi; -# -# if RemInt(n,3) = 2 then -# sup := Difference([1..n],zim); -# if IsImagePoint(n,z,g,h,sup[1],(h^(g^(-1)))^z, -# (h^(g^(-2)))^z ) then -# zim[n] := sup[1]; -# else -# zim[n] := sup[2]; -# fi; -# zim[n-1] := Difference(sup,[zim[n]])[1]; -# fi; -# -# if Length(Set(zim)) <> n then return fail; fi; -# -# return PermList(zim); -# -# end; -# -# -# ConstructXiAn := function( n, g, h ) -# -# local a, c, xis, xisl, k, m, b, i, j, cyc5, cyc, cyc10, -# a1, b1, a2, b2, aux, a3, b3, anew; -# -# k := QuoInt( n, 5 ); -# # m = Ceil( log_2 (k+1) ) -# m := 0; -# while 2^m < k+1 do -# m := m + 1; -# od; -# -# c := g^5; -# -# if (n mod 2) = 1 then -# if (n mod 5) = 0 then -# a := h * (h^g)^(-1) * h^(g^2); # (1,2,3,4,5) -# cyc := g*h; # (1,2,3,...,n) -# cyc5 := cyc^5; -# cyc10 := cyc5^2; -# a1 := a^(cyc^2); # (3,4,5,6,7) -# b1 := a^c; # (1,2,8,9,10) -# anew := a^(cyc^5); # (6,7,8,9,10) -# a2 := (b1^h)^anew; # (2,3,9,10,6) -# b2 := (a1^h)^anew; # (1,4,5,7,8) -# aux := a1^(g^2); # (5,6,7,8,9) -# a3 := a1^(aux^2); # (3,4,7,8,9) -# b3 := ((a^aux)^(anew^2))^(g^2); # (1,2,5,6,10) -# -# xis := [a]; -# xisl := [ [ [1 .. 5] ] ]; -# -# for j in [ 2 .. m] do -# xis[j] := g^0; -# xisl[j] := [ ]; -# od; -# -# xis[m+1] := a1; -# xisl[m+1] := [ [3..7] ]; -# xis[m+2] := a2; -# xisl[m+2] := [ [2,3,6,9,10] ]; -# xis[m+3] := a3; -# xisl[m+3] := [ [3,4,7,8,9] ]; -# xis[m+4] := g^0; -# xisl[m+4] := []; -# -# for j in [m+5 .. 2*m+3 ] do -# xis[j] := a; -# xisl[j] := [ [1 .. 5] ]; -# od; -# -# xis[2*m+4] := b1; -# xisl[2*m+4] := [ [1,2,8,9,10] ]; -# xis[2*m+5] := b2; -# xisl[2*m+5] := [ [1,4,5,7,8] ]; -# xis[2*m+6] := b3; -# xisl[2*m+6] := [ [1,2,5,6,10] ]; -# -# for i in [ 2 .. k ] do -# if ((i mod 2) = 1) and (i 0 -# a := h * (h^g)^(-1) * h^(g^2); # (1,2,3,4,5) -# cyc := g*h; # (1,2,3,...,n) -# cyc5 := cyc^5; -# cyc10 := cyc5^2; -# a1 := a^(cyc^2); # (3,4,5,6,7) -# b1 := a^c; # (1,2,8,9,10) -# anew := a^(cyc^5); # (6,7,8,9,10) -# a2 := (b1^h)^anew; # (2,3,9,10,6) -# b2 := (a1^h)^anew; # (1,4,5,7,8) -# aux := a1^(g^2); # (5,6,7,8,9) -# a3 := a1^(aux^2); # (3,4,7,8,9) -# b3 := ((a^aux)^(anew^2))^(g^2); # (1,2,5,6,10) -# -# xis := [a]; -# xisl := [ [ [1 .. 5] ] ]; -# -# for j in [ 2 .. m] do -# xis[j] := g^0; -# xisl[j] := [ ]; -# od; -# -# xis[m+1] := a1; -# xisl[m+1] := [ [3..7] ]; -# xis[m+2] := a2; -# xisl[m+2] := [ [2,3,6,9,10] ]; -# xis[m+3] := a3; -# xisl[m+3] := [ [3,4,7,8,9] ]; -# xis[m+5] := g^0; -# xisl[m+5] := []; -# -# for j in [m+6 .. 2*m+4 ] do -# xis[j] := a; -# xisl[j] := [ [1 .. 5] ]; -# od; -# -# xis[2*m+5] := b1; -# xisl[2*m+5] := [ [1,2,8,9,10] ]; -# xis[2*m+6] := b2; -# xisl[2*m+6] := [ [1,4,5,7,8] ]; -# xis[2*m+7] := b3; -# xisl[2*m+7] := [ [1,2,5,6,10] ]; -# -# for i in [ 2 .. k ] do -# if ((i mod 2) = 1) and (i 0 -# cyc := g*h^2; # (2,3,...,n) -# cyc5 := cyc^5; -# cyc10 := cyc5^2; -# a1 := (a^(cyc^2))^(h^2); # (3,4,5,6,7) -# b1 := a^c; # (2,1,8,9,10) -# a2 := (b1^h)^anew; # (3,2,9,10,6) -# b2 := (a1^h)^anew; # (1,4,5,7,8) -# aux := a1^(g^2); # (5,6,7,8,9) -# a3 := a1^(aux^2); # (3,4,7,8,9) -# b3 := ((a^aux)^(anew^2))^(g^2); # (1,2,5,6,10) -# -# xis := [a]; -# xisl := [ [ [1 .. 5] ] ]; -# -# for j in [ 2 .. m] do -# xis[j] := g^0; -# xisl[j] := [ ]; -# od; -# -# xis[m+1] := a1; -# xisl[m+1] := [ [3..7] ]; -# xis[m+2] := a2; -# xisl[m+2] := [ [2,3,6,9,10] ]; -# xis[m+3] := a3; -# xisl[m+3] := [ [3,4,7,8,9] ]; -# xis[m+5] := g^0; -# xisl[m+5] := []; -# -# for j in [m+6 .. 2*m+4 ] do -# xis[j] := a; -# xisl[j] := [ [1 .. 5] ]; -# od; -# -# xis[2*m+5] := b1; -# xisl[2*m+5] := [ [1,2,8,9,10] ]; -# xis[2*m+6] := b2; -# xisl[2*m+6] := [ [1,4,5,7,8] ]; -# xis[2*m+7] := b3; -# xisl[2*m+7] := [ [1,2,5,6,10] ]; -# -# a1 := a1^cyc10; -# b1 := ((b1^(cyc^2))^(h^2))^(cyc^8); -# a2 := a2^cyc10; -# b2 := ((b2^(cyc^2))^(h^2))^(cyc^8); -# a3 := a3^cyc10; -# b3 := ((b3^(cyc^2))^(h^2))^(cyc^8); -# -# for i in [ 2 .. k ] do -# if ((i mod 2) = 1) and (iUnion(z)); -# -# return [xis,xisl]; -# -# end; -# -# -# # Test whether i^z = j -# -# IsImagePointAn := function ( n, z, g, h, j, s, a, b, t1z, t2z ) -# -# local sc, k, cnt, bj; -# -# sc := ShallowCopy(s); -# -# if n mod 2 = 0 and j-1 = 1 then -# for k in [ 1 .. 5 ] do sc[k] := sc[k]^a; od; -# elif n mod 2 = 0 and j > 1 then -# bj := b^(j-2); -# for k in [ 1 .. 5 ] do sc[k] := sc[k]^bj; od; -# else -# bj := b^(j-1); -# for k in [ 1 .. 5 ] do sc[k] := sc[k]^bj; od; -# fi; -# -# cnt := 0; -# for k in [ 1 .. 5 ] do -# if not RecSnAnEq(t1z*sc[k],sc[k]*t1z) then -# cnt := cnt + 1; -# fi; -# od; -# if cnt < 4 then return false; fi; -# -# cnt := 0; -# for k in [ 1 .. 5 ] do -# if not RecSnAnEq(t2z*sc[k],sc[k]*t2z) then -# cnt := cnt + 1; -# fi; -# od; -# if cnt < 4 then return false; fi; -# -# return true; -# -# end; -# -# -# ## Determine the image of z under lambda -# -# FindImageAn := function( n, z, g, h, xis, xisl ) -# -# local i, j, jj, d, dd, t, k, ind, indices, sup, m, rest, lp1, -# findp, mxj, mxjpm, zim, l, inds, a, b, c, tim, tc, tdz, s; -# -# m := Length(xisl)/2; -# # list of pairs of 3-cycles intersecting in i is in ith entry -# findp := [[1,7], [1,8], [1,5], [2,5], [4,7] ]; -# ## Find two 3-cycles which have the other two points in common -# ## with the d-th 3-cycle, e.g. -# ## if t[d] = (1,2,3) then we want (1,2,4) and (1,2,5) -# tc := [[2,4],[1,7],[1,4],[1,3],[3,6],[1,5],[2,5],[2,3],[1,2],[1,5]]; -# rest := [ 5*QuoInt(n,5)+1 .. 5*QuoInt(n,5) + RemInt(n,5) ]; -# -# # first we have to construct 10 elements such that -# # their supports are all 3-subsets of {i, .., i+4} -# if n mod 2 <> 0 then -# b := g * h; # the n-cycle -# c := (h^(b^2))*h; # (1,2,3,4,5) -# t := []; -# for i in [ 0 .. 4 ] do -# Add(t,h^(c^i)); -# Add(t,(h^(c*h^(-1)))^(c^i)); -# od; -# a := b^0; -# tim := [[1,2,3], [1,2,4], [2,3,4], [2,3,5], [3,4,5], -# [1,3,4], [1,4,5], [2,4,5], [1,2,5], [1,3,5] ]; -# else -# b := g * h; # the (n-1)-cycle without 2 -# c := (h^2*((h^2)^(b^2)) * h^2); # (1,2,3,4,5) -# t := []; -# for i in [ 0 .. 4 ] do -# Add(t,h^(c^i)); -# Add(t,((h^g)^(-1))^(c^i)); -# od; -# tim := [[1,2,3], [1,2,4], [2,3,4], [2,3,5], [3,4,5], -# [1,3,4], [1,4,5], [2,4,5], [1,2,5], [1,3,5] ]; -# a := c * (t[6]^(g^3) * t[6]^(g^5) * t[6]^(g^7))^(h^2); -# # (1,2,3,4,5,6,7,8,9,10,11) -# fi; -# -# s := []; -# s[1] := h; -# s[2] := s[1]^(c^3); -# s[3] := s[2]^(g^2); -# s[4] := s[3]^(g^2); -# s[5] := s[4]^(g^2); -# zim := []; -# -# # compute images of i, .., i+4 -# i := 1; -# while i <= n-4 do -# tdz := List(t, x->x^z); -# sup := [ [1..n], [1..n], [1..n], [1..n], [1..n] ]; -# for j in [1 .. m] do -# d := 1; -# mxj := xisl[j]; -# mxjpm := xisl[j+m]; -# while d <= 10 do -# if RecSnAnEq(tdz[d]*xis[j],xis[j]*tdz[d]) then -# sup[tim[d][1]] := Difference( sup[tim[d][1]], mxj); -# sup[tim[d][2]] := Difference( sup[tim[d][2]], mxj); -# sup[tim[d][3]] := Difference( sup[tim[d][3]], mxj); -# k := tc[d]; -# for jj in [ 1 .. 2 ] do -# dd := Difference(tim[k[jj]], tim[d])[1]; -# if RecSnAnEq(tdz[k[jj]]*xis[j],xis[j]*tdz[k[jj]]) then -# sup[dd] := Difference( sup[dd], mxj); -# else -# sup[dd] := Difference( sup[dd], mxjpm); -# fi; -# od; -# d := 11; -# elif RecSnAnEq(tdz[d]*xis[j+m],xis[j+m]*tdz[d]) then -# sup[tim[d][1]] := Difference(sup[tim[d][1]], mxjpm); -# sup[tim[d][2]] := Difference(sup[tim[d][2]], mxjpm); -# sup[tim[d][3]] := Difference(sup[tim[d][3]], mxjpm); -# k := tc[d]; -# for jj in [ 1 .. 2 ] do -# dd := Difference(tim[k[jj]], tim[d])[1]; -# if RecSnAnEq(tdz[k[jj]]*xis[j+m],xis[j+m]*tdz[k[jj]]) then -# sup[dd] := Difference( sup[dd], mxjpm); -# else -# sup[dd] := Difference( sup[dd], mxj); -# fi; -# od; -# d := 11; -# fi; -# d := d + 1; -# od; -# od; -# -# # Now determine the images of these 5 points -# for l in [ 1 .. 5 ] do -# if Length(sup[l]) = 1 -# then zim[i+l-1] := sup[l][1]; -# else -# for j in [1..Length(sup[l])] do -# if not IsBound(zim[i+l-1]) then -# if IsImagePointAn(n,z,g,h,sup[l][j],s,a,b, -# t[findp[l][1]]^z, t[findp[l][2]]^z ) then -# zim[i+l-1] := sup[l][j]; -# fi; -# fi; -# od; -# fi; -# od; -# -# if i = 1 and (n mod 2 = 0) then -# t := List( t, j -> j^(a^5)); -# else -# t := List( t, j -> j^(b^5)); -# fi; -# -# i := i + 5; -# od; -# -# if RemInt(n,5) = 1 then -# zim[n] := Difference([1..n],zim)[1]; -# elif RemInt(n,5) > 1 then -# t := List( t, j -> j^(b^(-5+RemInt(n,5)))); -# for k in [ 1 .. RemInt(n,5)-1 ] do -# sup := Difference([1..n],zim); -# for j in sup do -# if not IsBound(zim[n+1-k]) then -# if IsImagePointAn(n,z,g,h,j,s,a,b, -# t[findp[6-k][1]]^z, t[findp[6-k][2]]^z ) then -# zim[n+1-k] := j; -# sup := Difference(sup,[j]); -# fi; -# fi; -# od; -# od; -# zim[n+1-RemInt(n,5)] := sup[1]; -# fi; -# -# if Length(Set(zim)) <> n then return fail; fi; -# -# return PermList(zim); -# -# end; -# -# -# ## SLP for pi from (1,2), (1,...,n) -# -# # FIXME: dead code? (it's callers are all dead) -# # FIXME: duplicate of RECOG.SLPforSn in giant.gi -# SLPforSn := function( n, pi ) -# -# local cycles, initpts, c, newc, i, R, ci, cycslp, k ; -# -# if IsOne(pi) then -# return StraightLineProgram([[1,0]],2); -# 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 -# -# # FIXME: dead code? (it's callers are all dead) -# # FIXME: duplicate of RECOG.SLPforAn in giant.gi -# SLPforAn := function( n, pi ) -# -# local cycles, initpts, c, newc, R, i, nexttrpn, ci, cycslp, k, j, -# nexttau, nextsigma ; -# -# if IsOne(pi) then -# return StraightLineProgram([[1,0]],2); -# 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 -# Append( cycslp, -# [ 3,i+2-n, 2,2, 3,1, 2,1, 3,n-i-3 ] ); -# 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 -# Append( cycslp, -# [ 3,i+3-n, 2,2, 3,-1, 2,1, 3,n-i-2 ] ); -# 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; -# -# -# ###################################################################### -# ## -# #F RecogniseSnAn(, , ) . . . . . . recognition function -# ## -# ## The main function. -# -# # FIXME: dead code? (it's callers are all dead) -# RecogniseSnAn := function( n, grp, eps ) -# -# local N, gens, le, g, h, slp, gl, b, eval, xis; -# -# le := 0; -# while 2^le < eps^-1 do -# le := le + 1; -# od; -# -# #N := Int(24 * (4/3)^3 * le * 6 * n); -# N := 20 * n; -# -# gens := NiceGeneratorsSnAn( n, grp, N ); -# if gens = fail then return fail; fi; -# -# if gens[3] = "Sn" then -# xis := ConstructXiSn( n, gens[1], gens[2] ); -# for g in GeneratorsOfGroup(grp) do -# gl := FindImageSn( n, g, gens[1], gens[2], xis[1], xis[2] ); -# if gl = fail then return fail; fi; -# slp := SLPforSn( n, gl ); -# eval := ResultOfStraightLineProgram(slp, [gens[2],gens[1]]); -# if not RecSnAnEq(eval,g) then return fail; fi; -# od; -# return [ "Sn", [gens[1],gens[2]], xis ]; -# else -# xis := ConstructXiAn( n, gens[1], gens[2] ); -# for g in GeneratorsOfGroup(grp) do -# gl := FindImageAn( n, g, gens[1], gens[2], xis[1], xis[2] ); -# if gl = fail then return fail; fi; -# if SignPerm(gl) = -1 then -# # we found an odd permutation, -# # so the group cannot be An -# slp := SLPforAn( n, (1,2)*gl ); -# eval:=ResultOfStraightLineProgram(slp,[gens[2],gens[1]]); -# h := eval * g^-1; -# if n mod 2 <> 0 then -# b := gens[1] * gens[2]; -# else -# b := h * gens[1] * gens[2]; -# fi; -# if SatisfiesSnPresentation( n, b, h ) then -# xis := ConstructXiSn( n, b, h ); -# for g in GeneratorsOfGroup(grp) do -# gl := FindImageSn(n,g,b,h,xis[1],xis[2] ); -# if gl = fail then return fail; fi; -# slp := SLPforSn(n, gl); -# eval := ResultOfStraightLineProgram(slp,[h,b]); -# if not RecSnAnEq(eval,g) then return fail; fi; -# od; -# return [ "Sn", [b,h] ,xis ]; -# else -# return fail; -# fi; -# else -# slp := SLPforAn( n, gl ); -# eval:=ResultOfStraightLineProgram(slp,[gens[2],gens[1]]); -# if not RecSnAnEq(eval,g) then return fail; fi; -# fi; -# od; -# -# return ["An", [gens[1],gens[2]], xis]; -# fi; -# -# end; diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi new file mode 100644 index 000000000..4d026f750 --- /dev/null +++ b/gap/generic/SnAnUnknownDegree.gi @@ -0,0 +1,877 @@ +############################################################################# +## +## 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 Friedrich Rober and Sergio Siccha. +## +## 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 +## is isomorphic to an alternating or symmetric group. It implements +## . +## +############################################################################# +# +# eps : real number, the error bound +# N : integer, upper bound for the degree of G +# +# Returns a record of constants used in ThreeCyclesCanditatesIterator. +RECOG.ThreeCycleCandidatesConstants := function(eps, N) + local M, p; + # Constants + M := 1; + RECOG.CachePrimesUpTo(N); + for p in RECOG.PrimesCache do + if p = 2 then continue; fi; + if p > N then break; fi; + M := M * p ^ LogInt(N, p); + od; + return rec( + M := M, + B := Int(Ceil(13 * Log(Float(N)) * Log(3 / Float(eps)))), + T := Int(Ceil(3 * Log(3 / Float(eps)))), + C := Int(Ceil(Float(3 * N * ~.T / 5))), + logInt2N := LogInt(N, 2) + ); +end; + +# ri : recog info record with group G +# constants : a record with components M, B, T, C, and logInt2N +# +# The following algorithm constructs a set of possible 3-cycles. It is based +# on the simple observation that the product of two involutions t1, t2, which +# only move one common point, squares to a 3-cycle. +# +# Creates and returns a function, here called oneThreeCycleCandidate. The +# function oneThreeCycleCandidate returns one of the following: +# - a three cycle candidate, i.e. an element of G +# - TemporaryFailure, if we exhausted all attempts +# - NeverApplicable, if we found out that G can't be an Sn or An +# +# Lower Bounds need n >= 9. +RECOG.ThreeCycleCandidatesIterator := function(ri, constants) + local + # involution + t, + # integers, controlling the number of iterations + M, B, T, C, logInt2N, + # counters + nrInvolutions, nrTriedConjugates, nrThreeCycleCandidates, + # helper functions + tryThreeCycleCandidate, oneThreeCycleCandidate; + # Step 1: Initialization + # The current involution t_i + t := fail; + + M := constants.M; + B := constants.B; + T := constants.T; + C := constants.C; + logInt2N := constants.logInt2N; + + # Counters + # Counts the constructed involutions t_i in steps 2 & 3. + nrInvolutions := 0; + # Counts the elements c in step 4 that we use to conjugate the current + # involution t_i. We initialize nrTriedConjugates to C such that "steps 2 + # & 3" in tryThreeCycleCandidate immediately construct an involution. + nrTriedConjugates := C; + # counts the size of the set Gamma_i in step 4 for the current involution + # t_i + nrThreeCycleCandidates := 0; + + # Helper functions + # tryThreeCycleCandidate returns one of the following: + # - a three cycle candidate, i.e. an element of G + # - fail, if the random conjugate c from step 4 and t commute. Then we have + # to call tryThreeCycleCandidate again + # - NeverApplicable, if G can not be an Sn or An + tryThreeCycleCandidate := function() + local + # integer, loop variable + a, + # elements, in G + r, tPower, tPowerOld, c; + # Steps 2 & 3: New involution + # Check if we either tried enough conjugates or constructed enough + # three cycle candidates for the current involution t. + # If this is the case, we need to construct the next involution + if nrTriedConjugates >= C or nrThreeCycleCandidates >= T then + r := RandomElm(ri, "SnAnUnknownDegree", true)!.el; + tPower := r ^ M; + # Invariant: tPower = (r ^ M) ^ (2 ^ a) + # We make a small improvement to the version described in + # . The order of r ^ M is a 2-power. + # It can be at most 2 ^ logInt2N. Thus, if we find an r such that + # (r ^ M) ^ (2 ^ logInt2N) is non-trivial, then we can return + # NeverApplicable. + for a in [1 .. logInt2N] do + tPowerOld := tPower; + tPower := tPower ^ 2; + if isone(ri)(tPower) then break; fi; + od; + if not isone(ri)(tPower) then + return NeverApplicable; + fi; + t := tPowerOld; + nrInvolutions := nrInvolutions + 1; + nrTriedConjugates := 0; + nrThreeCycleCandidates := 0; + fi; + # Steps 4 & 5: new three cycle candidate + # Try to construct a three cycle candidate via a conjugate of t. See + # the comment above this function. + nrTriedConjugates := nrTriedConjugates + 1; + c := t ^ RandomElm(ri, "SnAnUnknownDegree", true)!.el; + if not isequal(ri)(t * c, c * t) then + nrThreeCycleCandidates := nrThreeCycleCandidates + 1; + return (t * c) ^ 2; + else + # we have to call tryThreeCycleCandidate again + return fail; + fi; + end; + # construct the iterator + oneThreeCycleCandidate := function() + local candidate; + repeat + if nrInvolutions >= B + and (nrTriedConjugates >= C or nrThreeCycleCandidates >= T) + then + # With probability at least 1 - eps we constructed at least one + # three cycle with this iterator. + return fail; + fi; + candidate := tryThreeCycleCandidate(); + if candidate = NeverApplicable then + return NeverApplicable; + fi; + until candidate <> fail; + return candidate; + end; + return oneThreeCycleCandidate; +end; + +# ri : recog info record with group G +# c : element of G, +# should be a 3-cycle +# eps : real number, the error bound +# N : integer, upper bound for the degree of G +# +# Returns a list of elements of G. +# +# If the input is as assumed, then this function returns a list of bolstering +# elements with respect to c. +# +# Lower Bounds need n >= 9. +# Bolstering Elements are only defined for n >= 7. +RECOG.BolsteringElements := function(ri, cWithMem, eps, N) + local result, R, S, nrPrebolsteringElms, i, c, rWithMem, r, cr, cr2; + result := []; + c := StripMemory(cWithMem); + R := Int(Ceil(7 / 4 * Log(Float(eps ^ -1)))); + S := 7 * N * R; + # find pre-bolstering elements + for i in [0 .. S] do + rWithMem := RandomElm(ri, "SnAnUnknownDegree", true)!.el; + r := StripMemory(rWithMem); + # test whether r is pre-bolstering + cr := c ^ r; + cr2 := cr ^ r; + if not docommute(ri)(cr, c) + and not isequal(ri)(cr2, c) + and not isequal(ri)(cr2, c ^ 2) + and docommute(ri)(cr2, c) + then + if isone(ri)((cr ^ (c * r) + * cr ^ (cr2 * c)) ^ 3) + then + Add(result, cWithMem ^ 2 * rWithMem); + else + Add(result, cWithMem * rWithMem); + fi; + fi; + if Length(result) > R then break; fi; + od; + return result; +end; + +# ri : recog info record with group G +# g : element of G, +# should be a cycle matching c +# c : element of G, +# should be a 3-cycle +# r : element of G +# +# Returns a boolean. +# +# If the input is as assumed, that is in particular the supports of c and +# c^(g^2) have exactly one point, say alpha, in common, then this function +# returns whether alpha is a fixed point of r. +RECOG.IsFixedPoint := function(ri, g, c, r) + local + # respectively c ^ (g ^ i) + cg, cg2, cg3, cg4, + # temporary holder of H1, H2 + temp, + # (sets of) elements of G + H1, H2, x1, x2, x3, + # helper function + commutesWithAtMostOne; + # Helper function + commutesWithAtMostOne := function(ri, x, H) + local nrTrivialComm, h; + nrTrivialComm := 0; + for h in H do + if docommute(ri)(x, h) then + nrTrivialComm := nrTrivialComm + 1; + fi; + if nrTrivialComm >= 2 then + return false; + fi; + od; + return true; + end; + cg := c ^ g; + cg2 := cg ^ g; + cg3 := cg2 ^ g; + cg4 := cg3 ^ g; + H1 := [ c ^ 2, c ^ cg, ~[2] ^ cg3, ~[3] ^ cg3, ~[4] ^ cg4 ]; + # Test whether an element of the set X commutes with at least + # two elements of H1. + x1 := c ^ r; + if not commutesWithAtMostOne(ri, x1, H1) then return false; fi; + x2 := cg2 ^ r; + if not commutesWithAtMostOne(ri, x2, H1) then return false; fi; + x3 := ((cg2 ^ cg3) ^ cg4) ^ r; + if not commutesWithAtMostOne(ri, x3, H1) then return false; fi; + # Test whether an elm of the set X commutes with at least + # two elements of H2. + H2 := [c, cg, ~[2] ^ cg3, ~[3] ^ cg3, ~[4] ^ cg4]; + if not commutesWithAtMostOne(ri, x1, H2) then return false; fi; + if not commutesWithAtMostOne(ri, x2, H2) then return false; fi; + if not commutesWithAtMostOne(ri, x3, H2) then return false; fi; + return true; +end; + +# ri : recog info record with group G +# g : element of G, +# should be a k-cycle matching c +# c : element of G, +# should be a 3-cycle +# r : element of G, +# should have at least one moved point in common with g and should fix at +# least two moved points of g +# k : integer, +# should be length of cycle g +# +# Returns fail or a conjugate of r. +# +# W.l.o.g. let g = (1, ..., k) and c = (1, 2, 3). +# If the input is as assumed, then the algorithm returns a conjugate r ^ x such +# that r ^ x fixes the points 1, 2 but not the point 3. +RECOG.AdjustCycle := function(ri, g, c, r, k) + local + # list of 4 booleans, is point j fixed point + F4, + # smallest fixed point + f1, + # second smallest fixed point + f2, + # smallest non-fixed point + m, + # bool, false if |F| < 2 or |F| = k + success, + # integer, loop variable over [1 .. k] + j, + # element of G, loop variable + t, + # conjugating element + x; + # According to the paper we have: + # F := { 1 <= j <= k | RECOG.IsFixedPoint(g, c ^ (g ^ (j - 3)), r) = true } + # f1 := smallest number in F + # f2 := second smallest number in F + # m := smallest number *not* in F + # We do not store F explicitely. Instead we store the intersection of F and + # {1, 2, 3, 4} in the variable F4. + F4 := [false, false, false, false]; + f1 := fail; + f2 := fail; + m := fail; + t := c ^ (g ^ -3); + for j in [1 .. k] do + # invariant: t = c ^ (g ^ (j - 3)) + t := t ^ g; + if RECOG.IsFixedPoint(ri, g, t, r) then + if j <= 4 then + F4[j] := true; + fi; + if f1 = fail then + f1 := j; + elif f2 = fail then + f2 := j; + fi; + elif m = fail then + m := j; + fi; + # f1 and f2 not being fail is equivalent to |F| >= 2 + # m not being fail is equivalent to |F| < k + success := f1 <> fail and f2 <> fail and m <> fail; + if success then + if j >= 4 then + break; + # case 2, we do not need to compute F4[4] + elif f1 = 1 and f2 = 2 and m = 3 then + return r; + fi; + fi; + od; + if not success then + return fail; + fi; + # case distinction on F as in the table of Algorithm 4.20 + # via a decision tree + if F4[1] then + if F4[2] then + # We are in case 1, since case 2 is handled during the + # computation of F4 above. + x := c ^ ((g * c ^ 2) ^ (m - 3) * c) * c; + else + if F4[3] then + if F4[4] then + # case 3 + x := c ^ g; + else + # case 4 + x := (c ^ 2) ^ g; + fi; + else + # case 5 + x := c ^ ((g * c ^ 2) ^ (f2 - 3) * c); + fi; + fi; + else + if F4[2] then + if F4[4] then + # case 6 + x := c ^ (c ^ g); + else + if F4[3] then + # case 7 + x := (c ^ 2) ^ (c ^ g); + else + # case 8 + x := c ^ ((g * c ^ 2) ^ (f2 - 3) * c ^ g); + fi; + fi; + else + if F4[3] then + # case 9 + x := (c ^ 2) ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ 2; + else + # case 10 + x := c ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ ((g * c ^ 2) ^ (f1 - 3)); + fi; + fi; + fi; + return r^x; +end; + +# ri : recog info record with group G +# g : element of G, +# should be a k-cycle matching c +# c : element of G, +# should be a 3-cycle +# r : element of G, +# should be a cycle as in the return value of RECOG.AdjustCycle. If e.g. +# g = (1, 2, ..., k), then r would be a cycle fixing 1 and 2 and moving 3. +# s : element of group G, +# should be a storage cycle +# k : integer, +# should be length of cycle g +# k0 : integer, +# should be length of cycle r +# +# Returns a list consisting of: +# - gTilde: element of G, +# should be a cycle matching g +# - sTilde: element of G, +# should be current storage cycle, since we may call RECOG.AppendPoints +# several times and may not have used the last sTilde. +# - kTilde: integer, +# should be the length of gTilde +# +# The algorithm appends new points to the cycle g. Since g will always be a +# cycle of odd length, new points can only be appended in pairs. We identify +# the point j in {1, ..., k} with the 3-cycle c ^ (g ^ (j - 3)). We store new +# points in the storage cycle sTilde until we have found two different points. +# Then we append these to g. +RECOG.AppendPoints := function(ri, g, c, r, s, k, k0) + local gTilde, sTilde, kTilde, gc2, x, j; + gTilde := g; + sTilde := s; + kTilde := k; + x := c; + for j in [1 .. k0 - 1] do + # invariant: x = c ^ (r ^ j) + x := x ^ r; + if docommute(ri)(x, gTilde * c ^ 2) then + # If sTilde doesn't already store a point, then store x. + if isone(ri)(sTilde) then + sTilde := x; + fi; + # Do we now have two different points? If so, append them. + if not isone(ri)(sTilde) and not isequal(ri)(sTilde, x) then + kTilde := kTilde + 2; + gTilde := gTilde * sTilde ^ (x ^ 2); + sTilde := One(gTilde); + fi; + fi; + od; + return [gTilde, sTilde, kTilde]; +end; + +# ri : recog info record with group G +# g : element of G +# p : prime +# Returns whether g is an element of order p. +RECOG.IsElmOfPrimeOrder := function(ri, g, p) + if not isone(ri)(g) and isone(ri)(g ^ p) then + return true; + else + return false; + fi; +end; + +# ri : recog info record with group G +# c : a 3-cycle of a group G +# x : bolstering element with respect to c +# N : integer, upper bound for the degree of G +# +# returns either fail or a list consisting of: +# - g, cycle matching c +# - k, length of cycle g. +# +# We return fail if one of the following holds: +# - N is not an upper bound for the degree of G +# - c is not a 3-cycle +RECOG.BuildCycle := function(ri, c, x, N) + local + # integers + m, mDash, + # group elements + d, y, dx, e, z, f, g, x2; + # Compute m. + # m is the least natural number such that with + # d = c ^ (x ^ (m + 1)) + # we have Order(d * c) <> 5. Note that m >= 1. + # We also compute + # y = c * (c ^ x) * (c ^ (x ^ 2)) * ... * (c ^ (x ^ m)). + # The next three lines correspond to m = 1 + # We use x ^ 2 several times. + x2 := x ^ 2; + m := 1; + y := c * (c ^ x); + d := c ^ x2; + while true do + if m >= N / 2 then + return fail; + elif RECOG.IsElmOfPrimeOrder(ri, d * c, 5) then + m := m + 1; + else + break; + fi; + y := y * d; + d := d ^ x; + od; + if m = 1 then + return fail; + fi; + # case |alpha - beta| = 0 + if isequal(ri)(d, c) or isequal(ri)(d, c ^ 2) then + return [y, 2 * m + 3]; + fi; + # case |alpha - beta| = 1 + dx := d ^ x; + if not RECOG.IsElmOfPrimeOrder(ri, dx * c, 5) then + return [y, 2 * m + 3]; + fi; + # case |alpha - beta| >= 2 + # case distinction on element e + # w in v ^ + if not RECOG.IsElmOfPrimeOrder(ri, d * c, 2) then + # case 1, alpha > beta + if docommute(ri)(dx, d ^ c) then + e := dx ^ c; + # case 2, alpha < beta + else + e := (dx ^ (c ^ 2)) ^ 2; + fi; + # w not in v ^ + else + # case 3, alpha > beta + if not docommute(ri)(dx, d ^ c) then + e := dx ^ (c ^ 2); + # case 4, alpha < beta + else + e := (dx ^ c) ^ 2; + fi; + fi; + z := d ^ e; + # Compute m' (here mDash). + # mDash is the least natural number such that with + # f := z ^ (x ^ (2 * mDash)) + # we have Order(f * c) <> 5. Note that mDash >= 1. + # We also compute + # g = y * z * (z ^ (x ^ 2)) * ... * (z ^ (x ^ (2 * (mDash - 1)))). + # The next three lines correspond to mDash = 1 + mDash := 1; + g := y * z; + f := z ^ x2; + while true do + if mDash >= N / 2 then + return fail; + elif RECOG.IsElmOfPrimeOrder(ri, f * c, 5) then + mDash := mDash + 1; + else + break; + fi; + g := g * f; + f := f ^ x2; + od; + return [g, 2 * mDash + 2 * m + 3]; +end; + +# ri : recog info record with group G +# c : element of G, +# should be a 3-cycle +# eps : real number, the error bound +# N : integer, upper bound for the degree of G +# +# Returns fail or a list [g, k] consisting of: +# - g: element of G, +# should be a k-cycle matching c +# - k: integer, +# should be length of cycle g. +# +# Note that the order of the returned list is reversed with respect to the +# paper to be consistent with the return values of the other functions. +# +# We return fail if one of the following holds: +# - the list of bolstering elements is too small +# - N is not an upper bound for the degree of G +# - c is not a 3-cycle +RECOG.ConstructLongCycle := function(ri, c, eps, N) + local g, k, tmp, B, x; + B := RECOG.BolsteringElements(ri, c, Float(eps) / 2., N); + if Length(B) < Int(Ceil(7. / 4. * Log(2. / Float(eps)))) then + return fail; + fi; + k := 0; + for x in B do + tmp := RECOG.BuildCycle(ri, c, x, N); + if tmp = fail then + return fail; + elif tmp[2] > k then + g := tmp[1]; + k := tmp[2]; + fi; + od; + return [g, k]; +end; + +# ri : recog info record with group G +# g : element of G, +# should be a k-cycle matching c +# c : element of G, +# should be a 3-cycle +# k : integer, +# should be length of cycle g +# eps : real number, the error bound +# N : integer, upper bound for the degree of G +# +# Returns fail or a list consisting of: +# - gTilde : element of G, +# long cycle, a standard generator of An < G +# - cTilde : element of G, +# 3-cycle, a standard generator of An < G +# - kTilde : integer, +# degree of group An < G, that is generated by gTilde and cTilde +RECOG.StandardGenerators := function(ri, g, c, k, eps, N) + local s, k0, c2, r, kTilde, gTilde, i, x, m, tmp, cTilde; + s := One(g); + k0 := k - 2; + c2 := c ^ 2; + r := g * c2; + kTilde := k; + gTilde := g; + for i in [1 .. Int(Ceil(Log(10. / 3.) ^ (-1) + * (Log(Float(N)) + Log(1 / Float(eps)))))] do + x := r ^ RandomElm(ri, "SnAnUnknownDegree", true)!.el; + m := RECOG.AdjustCycle(ri, gTilde, c, x, kTilde); + if m = fail then return fail; fi; + tmp := RECOG.AppendPoints(ri, gTilde, c, m, s, kTilde, k0); + gTilde := tmp[1]; + s := tmp[2]; + kTilde := tmp[3]; + if kTilde > N then return fail; fi; + od; + if isone(ri)(s) then + gTilde := c2 * gTilde; + cTilde := c; + else + kTilde := kTilde + 1; + gTilde := gTilde * s; + cTilde := s; + fi; + if RECOG.SatisfiesAnPresentation(ri, + StripMemory(gTilde), + StripMemory(cTilde), + kTilde) then + return [gTilde, cTilde, kTilde]; + else + return fail; + fi; +end; + +# This function is an excerpt of the function RECOG.RecogniseSnAn in gap/SnAnBB.gi +# ri : recog info record with group G, +# n : degree +# stdGensAnWithMemory : standard generators of An < G +# +# Returns either fail or a record with components: +# [s, stdGens, xis, n], where: +# - type: the isomorphism type, that is either the string "Sn" or "An". +# - isoData: a list [stdGens, xis, n] where +# - stdGens are the standard generators of G. They do not have memory. +# - xis implicitly defines the isomorphism. It is used by RECOG.FindImageSn +# and RECOG.FindImageAn to compute the isomorphism. +# - n is the degree of the group. +# - slpToStdGens: an SLP to stdGens. +# +# TODO: Image Computation requires n >= 11. +RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAnWithMemory) + local stdGensAn, xis, gImage, foundOddPermutation, slp, eval, + hWithMemory, bWithMemory, stdGensSnWithMemory, b, h, g; + stdGensAn := StripMemory(stdGensAnWithMemory); + xis := RECOG.ConstructXiAn(n, stdGensAn[1], stdGensAn[2]); + foundOddPermutation := false; + for g in ri!.gensHmem do + gImage := RECOG.FindImageAn(ri, n, StripMemory(g), + stdGensAn[1], stdGensAn[2], + xis[1], xis[2]); + if gImage = fail then return fail; fi; + if SignPerm(gImage) = -1 then + # we found an odd permutation, + # so the group cannot be An + foundOddPermutation := true; + break; + fi; + slp := RECOG.SLPforAn(n, gImage); + eval := ResultOfStraightLineProgram(slp, + [stdGensAn[2], stdGensAn[1]]); + if not isequal(ri)(eval, StripMemory(g)) then return fail; fi; + od; + if not foundOddPermutation then + return rec(type := "An", + isoData := [[stdGensAn[1], stdGensAn[2]], xis, n], + slpToStdGens := SLPOfElms(stdGensAnWithMemory)); + fi; + # Construct standard generators for Sn: [bWithMemory, hWithMemory]. + slp := RECOG.SLPforAn(n, (1,2) * gImage); + eval := ResultOfStraightLineProgram( + slp, [stdGensAnWithMemory[2], stdGensAnWithMemory[1]] + ); + hWithMemory := eval * g ^ -1; + bWithMemory := stdGensAnWithMemory[1] * stdGensAnWithMemory[2]; + if n mod 2 = 0 then + bWithMemory := hWithMemory * bWithMemory; + fi; + stdGensSnWithMemory := [bWithMemory, hWithMemory]; + b := StripMemory(bWithMemory); + h := StripMemory(hWithMemory); + if not RECOG.SatisfiesSnPresentation(ri, n, b, h) then + return fail; + fi; + xis := RECOG.ConstructXiSn(n, b, h); + for g in ri!.gensHmem do + gImage := RECOG.FindImageSn(ri, n, StripMemory(g), + b, h, + xis[1], xis[2]); + if gImage = fail then return fail; fi; + slp := RECOG.SLPforSn(n, gImage); + eval := ResultOfStraightLineProgram(slp, [h, b]); + if not isequal(ri)(eval, StripMemory(g)) then return fail; fi; + od; + return rec(type := "Sn", + isoData := [[b, h], xis, n], + slpToStdGens := SLPOfElms(stdGensSnWithMemory)); +end; + +# This method is an implementation of . It is the main +# function of SnAnUnknownDegree. +# Note that it currently only works for 11 <= n. TODO: make it work with +# smaller n, that is include fixes from Jonathan Conder's B.Sc. +# Thesis "Algorithms for Permutation Groups", see PR #265. +# +# From : +# RECOG.RecogniseSnAn is a one-sided Monte-Carlo algorithm with the following +# properties. It takes as input a black-box group G, a natural number +# N and a real number eps with 0 < eps < 1. If G is +# isomorphic to An or Sn for some 9 <= n <= N, it returns with +# probability at least 1 - eps the degree n and an +# isomorphism from G to An or Sn. +RECOG.RecogniseSnAn := function(ri, eps, N) + local T, foundPreImagesOfStdGens, constants, iterator, c, tmp, recogData, i; + T := Int(Ceil(Log2(1 / Float(eps)))); + foundPreImagesOfStdGens := false; + constants := RECOG.ThreeCycleCandidatesConstants(1. / 4., N); + for i in [1 .. T] do + iterator := RECOG.ThreeCycleCandidatesIterator(ri, constants); + c := iterator(); + while c <> fail do + if c = NeverApplicable then return NeverApplicable; fi; + # This is a very cheap test to determine + # if our candidate c could be a three cycle. + if not isone(ri)(StripMemory(c) ^ 3) then + c := iterator(); + continue; + fi; + tmp := RECOG.ConstructLongCycle(ri, c, 1. / 8., N); + if tmp = fail then + c := iterator(); + continue; + fi; + # Now tmp contains [g, k] where + # g corresponds to a long cycle + # k is its length + tmp := RECOG.StandardGenerators(ri, tmp[1], c, tmp[2], 1. / 8., N); + if tmp = fail then + c := iterator(); + continue; + fi; + # Now tmp contains [g, c, n] where + # g, c correspond to standard generators of An + recogData := RECOG.ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); + if recogData = fail then continue; fi; + return recogData; + od; + od; + return TemporaryFailure; +end; + +#! @BeginChunk SnAnUnknownDegree +#! This method tries to determine whether the input group given by ri is +#! isomorphic to a symmetric group Sn or alternating group An with +#! 11 \leq n. +#! It is an implementation of . +#! +#! If Grp(ri) is a permutation group, we assume that it is primitive and +#! not a giant (a giant is Sn or An in natural action). +#! +#! @EndChunk +FindHomMethodsGeneric.SnAnUnknownDegree := function(ri, G) + local eps, N, p, d, recogData, isoData, degree, swapSLP; + #G := Grp(ri); + # TODO find value for eps + eps := 1 / 10^2; + # Check magma + if IsPermGroup(G) then + # We assume that G is primitive and not a giant. + # The smallest non-natural primitive action of Sn or An induces + # a large base group. Thus by [L84] its degree is smallest, when the + # action is on 2-subsets. Thus its degree is at least n * (n-1) / 2. + # Thus for a given degree k, we have + # n >= 1/2 + Sqrt(1/4 + 2*k). + N := Int(Ceil(1/2 + Sqrt(Float(1/4 + 2 * NrMovedPoints(G))))); + elif IsMatrixGroup(G) then + p := Characteristic(DefaultFieldOfMatrixGroup(G)); + d := DimensionOfMatrixGroup(G); + # Let N be the largest integer such that A_N has a representation of + # dimension d. + if ri!.projective then + # If n >= 9, then the smallest irreducible projective An-module has + # dimension n-2, see [KL90], Proposition 5.3.7. + # Assume N >= 9 and use the comment above to compute N. If we + # arrive at a value < 9 for N, then we must have been in the case N + # < 9. + # TODO: The table in [KL90], Proposition 5.3.7. has more detailed + # values for 5 <= n < 9. Do we want to use that? + N := Maximum(8, d + 2); + else + # If n >= 10, then the smallest irreducible An-module is the + # fully deleted permutation module, see [KL90], Proposition 5.3.5. + # It has dimension n-2 if p|n and dimension n-1 otherwise. + # Assume N >= 10 and use the comment above to compute N. If we + # arrive at a value < 10 for N, then we must have been in the case + # N < 10. + if (d + 2) mod p = 0 then + N := d + 2; + else + N := d + 1; + fi; + N := Maximum(9, N); + fi; + else + N := ErrorNoReturn("SnAnUnknownDegree: no method to compute bound", + " , Grp() must be an IsPermGroup or an", + " IsMatrixGroup"); + fi; + # Try to find an isomorphism + recogData := RECOG.RecogniseSnAn(ri, eps, N); + # RECOG.RecogniseSnAn returned NeverApplicable or TemporaryFailure + if not IsRecord(recogData) then + return recogData; + fi; + isoData := recogData.isoData; + ri!.SnAnUnknownDegreeIsoData := isoData; + SetFilterObj(ri, IsLeaf); + degree := isoData[3]; + if recogData.type = "Sn" then + SetSize(ri, Factorial(degree)); + SetIsRecogInfoForAlmostSimpleGroup(ri, true); + else + SetSize(ri, Factorial(degree) / 2); + SetIsRecogInfoForSimpleGroup(ri, true); + fi; + # Note that when setting the nice generators we reverse their order, such + # that it fits to the SLPforSn/SLPforAn function! + SetNiceGens(ri, Reversed(isoData[1])); + swapSLP := StraightLineProgram([[[2, 1], [1, 1]]], 2); + Setslptonice(ri, + CompositionOfStraightLinePrograms(swapSLP, + recogData.slpToStdGens)); + if recogData.type = "Sn" then + Setslpforelement(ri, SLPforElementFuncsGeneric.SnUnknownDegree); + else + Setslpforelement(ri, SLPforElementFuncsGeneric.AnUnknownDegree); + fi; + return Success; +end; + +# The SLP function if G is isomorphic to Sn. +SLPforElementFuncsGeneric.SnUnknownDegree := function(ri, g) + local isoData, degree, image; + isoData := ri!.SnAnUnknownDegreeIsoData; + degree := isoData[3]; + image := RECOG.FindImageSn(ri, degree, g, isoData[1][1], isoData[1][2], + isoData[2][1], isoData[2][2]); + return RECOG.SLPforSn(degree, image); +end; + +# The SLP function if G is isomorphic to An. +SLPforElementFuncsGeneric.AnUnknownDegree := function(ri, g) + local isoData, degree, image; + isoData := ri!.SnAnUnknownDegreeIsoData; + degree := isoData[3]; + image := RECOG.FindImageAn(ri, degree, g, isoData[1][1], isoData[1][2], + isoData[2][1], isoData[2][2]); + return RECOG.SLPforAn(degree, image); +end; diff --git a/gap/tools.gi b/gap/utils.gi similarity index 81% rename from gap/tools.gi rename to gap/utils.gi index dabe63887..e9af3a5ba 100644 --- a/gap/tools.gi +++ b/gap/utils.gi @@ -103,3 +103,30 @@ RECOG.CheckFingerPrint := function(fp,orders) count := Number(orders,o->o in fp.freqorders); return RECOG.BinomialTab[Length(orders)][count+1]/2^(Length(orders)); end; + +# Helper function to compute all primes up to a given integer via a prime sieve +RECOG.PrimesCache := ShallowCopy(Primes); # all primes < 1000 +RECOG.PrimesCacheUpperBound := 1000; +RECOG.CachePrimesUpTo := function(n) + local i, j, sieve; + if RECOG.PrimesCacheUpperBound >= n then return; fi; + sieve := BlistList([1..n], [1..n]); + sieve[1] := false; + for i in [2..Int(n/2)] do + sieve[i*2] := false; + od; + i := 3; + while i * i <= n do + if sieve[i] then + j := 3*i; + while j <= n do + sieve[j] := false; + j := j + 2*i; + od; + fi; + i := i + 2; + od; + RECOG.PrimesCache := ListBlist([1..n], sieve); + RECOG.PrimesCacheUpperBound := n; +end; + diff --git a/read.g b/read.g index bcadc84f5..5fa7ed1dc 100644 --- a/read.g +++ b/read.g @@ -25,7 +25,7 @@ ReadPackage("recog","gap/base/projective.gi"); # Some tools: -ReadPackage("recog","gap/tools.gi"); +ReadPackage("recog","gap/utils.gi"); # generic ReadPackage("recog","gap/generic/kernel.gi"); @@ -36,9 +36,8 @@ ReadPackage("recog","gap/generic/KnownNilpotent.gi"); # Permutations: ReadPackage("recog","gap/perm/giant.gi"); ReadPackage("recog","gap/perm/largebase.gi"); - -# Up to now there is not much here: ReadPackage("recog","gap/SnAnBB.gi"); +ReadPackage("recog","gap/generic/SnAnUnknownDegree.gi"); # Matrices/Projective: ReadPackage("recog","gap/projective/findnormal.gi"); diff --git a/tst/working/quick/GenericSnAnUnknownDegree.tst b/tst/working/quick/GenericSnAnUnknownDegree.tst new file mode 100644 index 000000000..375380287 --- /dev/null +++ b/tst/working/quick/GenericSnAnUnknownDegree.tst @@ -0,0 +1,327 @@ +#@local testFunction, IsBolsteringElement, data +#@local altGroups, symGroups, permMatGroup, altMatGroups, nonAltOrSymGroups +#@local ri, g, c, r, i, x, slp +#@local S11On2Sets, d, sets, SdOn2Sets, success, res, isoData, gens, g1, img1, g2, img2 +#@local SymOnKSets, AltOnKSets +# +# Hack to insert the method +gap> AddMethod(FindHomDbPerm, +> rec( +> method := FindHomMethodsGeneric.SnAnUnknownDegree, +> rank := 58, +> stamp := "SnAnUnknownDegreeHack", +> comment := "HACK", +> ) +> );; +gap> AddMethod(FindHomDbMatrix, +> rec( +> method := FindHomMethodsGeneric.SnAnUnknownDegree, +> rank := 1070, +> stamp := "SnAnUnknownDegreeHack", +> comment := "HACK", +> ) +> );; +gap> AddMethod(FindHomDbProjective, +> rec( +> method := FindHomMethodsGeneric.SnAnUnknownDegree, +> rank := 1220, +> stamp := "SnAnUnknownDegreeHack", +> comment := "HACK", +> ) +> );; + +# +# testing matrix: +# - isomorphic: yes, no +# different representations: +# - permutation groups: natural, on 2-subsets +# - finitely presented group +# - permutation matrices: compressed matrices, uncompressed matrices +# - projective matrix groups +# +# TODO: Use RECOG.TestGroup? +# TODO: better name for testFunction +# tests RECOG.ThreeCycleCandidatesIterator and RECOG.BolsteringElements +gap> testFunction := function(G, eps, N) +> local ri, iterator, candidate, i, j; +> ri := EmptyRecognitionInfoRecord(rec(), G, false); +> iterator := RECOG.ThreeCycleCandidatesIterator(ri, RECOG.ThreeCycleCandidatesConstants(eps, N)); +> for i in [1 .. 4] do +> candidate := iterator(); +> for j in [1 .. 4] do +> if candidate <> NeverApplicable +> and candidate <> TemporaryFailure then +> RECOG.BolsteringElements(ri, candidate, eps, +> N); +> fi; +> od; +> od; +> end;; + +# +# x : permutation +# c : permutation, +# should be a 3-cycle +# +# Returns true, if x is a bolstering element with respect to the 3-cycle c. +# +# Let c = (u, v, w). We call x a bolstering element with respect to c, if +# x = (v, a_1, ..., a_alpha)(w, b_1, ..., b_beta)(...) or +# x = (v, a_1, ..., a_alpha, w, b_1, ..., b_beta)(...) +# with u in fix(x) and alpha, beta >= 2. +gap> IsBolsteringElement := +> function(x, c) +> local suppC, dist, i, k, p, pos1; +> # suppC = [u, v, w] +> suppC := MovedPoints(c); +> if Size(suppC) <> 3 then return false; fi; +> # dist = [k_u, k_v, k_w], +> # where for each p in suppC, k_p is the minimal integer such that p^(x^k) in suppC +> dist := [0, 0, 0]; +> for i in [1..3] do +> k := 1; +> p := suppC[i]^x; +> while not p in suppC do +> k := k + 1; +> p := p ^ x; +> od; +> dist[i] := k; +> od; +> # One point of suppC is fixed by x +> pos1 := PositionProperty(dist, k -> k = 1); +> if pos1 = fail then return false; fi; +> Remove(dist, pos1); +> # The other two points of cuppC have distance at least 2 +> if ForAny(dist, k -> k < 2) then return false; fi; +> return true; +> end;; + +# For each entry (d, k) we construct Sym(d)/Alt(d) acting on k-sets. +# For each entry (d, k), we must have 2 * k ^ 2 > d, +# otherwise LargeBasePrimitive recognises the group instead of SnAnUnknownDegree. +gap> data := [[11, 3], [12, 3], [13, 3]];; + +# TODO: more non-isomorphic examples +# TODO: add projective groups +# +# SymmetricGroup action on k-sets +gap> SymOnKSets := function(d, k) +> local sets; +> sets := Combinations([1 .. d], k);; +> return Action(SymmetricGroup(d), sets, OnSets);; +> end;; + +# +# AlternatingGroup action on 2-sets +gap> AltOnKSets := function(d, k) +> local sets; +> sets := Combinations([1 .. d], k);; +> return Action(AlternatingGroup(d), sets, OnSets);; +> end;; + +# +gap> altGroups := List(data, entry -> AltOnKSets(entry[1], entry[2]));; +gap> symGroups := List(data, entry -> SymOnKSets(entry[1], entry[2]));; +gap> permMatGroup := G -> Group(List( +> GeneratorsOfGroup(G), +> x -> ImmutableMatrix(7, PermutationMat(x, NrMovedPoints(G), GF(7))) +> ));; +gap> altMatGroups := List([11], +> n -> permMatGroup(AlternatingGroup(n)));; +gap> nonAltOrSymGroups := [ +> DihedralGroup(IsPermGroup, 10), +> #DihedralGroup(IsPcGroup, 10), +> #DihedralGroup(IsPermGroup, 2000), +> #DihedralGroup(IsPcGroup, 2000), +> PSL(3, 5), +> SL(3, 5), +> Omega(-1, 4, 5), +> Omega(-1, 4, 3), +> Omega(+1, 4, 5), +> Omega(+1, 4, 3), +> Omega(+1, 8, 5), +> Omega(+1, 8, 3), +> Omega(0, 5, 5), +> Omega(0, 5, 3), +> ];; + +# Test +gap> for i in [1 .. Length(data)] do +> RECOG.TestGroup(altGroups[i], false, Factorial(data[i, 1])/2); +> RECOG.TestGroup(symGroups[i], false, Factorial(data[i, 1])); +> od; +gap> for i in [1 .. Length(altMatGroups)] do +> RECOG.TestGroup(altMatGroups[i], false, Size(altMatGroups[i])); +> od; +gap> for i in [1 .. Length(altMatGroups)] do +> RECOG.TestGroup(altMatGroups[i], true, Size(altMatGroups[i])); +> od; +gap> for i in [1 .. Length(nonAltOrSymGroups)] do +> if FindHomMethodsGeneric.SnAnUnknownDegree(EmptyRecognitionInfoRecord(rec(), nonAltOrSymGroups[i], false), nonAltOrSymGroups[i]) = Success then +> Print("ERROR: Recognised group [", i, "] wrongly as Sn/An!\n"); +> fi; +> od; + +# RECOG.IsFixedPoint +gap> ri := EmptyRecognitionInfoRecord(rec(), SymmetricGroup(10), false);; +gap> g := (1,2,3,4,5,6,7,8);; +gap> c := (1,2,3);; +gap> r := (1,2)(4,5,6);; +gap> RECOG.IsFixedPoint(ri, g,c,r); +true +gap> r := (2,3,4);; +gap> RECOG.IsFixedPoint(ri, g,c,r); +false + +# RECOG.AdjustCycle +gap> ri := EmptyRecognitionInfoRecord(rec(), SymmetricGroup(10), false);; +gap> g := (1,2,3,4,5,6,7,8);; +gap> c := (1,2,3);; +gap> r := (4,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5) +gap> r := (3,4,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,4,5) +gap> r := (2,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5) +gap> r := (2,4,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5,4) +gap> r := (2,3,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,4,5) +gap> r := (1,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5) +gap> r := (1,4,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5,4) +gap> r := (1,3,4,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,6,4,5) +gap> r := (1,2,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5,4) +gap> r := (1,2,3,5);; +gap> RECOG.AdjustCycle(ri, g, c, r, 8); +(3,5,4,6) + +# RECOG.BuildCycle +gap> ri := EmptyRecognitionInfoRecord(rec(), SymmetricGroup(10), false);; + +# c = (u,v,w) +gap> c := (1,2,3);; + +# Form 1: x = (v,a_1,...,a_alpha) * (w,b_1,....,b_beta) * (...) +# alpha - beta = 0 +gap> x := (2,4,5,6)* (3,7,8,9);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,9), 9 ] + +# alpha - beta = -1 +gap> x := (2,4,5,6)* (3,7,8,9,10);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,9), 9 ] + +# alpha - beta = 1 +gap> x := (2,4,5,6,10)* (3,7,8,9);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,9), 9 ] + +# alpha - beta = -2 +gap> x := (2,4,5) * (3,7,8,9,10);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,10,9), 9 ] + +# alpha - beta = 2 +gap> x := (2,4,5,6,10) * (3,7,8);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,10), 9 ] + +# Form 2: x = (v,a_1,...,a_alpha,w,b_1,....,b_beta) * (...) +# alpha - beta = 0 +gap> x := (2,4,5,6,3,7,8,9);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,9), 9 ] + +# alpha - beta = -1 +gap> x := (2,4,5,6,3,7,8,9,10);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,9), 9 ] + +# alpha - beta = 1 +gap> x := (2,4,5,6,10,3,7,8,9);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,9), 9 ] + +# alpha - beta = -2 +gap> x := (2,4,5,3,7,8,9,10);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,10,9), 9 ] + +# alpha - beta = 2 +gap> x := (2,4,5,6,10,3,7,8);; +gap> RECOG.BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,10), 9 ] + +# Construct isomorphism between S_11 on 2-sets and S_11 in natural +# representation. +gap> sets := Combinations([1 .. 11], 2);; +gap> S11On2Sets := Action(SymmetricGroup(11), sets, OnSets);; +gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; +gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri, S11On2Sets);; +gap> isoData := ri!.SnAnUnknownDegreeIsoData;; +gap> gens := GeneratorsOfGroup(S11On2Sets);; +gap> g1 := gens[1];; +gap> img1 := RECOG.FindImageSn(ri, 11, g1, isoData[1][1], isoData[1][2], +> isoData[2][1], isoData[2][2]);; +gap> CycleStructurePerm(img1); +[ ,,,,,,,,, 1 ] +gap> g2 := gens[2];; +gap> img2 := RECOG.FindImageSn(ri, 11, g2, isoData[1][1], isoData[1][2], +> isoData[2][1], isoData[2][2]);; +gap> CycleStructurePerm(img2); +[ 1 ] + +# FindHomMethodsGeneric.SnAnUnknownDegree +# Sn +gap> for d in [11 .. 15] do +> sets := Combinations([1 .. d], 2);; +> SdOn2Sets := Action(SymmetricGroup(d), sets, OnSets);; +> ri := EmptyRecognitionInfoRecord(rec(), SdOn2Sets, false);; +> success := FindHomMethodsGeneric.SnAnUnknownDegree(ri, SdOn2Sets); +> if not success or not Size(ri) = Factorial(d) then +> Print("wrong result! degree ", d, "\n"); +> fi; +> od; + +# An +gap> for d in [11 .. 15] do +> sets := Combinations([1 .. d], 2);; +> SdOn2Sets := Action(AlternatingGroup(d), sets, OnSets);; +> ri := EmptyRecognitionInfoRecord(rec(), SdOn2Sets, false);; +> success := FindHomMethodsGeneric.SnAnUnknownDegree(ri, SdOn2Sets); +> if not success or not Size(ri) = Factorial(d)/2 then +> Print("wrong result! degree ", d, "\n"); +> fi; +> od; + +# Check Slp function +gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; +gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri, S11On2Sets); +true +gap> x := PseudoRandom(Grp(ri));; +gap> slp := SLPforElement(ri, x);; +gap> x = ResultOfStraightLineProgram(slp, NiceGens(ri)); +true + +# +# Remove Hacky injection of our method +gap> Remove(FindHomDbPerm, +> PositionProperty(FindHomDbPerm, x -> x.stamp = "SnAnUnknownDegreeHack"));; +gap> Remove(FindHomDbMatrix, +> PositionProperty(FindHomDbMatrix, x -> x.stamp = "SnAnUnknownDegreeHack"));; +gap> Remove(FindHomDbProjective, +> PositionProperty(FindHomDbProjective, x -> x.stamp = "SnAnUnknownDegreeHack"));;