diff --git a/README.md b/README.md index c2bf50d..d7218ae 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ The repository contains code for running experiments for -_Hyperbolic generalized triangle groups_ by +[_Hyperbolic generalized triangle groups, property (T) and finite simple quotients_](https://arxiv.org/abs/2011.09276) by [Pierre-Emmanuel Caprace](https://perso.uclouvain.be/pierre-emmanuel.caprace/), [Marston Conder](https://www.math.auckland.ac.nz/~conder/), [Marek Kaluba](https://kalmar.faculty.wmi.amu.edu.pl/) and [Stefan Witzel](https://www.math.uni-bielefeld.de/~switzel/). -There are two disjoint computations covered in this repository. +There are three disjoint computations covered in this repository. ## Eigenvalues computations for _PSL₂(p)_ @@ -138,3 +138,14 @@ One can perform those computations in bulk by e.g. calling make 2_4_4 ``` to run all examples in `presentations_2_4_4.txt` in parallel. + +## Creating the tables of [arXiv:2011.09276](https://arxiv.org/abs/2011.09276) + +The scripts are located in `magma` directory and thoroughly commented. +There are two files, one contains the core Magma code used to create the tables, +the other one is a python script that augments the magma file by a list of +hyperbolic words. To use it put both files in a common folder, run +```bash +python3 hyperbolic_words.py +``` +and then load the resulting file `small_hyperbolic.magma` in Magma. diff --git a/magma/hyperbolic_words.py b/magma/hyperbolic_words.py new file mode 100644 index 0000000..dfa959b --- /dev/null +++ b/magma/hyperbolic_words.py @@ -0,0 +1,27 @@ +# This script augments creates the magma file small_hyperbolic.magma out of +# the file small_hyperbolic.magma_template by filling in the lines +# "hyp_words_a := ..." and "hyp_words_c := ..." with lists of all short words +# representing short hyperbolic elements. + +from itertools import permutations,product +import sys +basic_words_a = ['abcb','abcabc','abcbabcb','abcabcabcb','abcbabcbabcb','abcabcabcabc']#,'abcabcabcbabcb'] +basic_words_c = ['acbc','cbca','acabcb','cabcba','acbcacbc','cbcacbca','acabcabcbc','cabcabcbca','acabcbacabcb','cabcbacabcba','acbcacbcacbc','cbcacbcacbca'] + +def words(basic_word): + for p in permutations('ab'): + d = dict(zip('abc',p + ('c',))) + subs_word = ''.join(d[i] for i in basic_word) + for exps in product(('','^-1'), repeat=len(subs_word)): + word = ' * '.join((c + e) for (c,e) in zip(subs_word,exps)) + yield word + +with open("small_hyperbolic.magma_template","r") as magma_template: + with open("small_hyperbolic.magma","w") as magma: + for line in magma_template: + if 'hyp_words_a := ' in line: + magma.write('hyp_words_a := [ %s ];\n' % ' , '.join('{ %s }' % ', '.join(words(basic_word)) for basic_word in basic_words_a)) + elif 'hyp_words_c := ' in line: + magma.write('hyp_words_c := [ %s ];\n' % ' , '.join('{ %s }' % ', '.join(words(basic_word)) for basic_word in basic_words_c)) + else: + magma.write(line) diff --git a/magma/small_hyperbolic.magma_template b/magma/small_hyperbolic.magma_template new file mode 100644 index 0000000..e2145a1 --- /dev/null +++ b/magma/small_hyperbolic.magma_template @@ -0,0 +1,135 @@ +// Magma Functions related to the article +// +// Hyperbolic generalized triangle groups, property (T) and finite simple quotients +// by Pierre-Emmanuel Caprace, Marston Conder, Marek Kaluba, Stefan Witzel +// +// The functions and procedures in this file were written by Pierre-Emmanuel Caprace and Stefan Witzel +// +// The file is working magma code except for the two lines definint hyp_words_a and hyp_words_c that need to be replaced using hyperbolic_words.py +// It does not contain (all) the code that was used to create the tables but it is suited to reconstruct the tables. + +SetColumns(0); +SetAutoColumns(false); +SetVerbose("KBMAG",1); + +max_quotient_order:=5*10^7; + +// Procedure testing whether a trivalent generalized triangle group of half girth type (3,3,3) ("type A") or half girth type (2,4,4) ("type C") contains a copy of Z^2 generated by short elements. +// +// The arguments are an automatic group representing a generalized triangle group and the list hyp_words_a or hyp_words_c depening on type (these lists are the only part specific to trivalent triangle groups). +// +// The prints generators of a copy of Z^2 f one is found (so the group is not hyperbolic). If none is found the group may or may not be hyperbolic. + +find_flat := procedure(GA, ~hyp_words) + printf "Commuting pair: "; + for s in [1..#hyp_words] do + for i in [1..s] do + for x in hyp_words[i] do + for y in hyp_words[i] do + // Do x and y commute? + if (x, y) ne GA!1 then + continue; + end if; + + // If so, do they span a cyclic group? + num := GreatestCommonDivisor(#x,#y); + ex := Round(#y/num); + ey := Round(#x/num); + if x^ex eq y^ey or x^ex eq y^(-ey) then + continue; + end if; + + // If not they span a copy of Z^2 + printf "%o, %o;\t", x, y; + return; + end for; + end for; + end for; + end for; + printf "\n"; +end procedure; + +// Auxiliary function determining the name of a simple quotient +identify := function(Qs) + succ, res := SimpleGroupName(Image(Qs[1])); + if succ then + return [*res,Order(Image(Qs[1])), #Qs*]; + else + return [* [*<0,0,0>*], Order(Image(Qs[1])),#Qs*]; + end if; +end function; + +// Procedure collecting information around the hyperbolicity of a generalized triangle group of half girth type (3,3,3) (type A) or (2,4,4) (type C). +// +// Arguments are a generalized triangle group (as a finitely presented group) and "A" or "C" describing the type. +// +// It will first try to find an automatic structure and prints whether it has found one (this should never fail). +// Based on the automatic struture, it tries to prove the group hyperbolic and prints whether it manged. +// If the group could not be verified to be hyperbolic, the procedure tries to find a copy of Z^2 and print, whether it has found one. +// +// Of course, if a group is expected to contain Z^2, it is reasonable to call find_flat before calling IsHyperbolic. + +hyperbolic := procedure(G, type) + isa, GA := IsAutomaticGroup(G); + printf "automatic: %o\n", isa; + if not isa then + return; + end if; + ish, GH := IsHyperbolic(GA: MaxTries := 20); + printf "hyperbolic: %o\n", ish; + if ish then + return; + end if; + a := Generators(GA)[1]; + b := Generators(GA)[2]; + c := Generators(GA)[3]; + if type eq "A" then + hyp_words_a := [ False ]; + find_flat(GA, ~hyp_words_a); + elif type eq "C" then + hyp_words_c := [ False ]; + find_flat(GA, ~hyp_words_c); + end if; +end procedure; + +// Procedure collecting information abound finite simple quotients of a finitely presented group +// +// Arguments are a finitely presented group and a bound on the order of quotients (such as max_quotient_order) +// +// Prints the abelianization, the L2 quotients, and the finite simple quotients that are not L2 quotients up to the given order. + +quotients := procedure(G,n) + Q, mor := AbelianQuotient(G);; + printf "rk(H_1): %o\n", #Generators(AbelianQuotient(G)); + printf "l2-quotients: %o\n", L2Quotients(G); + printf "quotients: %o, %o\n", [identify(Qs) : Qs in SimpleQuotients(G,n:Family:="notPSL2",Limit:=0)], n; +end procedure; + + +// Function testing whether a generalized triangle group given in triangular presentation is virtually torsion free (VTF) +// +// Returns "true" if group is certified to be virtually torsion-free. The outpue "false" is inconclusive. +// +// The input is a quadruple consisting of the group presentation, followed by the triple of the orders of the vertex links, respectively corresponding to , , + +VTF:=function(g, n1, n2, n3) + o1:=n1*3/2; // Order group vx group generated by a, b + o2:=n2*3/2; // Order group vx group generated by b, c + o3:=n3*3/2; // Order group vx group generated by c, a + + // Test whether vertex groups inject in simple quotients + t:=false; + quot:=SimpleQuotientProcess(g, 6, 10^3, 1, 5*10^7:Limit:=1); + + while not t and not IsEmptySimpleQuotientProcess(quot) do + f:=SimpleEpimorphisms(quot)[1]; + Im:=Parent(f(g.1)); + o_im_1:=#sub; + o_im_2:=#sub; + o_im_3:=#sub; + t:=o1 eq o_im_1 and o2 eq o_im_2 and o3 eq o_im_3; + NextSimpleQuotient(~quot); + end while; + + return t; +end function; diff --git a/precomputed_reps_spectral_gap.jl b/precomputed_reps_spectral_gap.jl deleted file mode 100644 index a666bc6..0000000 --- a/precomputed_reps_spectral_gap.jl +++ /dev/null @@ -1,102 +0,0 @@ -using Nemo -using DelimitedFiles -using LinearAlgebra - -include("src/nemo_utils.jl") - -const PRECISION = 256 - -function parse_eval(expr_str, value, var_name) - ex = Meta.parse(expr_str) - svar = :($var_name) - return @eval begin - let $svar = $value - $ex - end - end -end - -function read_eval(fname, var_name, value) - a = readdlm(fname, ',', String) - a .= replace.(a, '/' => "//") - return parse_eval.(a, value, var_name) -end - -function load_discrete_repr(i, q = 109; CC = AcbField(PRECISION)) - ζ = root_of_unity(CC, (q + 1) ÷ 2) - degree = q - 1 - - ra = read_eval( - "data/Discrete reps PSL(2, $q)/discrete_rep_$(i)_a.txt", - :Z, - ζ, - ) - a = matrix(CC, [CC(s) for s in ra[1:degree, 1:degree]]) - - rb = read_eval( - "data/Discrete reps PSL(2, $q)/discrete_rep_$(i)_b.txt", - :Z, - ζ, - ) - b = matrix(CC, [CC(s) for s in rb[1:degree, 1:degree]]) - @assert contains(det(a), 1) - @assert contains(det(b), 1) - - return a, b -end - -function load_principal_repr(i, q = 109; CC = AcbField(PRECISION)) - ζ = root_of_unity(CC, (q - 1) ÷ 2) - degree = q + 1 - - ra = read_eval( - "data/Principal reps PSL(2, $q)/principal_rep_$(i)_a.txt", - :zz, - ζ, - ) - a = matrix(CC, [CC(z) for z in ra[1:degree, 1:degree]]) - - rb = read_eval( - "data/Principal reps PSL(2, $q)/principal_rep_$(i)_b.txt", - :zz, - ζ, - ) - b = matrix(CC, [CC(z) for z in rb[1:degree, 1:degree]]) - @assert contains(det(a), 1) - @assert contains(det(b), 1) - - return a, b -end - -if !isinteractive() - - for i = 0:27 - try - a, b = load_principal_repr(i) - adjacency = sum(a^i for i = 1:4) + sum(b^i for i = 1:4) - @time ev = let evs = safe_eigvals(adjacency) - _count_multiplicites(evs) - end - - @info "Principal Series Representation $i" ev[1:2] ev[end] - catch ex - @error "Principal Series Representation $i failed" ex - ex isa InterruptException && throw(ex) - end - end - - for i = 1:27 - try - a, b = load_discrete_repr(i) - adjacency = sum(a^i for i = 1:4) + sum(b^i for i = 1:4) - @time ev = let evs = safe_eigvals(adjacency) - _count_multiplicites(evs) - end - - @info "Discrete Series Representation $i" ev[1:2] ev[end] - catch ex - @error "Discrete Series Representation $i : failed" ex - ex isa InterruptException && rethrow(ex) - end - end -end