From 50a3ae6fda1b1baaaa74f869b931a0840e4829b5 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 16:14:02 +0200 Subject: [PATCH 01/64] Undo commenting out of unused code in gap/SnAnBB.gi RecogniseSnAn and NiceGeneratorsSnAn are still unused and are therefore left commented out. --- gap/SnAnBB.gi | 2180 ++++++++++++++++++++++++------------------------- 1 file changed, 1090 insertions(+), 1090 deletions(-) diff --git a/gap/SnAnBB.gi b/gap/SnAnBB.gi index 9c63ef047..603a78b9e 100644 --- a/gap/SnAnBB.gi +++ b/gap/SnAnBB.gi @@ -18,100 +18,100 @@ ## 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; -# -# Info( InfoRecSnAn, 1, "calling Satisfies Sn Presentation"); -# -# if not(RecSnAnIsOne((r * s)^(n-1))) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation -1"); -# return false; -# fi; -# -# 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; -# 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"); -# -# if not(RecSnAnIsOne(s^(n-2))) or not(RecSnAnIsOne(t^3)) then -# Info( InfoRecSnAn, 1, "does not satisfy presentation-1"); -# return false; -# 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; -# od; -# return true; -# 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; -# fi; -# j := j + 1; -# od; -# return true; -# fi; -# -# end; -# -# +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; + + Info( InfoRecSnAn, 1, "calling Satisfies Sn Presentation"); + + if not(RecSnAnIsOne((r * s)^(n-1))) then + Info( InfoRecSnAn, 1, "does not satisfy presentation -1"); + return false; + fi; + + 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; + 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"); + + if not(RecSnAnIsOne(s^(n-2))) or not(RecSnAnIsOne(t^3)) then + Info( InfoRecSnAn, 1, "does not satisfy presentation-1"); + return false; + 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; + od; + return true; + 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; + fi; + j := j + 1; + od; + return true; + fi; + +end; + + # NiceGeneratorsSnAn := function ( n, grp, N ) # # local AddStack, g1, g2, g3, g4, g, h, a, b, c, t, i, k, l, @@ -374,1002 +374,1002 @@ # 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; -# -# + + +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 From bfd9859ca6303836540edef751050c5876d01d97 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 16:16:15 +0200 Subject: [PATCH 02/64] Move NiceGeneratorsSnAn to end of gap/SnAnBB.gi --- gap/SnAnBB.gi | 644 +++++++++++++++++++++++++------------------------- 1 file changed, 322 insertions(+), 322 deletions(-) diff --git a/gap/SnAnBB.gi b/gap/SnAnBB.gi index 603a78b9e..ff1051df5 100644 --- a/gap/SnAnBB.gi +++ b/gap/SnAnBB.gi @@ -112,270 +112,6 @@ SatisfiesAnPresentation := function( n, s, t ) end; -# NiceGeneratorsSnAn := function ( n, grp, N ) -# -# local AddStack, g1, g2, g3, g4, g, h, a, b, c, t, i, k, l, -# delta, elfound, m, x, y; -# -# # we put the elements that we look for on stacks -# AddStack := function( stk, e ) -# if Length(stk) = 0 then -# stk[1] := e; -# elif Length(stk) = 1 then -# stk[2] := e; -# else -# stk[1] := stk[2]; -# stk[2] := e; -# fi; -# end; -# -# elfound := [false, false, false, false]; -# -# delta := 1 - (n mod 2); -# -# l := One(grp); -# -# m := n mod 6; -# if m = 0 then k := 5; -# elif m = 1 then k := 6; -# elif m = 2 or m = 4 then k := 3; -# elif m = 3 or m = 5 then k := 4; -# fi; -# -# g1 := []; # $n$-cycles -# g2 := []; # transpositions -# g3 := []; # $n$ or $n-1$-cycles -# g4 := []; # 3-cycles -# -# while N > 0 do -# N := N - 1; -# t := PseudoRandom(grp); -# -# # 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 -# # a is not a transposition -# Info( InfoRecSnAn, 2, "a is not a transposition"); -# RemoveElmList(g2,Position(g2,a)); -# if Length(g2) = 0 then elfound[2] := false; fi; -# fi; -# od; -# -# # 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 -# # a is not a 3-cycle -# Info( InfoRecSnAn, 2, "a is not a 3-cycle"); -# RemoveElmList(g4,Position(g4,a)); -# if Length(g4) = 0 then elfound[4] := false; fi; -# fi; -# od; -# -# if not(RecSnAnIsOne(t)) and RecSnAnIsOne(t^n) then -# # we hope we found an n-cycle -# AddStack(g1,t); -# elfound[1] := true; -# Info( InfoRecSnAn, 2, "found n-cycle"); -# if delta = 0 then -# elfound[3] := true; -# AddStack(g3,t); -# fi; -# fi; -# -# b := t^(n-2-delta); -# if not(RecSnAnIsOne(b)) and RecSnAnIsOne(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 -# # we hope we found an n or (n-1)-cycle -# AddStack(g3,t); -# elfound[3] := true; -# Info( InfoRecSnAn, 2, "found (n-1)-cycle"); -# fi; -# -# b := t^(n-k); -# if not(RecSnAnIsOne(b)) and RecSnAnIsOne(b^3) then -# # we hope we found a 3(n-k)-element -# AddStack(g4,b); -# elfound[4] := true; -# Info( InfoRecSnAn, 2, "found 3-cycle"); -# fi; -# -# # if we have an n-cycle and a transposition, test for Sn -# if elfound[1] and elfound[2] then -# # hopefully $g2\lambda$ is a transposition -# for a in g2 do # choose a transposition -# i := n-1; -# while N>0 and i>0 do # take up to n-1 conjugates, -# # check if they match some n-cycle -# i := i-1; -# h := a^PseudoRandom(grp); -# # 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 -# # a is not a transposition -# Info(InfoRecSnAn,2,"a is not a transposition"); -# RemoveElmList(g2,Position(g2,a)); -# if Length(g2) = 0 then elfound[2] := false; fi; -# i := 0; -# 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 -# Info(InfoRecSnAn,1,"found good transposition"); -# if SatisfiesSnPresentation( n, b, h ) then -# Info( InfoRecSnAn, 1, -# "Group satisfies presentation for Sn ",N); -# return [ b, h, "Sn" ]; -# else -# RemoveElmList(g1,Position(g1,b)); -# if Length(g1)=0 then elfound[1]:=false;fi; -# fi; -# fi; -# od; #for -# fi; -# od; # while -# od; # for a in g2 -# fi; -# -# # if we have an n- or (n-1)-cycle and a 3-cycle, test for An -# if elfound[3] and elfound[4] and n mod 2 <> 0 then -# for a in g4 do # choose a 3-cycle -# i := 1 + Int(n/3); -# while N > 0 and i > 0 do -# i := i-1; -# c := a^PseudoRandom(grp); -# # 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 -# # a is not a 3-cycle -# Info( InfoRecSnAn, 2, "a is not a 3-cycle"); -# RemoveElmList(g4,Position(g4,a)); -# if Length(g4)=0 then elfound[4]:=false;fi; -# i := 0; -# else -# for b in g3 do # choose an n- or (n-1)-cycle -# if not(RecSnAnIsOne(Comm(c,c^b))) then -# # hope: supp (c) = {1,2,k} -# t := c*c^b; -# if RecSnAnEq(t^2,t) then -# # k = 3 -# x := c^(b^2); -# y := c^x; -# if RecSnAnIsOne(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 -# # 5 <= k <= n -2 -# x := c^b; -# y := c^x; -# if RecSnAnIsOne(Comm(y,y^b)) then -# # y = (1,3,k) hence c = (1,2,k) -# h := Comm(c^2, x); -# else -# h := Comm(c,x^2); -# fi; -# else -# # k= 4, n-1 -# x := c^b; -# y := c^x; -# if RecSnAnIsOne(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 -# # y = (1,4,5) c = (1,4,2) -# h := Comm(c,x^2); -# elif RecSnAnIsOne((y*y^b)^2) then -# # y = (1, n-1, n) c = (1, n-1, 2) -# h := Comm(c,x^2); -# else -# # y = (1,3,4) c = ( 1,2,4) -# h := Comm(c^2,x); -# fi; -# fi; -# -# g := b * h^2; -# -# if SatisfiesAnPresentation( n, g, h ) then -# Info( InfoRecSnAn, 1, -# "Group satisfies presentation for An ",N); -# return [ g, h, "An" ]; -# else -# RemoveElmList(g3,Position(g3,b)); -# if Length(g3)=0 then elfound[3]:=false;fi; -# fi; -# fi; -# od; # for b in g3 -# fi; -# od; # while -# od; # for a in g4 -# fi; -# -# # if we have an n- or (n-1)-cycle and a 3-cycle, test for An -# if elfound[3] and elfound[4] and n mod 2 = 0 then -# for a in g4 do -# i := Int(2 * n/3); -# while N > 0 and i > 0 do -# i := i-1; -# c := a^PseudoRandom(grp); -# # 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 -# # a is not a 3-cycle -# Info( InfoRecSnAn, 2, "a is not a 3-cycle"); -# RemoveElmList(g4,Position(g4,a)); -# if Length(g4)=0 then elfound[4]:=false;fi; -# 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 -# # 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 -# Info( InfoRecSnAn, 1, -# "Group satisfies presentation for An ", N); -# return [ g, h, "An" ]; -# else -# RemoveElmList(g3,Position(g3,b)); -# if Length(g3)=0 then elfound[3]:=false;fi; -# fi; -# fi; -# od; -# fi; -# od; # while -# od; # for a in g4 -# fi; -# -# od; # loop over random elements -# -# return fail; -# -# end; - - Binary := function( i, m ) local j, bin, le; bin := []; @@ -1376,69 +1112,333 @@ end; # ## # ## The main function. # -# # FIXME: dead code? (it's callers are all dead) -# RecogniseSnAn := function( n, grp, eps ) +# # 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; +# +# +# NiceGeneratorsSnAn := function ( n, grp, N ) +# +# local AddStack, g1, g2, g3, g4, g, h, a, b, c, t, i, k, l, +# delta, elfound, m, x, y; +# +# # we put the elements that we look for on stacks +# AddStack := function( stk, e ) +# if Length(stk) = 0 then +# stk[1] := e; +# elif Length(stk) = 1 then +# stk[2] := e; +# else +# stk[1] := stk[2]; +# stk[2] := e; +# fi; +# end; +# +# elfound := [false, false, false, false]; +# +# delta := 1 - (n mod 2); +# +# l := One(grp); +# +# m := n mod 6; +# if m = 0 then k := 5; +# elif m = 1 then k := 6; +# elif m = 2 or m = 4 then k := 3; +# elif m = 3 or m = 5 then k := 4; +# fi; +# +# g1 := []; # $n$-cycles +# g2 := []; # transpositions +# g3 := []; # $n$ or $n-1$-cycles +# g4 := []; # 3-cycles +# +# while N > 0 do +# N := N - 1; +# t := PseudoRandom(grp); +# +# # 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 +# # a is not a transposition +# Info( InfoRecSnAn, 2, "a is not a transposition"); +# RemoveElmList(g2,Position(g2,a)); +# if Length(g2) = 0 then elfound[2] := false; fi; +# fi; +# od; +# +# # 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 +# # a is not a 3-cycle +# Info( InfoRecSnAn, 2, "a is not a 3-cycle"); +# RemoveElmList(g4,Position(g4,a)); +# if Length(g4) = 0 then elfound[4] := false; fi; +# fi; +# od; +# +# if not(RecSnAnIsOne(t)) and RecSnAnIsOne(t^n) then +# # we hope we found an n-cycle +# AddStack(g1,t); +# elfound[1] := true; +# Info( InfoRecSnAn, 2, "found n-cycle"); +# if delta = 0 then +# elfound[3] := true; +# AddStack(g3,t); +# fi; +# fi; # -# local N, gens, le, g, h, slp, gl, b, eval, xis; +# b := t^(n-2-delta); +# if not(RecSnAnIsOne(b)) and RecSnAnIsOne(b^2) then +# # we hope we found a 2(n-2)-cycle +# AddStack(g2,b); +# elfound[2] := true; +# Info( InfoRecSnAn, 2, "found transposition"); +# fi; # -# le := 0; -# while 2^le < eps^-1 do -# le := le + 1; -# od; +# if delta = 1 and not(RecSnAnIsOne(t)) and RecSnAnIsOne(t^(n-1)) then +# # we hope we found an n or (n-1)-cycle +# AddStack(g3,t); +# elfound[3] := true; +# Info( InfoRecSnAn, 2, "found (n-1)-cycle"); +# fi; # -# #N := Int(24 * (4/3)^3 * le * 6 * n); -# N := 20 * n; +# b := t^(n-k); +# if not(RecSnAnIsOne(b)) and RecSnAnIsOne(b^3) then +# # we hope we found a 3(n-k)-element +# AddStack(g4,b); +# elfound[4] := true; +# Info( InfoRecSnAn, 2, "found 3-cycle"); +# fi; # -# gens := NiceGeneratorsSnAn( n, grp, N ); -# if gens = fail then return fail; fi; +# # if we have an n-cycle and a transposition, test for Sn +# if elfound[1] and elfound[2] then +# # hopefully $g2\lambda$ is a transposition +# for a in g2 do # choose a transposition +# i := n-1; +# while N>0 and i>0 do # take up to n-1 conjugates, +# # check if they match some n-cycle +# i := i-1; +# h := a^PseudoRandom(grp); +# # 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 +# # a is not a transposition +# Info(InfoRecSnAn,2,"a is not a transposition"); +# RemoveElmList(g2,Position(g2,a)); +# if Length(g2) = 0 then elfound[2] := false; fi; +# i := 0; +# 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 +# Info(InfoRecSnAn,1,"found good transposition"); +# if SatisfiesSnPresentation( n, b, h ) then +# Info( InfoRecSnAn, 1, +# "Group satisfies presentation for Sn ",N); +# return [ b, h, "Sn" ]; +# else +# RemoveElmList(g1,Position(g1,b)); +# if Length(g1)=0 then elfound[1]:=false;fi; +# fi; +# fi; +# od; #for +# fi; +# od; # while +# od; # for a in g2 +# 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; +# # if we have an n- or (n-1)-cycle and a 3-cycle, test for An +# if elfound[3] and elfound[4] and n mod 2 <> 0 then +# for a in g4 do # choose a 3-cycle +# i := 1 + Int(n/3); +# while N > 0 and i > 0 do +# i := i-1; +# c := a^PseudoRandom(grp); +# # 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 +# # a is not a 3-cycle +# Info( InfoRecSnAn, 2, "a is not a 3-cycle"); +# RemoveElmList(g4,Position(g4,a)); +# if Length(g4)=0 then elfound[4]:=false;fi; +# i := 0; +# else +# for b in g3 do # choose an n- or (n-1)-cycle +# if not(RecSnAnIsOne(Comm(c,c^b))) then +# # hope: supp (c) = {1,2,k} +# t := c*c^b; +# if RecSnAnEq(t^2,t) then +# # k = 3 +# x := c^(b^2); +# y := c^x; +# if RecSnAnIsOne(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 +# # 5 <= k <= n -2 +# x := c^b; +# y := c^x; +# if RecSnAnIsOne(Comm(y,y^b)) then +# # y = (1,3,k) hence c = (1,2,k) +# h := Comm(c^2, x); +# else +# h := Comm(c,x^2); +# fi; +# else +# # k= 4, n-1 +# x := c^b; +# y := c^x; +# if RecSnAnIsOne(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 +# # y = (1,4,5) c = (1,4,2) +# h := Comm(c,x^2); +# elif RecSnAnIsOne((y*y^b)^2) then +# # y = (1, n-1, n) c = (1, n-1, 2) +# h := Comm(c,x^2); +# else +# # y = (1,3,4) c = ( 1,2,4) +# h := Comm(c^2,x); +# fi; +# fi; # -# return ["An", [gens[1],gens[2]], xis]; -# fi; +# g := b * h^2; +# +# if SatisfiesAnPresentation( n, g, h ) then +# Info( InfoRecSnAn, 1, +# "Group satisfies presentation for An ",N); +# return [ g, h, "An" ]; +# else +# RemoveElmList(g3,Position(g3,b)); +# if Length(g3)=0 then elfound[3]:=false;fi; +# fi; +# fi; +# od; # for b in g3 +# fi; +# od; # while +# od; # for a in g4 +# fi; +# +# # if we have an n- or (n-1)-cycle and a 3-cycle, test for An +# if elfound[3] and elfound[4] and n mod 2 = 0 then +# for a in g4 do +# i := Int(2 * n/3); +# while N > 0 and i > 0 do +# i := i-1; +# c := a^PseudoRandom(grp); +# # 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 +# # a is not a 3-cycle +# Info( InfoRecSnAn, 2, "a is not a 3-cycle"); +# RemoveElmList(g4,Position(g4,a)); +# if Length(g4)=0 then elfound[4]:=false;fi; +# 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 +# # 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 +# Info( InfoRecSnAn, 1, +# "Group satisfies presentation for An ", N); +# return [ g, h, "An" ]; +# else +# RemoveElmList(g3,Position(g3,b)); +# if Length(g3)=0 then elfound[3]:=false;fi; +# fi; +# fi; +# od; +# fi; +# od; # while +# od; # for a in g4 +# fi; +# +# od; # loop over random elements +# +# return fail; # # end; From afea5256d099d2a9557972c7df3f92b93610bc5f Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 16:23:23 +0200 Subject: [PATCH 03/64] Remove duplicate code from gap/SnAnBB.gi Namely the functions SLPforAn and SLPforSn. They are already contained in giant.gi. --- gap/SnAnBB.gi | 203 -------------------------------------------------- 1 file changed, 203 deletions(-) diff --git a/gap/SnAnBB.gi b/gap/SnAnBB.gi index ff1051df5..c4c44bcff 100644 --- a/gap/SnAnBB.gi +++ b/gap/SnAnBB.gi @@ -900,209 +900,6 @@ FindImageAn := function( n, z, g, h, xis, xisl ) 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; From 5b91908d1349131aee6eebb1b29332777e69c8ca Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 16:24:43 +0200 Subject: [PATCH 04/64] Update SnAnBB.gi Remove the InfoClass `InfoRecSnAn`. Remove the global variables `RecSnAnIsOne` and `RecSnAnEq`. Instead add `ri` as additional argument to all functions and use `isone(ri)` and `iseq(ri)`. Prefix all functions with `RECOG.` --- gap/SnAnBB.gi | 237 +++++++++++++++++++------------------------------- 1 file changed, 89 insertions(+), 148 deletions(-) diff --git a/gap/SnAnBB.gi b/gap/SnAnBB.gi index c4c44bcff..9faff0f10 100644 --- a/gap/SnAnBB.gi +++ b/gap/SnAnBB.gi @@ -18,101 +18,64 @@ ## 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 ) - +RECOG.SatisfiesSnPresentation := function(ri, n, r, s) local j, t; - - Info( InfoRecSnAn, 1, "calling Satisfies Sn Presentation"); - - if not(RecSnAnIsOne((r * s)^(n-1))) then - Info( InfoRecSnAn, 1, "does not satisfy presentation -1"); + 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 RecSnAnIsOne(Comm(s,t)^2) then - Info( InfoRecSnAn, 1, "does not satisfy presentation"); + if not isone(ri)(Comm(s,t)^2) then return false; fi; j := j + 1; od; - - Info( InfoRecSnAn, 1, "satisfies Sn presentation"); return true; - end; +RECOG.SatisfiesAnPresentation := function(ri, s, t, n) + local j, r, ti, tr; -## is in A_n - -SatisfiesAnPresentation := function( n, s, t ) - - local j, r, ti; - - Info( InfoRecSnAn, 1, "calling Satisfies An Presentation"); - - if not(RecSnAnIsOne(s^(n-2))) or not(RecSnAnIsOne(t^3)) then - Info( InfoRecSnAn, 1, "does not satisfy presentation-1"); + if not isone(ri)(s^(n-2)) or not isone(ri)(t^3) then return false; fi; - if n mod 2 <> 0 then + if IsOddInt(n) then # we already know s^(n-2) = t^3 = 1 - if not(RecSnAnIsOne((s * t)^n)) then - Info( InfoRecSnAn, 1, "does not satisfy presentation"); + if not isone(ri)((s * t)^n) then 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"); + 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; - j := j + 1; od; return true; 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"); + 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; - 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"); + 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; - -Binary := function( i, m ) +RECOG.Binary := function( i, m ) local j, bin, le; bin := []; for j in [ 1 .. m ] do @@ -125,9 +88,7 @@ Binary := function( i, m ) return bin; end; - -ConstructXiSn := function( n, g, h ) - +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 ); @@ -167,7 +128,7 @@ ConstructXiSn := function( n, g, h ) conj := conj * q4; pow := pow * g4; fi; - b := Binary(i, m); + b := RECOG.Binary(i, m); for j in [1 .. m] do if b[j] = 1 then xis[j] := xis[j] * a; @@ -200,7 +161,7 @@ ConstructXiSn := function( n, g, h ) conj := conj * q4; pow := pow * g4; fi; - b := Binary(i, m); + b := RECOG.Binary(i, m); for j in [1 .. m] do if b[j] = 1 then xis[j] := xis[j] * a; @@ -228,11 +189,8 @@ ConstructXiSn := function( n, g, h ) end; - ## Test whether i^z = j - -IsImagePoint := function ( n, z, g, h, j, t1z, t2z ) - +RECOG.IsImagePointSn := function(ri, n, z, g, h, j, t1z, t2z) local s, k, cnt, gj; gj := g^(j-3); @@ -244,7 +202,7 @@ IsImagePoint := function ( n, z, g, h, j, t1z, t2z ) cnt := 0; for k in [ 1 .. 4 ] do - if not RecSnAnEq(t1z*s[k],s[k]*t1z) then + if not isequal(ri)(t1z*s[k],s[k]*t1z) then cnt := cnt + 1; fi; od; @@ -252,7 +210,7 @@ IsImagePoint := function ( n, z, g, h, j, t1z, t2z ) cnt := 0; for k in [ 1 .. 4 ] do - if not RecSnAnEq(t2z*s[k],s[k]*t2z) then + if not isequal(ri)(t2z*s[k],s[k]*t2z) then cnt := cnt + 1; fi; od; @@ -262,12 +220,8 @@ IsImagePoint := function ( n, z, g, h, j, t1z, t2z ) 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 ) - +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; @@ -287,10 +241,10 @@ FindImageSn := function( n, z, g, h, xis, xisl ) 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 + 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 RecSnAnEq(tz[lp1]*xis[j],xis[j]*tz[lp1]) then + 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 @@ -298,10 +252,10 @@ FindImageSn := function( n, z, g, h, xis, xisl ) 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 + 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 RecSnAnEq(tz[lp1]*xis[j+m],xis[j+m]*tz[lp1]) then + 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 @@ -321,7 +275,7 @@ FindImageSn := function( n, z, g, h, xis, xisl ) 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) + 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; @@ -341,7 +295,7 @@ FindImageSn := function( n, z, g, h, xis, xisl ) if RemInt(n,3) = 2 then sup := Difference([1..n],zim); - if IsImagePoint(n,z,g,h,sup[1],(h^(g^(-1)))^z, + if RECOG.IsImagePointSn(ri, n,z,g,h,sup[1],(h^(g^(-1)))^z, (h^(g^(-2)))^z ) then zim[n] := sup[1]; else @@ -353,12 +307,9 @@ FindImageSn := function( n, z, g, h, xis, xisl ) if Length(Set(zim)) <> n then return fail; fi; return PermList(zim); - end; - -ConstructXiAn := function( n, g, h ) - +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; @@ -436,7 +387,7 @@ ConstructXiAn := function( n, g, h ) xis[2*m+6] := xis[2*m+6] * b3; Add(xisl[2*m+6], [5*i-4,5*i-3,5*i,5*i+1,5*i+5] ); fi; - b := Binary(i, m); + b := RECOG.Binary(i, m); for j in [1 .. m] do if b[j] = 1 then xis[j] := xis[j] * anew; @@ -514,7 +465,7 @@ ConstructXiAn := function( n, g, h ) xis[2*m+7] := xis[2*m+7] * b3; Add(xisl[2*m+7], [5*i-4,5*i-3,5*i,5*i+1,5*i+5] ); fi; - b := Binary(i, m); + b := RECOG.Binary(i, m); for j in [1 .. m] do if b[j] = 1 then xis[j] := xis[j] * anew; @@ -607,7 +558,7 @@ ConstructXiAn := function( n, g, h ) a3 := a3^cyc10; b3 := b3^cyc10; fi; - b := Binary(i, m); + b := RECOG.Binary(i, m); for j in [1 .. m] do if b[j] = 1 then xis[j] := xis[j] * anew; @@ -690,7 +641,7 @@ ConstructXiAn := function( n, g, h ) a3 := a3^cyc10; b3 := b3^cyc10; fi; - b := Binary(i, m); + b := RECOG.Binary(i, m); for j in [1 .. m] do if b[j] = 1 then xis[j] := xis[j] * anew; @@ -716,14 +667,10 @@ ConstructXiAn := function( n, g, h ) xisl := List(xisl, z->Union(z)); return [xis,xisl]; - end; - # Test whether i^z = j - -IsImagePointAn := function ( n, z, g, h, j, s, a, b, t1z, t2z ) - +RECOG.IsImagePointAn := function(ri, n, z, g, h, j, s, a, b, t1z, t2z) local sc, k, cnt, bj; sc := ShallowCopy(s); @@ -740,7 +687,7 @@ IsImagePointAn := function ( n, z, g, h, j, s, a, b, t1z, t2z ) cnt := 0; for k in [ 1 .. 5 ] do - if not RecSnAnEq(t1z*sc[k],sc[k]*t1z) then + if not isequal(ri)(t1z*sc[k],sc[k]*t1z) then cnt := cnt + 1; fi; od; @@ -748,21 +695,16 @@ IsImagePointAn := function ( n, z, g, h, j, s, a, b, t1z, t2z ) cnt := 0; for k in [ 1 .. 5 ] do - if not RecSnAnEq(t2z*sc[k],sc[k]*t2z) then + 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 - -FindImageAn := function( n, z, g, h, xis, xisl ) - +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; @@ -820,28 +762,28 @@ FindImageAn := function( n, z, g, h, xis, xisl ) mxj := xisl[j]; mxjpm := xisl[j+m]; while d <= 10 do - if RecSnAnEq(tdz[d]*xis[j],xis[j]*tdz[d]) then + 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 RecSnAnEq(tdz[k[jj]]*xis[j],xis[j]*tdz[k[jj]]) then + 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 RecSnAnEq(tdz[d]*xis[j+m],xis[j+m]*tdz[d]) then + 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 RecSnAnEq(tdz[k[jj]]*xis[j+m],xis[j+m]*tdz[k[jj]]) then + 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); @@ -860,7 +802,7 @@ FindImageAn := function( n, z, g, h, xis, xisl ) 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, + 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; @@ -886,7 +828,7 @@ FindImageAn := function( n, z, g, h, xis, xisl ) 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, + 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]); @@ -926,24 +868,24 @@ end; # if gens = fail then return fail; fi; # # if gens[3] = "Sn" then -# xis := ConstructXiSn( n, gens[1], gens[2] ); +# xis := RECOG.ConstructXiSn( n, gens[1], gens[2] ); # for g in GeneratorsOfGroup(grp) do -# gl := FindImageSn( n, g, gens[1], gens[2], xis[1], xis[2] ); +# gl := RECOG.FindImageSn( n, g, gens[1], gens[2], xis[1], xis[2] ); # if gl = fail then return fail; fi; -# slp := SLPforSn( n, gl ); +# slp := RECOG.SLPforSn( n, gl ); # eval := ResultOfStraightLineProgram(slp, [gens[2],gens[1]]); -# if not RecSnAnEq(eval,g) then return fail; fi; +# if not isequal(ri)(eval,g) then return fail; fi; # od; # return [ "Sn", [gens[1],gens[2]], xis ]; # else -# xis := ConstructXiAn( n, gens[1], gens[2] ); +# xis := RECOG.ConstructXiAn( n, gens[1], gens[2] ); # for g in GeneratorsOfGroup(grp) do -# gl := FindImageAn( n, g, gens[1], gens[2], xis[1], xis[2] ); +# 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 := SLPforAn( n, (1,2)*gl ); +# slp := RECOG.SLPforAn( n, (1,2)*gl ); # eval:=ResultOfStraightLineProgram(slp,[gens[2],gens[1]]); # h := eval * g^-1; # if n mod 2 <> 0 then @@ -951,23 +893,23 @@ end; # else # b := h * gens[1] * gens[2]; # fi; -# if SatisfiesSnPresentation( n, b, h ) then -# xis := ConstructXiSn( n, b, h ); +# if RECOG.SatisfiesSnPresentation( n, b, h ) then +# xis := RECOG.ConstructXiSn( n, b, h ); # for g in GeneratorsOfGroup(grp) do -# gl := FindImageSn(n,g,b,h,xis[1],xis[2] ); +# gl := RECOG.FindImageSn(n,g,b,h,xis[1],xis[2] ); # if gl = fail then return fail; fi; -# slp := SLPforSn(n, gl); +# slp := RECOG.SLPforSn(n, gl); # eval := ResultOfStraightLineProgram(slp,[h,b]); -# if not RecSnAnEq(eval,g) then return fail; fi; +# if not isequal(ri)(eval,g) then return fail; fi; # od; # return [ "Sn", [b,h] ,xis ]; # else # return fail; # fi; # else -# slp := SLPforAn( n, gl ); +# slp := RECOG.SLPforAn( n, gl ); # eval:=ResultOfStraightLineProgram(slp,[gens[2],gens[1]]); -# if not RecSnAnEq(eval,g) then return fail; fi; +# if not isequal(ri)(eval,g) then return fail; fi; # fi; # od; # @@ -976,7 +918,6 @@ end; # # end; # -# # NiceGeneratorsSnAn := function ( n, grp, N ) # # local AddStack, g1, g2, g3, g4, g, h, a, b, c, t, i, k, l, @@ -1019,8 +960,8 @@ end; # # 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)); @@ -1031,8 +972,8 @@ end; # # 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)); @@ -1040,7 +981,7 @@ end; # 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; @@ -1052,14 +993,14 @@ end; # 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; @@ -1067,7 +1008,7 @@ end; # 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; @@ -1086,8 +1027,8 @@ end; # # 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)); @@ -1096,10 +1037,10 @@ end; # 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" ]; @@ -1124,8 +1065,8 @@ end; # # 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)); @@ -1133,25 +1074,25 @@ end; # 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 @@ -1161,13 +1102,13 @@ end; # # 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 @@ -1178,7 +1119,7 @@ end; # # 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" ]; @@ -1203,8 +1144,8 @@ end; # # 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)); @@ -1212,14 +1153,14 @@ end; # 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" ]; From d1fb7863c1f51f986e0f5a76e58a6b011a635e57 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 16:52:53 +0200 Subject: [PATCH 05/64] Rename gap/tools.gi -> gap/utils.gi --- gap/{tools.gi => utils.gi} | 0 read.g | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename gap/{tools.gi => utils.gi} (100%) diff --git a/gap/tools.gi b/gap/utils.gi similarity index 100% rename from gap/tools.gi rename to gap/utils.gi diff --git a/read.g b/read.g index bcadc84f5..996bd2255 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"); From e6cc378ee67e891954de0b6cb8cfc80579135476 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 16:53:24 +0200 Subject: [PATCH 06/64] Add a prime sieve algorithm --- gap/utils.gi | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/gap/utils.gi b/gap/utils.gi index dabe63887..e9af3a5ba 100644 --- a/gap/utils.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; + From 8b145e3c1bd98d6a91774ca55fe2bf6a71cabec7 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Thu, 18 Jun 2020 14:02:02 +0200 Subject: [PATCH 07/64] Start SnAnUnknownDegree.gi --- gap/SnAnUnknownDegree.gd | 3 + gap/SnAnUnknownDegree.gi | 275 ++++++++++++++++++++++++++++++++++++++ gap/SnAnUnknownDegree.tst | 69 ++++++++++ init.g | 2 + read.g | 1 + 5 files changed, 350 insertions(+) create mode 100644 gap/SnAnUnknownDegree.gd create mode 100644 gap/SnAnUnknownDegree.gi create mode 100644 gap/SnAnUnknownDegree.tst diff --git a/gap/SnAnUnknownDegree.gd b/gap/SnAnUnknownDegree.gd new file mode 100644 index 000000000..ae696227c --- /dev/null +++ b/gap/SnAnUnknownDegree.gd @@ -0,0 +1,3 @@ +DeclareGlobalName("ThreeCycleCandidates"); +DeclareGlobalName("BolsteringElements"); +DeclareGlobalName("IsFixedPoint"); diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi new file mode 100644 index 000000000..d2127f8c3 --- /dev/null +++ b/gap/SnAnUnknownDegree.gi @@ -0,0 +1,275 @@ +# Input: Group G, upper error bound eps, upper degree bound N +# +# 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. +# +# Either returns a list of elements of G or NeverApplicable +# TODO: Rewrite this to a kind of iterator function since each candidate is tested one by one +BindGlobal("ThreeCycleCandidates", +function(G, eps, N, groupIsOne, groupIsEq) + local + # list, a set of three cycle candidates + threeCycleCandidates, + # list, a set of involutions + involutions, + # integers, number of iterations + M,B,T,C, + # integer, prime, loop variable + p, + # integer, loop variable + i,a, + # elements, in G + r,t,tPower,tPowerOld,c, + # integer, max power we need to consider in 3. Step + maxPower, + # integer, loop variables in 4. Step + nrNewCandidates, nrIterations; + # 1. Step + # TODO: better iteration over primes + M := 1; + p := 3; + while p <= N do + M := M * p ^ LogInt(N, p); + p := NextPrimeInt(p); + od; + B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))); + T := Int(Ceil(3 * Log2(3 / Float(eps)))); + C := Int(Ceil(Float(3 * N * T / 5))); + # 2. + 3. Step + # construct involutions + involutions := []; + maxPower := LogInt(N, 2); + for i in [1 .. B] do + r := PseudoRandom(G); + t := r^M; + a := 0; + tPower := t; + # invariant: tPower = t ^ (2 ^ a) + repeat + a := a + 1; + tPowerOld := tPower; + tPower := tPower ^ 2; + until a = maxPower or groupIsOne(tPower); + if a = maxPower then + return NeverApplicable; + fi; + Add(involutions, tPowerOld); + od; + # 4. + 5. Step + # use the observation described in the comment above this function to + # generate candidate for three-cycles from the involutions. + threeCycleCandidates := []; + for t in involutions do + nrNewCandidates := 0; + nrIterations := 0; + while nrIterations < C and nrNewCandidates < T do + c := t ^ PseudoRandom(G); + # TODO: form a set. Can we assume that group elements have an + # ordering and simply call Set? Benchmark this with groups that are + # so small that we possibly generate lots of the same elements. + if not groupIsEq(t * c, c * t) then + Add(threeCycleCandidates, (t * c) ^ 2); + nrNewCandidates := nrNewCandidates + 1; + fi; + nrIterations := nrIterations + 1; + od; + od; + return threeCycleCandidates; +end); + +# G: the group to recognize +# c: possibly a 3-cycle +# returns a list of group elements. If G is isomorphic to an alternating or +# symmetric group and c is a 3-cycle, then this function returns a list of +# bolstering elements with respect to c. +BindGlobal("BolsteringElements", +function(G, c, eps, N, groupIsOne, groupIsEq) + local result, R, S, prebolsteringElms, i, r, cr, cr2; + result := []; + R := Int(Ceil(7 / 4 * Log2(Float(eps ^ -1)))); + S := 7 * N * R; + prebolsteringElms := []; + i := 0; + # find pre-bolstering elements + while i <= S and Length(prebolsteringElms) <= R do + r := PseudoRandom(G); + # test whether r is pre-bolstering + cr := c ^ r; + cr2 := c ^ (r ^ 2); + if not groupIsOne(Comm(cr, c)) + and not groupIsEq(cr2, c) + and not groupIsEq(cr2, c ^ 2) + and groupIsOne(Comm(cr2, c)) + then + Add(prebolsteringElms, r); + fi; + i := i + 1; + od; + # construct bolstering elements + for r in prebolsteringElms do + if groupIsOne((c ^ (r * c * r) + * c ^ (r * c ^ (r ^ 2) * c)) ^ 3) + then + Add(result, c ^ 2 * r); + else + Add(result, cr); + fi; + od; + return result; +end); + +# g: a cycle matching c of a group G +# c: a 3-cycle of a group G +# r: arbitrary element of a group G +# The supports of c and c^(g^2) have exactly one point, say alpha, in common. +# Let phi be an isomorphism from G to a natural alternating or symmetric group. +# This function decides whether alpha is a fixed point of phi(r). +BindGlobal("IsFixedPoint", +function(g, c, r, groupIsOne, groupIsEq) + 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 + isElmPassingTest; + # Helper function + isElmPassingTest := function(x, H, groupIsOne) + local nrTrivialComm, h; + nrTrivialComm := 0; + for h in H do + if groupIsOne(Comm(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 elm of the set X commutes with at least + # two elements of H1. + x1 := c ^ r; + if not isElmPassingTest(x1, H1, groupIsOne) then return false; fi; + x2 := cg2 ^ r; + if not isElmPassingTest(x2, H1, groupIsOne) then return false; fi; + x3 := ((cg2 ^ cg3) ^ cg4) ^ r; + if not isElmPassingTest(x3, H1, groupIsOne) 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 isElmPassingTest(x1, H2, groupIsOne) then return false; fi; + if not isElmPassingTest(x2, H2, groupIsOne) then return false; fi; + if not isElmPassingTest(x3, H2, groupIsOne) then return false; fi; + return true; +end); + +# g: a k-cycle matching c of a group G +# c: a 3-cycle of a group G +# r: element of a group G +# W.l.o.g. let g = (1, ..., k) and c = (1, 2, 3). +# If the support of g has at least one point in common with the support of r +# and at least two points of support of g are fixed by r, +# then the algorithm returns a conjugate r^x such that r fixes the points 1, 2 +# but not the point 3. +BindGlobal("AdjustCycle", +function(g, c, r, k, groupIsOne, groupIsEq) + local + # list of 4 booleans, is point j fixed point + F, + # smallest fixed point + f1, + # second smallest fixed point + f2, + # smallest non-fixed point + m, + # integer, loop variable over [1 .. k] + j, + # element of G, loop variable + t, + # conjugating element + x; + F := [false, false, false, false]; + f1 := fail; + f2 := fail; + m := fail; + j := 0; + t := c ^ (g ^ -3); + # invariant: t = c ^ (g ^ (j - 3)) + repeat + j := j + 1; + t := t ^ g; + if IsFixedPoint(g, t, r, groupIsOne, groupIsEq) then + if j <= 4 then + F[j] := true; + fi; + if f1 = fail then + f1 := j; + elif f2 = fail then + f2 := j; + fi; + elif m = fail then + m := j; + fi; + until j >= k or (j >= 4 and f1 <> fail and f2 <> fail and m <> fail); + if f1 = fail or f2 = fail or m =fail then + return fail; + fi; + # case distinction on F as in the table of Algorithm 4.20 + if F[1] then + if F[2] then + if F[3] then + # 1. Case + x := c ^ ((g * c ^ 2) ^ (m - 3) * c) * c; + else + # 2. Case + x := One(c); + fi; + else + if F[3] then + if F[4] then + # 3. Case + x := c ^ g; + else + # 4. Case + x := (c ^ 2) ^ g; + fi; + else + # 5. Case + x := c ^ ((g * c ^ 2) ^ (f2 - 3) * c); + fi; + fi; + else + if F[2] then + if F[4] then + # 6. Case + x := c ^ (c ^ g); + else + if F[3] then + # 7. Case + x := (c ^ 2) ^ (c ^ g); + else + # 8. Case + x := c ^ ((g * c ^ 2) ^ (f2 - 3) * c ^ g); + fi; + fi; + else + if F[3] then + # 9. Case + x := (c ^ 2) ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ 2; + else + # 10. Case + x := c ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ ((g * c ^ 2) ^ (f1 - 3)); + fi; + fi; + fi; + return r^x; +end); diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst new file mode 100644 index 000000000..9920d2ada --- /dev/null +++ b/gap/SnAnUnknownDegree.tst @@ -0,0 +1,69 @@ +#@local testFunction, permToPermMat, degreesToTest, isos; +#@local nonIsomorphicGroups; +#@local g, c, r, i; +# +# 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? +gap> testFunction := function(G, eps, N) +> local C, i; +> C := ThreeCycleCandidates(G, eps, N, IsOne, EQ); +> if C <> NeverApplicable then +> for i in [1 .. 10] do +> BolsteringElements(G, PseudoRandom(C), eps, N, IsOne, EQ); +> od; +> fi; +> end;; +gap> degreesToTest := Concatenation( +> [10, 20, 30, 40, 50, 60, 70], +> Primes{[5 .. 15]} +> );; +# TODO: more non-isomorphic examples +gap> nonIsomorphicGroups := [ +> DihedralGroup(IsPermGroup,10), +> DihedralGroup(IsPcGroup, 10), +> DihedralGroup(IsPermGroup, 2000), +> DihedralGroup(IsPcGroup, 2000), +> SL(3,5), +> ];; +gap> permToPermMat := +> {x, deg, field} +> -> +> ImmutableMatrix(field, PermutationMat(x, deg, field));; +gap> # TODO: use permToPermMat with varying degrees and fields +gap> isos := [];; + + +# ThreeCycleCandidates +gap> for i in [1 .. Length(testGroups)] do +> ThreeCycleCandidates(testGroups[i], 1/100, degrees[i], IsOne, EQ); +> od; + +# BolsteringElements +gap> for i in [1 .. Length(testGroups)] do +> G := testGroups[i]; +> BolsteringElements(G, PseudoRandom(G), 1/100, degrees[i], IsOne, EQ); +> od; + +# IsFixedPoint +gap> g := (1,2,3,4,5,6,7,8);; +gap> c := (1,2,3);; +gap> r := (1,2)(4,5,6);; +gap> IsFixedPoint(g,c,r,IsOne,EQ); +true +gap> r := (2,3,4);; +gap> IsFixedPoint(g,c,r,IsOne,EQ); +false + +# AdjustCycle +gap> g := (1,2,3,4,5,6,7,8);; +gap> c := (1,2,3);; +gap> r := (1,2,3)(5,6);; +gap> AdjustCycle(g, c, r, 8, IsOne, EQ); +(3,4,7)(5,6) diff --git a/init.g b/init.g index 1136ee7ab..ef6ccc4fc 100644 --- a/init.g +++ b/init.g @@ -21,6 +21,8 @@ ReadPackage("recog","gap/base/recognition.gd"); # The following contain generic declarations for different types of groups: ReadPackage("recog","gap/base/projective.gd"); +ReadPackage("recog","gap/SnAnUnknownDegree.gd"); + ReadPackage("recog","gap/matrix.gd"); ReadPackage("recog","gap/matrix/ppd.gd"); diff --git a/read.g b/read.g index 996bd2255..a248bef95 100644 --- a/read.g +++ b/read.g @@ -36,6 +36,7 @@ ReadPackage("recog","gap/generic/KnownNilpotent.gi"); # Permutations: ReadPackage("recog","gap/perm/giant.gi"); ReadPackage("recog","gap/perm/largebase.gi"); +ReadPackage("recog","gap/SnAnUnknownDegree.gi"); # Up to now there is not much here: ReadPackage("recog","gap/SnAnBB.gi"); From 696287a87cc305c80a11965bee5f0d42a86579ff Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Fri, 17 Jul 2020 11:47:09 +0200 Subject: [PATCH 08/64] Make ThreeCycleCandidates an iterator --- gap/SnAnUnknownDegree.gd | 2 +- gap/SnAnUnknownDegree.gi | 152 ++++++++++++++++++++++++-------------- gap/SnAnUnknownDegree.tst | 35 +++++---- 3 files changed, 117 insertions(+), 72 deletions(-) diff --git a/gap/SnAnUnknownDegree.gd b/gap/SnAnUnknownDegree.gd index ae696227c..dbeaef9ac 100644 --- a/gap/SnAnUnknownDegree.gd +++ b/gap/SnAnUnknownDegree.gd @@ -1,3 +1,3 @@ -DeclareGlobalName("ThreeCycleCandidates"); +DeclareGlobalName("ThreeCycleCandidatesIterator"); DeclareGlobalName("BolsteringElements"); DeclareGlobalName("IsFixedPoint"); diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index d2127f8c3..75a7fee4c 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -4,28 +4,30 @@ # on the simple observation that the product of two involutions t1, t2, which # only move one common point, squares to a 3-cycle. # -# Either returns a list of elements of G or NeverApplicable -# TODO: Rewrite this to a kind of iterator function since each candidate is tested one by one -BindGlobal("ThreeCycleCandidates", -function(G, eps, N, groupIsOne, groupIsEq) +# TODO: take care of duplicate candidates? +# 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 +BindGlobal("ThreeCycleCandidatesIterator", + function(G, eps, N, groupIsOne, groupIsEq) local - # list, a set of three cycle candidates - threeCycleCandidates, - # list, a set of involutions - involutions, - # integers, number of iterations - M,B,T,C, + # involution + t, + # integers, controlling the number of iterations + M, B, T, C, logInt2N, # integer, prime, loop variable p, - # integer, loop variable - i,a, - # elements, in G - r,t,tPower,tPowerOld,c, - # integer, max power we need to consider in 3. Step - maxPower, - # integer, loop variables in 4. Step - nrNewCandidates, nrIterations; - # 1. Step + # counters + nrInvolutions, nrTriedConjugates, nrThreeCycleCandidates, + # helper functions + tryThreeCycleCandidate, oneThreeCycleCandidate; + # Step 1: Initialization + # The current involution t_i + t := fail; + + # Constants # TODO: better iteration over primes M := 1; p := 3; @@ -36,46 +38,82 @@ function(G, eps, N, groupIsOne, groupIsEq) B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))); T := Int(Ceil(3 * Log2(3 / Float(eps)))); C := Int(Ceil(Float(3 * N * T / 5))); - # 2. + 3. Step - # construct involutions - involutions := []; - maxPower := LogInt(N, 2); - for i in [1 .. B] do - r := PseudoRandom(G); - t := r^M; - a := 0; - tPower := t; - # invariant: tPower = t ^ (2 ^ a) - repeat - a := a + 1; - tPowerOld := tPower; - tPower := tPower ^ 2; - until a = maxPower or groupIsOne(tPower); - if a = maxPower then - return NeverApplicable; + logInt2N := LogInt(N, 2); + + # 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 + # - 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 := PseudoRandom(G); + a := 0; + tPower := r ^ M; + # Invariant: tPower = (r ^ M) ^ (2 ^ a) + repeat + a := a + 1; + tPowerOld := tPower; + tPower := tPower ^ 2; + until a = logInt2N or groupIsOne(tPower); + if a = logInt2N then + return NeverApplicable; + fi; + t := tPowerOld; + nrInvolutions := nrInvolutions + 1; + nrTriedConjugates := 0; + nrThreeCycleCandidates := 0; fi; - Add(involutions, tPowerOld); - od; - # 4. + 5. Step - # use the observation described in the comment above this function to - # generate candidate for three-cycles from the involutions. - threeCycleCandidates := []; - for t in involutions do - nrNewCandidates := 0; - nrIterations := 0; - while nrIterations < C and nrNewCandidates < T do - c := t ^ PseudoRandom(G); - # TODO: form a set. Can we assume that group elements have an - # ordering and simply call Set? Benchmark this with groups that are - # so small that we possibly generate lots of the same elements. - if not groupIsEq(t * c, c * t) then - Add(threeCycleCandidates, (t * c) ^ 2); - nrNewCandidates := nrNewCandidates + 1; + # 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 ^ PseudoRandom(G); + if not groupIsEq(t * c, c * t) then + nrThreeCycleCandidates := nrThreeCycleCandidates + 1; + return (t * c) ^ 2; + else + return fail; + fi; + end; + # construct the iterator + oneThreeCycleCandidate := function() + local candidate; + repeat + if nrInvolutions >= B + and (nrTriedConjugates >= C or nrThreeCycleCandidates >= T) + then + # We are done and were not able to recognize Sn or An. + return TemporaryFailure; fi; - nrIterations := nrIterations + 1; - od; - od; - return threeCycleCandidates; + candidate := tryThreeCycleCandidate(); + if candidate = NeverApplicable then + return NeverApplicable; + fi; + until candidate <> fail; + return candidate; + end; + return oneThreeCycleCandidate; end); # G: the group to recognize diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index 9920d2ada..a00059f77 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -1,6 +1,6 @@ -#@local testFunction, permToPermMat, degreesToTest, isos; -#@local nonIsomorphicGroups; -#@local g, c, r, i; +#@local testFunction, degreesToTest, permToPermMat, isos +#@local altAndSymGroups, nonAltOrSymGroups +#@local g, c, r, i # # testing matrix: # - isomorphic: yes, no @@ -13,36 +13,43 @@ # TODO: Use RECOG.TestGroup? gap> testFunction := function(G, eps, N) > local C, i; -> C := ThreeCycleCandidates(G, eps, N, IsOne, EQ); -> if C <> NeverApplicable then +> iterator := ThreeCycleCandidatesIterator(G, eps, N, IsOne, EQ); +> candidate := iterator(); +> if candidate <> NeverApplicable then > for i in [1 .. 10] do > BolsteringElements(G, PseudoRandom(C), eps, N, IsOne, EQ); > od; > fi; > end;; gap> degreesToTest := Concatenation( -> [10, 20, 30, 40, 50, 60, 70], +> [10, 11, 12, 20, 21, 30, 31, 40, 41, 50, 51], > Primes{[5 .. 15]} > );; # TODO: more non-isomorphic examples -gap> nonIsomorphicGroups := [ +gap> altAndSymGroups := Concatenation( +> List(degrees, AlternatingGroup), +> List(degrees, SymmetricGroup));; +gap> permToPermMat := +> {x, deg, field} +> -> +> ImmutableMatrix(field, PermutationMat(x, deg, field));; +# TODO: add a projective group +gap> nonAltOrSymGroups := [ > DihedralGroup(IsPermGroup,10), > DihedralGroup(IsPcGroup, 10), > DihedralGroup(IsPermGroup, 2000), > DihedralGroup(IsPcGroup, 2000), > SL(3,5), > ];; -gap> permToPermMat := -> {x, deg, field} -> -> -> ImmutableMatrix(field, PermutationMat(x, deg, field));; gap> # TODO: use permToPermMat with varying degrees and fields -gap> isos := [];; - # ThreeCycleCandidates gap> for i in [1 .. Length(testGroups)] do -> ThreeCycleCandidates(testGroups[i], 1/100, degrees[i], IsOne, EQ); +> ThreeCycleCandidatesIterator(testGroups[i], +> 1/100, +> degrees[i], +> IsOne, +> EQ); > od; # BolsteringElements From b6243e727cfd2001b3722bf23af9bfd85a760385 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Thu, 30 Jul 2020 11:43:00 +0200 Subject: [PATCH 09/64] Update SnAnUnknownDegree.gi --- gap/SnAnUnknownDegree.gd | 4 + gap/SnAnUnknownDegree.gi | 364 +++++++++++++++++++++++++++++++++----- gap/SnAnUnknownDegree.tst | 182 ++++++++++++++----- 3 files changed, 460 insertions(+), 90 deletions(-) diff --git a/gap/SnAnUnknownDegree.gd b/gap/SnAnUnknownDegree.gd index dbeaef9ac..6e68c0e64 100644 --- a/gap/SnAnUnknownDegree.gd +++ b/gap/SnAnUnknownDegree.gd @@ -1,3 +1,7 @@ DeclareGlobalName("ThreeCycleCandidatesIterator"); DeclareGlobalName("BolsteringElements"); DeclareGlobalName("IsFixedPoint"); +DeclareGlobalName("AdjustCycle"); +DeclareGlobalName("AppendPoints"); +DeclareGlobalName("BuildCycle"); +DeclareGlobalName("IsElmOfPrimeOrder"); diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 75a7fee4c..a24bb7f84 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -11,7 +11,7 @@ # - TemporaryFailure, if we exhausted all attempts # - NeverApplicable, if we found out that G can't be an Sn or An BindGlobal("ThreeCycleCandidatesIterator", - function(G, eps, N, groupIsOne, groupIsEq) + function(ri, eps, N) local # involution t, @@ -35,6 +35,7 @@ BindGlobal("ThreeCycleCandidatesIterator", M := M * p ^ LogInt(N, p); p := NextPrimeInt(p); od; + # FIXME: Probably B can be chosen smaller B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))); T := Int(Ceil(3 * Log2(3 / Float(eps)))); C := Int(Ceil(Float(3 * N * T / 5))); @@ -67,7 +68,7 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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 := PseudoRandom(G); + r := RandomElm(ri,"simplesocle",true)!.el; a := 0; tPower := r ^ M; # Invariant: tPower = (r ^ M) ^ (2 ^ a) @@ -75,7 +76,7 @@ BindGlobal("ThreeCycleCandidatesIterator", a := a + 1; tPowerOld := tPower; tPower := tPower ^ 2; - until a = logInt2N or groupIsOne(tPower); + until a = logInt2N or isone(ri)(tPower); if a = logInt2N then return NeverApplicable; fi; @@ -88,8 +89,8 @@ BindGlobal("ThreeCycleCandidatesIterator", # Try to construct a three cycle candidate via a conjugate of t. See # the comment above this function. nrTriedConjugates := nrTriedConjugates + 1; - c := t ^ PseudoRandom(G); - if not groupIsEq(t * c, c * t) then + c := t ^ RandomElm(ri,"simplesocle",true)!.el; + if not isequal(ri)(t * c, c * t) then nrThreeCycleCandidates := nrThreeCycleCandidates + 1; return (t * c) ^ 2; else @@ -122,7 +123,7 @@ end); # symmetric group and c is a 3-cycle, then this function returns a list of # bolstering elements with respect to c. BindGlobal("BolsteringElements", -function(G, c, eps, N, groupIsOne, groupIsEq) +function(ri, c, eps, N) local result, R, S, prebolsteringElms, i, r, cr, cr2; result := []; R := Int(Ceil(7 / 4 * Log2(Float(eps ^ -1)))); @@ -131,14 +132,14 @@ function(G, c, eps, N, groupIsOne, groupIsEq) i := 0; # find pre-bolstering elements while i <= S and Length(prebolsteringElms) <= R do - r := PseudoRandom(G); + r := RandomElm(ri,"simplesocle",true)!.el; # test whether r is pre-bolstering cr := c ^ r; cr2 := c ^ (r ^ 2); - if not groupIsOne(Comm(cr, c)) - and not groupIsEq(cr2, c) - and not groupIsEq(cr2, c ^ 2) - and groupIsOne(Comm(cr2, c)) + if not isone(ri)(Comm(cr, c)) + and not isequal(ri)(cr2, c) + and not isequal(ri)(cr2, c ^ 2) + and isone(ri)(Comm(cr2, c)) then Add(prebolsteringElms, r); fi; @@ -146,7 +147,7 @@ function(G, c, eps, N, groupIsOne, groupIsEq) od; # construct bolstering elements for r in prebolsteringElms do - if groupIsOne((c ^ (r * c * r) + if isone(ri)((c ^ (r * c * r) * c ^ (r * c ^ (r ^ 2) * c)) ^ 3) then Add(result, c ^ 2 * r); @@ -164,7 +165,7 @@ end); # Let phi be an isomorphism from G to a natural alternating or symmetric group. # This function decides whether alpha is a fixed point of phi(r). BindGlobal("IsFixedPoint", -function(g, c, r, groupIsOne, groupIsEq) +function(ri, g, c, r) local # respectively c ^ (g ^ i) cg, cg2, cg3, cg4, @@ -173,13 +174,13 @@ function(g, c, r, groupIsOne, groupIsEq) # (sets of) elements of G H1, H2, x1, x2, x3, # helper function - isElmPassingTest; + commutesWithAtMostOne; # Helper function - isElmPassingTest := function(x, H, groupIsOne) + commutesWithAtMostOne := function(ri, x, H) local nrTrivialComm, h; nrTrivialComm := 0; for h in H do - if groupIsOne(Comm(x, h)) then + if isone(ri)(Comm(x, h)) then nrTrivialComm := nrTrivialComm + 1; fi; if nrTrivialComm >= 2 then @@ -196,17 +197,17 @@ function(g, c, r, groupIsOne, groupIsEq) # Test whether an elm of the set X commutes with at least # two elements of H1. x1 := c ^ r; - if not isElmPassingTest(x1, H1, groupIsOne) then return false; fi; + if not commutesWithAtMostOne(ri, x1, H1) then return false; fi; x2 := cg2 ^ r; - if not isElmPassingTest(x2, H1, groupIsOne) then return false; fi; + if not commutesWithAtMostOne(ri, x2, H1) then return false; fi; x3 := ((cg2 ^ cg3) ^ cg4) ^ r; - if not isElmPassingTest(x3, H1, groupIsOne) then return false; fi; + 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 isElmPassingTest(x1, H2, groupIsOne) then return false; fi; - if not isElmPassingTest(x2, H2, groupIsOne) then return false; fi; - if not isElmPassingTest(x3, H2, groupIsOne) then return false; fi; + 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); @@ -219,35 +220,42 @@ end); # then the algorithm returns a conjugate r^x such that r fixes the points 1, 2 # but not the point 3. BindGlobal("AdjustCycle", -function(g, c, r, k, groupIsOne, groupIsEq) +function(ri, g, c, r, k) local # list of 4 booleans, is point j fixed point - F, + 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; - F := [false, false, false, false]; + # According to the paper we have: + # F := { 1 \leq j \leq k | 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; - j := 0; t := c ^ (g ^ -3); - # invariant: t = c ^ (g ^ (j - 3)) - repeat - j := j + 1; + for j in [1 .. k] do + # invariant: t = c ^ (g ^ (j - 3)) t := t ^ g; - if IsFixedPoint(g, t, r, groupIsOne, groupIsEq) then + if IsFixedPoint(ri, g, t, r) then if j <= 4 then - F[j] := true; + F4[j] := true; fi; if f1 = fail then f1 := j; @@ -257,23 +265,31 @@ function(g, c, r, k, groupIsOne, groupIsEq) elif m = fail then m := j; fi; - until j >= k or (j >= 4 and f1 <> fail and f2 <> fail and m <> fail); - if f1 = fail or f2 = fail or m =fail then + # 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; + # 2. Case, 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 - if F[1] then - if F[2] then - if F[3] then - # 1. Case - x := c ^ ((g * c ^ 2) ^ (m - 3) * c) * c; - else - # 2. Case - x := One(c); - fi; + # via a decision tree + if F4[1] then + if F4[2] then + # We are in the 1. Case, since the 2. Case is handled during the + # computation of F4 above. + x := c ^ ((g * c ^ 2) ^ (m - 3) * c) * c; else - if F[3] then - if F[4] then + if F4[3] then + if F4[4] then # 3. Case x := c ^ g; else @@ -286,12 +302,12 @@ function(g, c, r, k, groupIsOne, groupIsEq) fi; fi; else - if F[2] then - if F[4] then + if F4[2] then + if F4[4] then # 6. Case x := c ^ (c ^ g); else - if F[3] then + if F4[3] then # 7. Case x := (c ^ 2) ^ (c ^ g); else @@ -300,7 +316,7 @@ function(g, c, r, k, groupIsOne, groupIsEq) fi; fi; else - if F[3] then + if F4[3] then # 9. Case x := (c ^ 2) ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ 2; else @@ -311,3 +327,255 @@ function(g, c, r, k, groupIsOne, groupIsEq) fi; return r^x; end); + +# g: a k-cycle matching c of a group G +# c: a 3-cycle of a group G +# r: return value of AdjustCycle. If e.g. g = (1, 2, ..., k), then r would be a +# cycle fixing 1 and 2 and moving 3 +# The algorithm AppendPoints 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. +# +# We return a list consisting of: +# - gTilde, the new g +# - sTilde, since we may call AppendPoints several times and may not have used +# the last sTilde. +# - kTilde, the length of gTilde +BindGlobal("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 isone(ri)(Comm(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 +# g : element of a group +# p : prime +# We return true, if g is an element of order p. +BindGlobal("IsElmOfPrimeOrder", +function(ri, g, p) + if not isone(ri)(g) and isone(ri)(g ^ p) then + return true; + else + return false; + fi; +end); + +# c: a 3-cycle of a group G +# x : bolstering element with respect to c +# The algorithm BuildCycle determines a cycle g of length k matching c. +# We return either fail or a list consisting of: +# - g, cycle matching c +# - k, length of cycle g. +BindGlobal("BuildCycle", +function(ri, c, x, N) + local + # Floor(N / 2) + N2, + # min(alpha, beta) + m, + # d = c ^ (x ^ (m + 1)) + d, + # y = c * c ^ x * c ^ (x ^ 2) * ... * c ^ (x ^ m) + y, + # is false, if m >= N/2 + isMinInitialized, + # dx = d ^ x = c ^ (x ^ (m + 2)) + dx, + # element defined as in the case distinction + e, + # d ^ e + z, + # z ^ (x ^ 2 * (mDash - 1)) + zxMinus, + # z ^ (x ^ 2 * (mDash)) + zx, + # z ^ (x ^ 2 * (mDash + 1)) + zxPlus, + # integer computed as in Remark 4.9 + mDash, + # cycle matching c + g; + # Here we set m := 0 + N2 := Int(Floor(Float(N) / 2.)); + y := c; + d := c ^ x; + isMinInitialized := false; + for m in [1 .. N2] do + y := y * d; + d := d ^ x; + if not IsElmOfPrimeOrder(ri, d * c, 5) then + isMinInitialized := true; + break; + fi; + od; + if not isMinInitialized 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 IsElmOfPrimeOrder(ri, dx * c, 5) then + return [y, 2 * m + 3]; + fi; + # Case |alpha - beta| >= 2 + # Case distinction on element e + if IsElmOfPrimeOrder(ri, d * c, 2) then + # w not in v ^ + if isone(ri)(Comm(dx, d ^ c)) then + # Case 4, alpha < beta + e := (d ^ (x * c)) ^ 2; + else + # Case 3, alpha > beta + e := d ^ (x * c ^ 2); + fi; + else + # w in v ^ + if isone(ri)(Comm(dx, d ^ c)) then + # Case 1, alpha > beta + e := d ^ (x * c); + else + # Case 2, alpha < beta + e := (d ^ (x * c ^ 2)) ^ 2; + fi; + fi; + z := d ^ e; + # Here we set mDash := 1 + zxMinus := z; + zx := zxMinus ^ (x ^ 2); + zxPlus := zx ^ (x ^ 2); + g := y * zxMinus; + for mDash in [1 .. N2] do + if not IsElmOfPrimeOrder(ri, zxPlus, 5) then + return [g, 2 * mDash + 2 * m + 3]; + fi; + zxMinus := zx; + zx := zxPlus; + zxPlus := zxPlus ^ (x ^ 2); + g := y * zxMinus; + od; + # mDash >= N / 2 + return fail; +end); + +# ri : recog info record +# c : three-cycle +# eps : error probability +# N : upper bound for degree of the group +# We return either fail or a list consisting of: +# - g, cycle matching c +# - k, length of cycle g. +BindGlobal("ConstructLongCycle", +function(ri, c, eps, N) + local g, k, tmp, B, x; + B := 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 := 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 +# g : cycle matching c +# c : three-cycle +BindGlobal("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,"simplesocle",true)!.el; + m := AdjustCycle(ri, gTilde, c, x, kTilde); + if m = fail then return fail; fi; + tmp := 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 SatisfiesAnPresentation(ri, gTilde, cTilde, kTilde) then + return [gTilde, cTilde, kTilde]; + else + return fail; + fi; +end); + +# UNFINISHED +# currently returns standard gens of An +BindGlobal("RecogniseSnAn", +function(ri, eps, N) + local T, c, tmp, g, k, n, iterator; + T := Int(Ceil(Log(1 / Float(eps)))); + repeat + T := T - 1; + iterator := ThreeCycleCandidatesIterator(ri, eps, N); + c := iterator(); + while c <> TemporaryFailure do + if c = NeverApplicable then return NeverApplicable; fi; + tmp := ConstructLongCycle(ri, c, 1. / 8., N); + if tmp = fail then + c := iterator(); + continue; + fi; + g := tmp[1]; + k := tmp[2]; + tmp := StandardGenerators(ri, g, c, k, 1. / 8., N); + if tmp = fail then + c := iterator(); + continue; + fi; + g := tmp[1]; + c := tmp[2]; + n := tmp[3]; + return [g, c, n]; + od; + until T = 0; + return fail; +end); diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index a00059f77..db31fdffc 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -1,6 +1,6 @@ -#@local testFunction, degreesToTest, permToPermMat, isos -#@local altAndSymGroups, nonAltOrSymGroups -#@local g, c, r, i +#@local testFunction, degrees +#@local altGroups, symGroups, permMatGroup, altMatGroups, nonAltOrSymGroups +#@local ri, g, c, r, i, x # # testing matrix: # - isomorphic: yes, no @@ -11,66 +11,164 @@ # - projective matrix groups # # TODO: Use RECOG.TestGroup? +# TODO: better name for testFunction +# tests ThreeCycleCandidatesIterator and BolsteringElements gap> testFunction := function(G, eps, N) -> local C, i; -> iterator := ThreeCycleCandidatesIterator(G, eps, N, IsOne, EQ); -> candidate := iterator(); -> if candidate <> NeverApplicable then -> for i in [1 .. 10] do -> BolsteringElements(G, PseudoRandom(C), eps, N, IsOne, EQ); +> local ri, iterator, candidate, i, j; +> ri := EmptyRecognitionInfoRecord(rec(), G, false); +> iterator := ThreeCycleCandidatesIterator(ri, eps, N); +> for i in [1 .. 10] do +> candidate := iterator(); +> for j in [1 .. 10] do +> if candidate <> NeverApplicable +> and candidate <> TemporaryFailure then +> BolsteringElements(ri, candidate, eps, +> N); +> fi; > od; -> fi; +> od; > end;; -gap> degreesToTest := Concatenation( -> [10, 11, 12, 20, 21, 30, 31, 40, 41, 50, 51], +gap> degrees := Concatenation( +> [10, 12, 20, 21, 30, 35, 40, 42, 50, 51], > Primes{[5 .. 15]} > );; +gap> degrees := degrees{[1, 2, 11, 12]};; + # TODO: more non-isomorphic examples -gap> altAndSymGroups := Concatenation( -> List(degrees, AlternatingGroup), -> List(degrees, SymmetricGroup));; -gap> permToPermMat := -> {x, deg, field} -> -> -> ImmutableMatrix(field, PermutationMat(x, deg, field));; -# TODO: add a projective group +# TODO: add projective groups +gap> altGroups := List(degrees, AlternatingGroup);; +gap> symGroups := List(degrees, SymmetricGroup);; +gap> permMatGroup := G -> Group(List( +> GeneratorsOfGroup(G), +> x -> ImmutableMatrix(7, PermutationMat(x, NrMovedPoints(G), GF(7))) +> ));; +gap> altMatGroups := List([10], +> n -> permMatGroup(AlternatingGroup(n)));; gap> nonAltOrSymGroups := [ -> DihedralGroup(IsPermGroup,10), -> DihedralGroup(IsPcGroup, 10), -> DihedralGroup(IsPermGroup, 2000), -> DihedralGroup(IsPcGroup, 2000), -> SL(3,5), +> DihedralGroup(IsPermGroup, 10), +> #DihedralGroup(IsPcGroup, 10), +> #DihedralGroup(IsPermGroup, 2000), +> #DihedralGroup(IsPcGroup, 2000), +> #PSL(3, 5), +> SL(3, 5), +> #permMatGroup(DihedralGroup(IsPermGroup, 10)), +> #Omega(-1, 4, 5), +> #Omega(+1, 4, 5), +> #Omega(0, 5, 5), > ];; -gap> # TODO: use permToPermMat with varying degrees and fields # ThreeCycleCandidates -gap> for i in [1 .. Length(testGroups)] do -> ThreeCycleCandidatesIterator(testGroups[i], -> 1/100, -> degrees[i], -> IsOne, -> EQ); +gap> for i in [1 .. Length(degrees)] do +> testFunction(altGroups[i], 1/100, degrees[i]); +> testFunction(symGroups[i], 1/100, degrees[i]); > od; - -# BolsteringElements -gap> for i in [1 .. Length(testGroups)] do -> G := testGroups[i]; -> BolsteringElements(G, PseudoRandom(G), 1/100, degrees[i], IsOne, EQ); +gap> for i in [1 .. Length(altMatGroups)] do +> testFunction(altMatGroups[i], 1/100, 13); +> od; +gap> for i in [1 .. Length(nonAltOrSymGroups)] do +> testFunction(nonAltOrSymGroups[i], 1/100, 15); > od; # 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> IsFixedPoint(g,c,r,IsOne,EQ); +gap> IsFixedPoint(ri, g,c,r); true gap> r := (2,3,4);; -gap> IsFixedPoint(g,c,r,IsOne,EQ); +gap> IsFixedPoint(ri, g,c,r); false # 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 := (1,2,3)(5,6);; -gap> AdjustCycle(g, c, r, 8, IsOne, EQ); -(3,4,7)(5,6) +gap> r := (4,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5) +gap> r := (3,4,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,4,5) +gap> r := (2,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5) +gap> r := (2,4,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5,4) +gap> r := (2,3,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,4,5) +gap> r := (1,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5) +gap> r := (1,4,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5,4) +gap> r := (1,3,4,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,6,4,5) +gap> r := (1,2,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5,4) +gap> r := (1,2,3,5);; +gap> AdjustCycle(ri, g, c, r, 8); +(3,5,4,6) + +# 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> BuildCycle(ri, c, x, 10); +[ (1,2,3,4,7,5,8,6,10), 9 ] \ No newline at end of file From 0b3a5510718a58fbd3bf9c98e65bc810ab9acf6c Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Thu, 27 Aug 2020 14:44:08 +0200 Subject: [PATCH 10/64] Add basic framework for RecogniseSnAn Add the following functions: - Add ConstructLongCycle - Add StandardGenerators - Copy-Paste SatisfiesAnPresentation from AnSnBB.gi - Add RecogniseSnAn, that returns standard gens of An at the moment --- gap/SnAnUnknownDegree.gd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gap/SnAnUnknownDegree.gd b/gap/SnAnUnknownDegree.gd index 6e68c0e64..d65ffc93b 100644 --- a/gap/SnAnUnknownDegree.gd +++ b/gap/SnAnUnknownDegree.gd @@ -5,3 +5,8 @@ DeclareGlobalName("AdjustCycle"); DeclareGlobalName("AppendPoints"); DeclareGlobalName("BuildCycle"); DeclareGlobalName("IsElmOfPrimeOrder"); +DeclareGlobalName("ConstructLongCycle"); +DeclareGlobalName("StandardGenerators"); +DeclareGlobalName("SatisfiesAnPresentation"); +DeclareGlobalName("RecogniseSnAn"); + From 7a56db535431c9683d5a335d8ae3beb1b1ef2740 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Thu, 3 Sep 2020 15:19:17 +0200 Subject: [PATCH 11/64] SnAnUnknownDegree: Update comments --- gap/SnAnUnknownDegree.gi | 143 +++++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 45 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index a24bb7f84..ffc7b3e5b 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -117,11 +117,16 @@ BindGlobal("ThreeCycleCandidatesIterator", return oneThreeCycleCandidate; end); -# G: the group to recognize -# c: possibly a 3-cycle -# returns a list of group elements. If G is isomorphic to an alternating or -# symmetric group and c is a 3-cycle, then this function returns a list of -# bolstering elements with respect to c. +# 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. BindGlobal("BolsteringElements", function(ri, c, eps, N) local result, R, S, prebolsteringElms, i, r, cr, cr2; @@ -158,12 +163,18 @@ function(ri, c, eps, N) return result; end); -# g: a cycle matching c of a group G -# c: a 3-cycle of a group G -# r: arbitrary element of a group G -# The supports of c and c^(g^2) have exactly one point, say alpha, in common. -# Let phi be an isomorphism from G to a natural alternating or symmetric group. -# This function decides whether alpha is a fixed point of phi(r). +# 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, then the supports of c and c^(g^2) have exactly +# one point, say alpha, in common and this function returns whether alpha is a +# fixed point of r. BindGlobal("IsFixedPoint", function(ri, g, c, r) local @@ -211,14 +222,22 @@ function(ri, g, c, r) return true; end); -# g: a k-cycle matching c of a group G -# c: a 3-cycle of a group G -# r: element of a group G +# 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 support of g has at least one point in common with the support of r -# and at least two points of support of g are fixed by r, -# then the algorithm returns a conjugate r^x such that r fixes the points 1, 2 -# but not the point 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. BindGlobal("AdjustCycle", function(ri, g, c, r, k) local @@ -328,22 +347,36 @@ function(ri, g, c, r, k) return r^x; end); -# g: a k-cycle matching c of a group G -# c: a 3-cycle of a group G -# r: return value of AdjustCycle. If e.g. g = (1, 2, ..., k), then r would be a -# cycle fixing 1 and 2 and moving 3 -# The algorithm AppendPoints 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. +# 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 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 # -# 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. +# 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 AppendPoints +# several times and may not have used the last sTilde. +# - kTilde: integer, +# should be the length of gTilde # -# We return a list consisting of: -# - gTilde, the new g -# - sTilde, since we may call AppendPoints several times and may not have used -# the last sTilde. -# - kTilde, 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. + BindGlobal("AppendPoints", function(ri, g, c, r, s, k, k0) local gTilde, sTilde, kTilde, gc2, x, j; @@ -370,10 +403,10 @@ function(ri, g, c, r, s, k, k0) return [gTilde, sTilde, kTilde]; end); -# ri : recog info record -# g : element of a group +# ri : recog info record with group G +# g : element of G # p : prime -# We return true, if g is an element of order p. +# Returns whether g is an element of order p. BindGlobal("IsElmOfPrimeOrder", function(ri, g, p) if not isone(ri)(g) and isone(ri)(g ^ p) then @@ -383,12 +416,17 @@ function(ri, g, p) fi; end); -# c: a 3-cycle of a group G +# ri : recog info record with group G +# c : a 3-cycle of a group G # x : bolstering element with respect to c -# The algorithm BuildCycle determines a cycle g of length k matching c. -# We return either fail or a list consisting of: +# N : upper bound for 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 BindGlobal("BuildCycle", function(ri, c, x, N) local @@ -483,24 +521,39 @@ function(ri, c, x, N) return fail; end); -# ri : recog info record -# c : three-cycle -# eps : error probability -# N : upper bound for degree of the group -# We return either fail or a list consisting of: -# - g, cycle matching c -# - k, length of cycle g. +# NOTE: Output in paper is reversed. +# +# 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 consisting of: +# - g: element of G, +# should be a k-cycle matching c +# - k: integer, +# should be length of cycle g. +# +# 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 BindGlobal("ConstructLongCycle", function(ri, c, eps, N) local g, k, tmp, B, x; B := BolsteringElements(ri, c, Float(eps) / 2., N); if Length(B) < Int(Ceil(7./4. * Log(2. / Float(eps)))) then + # the list of bolstering elements is too small return fail; fi; k := 0; for x in B do tmp := BuildCycle(ri, c, x, N); if tmp = fail then + # One of the following holds: + # - N is not an upper bound for the degree of G + # - c is not a 3-cycle return fail; elif tmp[2] > k then g := tmp[1]; From 90660b7fe3ef03908ff8f424118063564bb59629 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 21 Sep 2020 14:05:44 +0200 Subject: [PATCH 12/64] SnAnUnknownDegree: Code-review by Max Co-authored-by: Max Horn --- gap/SnAnUnknownDegree.gi | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index ffc7b3e5b..6021686c7 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -129,37 +129,34 @@ end); # elements with respect to c. BindGlobal("BolsteringElements", function(ri, c, eps, N) - local result, R, S, prebolsteringElms, i, r, cr, cr2; + local result, R, S, NrPrebolsteringElms, i, r, cr, cr2; result := []; R := Int(Ceil(7 / 4 * Log2(Float(eps ^ -1)))); S := 7 * N * R; - prebolsteringElms := []; + NrPrebolsteringElms := 0; i := 0; # find pre-bolstering elements - while i <= S and Length(prebolsteringElms) <= R do + while i <= S and NrPrebolsteringElms <= R do r := RandomElm(ri,"simplesocle",true)!.el; # test whether r is pre-bolstering cr := c ^ r; - cr2 := c ^ (r ^ 2); + cr2 := cr ^ r; if not isone(ri)(Comm(cr, c)) and not isequal(ri)(cr2, c) and not isequal(ri)(cr2, c ^ 2) and isone(ri)(Comm(cr2, c)) then - Add(prebolsteringElms, r); + NrPrebolsteringElms := NrPrebolsteringElms + 1; + if isone(ri)((cr ^ (c * r) + * cr ^ (cr2 * c)) ^ 3) + then + Add(result, c ^ 2 * r); + else + Add(result, cr); + fi; fi; i := i + 1; od; - # construct bolstering elements - for r in prebolsteringElms do - if isone(ri)((c ^ (r * c * r) - * c ^ (r * c ^ (r ^ 2) * c)) ^ 3) - then - Add(result, c ^ 2 * r); - else - Add(result, cr); - fi; - od; return result; end); From bdff3ae31ff6b0f42f16f05aa6a8ce9456b62e03 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 21 Sep 2020 14:21:19 +0200 Subject: [PATCH 13/64] Change NrPrebolsteringElms -> nrPrebolsteringElms --- gap/SnAnUnknownDegree.gi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 6021686c7..b1deec790 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -129,14 +129,14 @@ end); # elements with respect to c. BindGlobal("BolsteringElements", function(ri, c, eps, N) - local result, R, S, NrPrebolsteringElms, i, r, cr, cr2; + local result, R, S, nrPrebolsteringElms, i, r, cr, cr2; result := []; R := Int(Ceil(7 / 4 * Log2(Float(eps ^ -1)))); S := 7 * N * R; - NrPrebolsteringElms := 0; + nrPrebolsteringElms := 0; i := 0; # find pre-bolstering elements - while i <= S and NrPrebolsteringElms <= R do + while i <= S and nrPrebolsteringElms <= R do r := RandomElm(ri,"simplesocle",true)!.el; # test whether r is pre-bolstering cr := c ^ r; @@ -146,7 +146,7 @@ function(ri, c, eps, N) and not isequal(ri)(cr2, c ^ 2) and isone(ri)(Comm(cr2, c)) then - NrPrebolsteringElms := NrPrebolsteringElms + 1; + nrPrebolsteringElms := nrPrebolsteringElms + 1; if isone(ri)((cr ^ (c * r) * cr ^ (cr2 * c)) ^ 3) then From 045933a08cf875c65d356a8b1233395d676ead83 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 21 Sep 2020 15:01:39 +0200 Subject: [PATCH 14/64] Use docommute in SnAnUnknownDegree.gi --- gap/SnAnUnknownDegree.gi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index b1deec790..aeedd6008 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -141,10 +141,10 @@ function(ri, c, eps, N) # test whether r is pre-bolstering cr := c ^ r; cr2 := cr ^ r; - if not isone(ri)(Comm(cr, c)) + if not docommute(ri)(cr, c) and not isequal(ri)(cr2, c) and not isequal(ri)(cr2, c ^ 2) - and isone(ri)(Comm(cr2, c)) + and docommute(ri)(cr2, c) then nrPrebolsteringElms := nrPrebolsteringElms + 1; if isone(ri)((cr ^ (c * r) @@ -188,7 +188,7 @@ function(ri, g, c, r) local nrTrivialComm, h; nrTrivialComm := 0; for h in H do - if isone(ri)(Comm(x, h)) then + if docommute(ri)(x, h) then nrTrivialComm := nrTrivialComm + 1; fi; if nrTrivialComm >= 2 then @@ -384,7 +384,7 @@ function(ri, g, c, r, s, k, k0) for j in [1 .. k0 - 1] do # invariant: x = c ^ (r ^ j) x := x ^ r; - if isone(ri)(Comm(x, gTilde * c ^ 2)) then + 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; @@ -482,7 +482,7 @@ function(ri, c, x, N) # Case distinction on element e if IsElmOfPrimeOrder(ri, d * c, 2) then # w not in v ^ - if isone(ri)(Comm(dx, d ^ c)) then + if docommute(ri)(dx, d ^ c) then # Case 4, alpha < beta e := (d ^ (x * c)) ^ 2; else @@ -491,7 +491,7 @@ function(ri, c, x, N) fi; else # w in v ^ - if isone(ri)(Comm(dx, d ^ c)) then + if docommute(ri)(dx, d ^ c) then # Case 1, alpha > beta e := d ^ (x * c); else From 442eb41fd3ce292c924d1f82e8665e1c3c38c21f Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 21 Sep 2020 17:07:18 +0200 Subject: [PATCH 15/64] Improve BuildCycle --- gap/SnAnUnknownDegree.gi | 120 +++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 63 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index aeedd6008..30b866884 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -427,46 +427,34 @@ end); BindGlobal("BuildCycle", function(ri, c, x, N) local - # Floor(N / 2) - N2, - # min(alpha, beta) - m, - # d = c ^ (x ^ (m + 1)) - d, - # y = c * c ^ x * c ^ (x ^ 2) * ... * c ^ (x ^ m) - y, - # is false, if m >= N/2 - isMinInitialized, - # dx = d ^ x = c ^ (x ^ (m + 2)) - dx, - # element defined as in the case distinction - e, - # d ^ e - z, - # z ^ (x ^ 2 * (mDash - 1)) - zxMinus, - # z ^ (x ^ 2 * (mDash)) - zx, - # z ^ (x ^ 2 * (mDash + 1)) - zxPlus, - # integer computed as in Remark 4.9 - mDash, - # cycle matching c - g; - # Here we set m := 0 - N2 := Int(Floor(Float(N) / 2.)); - y := c; - d := c ^ x; - isMinInitialized := false; - for m in [1 .. N2] do - y := y * d; - d := d ^ x; - if not IsElmOfPrimeOrder(ri, d * c, 5) then - isMinInitialized := true; + # integers + m, mDash, + # group elements + d, y, dx, e, z, f, g, xSquared; + # 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. + xSquared := x ^ 2; + m := 1; + y := c * (c ^ x); + d := c ^ xSquared; + while true do + if m >= N / 2 then + return fail; + elif IsElmOfPrimeOrder(ri, d * c, 5) then + m := m + 1; + else break; fi; + y := y * d; + d := d ^ x; od; - if not isMinInitialized then + if m = 1 then return fail; fi; # Case |alpha - beta| = 0 @@ -480,42 +468,48 @@ function(ri, c, x, N) fi; # Case |alpha - beta| >= 2 # Case distinction on element e - if IsElmOfPrimeOrder(ri, d * c, 2) then - # w not in v ^ + # w in v ^ + if not IsElmOfPrimeOrder(ri, d * c, 2) then + # Case 1, alpha > beta if docommute(ri)(dx, d ^ c) then - # Case 4, alpha < beta - e := (d ^ (x * c)) ^ 2; + e := dx ^ c; + # Case 2, alpha < beta else - # Case 3, alpha > beta - e := d ^ (x * c ^ 2); + e := (dx ^ (c ^ 2)) ^ 2; fi; + # w not in v ^ else - # w in v ^ - if docommute(ri)(dx, d ^ c) then - # Case 1, alpha > beta - e := d ^ (x * c); + # Case 3, alpha > beta + if not docommute(ri)(dx, d ^ c) then + e := dx ^ (c ^ 2); + # Case 4, alpha < beta else - # Case 2, alpha < beta - e := (d ^ (x * c ^ 2)) ^ 2; + e := (dx ^ c) ^ 2; fi; fi; z := d ^ e; - # Here we set mDash := 1 - zxMinus := z; - zx := zxMinus ^ (x ^ 2); - zxPlus := zx ^ (x ^ 2); - g := y * zxMinus; - for mDash in [1 .. N2] do - if not IsElmOfPrimeOrder(ri, zxPlus, 5) then - return [g, 2 * mDash + 2 * m + 3]; + # 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 ^ xSquared; + while true do + if mDash >= N / 2 then + return fail; + elif IsElmOfPrimeOrder(ri, f * c, 5) then + mDash := mDash + 1; + else + break; fi; - zxMinus := zx; - zx := zxPlus; - zxPlus := zxPlus ^ (x ^ 2); - g := y * zxMinus; + g := g * f; + f := f ^ xSquared; od; - # mDash >= N / 2 - return fail; + return [g, 2 * mDash + 2 * m + 3]; end); # NOTE: Output in paper is reversed. From c6957d181e4874299ee46cbf70eaaaaf27b0c470 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 21 Sep 2020 15:51:20 +0200 Subject: [PATCH 16/64] Add Prime Sieve --- gap/SnAnUnknownDegree.gd | 1 + gap/SnAnUnknownDegree.gi | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/gap/SnAnUnknownDegree.gd b/gap/SnAnUnknownDegree.gd index d65ffc93b..35a714d93 100644 --- a/gap/SnAnUnknownDegree.gd +++ b/gap/SnAnUnknownDegree.gd @@ -1,3 +1,4 @@ +DeclareGlobalName("AllPrimesUpTo"); DeclareGlobalName("ThreeCycleCandidatesIterator"); DeclareGlobalName("BolsteringElements"); DeclareGlobalName("IsFixedPoint"); diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 30b866884..d84d6132c 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -1,3 +1,31 @@ +# FIXME: Move me into GAP +# Helper function to compute all primes up to a given integer via a prime sieve +BindGlobal("AllPrimesUpTo", +function(n) + local i, j, sieve, result; + if n <= 1000 then + return Primes{[1..PositionSorted(Primes, n+1)-1]}; + 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; + return ListBlist([1..n], sieve); +end); + + # Input: Group G, upper error bound eps, upper degree bound N # # The following algorithm constructs a set of possible 3-cycles. It is based @@ -17,8 +45,8 @@ BindGlobal("ThreeCycleCandidatesIterator", t, # integers, controlling the number of iterations M, B, T, C, logInt2N, - # integer, prime, loop variable - p, + # iteration over all primes up to N + allPrimes, i, p, # counters nrInvolutions, nrTriedConjugates, nrThreeCycleCandidates, # helper functions @@ -30,10 +58,10 @@ BindGlobal("ThreeCycleCandidatesIterator", # Constants # TODO: better iteration over primes M := 1; - p := 3; - while p <= N do + allPrimes := AllPrimesUpTo(N); + for i in [2 .. Length(allPrimes)] do + p := allPrimes[i]; M := M * p ^ LogInt(N, p); - p := NextPrimeInt(p); od; # FIXME: Probably B can be chosen smaller B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))); From 1a7007d0ff22edb063d2171baf487023965da91a Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Wed, 23 Sep 2020 12:18:02 +0200 Subject: [PATCH 17/64] Improve ConstructLongCycle --- gap/SnAnUnknownDegree.gi | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index d84d6132c..79eec557a 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -562,17 +562,13 @@ BindGlobal("ConstructLongCycle", function(ri, c, eps, N) local g, k, tmp, B, x; B := BolsteringElements(ri, c, Float(eps) / 2., N); - if Length(B) < Int(Ceil(7./4. * Log(2. / Float(eps)))) then - # the list of bolstering elements is too small + if Length(B) < Int(Ceil(7. / 4. * Log(2. / Float(eps)))) then return fail; fi; k := 0; for x in B do tmp := BuildCycle(ri, c, x, N); if tmp = fail then - # One of the following holds: - # - N is not an upper bound for the degree of G - # - c is not a 3-cycle return fail; elif tmp[2] > k then g := tmp[1]; From 56a75564230561603fae28bbd0affd78a92300f3 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Wed, 23 Sep 2020 12:16:49 +0200 Subject: [PATCH 18/64] Improve comments --- gap/SnAnUnknownDegree.gi | 52 +++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 79eec557a..1b71c4b11 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -26,7 +26,9 @@ function(n) end); -# Input: Group G, upper error bound eps, upper degree bound N +# ri : recog info record with group G +# eps : real number, the error bound +# N : integer, upper bound for the degree of G # # 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 @@ -197,9 +199,9 @@ end); # # Returns a boolean. # -# If the input is as assumed, then the supports of c and c^(g^2) have exactly -# one point, say alpha, in common and this function returns whether alpha is a -# fixed point of r. +# 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. BindGlobal("IsFixedPoint", function(ri, g, c, r) local @@ -401,7 +403,6 @@ end); # 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. - BindGlobal("AppendPoints", function(ri, g, c, r, s, k, k0) local gTilde, sTilde, kTilde, gc2, x, j; @@ -444,7 +445,8 @@ end); # ri : recog info record with group G # c : a 3-cycle of a group G # x : bolstering element with respect to c -# N : upper bound for degree of G +# 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. @@ -458,7 +460,7 @@ function(ri, c, x, N) # integers m, mDash, # group elements - d, y, dx, e, z, f, g, xSquared; + d, y, dx, e, z, f, g, x2; # Compute m. # m is the least natural number such that with # d = c ^ (x ^ (m + 1)) @@ -467,10 +469,10 @@ function(ri, c, x, N) # y = c * (c ^ x) * (c ^ (x ^ 2)) * ... * (c ^ (x ^ m)). # The next three lines correspond to m = 1 # We use x ^ 2 several times. - xSquared := x ^ 2; + x2 := x ^ 2; m := 1; y := c * (c ^ x); - d := c ^ xSquared; + d := c ^ x2; while true do if m >= N / 2 then return fail; @@ -525,7 +527,7 @@ function(ri, c, x, N) # The next three lines correspond to mDash = 1 mDash := 1; g := y * z; - f := z ^ xSquared; + f := z ^ x2; while true do if mDash >= N / 2 then return fail; @@ -535,13 +537,11 @@ function(ri, c, x, N) break; fi; g := g * f; - f := f ^ xSquared; + f := f ^ x2; od; return [g, 2 * mDash + 2 * m + 3]; end); -# NOTE: Output in paper is reversed. -# # ri : recog info record with group G # c : element of G, # should be a 3-cycle @@ -554,6 +554,9 @@ end); # - k: integer, # should be length of cycle g. # +# Note that the order of the returned list is reversed wrt 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 @@ -578,9 +581,23 @@ function(ri, c, eps, N) return [g, k]; end); -# ri : recog info record -# g : cycle matching c -# c : three-cycle +# 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 BindGlobal("StandardGenerators", function(ri, g, c, k, eps, N) local s, k0, c2, r, kTilde, gTilde, i, x, m, tmp, cTilde; @@ -590,7 +607,8 @@ function(ri, g, c, k, eps, N) 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 + for i in [1 .. Int(Ceil(Log(10. / 3.) ^ (-1) + * (Log(Float(N)) + Log(1 / Float(eps)))))] do x := r ^ RandomElm(ri,"simplesocle",true)!.el; m := AdjustCycle(ri, gTilde, c, x, kTilde); if m = fail then return fail; fi; From a439be6353bf41737c753d9b44e64ffbd40f34da Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Wed, 23 Sep 2020 13:23:41 +0200 Subject: [PATCH 19/64] Fix error bound in RecogniseSnAn --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 1b71c4b11..e632f28b1 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -641,7 +641,7 @@ function(ri, eps, N) T := Int(Ceil(Log(1 / Float(eps)))); repeat T := T - 1; - iterator := ThreeCycleCandidatesIterator(ri, eps, N); + iterator := ThreeCycleCandidatesIterator(ri, 1. / 4., N); c := iterator(); while c <> TemporaryFailure do if c = NeverApplicable then return NeverApplicable; fi; From daaa7f0bba86cc0d23dd30d3858a4c11146549a9 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Wed, 23 Sep 2020 13:28:26 +0200 Subject: [PATCH 20/64] Fix whitespaces --- gap/SnAnUnknownDegree.gi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index e632f28b1..fbfa8ef49 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -98,7 +98,7 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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,"simplesocle",true)!.el; + r := RandomElm(ri, "simplesocle", true)!.el; a := 0; tPower := r ^ M; # Invariant: tPower = (r ^ M) ^ (2 ^ a) @@ -119,7 +119,7 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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,"simplesocle",true)!.el; + c := t ^ RandomElm(ri, "simplesocle", true)!.el; if not isequal(ri)(t * c, c * t) then nrThreeCycleCandidates := nrThreeCycleCandidates + 1; return (t * c) ^ 2; @@ -167,7 +167,7 @@ function(ri, c, eps, N) i := 0; # find pre-bolstering elements while i <= S and nrPrebolsteringElms <= R do - r := RandomElm(ri,"simplesocle",true)!.el; + r := RandomElm(ri, "simplesocle", true)!.el; # test whether r is pre-bolstering cr := c ^ r; cr2 := cr ^ r; @@ -609,7 +609,7 @@ function(ri, g, c, k, eps, N) gTilde := g; for i in [1 .. Int(Ceil(Log(10. / 3.) ^ (-1) * (Log(Float(N)) + Log(1 / Float(eps)))))] do - x := r ^ RandomElm(ri,"simplesocle",true)!.el; + x := r ^ RandomElm(ri, "simplesocle", true)!.el; m := AdjustCycle(ri, gTilde, c, x, kTilde); if m = fail then return fail; fi; tmp := AppendPoints(ri, gTilde, c, m, s, kTilde, k0); From 514a04fe0630680f167ec30bec6d7245f2c7814b Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Oct 2020 16:14:28 +0200 Subject: [PATCH 21/64] Improve ThreeCycleCandidatesIterator --- gap/SnAnUnknownDegree.gi | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index fbfa8ef49..c58aaf593 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -85,7 +85,8 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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 + # - 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 @@ -124,6 +125,7 @@ BindGlobal("ThreeCycleCandidatesIterator", nrThreeCycleCandidates := nrThreeCycleCandidates + 1; return (t * c) ^ 2; else + # we have to call tryThreeCycleCandidate again return fail; fi; end; @@ -134,8 +136,9 @@ BindGlobal("ThreeCycleCandidatesIterator", if nrInvolutions >= B and (nrTriedConjugates >= C or nrThreeCycleCandidates >= T) then - # We are done and were not able to recognize Sn or An. - return TemporaryFailure; + # 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 @@ -643,7 +646,7 @@ function(ri, eps, N) T := T - 1; iterator := ThreeCycleCandidatesIterator(ri, 1. / 4., N); c := iterator(); - while c <> TemporaryFailure do + while c <> fail do if c = NeverApplicable then return NeverApplicable; fi; tmp := ConstructLongCycle(ri, c, 1. / 8., N); if tmp = fail then From c8d274b6557d8af7d303fd022eb383aac2eb6b91 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Oct 2020 17:28:30 +0200 Subject: [PATCH 22/64] Update init.g and read.g to use gap/SnAnBB.gi among other things. --- gap/SnAnUnknownDegree.gd | 13 ------------- init.g | 2 -- read.g | 4 +--- 3 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 gap/SnAnUnknownDegree.gd diff --git a/gap/SnAnUnknownDegree.gd b/gap/SnAnUnknownDegree.gd deleted file mode 100644 index 35a714d93..000000000 --- a/gap/SnAnUnknownDegree.gd +++ /dev/null @@ -1,13 +0,0 @@ -DeclareGlobalName("AllPrimesUpTo"); -DeclareGlobalName("ThreeCycleCandidatesIterator"); -DeclareGlobalName("BolsteringElements"); -DeclareGlobalName("IsFixedPoint"); -DeclareGlobalName("AdjustCycle"); -DeclareGlobalName("AppendPoints"); -DeclareGlobalName("BuildCycle"); -DeclareGlobalName("IsElmOfPrimeOrder"); -DeclareGlobalName("ConstructLongCycle"); -DeclareGlobalName("StandardGenerators"); -DeclareGlobalName("SatisfiesAnPresentation"); -DeclareGlobalName("RecogniseSnAn"); - diff --git a/init.g b/init.g index ef6ccc4fc..1136ee7ab 100644 --- a/init.g +++ b/init.g @@ -21,8 +21,6 @@ ReadPackage("recog","gap/base/recognition.gd"); # The following contain generic declarations for different types of groups: ReadPackage("recog","gap/base/projective.gd"); -ReadPackage("recog","gap/SnAnUnknownDegree.gd"); - ReadPackage("recog","gap/matrix.gd"); ReadPackage("recog","gap/matrix/ppd.gd"); diff --git a/read.g b/read.g index a248bef95..c70f1ca63 100644 --- a/read.g +++ b/read.g @@ -36,10 +36,8 @@ ReadPackage("recog","gap/generic/KnownNilpotent.gi"); # Permutations: ReadPackage("recog","gap/perm/giant.gi"); ReadPackage("recog","gap/perm/largebase.gi"); -ReadPackage("recog","gap/SnAnUnknownDegree.gi"); - -# Up to now there is not much here: ReadPackage("recog","gap/SnAnBB.gi"); +ReadPackage("recog","gap/SnAnUnknownDegree.gi"); # Matrices/Projective: ReadPackage("recog","gap/projective/findnormal.gi"); From e18b0630d999c39a199befd073f0560d2a1e1458 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Wed, 21 Oct 2020 12:10:05 +0200 Subject: [PATCH 23/64] SnAnUnknownDegree: Code review by Max Co-authored-by: Max Horn --- gap/SnAnUnknownDegree.gi | 49 +++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index c58aaf593..7b3038080 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -166,10 +166,8 @@ function(ri, c, eps, N) result := []; R := Int(Ceil(7 / 4 * Log2(Float(eps ^ -1)))); S := 7 * N * R; - nrPrebolsteringElms := 0; - i := 0; # find pre-bolstering elements - while i <= S and nrPrebolsteringElms <= R do + for i in [0 .. S] do r := RandomElm(ri, "simplesocle", true)!.el; # test whether r is pre-bolstering cr := c ^ r; @@ -179,7 +177,6 @@ function(ri, c, eps, N) and not isequal(ri)(cr2, c ^ 2) and docommute(ri)(cr2, c) then - nrPrebolsteringElms := nrPrebolsteringElms + 1; if isone(ri)((cr ^ (c * r) * cr ^ (cr2 * c)) ^ 3) then @@ -188,7 +185,7 @@ function(ri, c, eps, N) Add(result, cr); fi; fi; - i := i + 1; + if Length(result) > R then break; fi; od; return result; end); @@ -235,7 +232,7 @@ function(ri, g, c, r) cg3 := cg2 ^ g; cg4 := cg3 ^ g; H1 := [ c ^ 2, c ^ cg, ~[2] ^ cg3, ~[3] ^ cg3, ~[4] ^ cg4 ]; - # Test whether an elm of the set X commutes with at least + # 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; @@ -320,7 +317,7 @@ function(ri, g, c, r, k) if success then if j >= 4 then break; - # 2. Case, we do not need to compute F4[4] + # case 2, we do not need to compute F4[4] elif f1 = 1 and f2 = 2 and m = 3 then return r; fi; @@ -333,43 +330,43 @@ function(ri, g, c, r, k) # via a decision tree if F4[1] then if F4[2] then - # We are in the 1. Case, since the 2. Case is handled during the + # 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 - # 3. Case + # case 3 x := c ^ g; else - # 4. Case + # case 4 x := (c ^ 2) ^ g; fi; else - # 5. Case + # case 5 x := c ^ ((g * c ^ 2) ^ (f2 - 3) * c); fi; fi; else if F4[2] then if F4[4] then - # 6. Case + # case 6 x := c ^ (c ^ g); else if F4[3] then - # 7. Case + # case 7 x := (c ^ 2) ^ (c ^ g); else - # 8. Case + # case 8 x := c ^ ((g * c ^ 2) ^ (f2 - 3) * c ^ g); fi; fi; else if F4[3] then - # 9. Case + # case 9 x := (c ^ 2) ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ 2; else - # 10. Case + # case 10 x := c ^ ((g * c ^ 2) ^ (f2 - 3)) * c ^ ((g * c ^ 2) ^ (f1 - 3)); fi; fi; @@ -490,32 +487,32 @@ function(ri, c, x, N) if m = 1 then return fail; fi; - # Case |alpha - beta| = 0 + # 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 + # case |alpha - beta| = 1 dx := d ^ x; if not IsElmOfPrimeOrder(ri, dx * c, 5) then return [y, 2 * m + 3]; fi; - # Case |alpha - beta| >= 2 - # Case distinction on element e + # case |alpha - beta| >= 2 + # case distinction on element e # w in v ^ if not IsElmOfPrimeOrder(ri, d * c, 2) then - # Case 1, alpha > beta + # case 1, alpha > beta if docommute(ri)(dx, d ^ c) then e := dx ^ c; - # Case 2, alpha < beta + # case 2, alpha < beta else e := (dx ^ (c ^ 2)) ^ 2; fi; # w not in v ^ else - # Case 3, alpha > beta + # case 3, alpha > beta if not docommute(ri)(dx, d ^ c) then e := dx ^ (c ^ 2); - # Case 4, alpha < beta + # case 4, alpha < beta else e := (dx ^ c) ^ 2; fi; @@ -551,13 +548,13 @@ end); # eps : real number, the error bound # N : integer, upper bound for the degree of G # -# Returns fail or a list consisting of: +# 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 wrt the paper to be +# 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: From cf93bcd748436771221952a476e82b055f46a629 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 2 Nov 2020 16:12:29 +0100 Subject: [PATCH 24/64] Fix typo in BolsteringElements: cr -> c * r. cr = c ^ r ist always a three-cycle, whereas c * r is a bolstering element. For this reason the return list from BolsteringElement contained three-cycles and bolstering elements, instead of just bolstering elements. --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 7b3038080..0cf32ec31 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -182,7 +182,7 @@ function(ri, c, eps, N) then Add(result, c ^ 2 * r); else - Add(result, cr); + Add(result, c * r); fi; fi; if Length(result) > R then break; fi; From c95c83965654092320bac19012599545b0510b28 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Oct 2020 17:29:41 +0200 Subject: [PATCH 25/64] Finish ConstructSnAnIsomorphism --- gap/SnAnUnknownDegree.gi | 78 ++++++++++++++++++++++++++++++++------- gap/SnAnUnknownDegree.tst | 22 ++++++++++- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 0cf32ec31..f13899103 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -633,14 +633,61 @@ function(ri, g, c, k, eps, N) fi; end); -# UNFINISHED -# currently returns standard gens of An +# TODO: Use FindImageAn or FindImageSn to compute SLPs in nice gens. +# This function is taken from the function RecogniseSnAn in gap/SnAnBB.gi +# FIXME: describe return values etc +BindGlobal("ConstructSnAnIsomorphism", +function(ri, n, gens) + local grp, xis, gl, slp, eval, h, b, g; + grp := GroupWithMemory(Grp(ri)); + # TODO: strip here? + xis := ConstructXiAn(n, gens[1], gens[2]); + for g in GeneratorsOfGroup(grp) do + # TODO: can we take g, gens, xis to be without memory? Like this? + # gens := StripMemory(gens); xis := StripMemory(xis); + gl := FindImageAn(ri, 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 SatisfiesSnPresentation(ri, n, b, h) then + xis := ConstructXiSn(n, b, h); + for g in GeneratorsOfGroup(grp) do + gl := FindImageSn(ri, 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; + od; + + return ["An", [gens[1], gens[2]], xis]; +end); + +# FIXME: describe function BindGlobal("RecogniseSnAn", function(ri, eps, N) - local T, c, tmp, g, k, n, iterator; + local T, foundPreImagesOfStdGens, iterator, c, tmp, isoData, i; T := Int(Ceil(Log(1 / Float(eps)))); - repeat - T := T - 1; + foundPreImagesOfStdGens := false; + for i in [1 .. T] do iterator := ThreeCycleCandidatesIterator(ri, 1. / 4., N); c := iterator(); while c <> fail do @@ -650,18 +697,21 @@ function(ri, eps, N) c := iterator(); continue; fi; - g := tmp[1]; - k := tmp[2]; - tmp := StandardGenerators(ri, g, c, k, 1. / 8., N); + # Now tmp contains [g, k] where + # g corresponds to a long cycle + # k is its length + tmp := StandardGenerators(ri, tmp[1], c, tmp[2], 1. / 8., N); if tmp = fail then c := iterator(); continue; fi; - g := tmp[1]; - c := tmp[2]; - n := tmp[3]; - return [g, c, n]; + # Now tmp contains [g, c, n] where + # g, c correspond to standard generators of An + isoData := ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); + if isoData = fail then continue; fi; + Add(isoData, tmp[3]); + return isoData; od; - until T = 0; - return fail; + od; + return TemporaryFailure; end); diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index db31fdffc..96b635aad 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -1,6 +1,7 @@ #@local testFunction, degrees #@local altGroups, symGroups, permMatGroup, altMatGroups, nonAltOrSymGroups #@local ri, g, c, r, i, x +#@local sets, S11On2Sets, res, isoData, gensWithMem, g1, img1, g2, img2 # # testing matrix: # - isomorphic: yes, no @@ -171,4 +172,23 @@ gap> BuildCycle(ri, c, x, 10); # alpha - beta = 2 gap> x := (2,4,5,6,10,3,7,8);; gap> BuildCycle(ri, c, x, 10); -[ (1,2,3,4,7,5,8,6,10), 9 ] \ No newline at end of file +[ (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> res := RecogniseSnAn(ri, 1/10, 20);; +gap> isoData := ConstructSnAnIsomorphism(ri, res[3], [res[1], res[2]]);; +gap> gensWithMem := GeneratorsWithMemory(GeneratorsOfGroup(S11On2Sets));; +gap> g1 := gensWithMem[1];; +gap> img1 := FindImageSn(ri, 11, g1, isoData[2][1], isoData[2][2], +> isoData[3][1], isoData[3][2]);; +gap> CycleStructurePerm(img1); +[ ,,,,,,,,, 1 ] +gap> g2 := gensWithMem[2];; +gap> img2 := FindImageSn(ri, 11, g2, isoData[2][1], isoData[2][2], +> isoData[3][1], isoData[3][2]);; +gap> CycleStructurePerm(img2); +[ 1 ] From a4d72ed7c769300aeb555600c2a787b864b7dbfa Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 9 Nov 2020 14:31:24 +0100 Subject: [PATCH 26/64] SnAnUnknownDegree: improve tests --- gap/SnAnUnknownDegree.tst | 44 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index 96b635aad..313af6ec4 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -1,4 +1,4 @@ -#@local testFunction, degrees +#@local testFunction, IsBolsteringElement, degrees #@local altGroups, symGroups, permMatGroup, altMatGroups, nonAltOrSymGroups #@local ri, g, c, r, i, x #@local sets, S11On2Sets, res, isoData, gensWithMem, g1, img1, g2, img2 @@ -29,6 +29,44 @@ gap> testFunction := function(G, eps, N) > 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;; gap> degrees := Concatenation( > [10, 12, 20, 21, 30, 35, 40, 42, 50, 51], > Primes{[5 .. 15]} @@ -58,6 +96,7 @@ gap> nonAltOrSymGroups := [ > #Omega(0, 5, 5), > ];; +# FIXME: This is super slow. # ThreeCycleCandidates gap> for i in [1 .. Length(degrees)] do > testFunction(altGroups[i], 1/100, degrees[i]); @@ -179,8 +218,7 @@ gap> BuildCycle(ri, c, x, 10); gap> sets := Combinations([1 .. 11], 2);; gap> S11On2Sets := Action(SymmetricGroup(11), sets, OnSets);; gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; -gap> res := RecogniseSnAn(ri, 1/10, 20);; -gap> isoData := ConstructSnAnIsomorphism(ri, res[3], [res[1], res[2]]);; +gap> isoData := RecogniseSnAn(ri, 1/10, 20);; gap> gensWithMem := GeneratorsWithMemory(GeneratorsOfGroup(S11On2Sets));; gap> g1 := gensWithMem[1];; gap> img1 := FindImageSn(ri, 11, g1, isoData[2][1], isoData[2][2], From 97ecce635eed70f8928f87352081ad1269116841 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 9 Nov 2020 16:32:48 +0100 Subject: [PATCH 27/64] Add function SnAnUnknownDegree --- gap/SnAnUnknownDegree.gi | 162 +++++++++++++++++++++++++++++++------- gap/SnAnUnknownDegree.tst | 33 ++++++-- 2 files changed, 162 insertions(+), 33 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index f13899103..212e32b25 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -1,3 +1,22 @@ +############################################################################# +## +## 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 [JLNP13]. +## +############################################################################# +# # FIXME: Move me into GAP # Helper function to compute all primes up to a given integer via a prime sieve BindGlobal("AllPrimesUpTo", @@ -633,55 +652,75 @@ function(ri, g, c, k, eps, N) fi; end); -# TODO: Use FindImageAn or FindImageSn to compute SLPs in nice gens. -# This function is taken from the function RecogniseSnAn in gap/SnAnBB.gi -# FIXME: describe return values etc +# This function is an excerpt of the function RecogniseSnAn in gap/SnAnBB.gi +# ri : recog info record with group G, +# n : degree +# stdGensAn : standard generators of An < G +# +# Returns either fail or a list [s, stdGens, xis], where: +# - s is the isomorphism type, that is either the string "Sn" or "An". +# - stdGens are the standard generators of G. Identical to stdGensAn if G is +# isomorphic to An +# - xis implicitly defines the isomorphism. It is used by FindImageSn and +# FindImageAn to compute the isomorphism. BindGlobal("ConstructSnAnIsomorphism", -function(ri, n, gens) - local grp, xis, gl, slp, eval, h, b, g; +function(ri, n, stdGensAn) + local grp, xis, gImage, gensWithoutMemory, bWithoutMemory, hWithoutMemory, slp, eval, h, b, g; grp := GroupWithMemory(Grp(ri)); - # TODO: strip here? - xis := ConstructXiAn(n, gens[1], gens[2]); + gensWithoutMemory := StripMemory(stdGensAn); + xis := ConstructXiAn(n, gensWithoutMemory[1], gensWithoutMemory[2]); for g in GeneratorsOfGroup(grp) do - # TODO: can we take g, gens, xis to be without memory? Like this? - # gens := StripMemory(gens); xis := StripMemory(xis); - gl := FindImageAn(ri, n, g, gens[1], gens[2], xis[1], xis[2]); - if gl = fail then return fail; fi; - if SignPerm(gl) = -1 then + gImage := FindImageAn(ri, n, StripMemory(g), gensWithoutMemory[1], + gensWithoutMemory[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 - slp := RECOG.SLPforAn(n, (1,2) * gl); - eval:=ResultOfStraightLineProgram(slp, [gens[2], gens[1]]); - h := eval * g ^ -1; + slp := RECOG.SLPforAn(n, (1,2) * gImage); + eval:=ResultOfStraightLineProgram(slp, [stdGensAn[2], stdGensAn[1]]); + h := eval * g ^ -1; if n mod 2 <> 0 then - b := gens[1] * gens[2]; + b := stdGensAn[1] * stdGensAn[2]; else - b := h * gens[1] * gens[2]; + b := h * stdGensAn[1] * stdGensAn[2]; fi; if SatisfiesSnPresentation(ri, n, b, h) then - xis := ConstructXiSn(n, b, h); + bWithoutMemory := StripMemory(b); + hWithoutMemory := StripMemory(h); + xis := ConstructXiSn(n, bWithoutMemory, hWithoutMemory); + # TODO: Move this loop, introduce a new variable foundOddPermutation, + # because we already computed this for the previous generators for g in GeneratorsOfGroup(grp) do - gl := FindImageSn(ri, n, g, b, h, xis[1], xis[2]); - if gl = fail then return fail; fi; - slp := RECOG.SLPforSn(n, gl); + gImage := FindImageSn(ri, n, StripMemory(g), bWithoutMemory, hWithoutMemory, 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, g) then return fail; fi; + if not isequal(ri)(eval, StripMemory(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; + slp := RECOG.SLPforAn(n, gImage); + eval:=ResultOfStraightLineProgram(slp, [gensWithoutMemory[2], gensWithoutMemory[1]]); + if not isequal(ri)(eval, StripMemory(g)) then return fail; fi; fi; od; - return ["An", [gens[1], gens[2]], xis]; + return ["An", [stdGensAn[1], stdGensAn[2]], xis]; end); -# FIXME: describe function +# This method is an implementation of . It is the main +# function of SnAnUnknownDegree. +# +# From , Theorem 1.1: +# 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. BindGlobal("RecogniseSnAn", function(ri, eps, N) local T, foundPreImagesOfStdGens, iterator, c, tmp, isoData, i; @@ -715,3 +754,72 @@ function(ri, eps, N) 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 +#! 9 <= n. +#! It is an implementation of . +#! @EndChunk +FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) + local G, N, isoData, degree; + G := Grp(ri); + # TODO find value for N and eps + # Check magma + # TODO: Can we assume that recognition of natural Sn and An came first? Can + # we explicitly check that by checking ri!.fhmethsel? + if IsPermGroup(G) then + N := NrMovedPoints(G); + else + N := ErrorNoReturn("TODO"); + fi; + # Try to find an isomorphism + isoData := RecogniseSnAn(ri, 1 / 10 ^ 6, N); + # NeverApplicable or TemporaryFailure + if not IsList(isoData) then + return isoData; + fi; + SetFilterObj(ri, IsLeaf); + degree := isoData[4]; + if isoData[1] = "Sn" then + SetSize(ri, Factorial(degree)); + SetIsRecogInfoForAlmostSimpleGroup(ri, true); + else + SetSize(ri, Factorial(degree) / 2); + SetIsRecogInfoForSimpleGroup(ri, true); + fi; + # Note that when putting the generators into the record, we reverse + # their order, such that it fits to the SLPforSn/SLPforAn function! + Setslptonice(ri, SLPOfElms(Reversed(isoData[2]))); + isoData[2] := StripMemory(isoData[2]); + SetNiceGens(ri, Reversed(isoData[2])); + # TODO do we need to StripMemory somewhere here? + # TODO better place to save these? + ri!.SnAnUnknownDegreeIsoData := isoData; + if isoData[1] = "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[4]; + image := FindImageSn(ri, degree, g, isoData[2][1], isoData[2][2], + isoData[3][1], isoData[3][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[4]; + image := FindImageAn(ri, degree, g, isoData[2][1], isoData[2][2], + isoData[3][1], isoData[3][2]); + return RECOG.SLPforAn(degree, image); +end; diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index 313af6ec4..342affd45 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -1,7 +1,7 @@ #@local testFunction, IsBolsteringElement, degrees #@local altGroups, symGroups, permMatGroup, altMatGroups, nonAltOrSymGroups -#@local ri, g, c, r, i, x -#@local sets, S11On2Sets, res, isoData, gensWithMem, g1, img1, g2, img2 +#@local ri, g, c, r, i, x, slp +#@local sets, S11On2Sets, res, isoData, gens, g1, img1, g2, img2 # # testing matrix: # - isomorphic: yes, no @@ -218,15 +218,36 @@ gap> BuildCycle(ri, c, x, 10); gap> sets := Combinations([1 .. 11], 2);; gap> S11On2Sets := Action(SymmetricGroup(11), sets, OnSets);; gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; -gap> isoData := RecogniseSnAn(ri, 1/10, 20);; -gap> gensWithMem := GeneratorsWithMemory(GeneratorsOfGroup(S11On2Sets));; -gap> g1 := gensWithMem[1];; +gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri);; +gap> isoData := ri!.SnAnUnknownDegreeIsoData;; +gap> gens := GeneratorsOfGroup(S11On2Sets);; +gap> g1 := gens[1];; gap> img1 := FindImageSn(ri, 11, g1, isoData[2][1], isoData[2][2], > isoData[3][1], isoData[3][2]);; gap> CycleStructurePerm(img1); [ ,,,,,,,,, 1 ] -gap> g2 := gensWithMem[2];; +gap> g2 := gens[2];; gap> img2 := FindImageSn(ri, 11, g2, isoData[2][1], isoData[2][2], > isoData[3][1], isoData[3][2]);; gap> CycleStructurePerm(img2); [ 1 ] + +# FindHomMethodsGeneric.SnAnUnknownDegree +gap> sets := Combinations([1 .. 11], 2);; +gap> S11On2Sets := Action(SymmetricGroup(11), sets, OnSets);; +gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; +gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri); +true +gap> Size(ri); +39916800 +gap> Size(SymmetricGroup(11)); +39916800 + +# Check Slp function +gap> ri := EmptyRecognitionInfoRecord(rec(), SymmetricGroup(11), false);; +gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri); +true +gap> x := PseudoRandom(Grp(ri));; +gap> slp := SLPforElement(ri, x);; +gap> x = ResultOfStraightLineProgram(slp, NiceGens(ri)); +true From eba8689cce1e054b2931780c3784280cd653a0eb Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 30 Nov 2020 15:04:52 +0100 Subject: [PATCH 28/64] Relocate computation of constants in ThreeCycleCandidatesIterator. --- gap/SnAnUnknownDegree.gi | 54 ++++++++++++++++++++++++--------------- gap/SnAnUnknownDegree.tst | 2 +- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 212e32b25..4f131d6b9 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -44,11 +44,34 @@ function(n) return ListBlist([1..n], sieve); end); - -# ri : recog info record with group G # eps : real number, the error bound # N : integer, upper bound for the degree of G # +# Returns constants used in ThreeCyclesCanditatesIterator +# as [M, B, T, C, logInt2N] +BindGlobal("ThreeCycleCandidatesConstants", + function(eps, N) + local M, allPrimes, i, p; + # Constants + # TODO: better iteration over primes + M := 1; + allPrimes := AllPrimesUpTo(N); + for i in [2 .. Length(allPrimes)] do + p := allPrimes[i]; + M := M * p ^ LogInt(N, p); + od; + # FIXME: Probably B can be chosen smaller + return [M, + Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))), + Int(Ceil(3 * Log2(3 / Float(eps)))), + Int(Ceil(Float(3 * N * ~[3] / 5))), + LogInt(N, 2) + ]; +end); + +# ri : recog info record with group G +# constants : list of integers [M, B, T, C, 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. @@ -60,14 +83,12 @@ end); # - TemporaryFailure, if we exhausted all attempts # - NeverApplicable, if we found out that G can't be an Sn or An BindGlobal("ThreeCycleCandidatesIterator", - function(ri, eps, N) + function(ri, constants) local # involution t, # integers, controlling the number of iterations M, B, T, C, logInt2N, - # iteration over all primes up to N - allPrimes, i, p, # counters nrInvolutions, nrTriedConjugates, nrThreeCycleCandidates, # helper functions @@ -76,19 +97,11 @@ BindGlobal("ThreeCycleCandidatesIterator", # The current involution t_i t := fail; - # Constants - # TODO: better iteration over primes - M := 1; - allPrimes := AllPrimesUpTo(N); - for i in [2 .. Length(allPrimes)] do - p := allPrimes[i]; - M := M * p ^ LogInt(N, p); - od; - # FIXME: Probably B can be chosen smaller - B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))); - T := Int(Ceil(3 * Log2(3 / Float(eps)))); - C := Int(Ceil(Float(3 * N * T / 5))); - logInt2N := LogInt(N, 2); + M := constants[1]; + B := constants[2]; + T := constants[3]; + C := constants[4]; + logInt2N := constants[5]; # Counters # Counts the constructed involutions t_i in steps 2 & 3. @@ -723,11 +736,12 @@ end); # isomorphism from G to An or Sn. BindGlobal("RecogniseSnAn", function(ri, eps, N) - local T, foundPreImagesOfStdGens, iterator, c, tmp, isoData, i; + local T, foundPreImagesOfStdGens, constants, iterator, c, tmp, isoData, i; T := Int(Ceil(Log(1 / Float(eps)))); foundPreImagesOfStdGens := false; + constants := ThreeCycleCandidatesConstants(1. / 4., N); for i in [1 .. T] do - iterator := ThreeCycleCandidatesIterator(ri, 1. / 4., N); + iterator := ThreeCycleCandidatesIterator(ri, constants); c := iterator(); while c <> fail do if c = NeverApplicable then return NeverApplicable; fi; diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index 342affd45..d007362a0 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -17,7 +17,7 @@ gap> testFunction := function(G, eps, N) > local ri, iterator, candidate, i, j; > ri := EmptyRecognitionInfoRecord(rec(), G, false); -> iterator := ThreeCycleCandidatesIterator(ri, eps, N); +> iterator := ThreeCycleCandidatesIterator(ri, ThreeCycleCandidatesConstants(eps, N)); > for i in [1 .. 10] do > candidate := iterator(); > for j in [1 .. 10] do From 65033d42b2ff90c1b0b86cd0fe0c71ad55bfea28 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 30 Nov 2020 15:08:30 +0100 Subject: [PATCH 29/64] Fix upper bound T in RecogniseSnAn --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 4f131d6b9..1ffe566bd 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -737,7 +737,7 @@ end); BindGlobal("RecogniseSnAn", function(ri, eps, N) local T, foundPreImagesOfStdGens, constants, iterator, c, tmp, isoData, i; - T := Int(Ceil(Log(1 / Float(eps)))); + T := Log2Int(1 / Float(eps)); foundPreImagesOfStdGens := false; constants := ThreeCycleCandidatesConstants(1. / 4., N); for i in [1 .. T] do From 9cda2133f619d403b09c517f23b5b8d96eb21c8a Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 30 Nov 2020 15:25:52 +0100 Subject: [PATCH 30/64] Adjust tryThreeCycleCandidate - Change repeat to for-loop - Change upper bound from logInt2N to logInt2N + 1 - Change condition in if-statement that returns NeverApplicable --- gap/SnAnUnknownDegree.gi | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 1ffe566bd..276c1b12f 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -132,15 +132,13 @@ BindGlobal("ThreeCycleCandidatesIterator", # If this is the case, we need to construct the next involution if nrTriedConjugates >= C or nrThreeCycleCandidates >= T then r := RandomElm(ri, "simplesocle", true)!.el; - a := 0; tPower := r ^ M; # Invariant: tPower = (r ^ M) ^ (2 ^ a) - repeat - a := a + 1; + for a in [1 .. logInt2N + 1] tPowerOld := tPower; tPower := tPower ^ 2; - until a = logInt2N or isone(ri)(tPower); - if a = logInt2N then + if isone(ri)(tPower) then break; fi; + if not isone(ri)(tPower) then return NeverApplicable; fi; t := tPowerOld; From 8bb7877372d63c7e9c4b537d4101664c76b696ce Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 15:37:42 +0100 Subject: [PATCH 31/64] Update comments in gap/SnAnUnknownDegree.gi --- gap/SnAnUnknownDegree.gi | 2 -- 1 file changed, 2 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 276c1b12f..f23465b67 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -53,7 +53,6 @@ BindGlobal("ThreeCycleCandidatesConstants", function(eps, N) local M, allPrimes, i, p; # Constants - # TODO: better iteration over primes M := 1; allPrimes := AllPrimesUpTo(N); for i in [2 .. Length(allPrimes)] do @@ -76,7 +75,6 @@ end); # on the simple observation that the product of two involutions t1, t2, which # only move one common point, squares to a 3-cycle. # -# TODO: take care of duplicate candidates? # 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 From 94275bd838c4986839b5e5de4d00464f80a1e367 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 16:57:20 +0100 Subject: [PATCH 32/64] Fix SnAnUnknownDegree subfunctions --- gap/SnAnUnknownDegree.gi | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index f23465b67..a5d1811d0 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -47,8 +47,7 @@ end); # eps : real number, the error bound # N : integer, upper bound for the degree of G # -# Returns constants used in ThreeCyclesCanditatesIterator -# as [M, B, T, C, logInt2N] +# Returns a record of constants used in ThreeCyclesCanditatesIterator. BindGlobal("ThreeCycleCandidatesConstants", function(eps, N) local M, allPrimes, i, p; @@ -59,17 +58,17 @@ BindGlobal("ThreeCycleCandidatesConstants", p := allPrimes[i]; M := M * p ^ LogInt(N, p); od; - # FIXME: Probably B can be chosen smaller - return [M, - Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))), - Int(Ceil(3 * Log2(3 / Float(eps)))), - Int(Ceil(Float(3 * N * ~[3] / 5))), - LogInt(N, 2) - ]; + return record( + M := M, + B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))), + T := Int(Ceil(3 * Log2(3 / Float(eps)))), + C := Int(Ceil(Float(3 * N * ~[3] / 5))), + logInt2N := LogInt(N, 2) + ); end); # ri : recog info record with group G -# constants : list of integers [M, B, T, C, logInt2N] +# 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 @@ -132,10 +131,16 @@ BindGlobal("ThreeCycleCandidatesIterator", r := RandomElm(ri, "simplesocle", true)!.el; tPower := r ^ M; # Invariant: tPower = (r ^ M) ^ (2 ^ a) - for a in [1 .. logInt2N + 1] + # We make a small improvement to the version described in the + # algorithm. 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] tPowerOld := tPower; tPower := tPower ^ 2; if isone(ri)(tPower) then break; fi; + od; if not isone(ri)(tPower) then return NeverApplicable; fi; @@ -733,7 +738,7 @@ end); BindGlobal("RecogniseSnAn", function(ri, eps, N) local T, foundPreImagesOfStdGens, constants, iterator, c, tmp, isoData, i; - T := Log2Int(1 / Float(eps)); + T := Int(Ceil(Log2(1 / Float(eps)))); foundPreImagesOfStdGens := false; constants := ThreeCycleCandidatesConstants(1. / 4., N); for i in [1 .. T] do From d4189bd1231b7049e1abca828e012f47a07a9490 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 16:57:52 +0100 Subject: [PATCH 33/64] SnAnUnknownDegree: improve comments --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index a5d1811d0..3447eff10 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -728,7 +728,7 @@ end); # This method is an implementation of . It is the main # function of SnAnUnknownDegree. # -# From , Theorem 1.1: +# From : # 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 From 6008209a03c6f0a41782ba7227accc0c0fc44aea Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 17:00:46 +0100 Subject: [PATCH 34/64] Fix ThreeCycleCandidatesConstants --- gap/SnAnUnknownDegree.gi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 3447eff10..d6834185c 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -58,7 +58,7 @@ BindGlobal("ThreeCycleCandidatesConstants", p := allPrimes[i]; M := M * p ^ LogInt(N, p); od; - return record( + return rec( M := M, B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))), T := Int(Ceil(3 * Log2(3 / Float(eps)))), @@ -94,11 +94,11 @@ BindGlobal("ThreeCycleCandidatesIterator", # The current involution t_i t := fail; - M := constants[1]; - B := constants[2]; - T := constants[3]; - C := constants[4]; - logInt2N := constants[5]; + 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. From 5865de8bf177cd229273d5f6540c8465207b032d Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 17:07:34 +0100 Subject: [PATCH 35/64] Fix stamps of some RandomElm calls --- gap/SnAnUnknownDegree.gi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index d6834185c..3f7e3b52d 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -128,7 +128,7 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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, "simplesocle", true)!.el; + 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 @@ -153,7 +153,7 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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, "simplesocle", true)!.el; + c := t ^ RandomElm(ri, "SnAnUnknownDegree", true)!.el; if not isequal(ri)(t * c, c * t) then nrThreeCycleCandidates := nrThreeCycleCandidates + 1; return (t * c) ^ 2; @@ -201,7 +201,7 @@ function(ri, c, eps, N) S := 7 * N * R; # find pre-bolstering elements for i in [0 .. S] do - r := RandomElm(ri, "simplesocle", true)!.el; + r := RandomElm(ri, "SnAnUnknownDegree", true)!.el; # test whether r is pre-bolstering cr := c ^ r; cr2 := cr ^ r; @@ -642,7 +642,7 @@ function(ri, g, c, k, eps, N) gTilde := g; for i in [1 .. Int(Ceil(Log(10. / 3.) ^ (-1) * (Log(Float(N)) + Log(1 / Float(eps)))))] do - x := r ^ RandomElm(ri, "simplesocle", true)!.el; + x := r ^ RandomElm(ri, "SnAnUnknownDegree", true)!.el; m := AdjustCycle(ri, gTilde, c, x, kTilde); if m = fail then return fail; fi; tmp := AppendPoints(ri, gTilde, c, m, s, kTilde, k0); From 1ac66b187e40fe5f95f1caff830428aa9f371b00 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 17:18:30 +0100 Subject: [PATCH 36/64] Fix ThreeCycleCandidatesIterator --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 3f7e3b52d..c00409a1f 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -136,7 +136,7 @@ BindGlobal("ThreeCycleCandidatesIterator", # 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] + for a in [1 .. logInt2N] do tPowerOld := tPower; tPower := tPower ^ 2; if isone(ri)(tPower) then break; fi; From dfb733450c23b2d5b6be907d319b7f4c2479dabe Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 17:21:31 +0100 Subject: [PATCH 37/64] Fix SnAnUnknownDegree documentation --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index c00409a1f..72af5b85b 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -773,7 +773,7 @@ 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 -#! 9 <= n. +#! 9 \leq n. #! It is an implementation of . #! @EndChunk FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) From 07314a528d2edb11bb456e954e29084e562e3987 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Mon, 30 Nov 2020 17:26:19 +0100 Subject: [PATCH 38/64] Fix ThreeCycleCandidatesConstants --- gap/SnAnUnknownDegree.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 72af5b85b..1b236af1e 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -62,7 +62,7 @@ BindGlobal("ThreeCycleCandidatesConstants", M := M, B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))), T := Int(Ceil(3 * Log2(3 / Float(eps)))), - C := Int(Ceil(Float(3 * N * ~[3] / 5))), + C := Int(Ceil(Float(3 * N * ~.T / 5))), logInt2N := LogInt(N, 2) ); end); From 02afbf2c2aca0d350e492180ce0cd51f9fdd5424 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 30 Nov 2020 17:34:43 +0100 Subject: [PATCH 39/64] Improve SnAnUnknownDegree --- gap/SnAnUnknownDegree.gi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 1b236af1e..d850da17d 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -794,6 +794,7 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) if not IsList(isoData) then return isoData; fi; + ri!.SnAnUnknownDegreeIsoData := isoData; SetFilterObj(ri, IsLeaf); degree := isoData[4]; if isoData[1] = "Sn" then @@ -808,9 +809,6 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) Setslptonice(ri, SLPOfElms(Reversed(isoData[2]))); isoData[2] := StripMemory(isoData[2]); SetNiceGens(ri, Reversed(isoData[2])); - # TODO do we need to StripMemory somewhere here? - # TODO better place to save these? - ri!.SnAnUnknownDegreeIsoData := isoData; if isoData[1] = "Sn" then Setslpforelement(ri, SLPforElementFuncsGeneric.SnUnknownDegree); else From dcb38758590eada73634724f67b35bd2089af201 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 15 Dec 2020 14:28:00 +0100 Subject: [PATCH 40/64] Add bib entry for Kleidman Liebeck --- doc/recog.bib | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/recog.bib b/doc/recog.bib index e553080a1..e9216be6d 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}, From 2552b42dc38fc4249c68992a332fe919a0c7f2dc Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 15 Dec 2020 14:28:50 +0100 Subject: [PATCH 41/64] Remove a comment --- gap/SnAnUnknownDegree.gi | 2 -- 1 file changed, 2 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index d850da17d..5a228ad7c 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -702,8 +702,6 @@ function(ri, n, stdGensAn) bWithoutMemory := StripMemory(b); hWithoutMemory := StripMemory(h); xis := ConstructXiSn(n, bWithoutMemory, hWithoutMemory); - # TODO: Move this loop, introduce a new variable foundOddPermutation, - # because we already computed this for the previous generators for g in GeneratorsOfGroup(grp) do gImage := FindImageSn(ri, n, StripMemory(g), bWithoutMemory, hWithoutMemory, xis[1], xis[2]); if gImage = fail then return fail; fi; From 9b5b89c0292fcfd897633b6c4ca0ef65febb8033 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Tue, 15 Dec 2020 14:29:34 +0100 Subject: [PATCH 42/64] Add degree bound N for matrix groups --- gap/SnAnUnknownDegree.gi | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 5a228ad7c..182ffc729 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -773,9 +773,13 @@ end); #! isomorphic to a symmetric group Sn or alternating group An with #! 9 \leq n. #! It is an implementation of . +#! +#! TODO: document the bound N. Refer to Kleidman Liebeck [KL90]. +#! +#! TODO: in the matrix case assumes that the group acts irreducibly. #! @EndChunk FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) - local G, N, isoData, degree; + local G, N, isoData, degree, p, d; G := Grp(ri); # TODO find value for N and eps # Check magma @@ -783,6 +787,31 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) # we explicitly check that by checking ri!.fhmethsel? if IsPermGroup(G) then N := 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: do we want to use the table for the other cases? + 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("TODO"); fi; From 53c8be02b27ee5ce05cda0337fc3853f248947aa Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 26 Jan 2021 14:40:37 +0100 Subject: [PATCH 43/64] Improve comments and an error message Remove some TODOs. --- gap/SnAnUnknownDegree.gi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 182ffc729..5e1415b56 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -774,18 +774,16 @@ end); #! 9 \leq n. #! It is an implementation of . #! -#! TODO: document the bound N. Refer to Kleidman Liebeck [KL90]. -#! -#! TODO: in the matrix case assumes that the group acts irreducibly. #! @EndChunk FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) local G, N, isoData, degree, p, d; G := Grp(ri); - # TODO find value for N and eps + # TODO find value for eps + eps := 1 / 10^2; # Check magma - # TODO: Can we assume that recognition of natural Sn and An came first? Can - # we explicitly check that by checking ri!.fhmethsel? if IsPermGroup(G) then + # TODO: Can we assume that recognition of natural Sn and An came first? Can + # we explicitly check that by checking ri!.fhmethsel? N := NrMovedPoints(G); elif IsMatrixGroup(G) then p := Characteristic(DefaultFieldOfMatrixGroup(G)); @@ -813,11 +811,13 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) N := Maximum(9, N); fi; else - N := ErrorNoReturn("TODO"); + N := ErrorNoReturn("SnAnUnknownDegree: no method to compute bound", + " , Grp() must be an IsPermGroup or an", + " IsMatrixGroup"); fi; # Try to find an isomorphism - isoData := RecogniseSnAn(ri, 1 / 10 ^ 6, N); - # NeverApplicable or TemporaryFailure + isoData := RecogniseSnAn(ri, eps, N); + # RecogniseSnAn returned NeverApplicable or TemporaryFailure if not IsList(isoData) then return isoData; fi; From be04dd16c407bedf401ae9c159996887aec60ced Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 26 Jan 2021 15:33:42 +0100 Subject: [PATCH 44/64] Improve SnAnUnknownDegree Calculate the bound N for permutation groups. Add a reference to Liebeck's "On minimal degrees and base sizes of primitive permutation groups". --- doc/recog.bib | 13 +++++++++++++ gap/SnAnUnknownDegree.gi | 15 +++++++++++---- gap/SnAnUnknownDegree.tst | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/doc/recog.bib b/doc/recog.bib index e9216be6d..20ffe346b 100644 --- a/doc/recog.bib +++ b/doc/recog.bib @@ -433,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/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 5e1415b56..f0e75578d 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -774,17 +774,24 @@ end); #! 9 \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) - local G, N, isoData, degree, p, d; + local G, eps, N, isoData, degree, p, d; G := Grp(ri); # TODO find value for eps eps := 1 / 10^2; # Check magma if IsPermGroup(G) then - # TODO: Can we assume that recognition of natural Sn and An came first? Can - # we explicitly check that by checking ri!.fhmethsel? - N := NrMovedPoints(G); + # 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); diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index d007362a0..9e8d6b848 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -244,7 +244,7 @@ gap> Size(SymmetricGroup(11)); 39916800 # Check Slp function -gap> ri := EmptyRecognitionInfoRecord(rec(), SymmetricGroup(11), false);; +gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri); true gap> x := PseudoRandom(Grp(ri));; From df772dbe1f69bedf30e19a694075c49fe1fc0f84 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 2 Feb 2021 15:13:38 +0100 Subject: [PATCH 45/64] Add prefixes to functions for AnSn recognition --- gap/SnAnUnknownDegree.gi | 151 ++++++++++++++++++-------------------- gap/SnAnUnknownDegree.tst | 60 +++++++-------- 2 files changed, 102 insertions(+), 109 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index f0e75578d..3b09259ad 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -19,8 +19,7 @@ # # FIXME: Move me into GAP # Helper function to compute all primes up to a given integer via a prime sieve -BindGlobal("AllPrimesUpTo", -function(n) +RECOG.AllPrimesUpTo := function(n) local i, j, sieve, result; if n <= 1000 then return Primes{[1..PositionSorted(Primes, n+1)-1]}; @@ -42,18 +41,17 @@ function(n) i := i + 2; od; return ListBlist([1..n], sieve); -end); +end; # eps : real number, the error bound # N : integer, upper bound for the degree of G # # Returns a record of constants used in ThreeCyclesCanditatesIterator. -BindGlobal("ThreeCycleCandidatesConstants", - function(eps, N) +RECOG.ThreeCycleCandidatesConstants := function(eps, N) local M, allPrimes, i, p; # Constants M := 1; - allPrimes := AllPrimesUpTo(N); + allPrimes := RECOG.AllPrimesUpTo(N); for i in [2 .. Length(allPrimes)] do p := allPrimes[i]; M := M * p ^ LogInt(N, p); @@ -65,7 +63,7 @@ BindGlobal("ThreeCycleCandidatesConstants", C := Int(Ceil(Float(3 * N * ~.T / 5))), logInt2N := LogInt(N, 2) ); -end); +end; # ri : recog info record with group G # constants : a record with components M, B, T, C, and logInt2N @@ -79,8 +77,7 @@ end); # - 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 -BindGlobal("ThreeCycleCandidatesIterator", - function(ri, constants) +RECOG.ThreeCycleCandidatesIterator := function(ri, constants) local # involution t, @@ -181,7 +178,7 @@ BindGlobal("ThreeCycleCandidatesIterator", return candidate; end; return oneThreeCycleCandidate; -end); +end; # ri : recog info record with group G # c : element of G, @@ -193,8 +190,7 @@ end); # # If the input is as assumed, then this function returns a list of bolstering # elements with respect to c. -BindGlobal("BolsteringElements", -function(ri, c, eps, N) +RECOG.BolsteringElements := function(ri, c, eps, N) local result, R, S, nrPrebolsteringElms, i, r, cr, cr2; result := []; R := Int(Ceil(7 / 4 * Log2(Float(eps ^ -1)))); @@ -221,7 +217,7 @@ function(ri, c, eps, N) if Length(result) > R then break; fi; od; return result; -end); +end; # ri : recog info record with group G # g : element of G, @@ -235,8 +231,7 @@ end); # 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. -BindGlobal("IsFixedPoint", -function(ri, g, c, r) +RECOG.IsFixedPoint := function(ri, g, c, r) local # respectively c ^ (g ^ i) cg, cg2, cg3, cg4, @@ -280,7 +275,7 @@ function(ri, g, c, r) if not commutesWithAtMostOne(ri, x2, H2) then return false; fi; if not commutesWithAtMostOne(ri, x3, H2) then return false; fi; return true; -end); +end; # ri : recog info record with group G # g : element of G, @@ -298,8 +293,7 @@ end); # 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. -BindGlobal("AdjustCycle", -function(ri, g, c, r, k) +RECOG.AdjustCycle := function(ri, g, c, r, k) local # list of 4 booleans, is point j fixed point F4, @@ -318,7 +312,7 @@ function(ri, g, c, r, k) # conjugating element x; # According to the paper we have: - # F := { 1 \leq j \leq k | IsFixedPoint(g, c ^ (g ^ (j - 3)), r) = true } + # 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 @@ -332,7 +326,7 @@ function(ri, g, c, r, k) for j in [1 .. k] do # invariant: t = c ^ (g ^ (j - 3)) t := t ^ g; - if IsFixedPoint(ri, g, t, r) then + if RECOG.IsFixedPoint(ri, g, t, r) then if j <= 4 then F4[j] := true; fi; @@ -405,7 +399,7 @@ function(ri, g, c, r, k) fi; fi; return r^x; -end); +end; # ri : recog info record with group G # g : element of G, @@ -413,7 +407,7 @@ end); # c : element of G, # should be a 3-cycle # r : element of G, -# should be a cycle as in the return value of AdjustCycle. If e.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 @@ -426,7 +420,7 @@ end); # - gTilde: element of G, # should be a cycle matching g # - sTilde: element of G, -# should be current storage cycle, since we may call AppendPoints +# 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 @@ -436,8 +430,7 @@ end); # 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. -BindGlobal("AppendPoints", -function(ri, g, c, r, s, k, k0) +RECOG.AppendPoints := function(ri, g, c, r, s, k, k0) local gTilde, sTilde, kTilde, gc2, x, j; gTilde := g; sTilde := s; @@ -460,20 +453,19 @@ function(ri, g, c, r, s, k, k0) fi; od; return [gTilde, sTilde, kTilde]; -end); +end; # ri : recog info record with group G # g : element of G # p : prime # Returns whether g is an element of order p. -BindGlobal("IsElmOfPrimeOrder", -function(ri, g, 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); +end; # ri : recog info record with group G # c : a 3-cycle of a group G @@ -487,8 +479,7 @@ end); # 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 -BindGlobal("BuildCycle", -function(ri, c, x, N) +RECOG.BuildCycle := function(ri, c, x, N) local # integers m, mDash, @@ -509,7 +500,7 @@ function(ri, c, x, N) while true do if m >= N / 2 then return fail; - elif IsElmOfPrimeOrder(ri, d * c, 5) then + elif RECOG.IsElmOfPrimeOrder(ri, d * c, 5) then m := m + 1; else break; @@ -526,13 +517,13 @@ function(ri, c, x, N) fi; # case |alpha - beta| = 1 dx := d ^ x; - if not IsElmOfPrimeOrder(ri, dx * c, 5) then + 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 IsElmOfPrimeOrder(ri, d * c, 2) then + if not RECOG.IsElmOfPrimeOrder(ri, d * c, 2) then # case 1, alpha > beta if docommute(ri)(dx, d ^ c) then e := dx ^ c; @@ -564,7 +555,7 @@ function(ri, c, x, N) while true do if mDash >= N / 2 then return fail; - elif IsElmOfPrimeOrder(ri, f * c, 5) then + elif RECOG.IsElmOfPrimeOrder(ri, f * c, 5) then mDash := mDash + 1; else break; @@ -573,7 +564,7 @@ function(ri, c, x, N) f := f ^ x2; od; return [g, 2 * mDash + 2 * m + 3]; -end); +end; # ri : recog info record with group G # c : element of G, @@ -587,23 +578,22 @@ end); # - 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. +# 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 -BindGlobal("ConstructLongCycle", -function(ri, c, eps, N) +RECOG.ConstructLongCycle := function(ri, c, eps, N) local g, k, tmp, B, x; - B := BolsteringElements(ri, c, Float(eps) / 2., N); + 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 := BuildCycle(ri, c, x, N); + tmp := RECOG.BuildCycle(ri, c, x, N); if tmp = fail then return fail; elif tmp[2] > k then @@ -612,7 +602,7 @@ function(ri, c, eps, N) fi; od; return [g, k]; -end); +end; # ri : recog info record with group G # g : element of G, @@ -631,8 +621,7 @@ end); # 3-cycle, a standard generator of An < G # - kTilde : integer, # degree of group An < G, that is generated by gTilde and cTilde -BindGlobal("StandardGenerators", -function(ri, g, c, k, eps, N) +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; @@ -643,9 +632,9 @@ function(ri, g, c, k, eps, N) 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 := AdjustCycle(ri, gTilde, c, x, kTilde); + m := RECOG.AdjustCycle(ri, gTilde, c, x, kTilde); if m = fail then return fail; fi; - tmp := AppendPoints(ri, gTilde, c, m, s, kTilde, k0); + tmp := RECOG.AppendPoints(ri, gTilde, c, m, s, kTilde, k0); gTilde := tmp[1]; s := tmp[2]; kTilde := tmp[3]; @@ -659,14 +648,14 @@ function(ri, g, c, k, eps, N) gTilde := gTilde * s; cTilde := s; fi; - if SatisfiesAnPresentation(ri, gTilde, cTilde, kTilde) then + if RECOG.SatisfiesAnPresentation(ri, gTilde, cTilde, kTilde) then return [gTilde, cTilde, kTilde]; else return fail; fi; -end); +end; -# This function is an excerpt of the function RecogniseSnAn in gap/SnAnBB.gi +# This function is an excerpt of the function RECOG.RecogniseSnAn in gap/SnAnBB.gi # ri : recog info record with group G, # n : degree # stdGensAn : standard generators of An < G @@ -675,16 +664,16 @@ end); # - s is the isomorphism type, that is either the string "Sn" or "An". # - stdGens are the standard generators of G. Identical to stdGensAn if G is # isomorphic to An -# - xis implicitly defines the isomorphism. It is used by FindImageSn and -# FindImageAn to compute the isomorphism. -BindGlobal("ConstructSnAnIsomorphism", -function(ri, n, stdGensAn) - local grp, xis, gImage, gensWithoutMemory, bWithoutMemory, hWithoutMemory, slp, eval, h, b, g; +# - xis implicitly defines the isomorphism. It is used by RECOG.FindImageSn and +# RECOG.FindImageAn to compute the isomorphism. +RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAn) + local grp, xis, gImage, gensWithoutMemory, bWithoutMemory, hWithoutMemory, + slp, eval, h, b, g; grp := GroupWithMemory(Grp(ri)); gensWithoutMemory := StripMemory(stdGensAn); - xis := ConstructXiAn(n, gensWithoutMemory[1], gensWithoutMemory[2]); + xis := RECOG.ConstructXiAn(n, gensWithoutMemory[1], gensWithoutMemory[2]); for g in GeneratorsOfGroup(grp) do - gImage := FindImageAn(ri, n, StripMemory(g), gensWithoutMemory[1], + gImage := RECOG.FindImageAn(ri, n, StripMemory(g), gensWithoutMemory[1], gensWithoutMemory[2], xis[1], xis[2]); if gImage = fail then return fail; fi; if SignPerm(gImage) = -1 then @@ -698,12 +687,14 @@ function(ri, n, stdGensAn) else b := h * stdGensAn[1] * stdGensAn[2]; fi; - if SatisfiesSnPresentation(ri, n, b, h) then + if RECOG.SatisfiesSnPresentation(ri, n, b, h) then bWithoutMemory := StripMemory(b); hWithoutMemory := StripMemory(h); - xis := ConstructXiSn(n, bWithoutMemory, hWithoutMemory); + xis := RECOG.ConstructXiSn(n, bWithoutMemory, hWithoutMemory); for g in GeneratorsOfGroup(grp) do - gImage := FindImageSn(ri, n, StripMemory(g), bWithoutMemory, hWithoutMemory, xis[1], xis[2]); + gImage := RECOG.FindImageSn(ri, n, StripMemory(g), + bWithoutMemory, hWithoutMemory, + xis[1], xis[2]); if gImage = fail then return fail; fi; slp := RECOG.SLPforSn(n, gImage); eval := ResultOfStraightLineProgram(slp, [h, b]); @@ -715,36 +706,36 @@ function(ri, n, stdGensAn) fi; else slp := RECOG.SLPforAn(n, gImage); - eval:=ResultOfStraightLineProgram(slp, [gensWithoutMemory[2], gensWithoutMemory[1]]); + eval := ResultOfStraightLineProgram(slp, [gensWithoutMemory[2], + gensWithoutMemory[1]]); if not isequal(ri)(eval, StripMemory(g)) then return fail; fi; fi; od; return ["An", [stdGensAn[1], stdGensAn[2]], xis]; -end); +end; # This method is an implementation of . It is the main # function of SnAnUnknownDegree. # # From : -# RecogniseSnAn is a one-sided Monte-Carlo algorithm with the following +# 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. -BindGlobal("RecogniseSnAn", -function(ri, eps, N) +RECOG.RecogniseSnAn := function(ri, eps, N) local T, foundPreImagesOfStdGens, constants, iterator, c, tmp, isoData, i; T := Int(Ceil(Log2(1 / Float(eps)))); foundPreImagesOfStdGens := false; - constants := ThreeCycleCandidatesConstants(1. / 4., N); + constants := RECOG.ThreeCycleCandidatesConstants(1. / 4., N); for i in [1 .. T] do - iterator := ThreeCycleCandidatesIterator(ri, constants); + iterator := RECOG.ThreeCycleCandidatesIterator(ri, constants); c := iterator(); while c <> fail do if c = NeverApplicable then return NeverApplicable; fi; - tmp := ConstructLongCycle(ri, c, 1. / 8., N); + tmp := RECOG.ConstructLongCycle(ri, c, 1. / 8., N); if tmp = fail then c := iterator(); continue; @@ -752,21 +743,21 @@ function(ri, eps, N) # Now tmp contains [g, k] where # g corresponds to a long cycle # k is its length - tmp := StandardGenerators(ri, tmp[1], c, tmp[2], 1. / 8., N); + 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 - isoData := ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); + isoData := RECOG.ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); if isoData = fail then continue; fi; Add(isoData, tmp[3]); return isoData; od; od; return TemporaryFailure; -end); +end; #! @BeginChunk SnAnUnknownDegree #! This method tries to determine whether the input group given by ri is @@ -800,16 +791,18 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) 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. + # 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: do we want to use the table for the other cases? 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. + # 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 @@ -823,8 +816,8 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) " IsMatrixGroup"); fi; # Try to find an isomorphism - isoData := RecogniseSnAn(ri, eps, N); - # RecogniseSnAn returned NeverApplicable or TemporaryFailure + isoData := RECOG.RecogniseSnAn(ri, eps, N); + # RECOG.RecogniseSnAn returned NeverApplicable or TemporaryFailure if not IsList(isoData) then return isoData; fi; @@ -856,7 +849,7 @@ SLPforElementFuncsGeneric.SnUnknownDegree := function(ri, g) local isoData, degree, image; isoData := ri!.SnAnUnknownDegreeIsoData; degree := isoData[4]; - image := FindImageSn(ri, degree, g, isoData[2][1], isoData[2][2], + image := RECOG.FindImageSn(ri, degree, g, isoData[2][1], isoData[2][2], isoData[3][1], isoData[3][2]); return RECOG.SLPforSn(degree, image); end; @@ -866,7 +859,7 @@ SLPforElementFuncsGeneric.AnUnknownDegree := function(ri, g) local isoData, degree, image; isoData := ri!.SnAnUnknownDegreeIsoData; degree := isoData[4]; - image := FindImageAn(ri, degree, g, isoData[2][1], isoData[2][2], + image := RECOG.FindImageAn(ri, degree, g, isoData[2][1], isoData[2][2], isoData[3][1], isoData[3][2]); return RECOG.SLPforAn(degree, image); end; diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index 9e8d6b848..0a69d6a6a 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -13,17 +13,17 @@ # # TODO: Use RECOG.TestGroup? # TODO: better name for testFunction -# tests ThreeCycleCandidatesIterator and BolsteringElements +# tests RECOG.ThreeCycleCandidatesIterator and RECOG.BolsteringElements gap> testFunction := function(G, eps, N) > local ri, iterator, candidate, i, j; > ri := EmptyRecognitionInfoRecord(rec(), G, false); -> iterator := ThreeCycleCandidatesIterator(ri, ThreeCycleCandidatesConstants(eps, N)); +> iterator := RECOG.ThreeCycleCandidatesIterator(ri, RECOG.ThreeCycleCandidatesConstants(eps, N)); > for i in [1 .. 10] do > candidate := iterator(); > for j in [1 .. 10] do > if candidate <> NeverApplicable > and candidate <> TemporaryFailure then -> BolsteringElements(ri, candidate, eps, +> RECOG.BolsteringElements(ri, candidate, eps, > N); > fi; > od; @@ -109,53 +109,53 @@ gap> for i in [1 .. Length(nonAltOrSymGroups)] do > testFunction(nonAltOrSymGroups[i], 1/100, 15); > od; -# IsFixedPoint +# 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> IsFixedPoint(ri, g,c,r); +gap> RECOG.IsFixedPoint(ri, g,c,r); true gap> r := (2,3,4);; -gap> IsFixedPoint(ri, g,c,r); +gap> RECOG.IsFixedPoint(ri, g,c,r); false -# AdjustCycle +# 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> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5) gap> r := (3,4,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,4,5) gap> r := (2,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5) gap> r := (2,4,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5,4) gap> r := (2,3,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,4,5) gap> r := (1,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5) gap> r := (1,4,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5,4) gap> r := (1,3,4,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,6,4,5) gap> r := (1,2,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5,4) gap> r := (1,2,3,5);; -gap> AdjustCycle(ri, g, c, r, 8); +gap> RECOG.AdjustCycle(ri, g, c, r, 8); (3,5,4,6) -# BuildCycle +# RECOG.BuildCycle gap> ri := EmptyRecognitionInfoRecord(rec(), SymmetricGroup(10), false);; # c = (u,v,w) @@ -164,53 +164,53 @@ 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> BuildCycle(ri, c, x, 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)* (3,7,8,9,10);; -gap> BuildCycle(ri, c, x, 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> BuildCycle(ri, c, x, 10); +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> BuildCycle(ri, c, x, 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> BuildCycle(ri, c, x, 10); +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> BuildCycle(ri, c, x, 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,3,7,8,9,10);; -gap> BuildCycle(ri, c, x, 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> BuildCycle(ri, c, x, 10); +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> BuildCycle(ri, c, x, 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> BuildCycle(ri, c, x, 10); +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 @@ -222,12 +222,12 @@ gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri);; gap> isoData := ri!.SnAnUnknownDegreeIsoData;; gap> gens := GeneratorsOfGroup(S11On2Sets);; gap> g1 := gens[1];; -gap> img1 := FindImageSn(ri, 11, g1, isoData[2][1], isoData[2][2], +gap> img1 := RECOG.FindImageSn(ri, 11, g1, isoData[2][1], isoData[2][2], > isoData[3][1], isoData[3][2]);; gap> CycleStructurePerm(img1); [ ,,,,,,,,, 1 ] gap> g2 := gens[2];; -gap> img2 := FindImageSn(ri, 11, g2, isoData[2][1], isoData[2][2], +gap> img2 := RECOG.FindImageSn(ri, 11, g2, isoData[2][1], isoData[2][2], > isoData[3][1], isoData[3][2]);; gap> CycleStructurePerm(img2); [ 1 ] From 69df35f36c5ed3d30080ac0f262f174f545cf36e Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Tue, 2 Feb 2021 15:23:40 +0100 Subject: [PATCH 46/64] Refactor RecogniseSnAn The degree n is now inserted into isoData in `ConstructSnAnIsomorphism` instead of `RecogniseSnAn`. --- gap/SnAnUnknownDegree.gi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 3b09259ad..7fbf2e369 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -660,12 +660,13 @@ end; # n : degree # stdGensAn : standard generators of An < G # -# Returns either fail or a list [s, stdGens, xis], where: +# Returns either fail or a list [s, stdGens, xis, n], where: # - s is the isomorphism type, that is either the string "Sn" or "An". # - stdGens are the standard generators of G. Identical to stdGensAn if G is # isomorphic to An # - 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 RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAn) local grp, xis, gImage, gensWithoutMemory, bWithoutMemory, hWithoutMemory, slp, eval, h, b, g; @@ -700,7 +701,7 @@ RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAn) eval := ResultOfStraightLineProgram(slp, [h, b]); if not isequal(ri)(eval, StripMemory(g)) then return fail; fi; od; - return ["Sn", [b, h], xis]; + return ["Sn", [b, h], xis, n]; else return fail; fi; @@ -712,7 +713,7 @@ RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAn) fi; od; - return ["An", [stdGensAn[1], stdGensAn[2]], xis]; + return ["An", [stdGensAn[1], stdGensAn[2]], xis, n]; end; # This method is an implementation of . It is the main @@ -752,7 +753,6 @@ RECOG.RecogniseSnAn := function(ri, eps, N) # g, c correspond to standard generators of An isoData := RECOG.ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); if isoData = fail then continue; fi; - Add(isoData, tmp[3]); return isoData; od; od; From 43bdea1b7456b9a7d91ab7af7af715009b4ded2a Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 2 Feb 2021 16:05:40 +0100 Subject: [PATCH 47/64] Refactor ConstructSnAnIsomorphism --- gap/SnAnUnknownDegree.gi | 144 +++++++++++++++++++++----------------- gap/SnAnUnknownDegree.tst | 8 +-- 2 files changed, 83 insertions(+), 69 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 7fbf2e369..e143325b3 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -658,62 +658,73 @@ end; # This function is an excerpt of the function RECOG.RecogniseSnAn in gap/SnAnBB.gi # ri : recog info record with group G, # n : degree -# stdGensAn : standard generators of An < G +# stdGensAnWithMemory : standard generators of An < G # -# Returns either fail or a list [s, stdGens, xis, n], where: -# - s is the isomorphism type, that is either the string "Sn" or "An". -# - stdGens are the standard generators of G. Identical to stdGensAn if G is -# isomorphic to An -# - 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 -RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAn) - local grp, xis, gImage, gensWithoutMemory, bWithoutMemory, hWithoutMemory, - slp, eval, h, b, 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. +RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAnWithMemory) + local grp, stdGensAn, xis, gImage, foundOddPermutation, slp, eval, + hWithMemory, bWithMemory, stdGensSnWithMemory, b, h, g; grp := GroupWithMemory(Grp(ri)); - gensWithoutMemory := StripMemory(stdGensAn); - xis := RECOG.ConstructXiAn(n, gensWithoutMemory[1], gensWithoutMemory[2]); + stdGensAn := StripMemory(stdGensAnWithMemory); + xis := RECOG.ConstructXiAn(n, stdGensAn[1], stdGensAn[2]); for g in GeneratorsOfGroup(grp) do - gImage := RECOG.FindImageAn(ri, n, StripMemory(g), gensWithoutMemory[1], - gensWithoutMemory[2], xis[1], xis[2]); + 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 - slp := RECOG.SLPforAn(n, (1,2) * gImage); - eval:=ResultOfStraightLineProgram(slp, [stdGensAn[2], stdGensAn[1]]); - h := eval * g ^ -1; - if n mod 2 <> 0 then - b := stdGensAn[1] * stdGensAn[2]; - else - b := h * stdGensAn[1] * stdGensAn[2]; - fi; - if RECOG.SatisfiesSnPresentation(ri, n, b, h) then - bWithoutMemory := StripMemory(b); - hWithoutMemory := StripMemory(h); - xis := RECOG.ConstructXiSn(n, bWithoutMemory, hWithoutMemory); - for g in GeneratorsOfGroup(grp) do - gImage := RECOG.FindImageSn(ri, n, StripMemory(g), - bWithoutMemory, hWithoutMemory, - 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 ["Sn", [b, h], xis, n]; - else - return fail; - fi; - else - slp := RECOG.SLPforAn(n, gImage); - eval := ResultOfStraightLineProgram(slp, [gensWithoutMemory[2], - gensWithoutMemory[1]]); - if not isequal(ri)(eval, StripMemory(g)) then return fail; fi; + 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; - - return ["An", [stdGensAn[1], stdGensAn[2]], xis, n]; + 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 GeneratorsOfGroup(grp) 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 @@ -770,7 +781,7 @@ end; #! #! @EndChunk FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) - local G, eps, N, isoData, degree, p, d; + local G, eps, N, p, d, recogData, isoData, degree, swapSLP; G := Grp(ri); # TODO find value for eps eps := 1 / 10^2; @@ -816,27 +827,30 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) " IsMatrixGroup"); fi; # Try to find an isomorphism - isoData := RECOG.RecogniseSnAn(ri, eps, N); + recogData := RECOG.RecogniseSnAn(ri, eps, N); # RECOG.RecogniseSnAn returned NeverApplicable or TemporaryFailure - if not IsList(isoData) then - return isoData; + if not IsRecord(recogData) then + return recogData; fi; + isoData := recogData.isoData; ri!.SnAnUnknownDegreeIsoData := isoData; SetFilterObj(ri, IsLeaf); - degree := isoData[4]; - if isoData[1] = "Sn" then + 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 putting the generators into the record, we reverse - # their order, such that it fits to the SLPforSn/SLPforAn function! - Setslptonice(ri, SLPOfElms(Reversed(isoData[2]))); - isoData[2] := StripMemory(isoData[2]); - SetNiceGens(ri, Reversed(isoData[2])); - if isoData[1] = "Sn" then + # 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(recogData.slpToStdGens, + swapSLP)); + if recogData.type = "Sn" then Setslpforelement(ri, SLPforElementFuncsGeneric.SnUnknownDegree); else Setslpforelement(ri, SLPforElementFuncsGeneric.AnUnknownDegree); @@ -848,9 +862,9 @@ end; SLPforElementFuncsGeneric.SnUnknownDegree := function(ri, g) local isoData, degree, image; isoData := ri!.SnAnUnknownDegreeIsoData; - degree := isoData[4]; - image := RECOG.FindImageSn(ri, degree, g, isoData[2][1], isoData[2][2], - isoData[3][1], isoData[3][2]); + 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; @@ -858,8 +872,8 @@ end; SLPforElementFuncsGeneric.AnUnknownDegree := function(ri, g) local isoData, degree, image; isoData := ri!.SnAnUnknownDegreeIsoData; - degree := isoData[4]; - image := RECOG.FindImageAn(ri, degree, g, isoData[2][1], isoData[2][2], - isoData[3][1], isoData[3][2]); + 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/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index 0a69d6a6a..f27fd3f30 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -222,13 +222,13 @@ gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri);; gap> isoData := ri!.SnAnUnknownDegreeIsoData;; gap> gens := GeneratorsOfGroup(S11On2Sets);; gap> g1 := gens[1];; -gap> img1 := RECOG.FindImageSn(ri, 11, g1, isoData[2][1], isoData[2][2], -> isoData[3][1], isoData[3][2]);; +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[2][1], isoData[2][2], -> isoData[3][1], isoData[3][2]);; +gap> img2 := RECOG.FindImageSn(ri, 11, g2, isoData[1][1], isoData[1][2], +> isoData[2][1], isoData[2][2]);; gap> CycleStructurePerm(img2); [ 1 ] From 8509c3388084818403638b418ff21048d2d22aae Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 2 Feb 2021 16:45:28 +0100 Subject: [PATCH 48/64] Improve RECOG.StandardGenerators --- gap/SnAnUnknownDegree.gi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index e143325b3..89f2dadb6 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -648,7 +648,10 @@ RECOG.StandardGenerators := function(ri, g, c, k, eps, N) gTilde := gTilde * s; cTilde := s; fi; - if RECOG.SatisfiesAnPresentation(ri, gTilde, cTilde, kTilde) then + if RECOG.SatisfiesAnPresentation(ri, + StripMemory(gTilde), + StripMemory(cTilde), + kTilde) then return [gTilde, cTilde, kTilde]; else return fail; From 6b528dd61be3d6fdfe7627846b6157b5b23daef6 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 2 Feb 2021 17:32:21 +0100 Subject: [PATCH 49/64] Remove some SnAnUnknownDegree tests to make the test suite finish quicker. --- gap/SnAnUnknownDegree.tst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index f27fd3f30..dda26e162 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -18,9 +18,9 @@ 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 .. 10] do +> for i in [1 .. 4] do > candidate := iterator(); -> for j in [1 .. 10] do +> for j in [1 .. 4] do > if candidate <> NeverApplicable > and candidate <> TemporaryFailure then > RECOG.BolsteringElements(ri, candidate, eps, From 27cd82f09cb2ae42f414a4bb807399d3dbd9cf56 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Tue, 2 Mar 2021 16:36:58 +0100 Subject: [PATCH 50/64] StripMemory in `BolsteringElements` for significant speed boost. We do a lot of checks with words in c and r. StripMemory reduces the overhead produced by managing SLPs in these computation. This reduces significantly the computation time in `BolsteringElements`. --- gap/SnAnUnknownDegree.gi | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index 89f2dadb6..eea6d97f5 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -190,14 +190,16 @@ end; # # If the input is as assumed, then this function returns a list of bolstering # elements with respect to c. -RECOG.BolsteringElements := function(ri, c, eps, N) - local result, R, S, nrPrebolsteringElms, i, r, cr, cr2; +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 * Log2(Float(eps ^ -1)))); S := 7 * N * R; # find pre-bolstering elements for i in [0 .. S] do - r := RandomElm(ri, "SnAnUnknownDegree", true)!.el; + rWithMem := RandomElm(ri, "SnAnUnknownDegree", true)!.el; + r := StripMemory(rWithMem); # test whether r is pre-bolstering cr := c ^ r; cr2 := cr ^ r; @@ -209,9 +211,9 @@ RECOG.BolsteringElements := function(ri, c, eps, N) if isone(ri)((cr ^ (c * r) * cr ^ (cr2 * c)) ^ 3) then - Add(result, c ^ 2 * r); + Add(result, cWithMem ^ 2 * rWithMem); else - Add(result, c * r); + Add(result, cWithMem * rWithMem); fi; fi; if Length(result) > R then break; fi; From 4dbdac5f6f510aeb5efacf96b980f97414e5150a Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Tue, 16 Mar 2021 17:09:17 +0100 Subject: [PATCH 51/64] SnAnUnknownDegree: fix usage of log2 Add comments to indicate our requirements for the degree n. --- gap/SnAnUnknownDegree.gi | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index eea6d97f5..cb3c90f4b 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -58,8 +58,8 @@ RECOG.ThreeCycleCandidatesConstants := function(eps, N) od; return rec( M := M, - B := Int(Ceil(13 * Log2(Float(N)) * Log2(3 / Float(eps)))), - T := Int(Ceil(3 * Log2(3 / Float(eps)))), + 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) ); @@ -77,6 +77,8 @@ end; # - 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 @@ -190,11 +192,14 @@ end; # # 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 * Log2(Float(eps ^ -1)))); + R := Int(Ceil(7 / 4 * Log(Float(eps ^ -1)))); S := 7 * N * R; # find pre-bolstering elements for i in [0 .. S] do @@ -674,6 +679,8 @@ end; # 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 grp, stdGensAn, xis, gImage, foundOddPermutation, slp, eval, hWithMemory, bWithMemory, stdGensSnWithMemory, b, h, g; @@ -778,7 +785,7 @@ 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 -#! 9 \leq n. +#! 11 \leq n. #! It is an implementation of . #! #! If Grp(ri) is a permutation group, we assume that it is primitive and From 227db8c739c197df1fdfc16c565f8c6c48085063 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 13:25:44 +0200 Subject: [PATCH 52/64] SnAnUnknownDegree: misc improvements --- gap/SnAnUnknownDegree.gi | 9 +++++---- gap/SnAnUnknownDegree.tst | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gap/SnAnUnknownDegree.gi b/gap/SnAnUnknownDegree.gi index cb3c90f4b..a5635a6a3 100644 --- a/gap/SnAnUnknownDegree.gi +++ b/gap/SnAnUnknownDegree.gi @@ -13,7 +13,8 @@ ## ## ## This file provides code for recognising whether a permutation group -## is isomorphic to an alternating or symmetric group. It implements [JLNP13]. +## is isomorphic to an alternating or symmetric group. It implements +## . ## ############################################################################# # @@ -130,9 +131,9 @@ RECOG.ThreeCycleCandidatesIterator := function(ri, constants) 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 - # algorithm. The order of r ^ M is a 2-power. It can be at most - # 2 ^ logInt2N. Thus, if we find an r such that + # 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 diff --git a/gap/SnAnUnknownDegree.tst b/gap/SnAnUnknownDegree.tst index dda26e162..e6d84192e 100644 --- a/gap/SnAnUnknownDegree.tst +++ b/gap/SnAnUnknownDegree.tst @@ -96,7 +96,6 @@ gap> nonAltOrSymGroups := [ > #Omega(0, 5, 5), > ];; -# FIXME: This is super slow. # ThreeCycleCandidates gap> for i in [1 .. Length(degrees)] do > testFunction(altGroups[i], 1/100, degrees[i]); From e86cf3eca090cb196cc2259d7c575c06be67f0a4 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 13:44:01 +0200 Subject: [PATCH 53/64] Move SnAnUnknownDegree.tst --- {gap => tst/working/quick}/SnAnUnknownDegree.tst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {gap => tst/working/quick}/SnAnUnknownDegree.tst (100%) diff --git a/gap/SnAnUnknownDegree.tst b/tst/working/quick/SnAnUnknownDegree.tst similarity index 100% rename from gap/SnAnUnknownDegree.tst rename to tst/working/quick/SnAnUnknownDegree.tst From db2340dc30d299d3518a4f7e71b7e1b9a4c60fe7 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 13:44:15 +0200 Subject: [PATCH 54/64] Move SnAnUnknownDegree.gi into gap/generic/ --- gap/{ => generic}/SnAnUnknownDegree.gi | 0 read.g | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename gap/{ => generic}/SnAnUnknownDegree.gi (100%) diff --git a/gap/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi similarity index 100% rename from gap/SnAnUnknownDegree.gi rename to gap/generic/SnAnUnknownDegree.gi diff --git a/read.g b/read.g index c70f1ca63..5fa7ed1dc 100644 --- a/read.g +++ b/read.g @@ -37,7 +37,7 @@ ReadPackage("recog","gap/generic/KnownNilpotent.gi"); ReadPackage("recog","gap/perm/giant.gi"); ReadPackage("recog","gap/perm/largebase.gi"); ReadPackage("recog","gap/SnAnBB.gi"); -ReadPackage("recog","gap/SnAnUnknownDegree.gi"); +ReadPackage("recog","gap/generic/SnAnUnknownDegree.gi"); # Matrices/Projective: ReadPackage("recog","gap/projective/findnormal.gi"); From 23ddf019d2077fb773b27b74e9de0cc01b0d881a Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 14:08:38 +0200 Subject: [PATCH 55/64] Update SnAnUnknownDegree.gi --- gap/generic/SnAnUnknownDegree.gi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index a5635a6a3..985632de1 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -742,6 +742,9 @@ end; # This method is an implementation of . It is the main # function of SnAnUnknownDegree. +# Note that it currently only works for 11 <= n. To make it work with +# smaller n, we need to include fixes from Jonathan Conder's B.Sc. +# Thesis "Algorithms for Permutation Groups". # # From : # RECOG.RecogniseSnAn is a one-sided Monte-Carlo algorithm with the following From f229d4fe4878c2341157c121576e87b33ad250f2 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 14:31:36 +0200 Subject: [PATCH 56/64] SnAnUnknownDegree.tst -> GenericSnAnUnknownDegree.tst --- .../quick/{SnAnUnknownDegree.tst => GenericSnAnUnknownDegree.tst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tst/working/quick/{SnAnUnknownDegree.tst => GenericSnAnUnknownDegree.tst} (100%) diff --git a/tst/working/quick/SnAnUnknownDegree.tst b/tst/working/quick/GenericSnAnUnknownDegree.tst similarity index 100% rename from tst/working/quick/SnAnUnknownDegree.tst rename to tst/working/quick/GenericSnAnUnknownDegree.tst From cab55b8bcd787096532d2c8c92a4def82d002004 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 14:50:49 +0200 Subject: [PATCH 57/64] Add SnAnRecogUnknownDegree tests --- .../quick/GenericSnAnUnknownDegree.tst | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/tst/working/quick/GenericSnAnUnknownDegree.tst b/tst/working/quick/GenericSnAnUnknownDegree.tst index e6d84192e..ef24089bb 100644 --- a/tst/working/quick/GenericSnAnUnknownDegree.tst +++ b/tst/working/quick/GenericSnAnUnknownDegree.tst @@ -1,7 +1,7 @@ #@local testFunction, IsBolsteringElement, degrees #@local altGroups, symGroups, permMatGroup, altMatGroups, nonAltOrSymGroups #@local ri, g, c, r, i, x, slp -#@local sets, S11On2Sets, res, isoData, gens, g1, img1, g2, img2 +#@local S11On2Sets, d, sets, SdOn2Sets, success, res, isoData, gens, g1, img1, g2, img2 # # testing matrix: # - isomorphic: yes, no @@ -232,15 +232,27 @@ gap> CycleStructurePerm(img2); [ 1 ] # FindHomMethodsGeneric.SnAnUnknownDegree -gap> sets := Combinations([1 .. 11], 2);; -gap> S11On2Sets := Action(SymmetricGroup(11), sets, OnSets);; -gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; -gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri); -true -gap> Size(ri); -39916800 -gap> Size(SymmetricGroup(11)); -39916800 +# 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); +> 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); +> 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);; From 1db85544ad00e00ade836b609f5a41fe1f2ccdfe Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Mon, 12 Apr 2021 18:17:17 +0200 Subject: [PATCH 58/64] Fix RECOG.ConstructSnAnIsomorphism --- gap/generic/SnAnUnknownDegree.gi | 1 + 1 file changed, 1 insertion(+) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index 985632de1..5f1c9ced6 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -688,6 +688,7 @@ RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAnWithMemory) grp := GroupWithMemory(Grp(ri)); stdGensAn := StripMemory(stdGensAnWithMemory); xis := RECOG.ConstructXiAn(n, stdGensAn[1], stdGensAn[2]); + foundOddPermutation := false; for g in GeneratorsOfGroup(grp) do gImage := RECOG.FindImageAn(ri, n, StripMemory(g), stdGensAn[1], stdGensAn[2], From e72306672a83fd29279927fc25188212c974cbf5 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Tue, 13 Apr 2021 17:52:25 +0200 Subject: [PATCH 59/64] SnAnUnknownDegree: use TestGroup and add fixes - Change input of recognition method `SnAnUnknownDegree` to `(ri, G)`. - Remove degrees smaller than `11` from tests, since they do not work currently. - Fix SLP reordering. - Rename `isoData` to `recogData` in `RecogniseSnAn`. --- gap/generic/SnAnUnknownDegree.gi | 18 +++--- .../quick/GenericSnAnUnknownDegree.tst | 62 ++++++++++++++----- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index 5f1c9ced6..8b9c272e5 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -755,7 +755,7 @@ end; # 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, isoData, i; + local T, foundPreImagesOfStdGens, constants, iterator, c, tmp, recogData, i; T := Int(Ceil(Log2(1 / Float(eps)))); foundPreImagesOfStdGens := false; constants := RECOG.ThreeCycleCandidatesConstants(1. / 4., N); @@ -779,9 +779,9 @@ RECOG.RecogniseSnAn := function(ri, eps, N) fi; # Now tmp contains [g, c, n] where # g, c correspond to standard generators of An - isoData := RECOG.ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); - if isoData = fail then continue; fi; - return isoData; + recogData := RECOG.ConstructSnAnIsomorphism(ri, tmp[3], tmp{[1,2]}); + if recogData = fail then continue; fi; + return recogData; od; od; return TemporaryFailure; @@ -797,9 +797,9 @@ end; #! not a giant (a giant is Sn or An in natural action). #! #! @EndChunk -FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) - local G, eps, N, p, d, recogData, isoData, degree, swapSLP; - G := Grp(ri); +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 @@ -865,8 +865,8 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri) SetNiceGens(ri, Reversed(isoData[1])); swapSLP := StraightLineProgram([[[2, 1], [1, 1]]], 2); Setslptonice(ri, - CompositionOfStraightLinePrograms(recogData.slpToStdGens, - swapSLP)); + CompositionOfStraightLinePrograms(swapSLP, + recogData.slpToStdGens)); if recogData.type = "Sn" then Setslpforelement(ri, SLPforElementFuncsGeneric.SnUnknownDegree); else diff --git a/tst/working/quick/GenericSnAnUnknownDegree.tst b/tst/working/quick/GenericSnAnUnknownDegree.tst index ef24089bb..0de05e4cd 100644 --- a/tst/working/quick/GenericSnAnUnknownDegree.tst +++ b/tst/working/quick/GenericSnAnUnknownDegree.tst @@ -2,6 +2,18 @@ #@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 SymOn2Sets, AltOn2Sets +# +# Hack to insert the method +gap> AddMethod(FindHomDbPerm, +> rec( +> method := FindHomMethodsGeneric.SnAnUnknownDegree, +> rank := 58, +> stamp := "SnAnUnknownDegreeHack", +> comment := "HACK", +> ) +> );; + # # testing matrix: # - isomorphic: yes, no @@ -67,16 +79,29 @@ gap> IsBolsteringElement := > if ForAny(dist, k -> k < 2) then return false; fi; > return true; > end;; -gap> degrees := Concatenation( -> [10, 12, 20, 21, 30, 35, 40, 42, 50, 51], -> Primes{[5 .. 15]} -> );; -gap> degrees := degrees{[1, 2, 11, 12]};; +gap> degrees := [11, 12, 13, 20, 21, 30, 35, 40, 42, 50, 51];; # TODO: more non-isomorphic examples # TODO: add projective groups -gap> altGroups := List(degrees, AlternatingGroup);; -gap> symGroups := List(degrees, SymmetricGroup);; +# +# SymmetricGroup action on 2-sets +gap> SymOn2Sets := function(d) +> local sets; +> sets := Combinations([1 .. d], 2);; +> return Action(SymmetricGroup(d), sets, OnSets);; +> end;; + +# +# AlternatingGroup action on 2-sets +gap> AltOn2Sets := function(d) +> local sets; +> sets := Combinations([1 .. d], 2);; +> return Action(AlternatingGroup(d), sets, OnSets);; +> end;; + +# +gap> altGroups := List(degrees, AltOn2Sets);; +gap> symGroups := List(degrees, SymOn2Sets);; gap> permMatGroup := G -> Group(List( > GeneratorsOfGroup(G), > x -> ImmutableMatrix(7, PermutationMat(x, NrMovedPoints(G), GF(7))) @@ -96,16 +121,16 @@ gap> nonAltOrSymGroups := [ > #Omega(0, 5, 5), > ];; -# ThreeCycleCandidates +# Test gap> for i in [1 .. Length(degrees)] do -> testFunction(altGroups[i], 1/100, degrees[i]); -> testFunction(symGroups[i], 1/100, degrees[i]); +> RECOG.TestGroup(altGroups[i], false, Factorial(degrees[i])/2); +> RECOG.TestGroup(symGroups[i], false, Factorial(degrees[i])); > od; gap> for i in [1 .. Length(altMatGroups)] do -> testFunction(altMatGroups[i], 1/100, 13); +> RECOG.TestGroup(altMatGroups[i], false, Size(altMatGroups[i])); > od; gap> for i in [1 .. Length(nonAltOrSymGroups)] do -> testFunction(nonAltOrSymGroups[i], 1/100, 15); +> RECOG.TestGroup(nonAltOrSymGroups[i], false, Size(nonAltOrSymGroups[i])); > od; # RECOG.IsFixedPoint @@ -217,7 +242,7 @@ gap> RECOG.BuildCycle(ri, c, x, 10); gap> sets := Combinations([1 .. 11], 2);; gap> S11On2Sets := Action(SymmetricGroup(11), sets, OnSets);; gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; -gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri);; +gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri, S11On2Sets);; gap> isoData := ri!.SnAnUnknownDegreeIsoData;; gap> gens := GeneratorsOfGroup(S11On2Sets);; gap> g1 := gens[1];; @@ -237,7 +262,7 @@ 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); +> success := FindHomMethodsGeneric.SnAnUnknownDegree(ri, SdOn2Sets); > if not success or not Size(ri) = Factorial(d) then > Print("wrong result! degree ", d, "\n"); > fi; @@ -248,7 +273,7 @@ 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); +> success := FindHomMethodsGeneric.SnAnUnknownDegree(ri, SdOn2Sets); > if not success or not Size(ri) = Factorial(d)/2 then > Print("wrong result! degree ", d, "\n"); > fi; @@ -256,9 +281,14 @@ gap> for d in [11 .. 15] do # Check Slp function gap> ri := EmptyRecognitionInfoRecord(rec(), S11On2Sets, false);; -gap> FindHomMethodsGeneric.SnAnUnknownDegree(ri); +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"));; \ No newline at end of file From dc1ce8244a4de476f51f512b148e238ee8f2f3c9 Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Wed, 14 Apr 2021 16:24:38 +0200 Subject: [PATCH 60/64] SnAnUnknownDegree: fix bug in SLP code --- gap/generic/SnAnUnknownDegree.gi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index 8b9c272e5..77529353a 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -683,13 +683,12 @@ end; # # TODO: Image Computation requires n >= 11. RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAnWithMemory) - local grp, stdGensAn, xis, gImage, foundOddPermutation, slp, eval, + local stdGensAn, xis, gImage, foundOddPermutation, slp, eval, hWithMemory, bWithMemory, stdGensSnWithMemory, b, h, g; - grp := GroupWithMemory(Grp(ri)); stdGensAn := StripMemory(stdGensAnWithMemory); xis := RECOG.ConstructXiAn(n, stdGensAn[1], stdGensAn[2]); foundOddPermutation := false; - for g in GeneratorsOfGroup(grp) do + for g in ri!.gensHmem do gImage := RECOG.FindImageAn(ri, n, StripMemory(g), stdGensAn[1], stdGensAn[2], xis[1], xis[2]); @@ -727,7 +726,7 @@ RECOG.ConstructSnAnIsomorphism := function(ri, n, stdGensAnWithMemory) return fail; fi; xis := RECOG.ConstructXiSn(n, b, h); - for g in GeneratorsOfGroup(grp) do + for g in ri!.gensHmem do gImage := RECOG.FindImageSn(ri, n, StripMemory(g), b, h, xis[1], xis[2]); From 27e39e75ccb296d2e125849d43d1a4c00b911cdd Mon Sep 17 00:00:00 2001 From: Sergio Siccha Date: Tue, 20 Apr 2021 14:55:06 +0200 Subject: [PATCH 61/64] SnAnUnknownDegree: improve comments --- gap/generic/SnAnUnknownDegree.gi | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index 77529353a..88969dfed 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -134,7 +134,7 @@ RECOG.ThreeCycleCandidatesIterator := function(ri, constants) # 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 + # (r ^ M) ^ (2 ^ logInt2N) is non-trivial, then we can return # NeverApplicable. for a in [1 .. logInt2N] do tPowerOld := tPower; @@ -742,9 +742,9 @@ end; # This method is an implementation of . It is the main # function of SnAnUnknownDegree. -# Note that it currently only works for 11 <= n. To make it work with -# smaller n, we need to include fixes from Jonathan Conder's B.Sc. -# Thesis "Algorithms for Permutation Groups". +# 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 @@ -821,7 +821,8 @@ FindHomMethodsGeneric.SnAnUnknownDegree := function(ri, G) # 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: do we want to use the table for the other cases? + # 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 From 0bdef3c5808972b7c33113933f6202898097386c Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Tue, 20 Apr 2021 14:44:45 +0200 Subject: [PATCH 62/64] Use RECOG.PrimesCache --- gap/generic/SnAnUnknownDegree.gi | 35 +++++--------------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index 88969dfed..5e2da15a0 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -18,43 +18,18 @@ ## ############################################################################# # -# FIXME: Move me into GAP -# Helper function to compute all primes up to a given integer via a prime sieve -RECOG.AllPrimesUpTo := function(n) - local i, j, sieve, result; - if n <= 1000 then - return Primes{[1..PositionSorted(Primes, n+1)-1]}; - 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; - return ListBlist([1..n], sieve); -end; - # 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, allPrimes, i, p; + local M, p; # Constants M := 1; - allPrimes := RECOG.AllPrimesUpTo(N); - for i in [2 .. Length(allPrimes)] do - p := allPrimes[i]; + 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( From 33ff249b7df8f4fb5abb7c02672bbb1511ca94a3 Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Wed, 12 May 2021 16:38:32 +0200 Subject: [PATCH 63/64] SnAnUnknownDegree: improve threeCycleCandidates A three cycle candidate `x` must satisfy `x ^ 3 = 1`. Obvious, but we missed it. This speeds up the function a lot. --- gap/generic/SnAnUnknownDegree.gi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gap/generic/SnAnUnknownDegree.gi b/gap/generic/SnAnUnknownDegree.gi index 5e2da15a0..4d026f750 100644 --- a/gap/generic/SnAnUnknownDegree.gi +++ b/gap/generic/SnAnUnknownDegree.gi @@ -738,6 +738,12 @@ RECOG.RecogniseSnAn := function(ri, eps, N) 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(); From 068e69d8a5333f4bc3da7937204e25018b8f590d Mon Sep 17 00:00:00 2001 From: Friedrich Rober Date: Wed, 9 Jun 2021 17:12:19 +0200 Subject: [PATCH 64/64] SnAnUnknownDegree: update tests --- .../quick/GenericSnAnUnknownDegree.tst | 75 +++++++++++++------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/tst/working/quick/GenericSnAnUnknownDegree.tst b/tst/working/quick/GenericSnAnUnknownDegree.tst index 0de05e4cd..375380287 100644 --- a/tst/working/quick/GenericSnAnUnknownDegree.tst +++ b/tst/working/quick/GenericSnAnUnknownDegree.tst @@ -1,8 +1,8 @@ -#@local testFunction, IsBolsteringElement, degrees +#@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 SymOn2Sets, AltOn2Sets +#@local SymOnKSets, AltOnKSets # # Hack to insert the method gap> AddMethod(FindHomDbPerm, @@ -13,6 +13,22 @@ gap> AddMethod(FindHomDbPerm, > 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: @@ -79,58 +95,71 @@ gap> IsBolsteringElement := > if ForAny(dist, k -> k < 2) then return false; fi; > return true; > end;; -gap> degrees := [11, 12, 13, 20, 21, 30, 35, 40, 42, 50, 51];; + +# 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 2-sets -gap> SymOn2Sets := function(d) +# SymmetricGroup action on k-sets +gap> SymOnKSets := function(d, k) > local sets; -> sets := Combinations([1 .. d], 2);; +> sets := Combinations([1 .. d], k);; > return Action(SymmetricGroup(d), sets, OnSets);; > end;; # # AlternatingGroup action on 2-sets -gap> AltOn2Sets := function(d) +gap> AltOnKSets := function(d, k) > local sets; -> sets := Combinations([1 .. d], 2);; +> sets := Combinations([1 .. d], k);; > return Action(AlternatingGroup(d), sets, OnSets);; > end;; # -gap> altGroups := List(degrees, AltOn2Sets);; -gap> symGroups := List(degrees, SymOn2Sets);; +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([10], +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), +> PSL(3, 5), > SL(3, 5), -> #permMatGroup(DihedralGroup(IsPermGroup, 10)), -> #Omega(-1, 4, 5), -> #Omega(+1, 4, 5), -> #Omega(0, 5, 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(degrees)] do -> RECOG.TestGroup(altGroups[i], false, Factorial(degrees[i])/2); -> RECOG.TestGroup(symGroups[i], false, Factorial(degrees[i])); +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 -> RECOG.TestGroup(nonAltOrSymGroups[i], false, Size(nonAltOrSymGroups[i])); +> 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 @@ -291,4 +320,8 @@ true # # Remove Hacky injection of our method gap> Remove(FindHomDbPerm, -> PositionProperty(FindHomDbPerm, x -> x.stamp = "SnAnUnknownDegreeHack"));; \ No newline at end of file +> PositionProperty(FindHomDbPerm, x -> x.stamp = "SnAnUnknownDegreeHack"));; +gap> Remove(FindHomDbMatrix, +> PositionProperty(FindHomDbMatrix, x -> x.stamp = "SnAnUnknownDegreeHack"));; +gap> Remove(FindHomDbProjective, +> PositionProperty(FindHomDbProjective, x -> x.stamp = "SnAnUnknownDegreeHack"));;