mirror of
https://github.com/kalmarek/SmallHyperbolic
synced 2024-11-23 15:35:27 +01:00
commit
89fbf76f32
15
README.md
15
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.
|
||||
|
27
magma/hyperbolic_words.py
Normal file
27
magma/hyperbolic_words.py
Normal file
@ -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)
|
135
magma/small_hyperbolic.magma_template
Normal file
135
magma/small_hyperbolic.magma_template
Normal file
@ -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 <a, b>, <b, c>, <c, a>
|
||||
|
||||
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<Im|f(g.1), f(g.2)>;
|
||||
o_im_2:=#sub<Im|f(g.2), f(g.3)>;
|
||||
o_im_3:=#sub<Im|f(g.3), f(g.1)>;
|
||||
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;
|
@ -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
|
Loading…
Reference in New Issue
Block a user