# Crossing the transcendental divide: from Schottky groups to algebraic curves

## Samantha Fairchild, Ángel David Ríos Ortiz

This is a Julia 1.8.2 notebook including computations used in the above named paper

All code was run on a MacBook Air with chip Apple M1 2020 and 8 GB memory

[1]:

import Pkg   ##Import any necessary packages

   Resolving package versions...
No Changes to ~/.julia/environments/v1.9/Project.toml
No Changes to ~/.julia/environments/v1.9/Manifest.toml
Resolving package versions...
No Changes to ~/.julia/environments/v1.9/Project.toml
No Changes to ~/.julia/environments/v1.9/Manifest.toml
Resolving package versions...
No Changes to ~/.julia/environments/v1.9/Project.toml
No Changes to ~/.julia/environments/v1.9/Manifest.toml

[2]:

using LinearAlgebra ##We use these particular Packages
using ImplicitEquations
using Plots


## Generating elements of the free group as matrices

It is important to minimize matrix multiplication, so we generate words of bounded length, keeping a tag to keep track of the first and last letter of each word to allow for computing representatives of cosets.

[3]:

##Function for constructing elements of free group up to bounded length
# list is elements of the form (matrix, last letter, first letter)

##INPUT: len is an integer >1
# g is the genus of the curve we are working with
# mat is a list of g 2x2 matrices generating the free group

function all_words_bounded_length(len,g, mat) #generate all words in the free group of length at most len
word_list= [(Matrix{ComplexF64}(I,2,2),0,0)]  #initiate identity element in list
for lev in 1:len
old_list = copy(word_list) #take all words of length < lev
word_list = [(Matrix{ComplexF64}(I,2,2),0,0)]
for oldword in old_list #iterate through all words of length = lev-1 and multiply to generate all words of length lev
for j in 1:g
if oldword[3] !=0 #if not multiplying by the identity, first letter is unchaged
if oldword[2] != -j
push!(word_list, (Matrix{ComplexF64}(oldword[1]*mat[j]), j, oldword[3]))
end
if oldword[2] != j
push!(word_list, (Matrix{ComplexF64}(oldword[1]*mat[j]^(-1)), -j, oldword[3]))
end
else #if multiplying by identity, first letter is last letter
if oldword[2] != -j
push!(word_list, (Matrix{ComplexF64}(oldword[1]*mat[j]), j, j))
end
if oldword[2] != j
push!(word_list, (Matrix{ComplexF64}(oldword[1]*mat[j]^(-1)), -j, -j))
end
end
end
end
end
return word_list
end

all_words_bounded_length (generic function with 1 method)


## Helper Functions

[4]:

##Function for easier evaluation of Mobius transformations
function mobius(matrix, num) #given a matrix [a b ; c d] and a number z, return az+b/cz+d
mobius = ((matrix[1,1]* num) + matrix[1,2])/((matrix[2,1]*num) + matrix[2,2])
return mobius
end

##Function for constructing centers and radii of the circles
function point_construct(eta, theta, g)
z1 = exp(im*((theta+eta)/2)) *sec((theta-eta)/2) #Center of generating circle
zs = [exp(((j-1)*2*pi*im) / g) * z1 for j in 1:g] #input first tuple of centers z1,....,zg
ws = [exp(((j-1)*2*pi*im) / g)*conj(z1) for j in 1:g] #input second tuple of center w1,...., wg
rs = [tan((theta-eta)/2) for _ in 1:g] #input radii of circles r1,...,rg
return (zs, ws, rs)
end

##Function for Constructing Matrices of the Schottky Group
function matrix_construct(ws, zs, rs)
g = length(ws)
M = zeros(Complex, 2,2)
mat = [M for idx in 1:g] #create an array of length g where ith entry is matrix of f_i
for j in 1:g
argpt =  angle(ws[j] -zs[j]) #Angle between isometric circle centers
A = Matrix{ComplexF64}([(exp(-im*argpt)* ws[j])/rs[j]  (-(ws[j]*zs[j]* exp(-2im*argpt) + rs[j]^2)/(rs[j]* exp(-im*argpt))); (exp(-im*argpt)/rs[j]) ((-zs[j]* exp(-im*argpt))/rs[j])])
mat[j] = A
end
return mat
end

##Function for evaluating truncated series
function ptheta(samplepts, mat,g, L) #samples Poincare Theta series for all words of length < L, given as a funciton of z
sampleproj = [zeros(Complex,1,g) for idx in samplepts];
list_of_words = all_words_bounded_length(L,g, mat)

for j in 1:g #create the jth coset G/ [mat[j]]
jCoset = []
for pts in list_of_words
if pts[2] != j
if pts[2] != -j
push!(jCoset, pts)
end
end
end
jCoset_mat = [pts[1] for pts in jCoset]
##Aj and Bj are the fixed points
jDisc = sqrt((mat[j][1,1] - mat[j][2,2])^2 + 4*mat[j][1,2]* mat[j][2,1]) #discriminant is sqrt((a-d)^2 + 4bc)
Aj = ((mat[j][1,1] - mat[j][2,2])+ jDisc)/(2*mat[j][2,1])
Bj = ((mat[j][1,1] - mat[j][2,2])- jDisc)/(2*mat[j][2,1])
#println(Aj)
#println(Bj)

#Now for each point in sapmleproj, evaluate truncated series and place into sampleproj[k][j]
for k in 1:length(samplepts)
samplevalue = 0
for sig in jCoset_mat
samplevalue = samplevalue + 1/(samplepts[k] - mobius(sig, Bj)) - 1/(samplepts[k] - mobius(sig, Aj))
end
sampleproj[k][j] = samplevalue
end
end
return sampleproj
end

ptheta (generic function with 1 method)


## Finding Weierstrass points in the case of Genus 2

Input - Genus $$g$$ - Two numbers $$0<\eta < \theta < \frac{\pi}{g}.$$ - The length of words that we are generating in the free group $$L$$

Output The approximate algebraic curve associated to the constructed curve, where we compute the 6 weierstrass points.

[5]:

function Genus2_WP(eta, theta, L)
g=2 ##We are in the case of genus 2
#L is the length of words that we are generating in the free group
(zs, ws, rs) = point_construct(eta, theta, g)
println("Initialized circles")

##6 Weierstrass points
##Solve for the two intersection points of C1 with circle centered at sec((theta + eta) / 2)
samplepts = [1, -1, exp(im*theta), exp(im*eta), exp(im* (pi-theta)), exp(im*(pi - eta))]

println("Sampled 6 points on the curve")

##CONSTRUCT MATRICES FOR SCHOTTKY GROUP
mat = matrix_construct(ws, zs, rs)
println("Computed Matrices")

##Evaluate the points in P^1 which are approximate images of the algebraic curve
PointsinPg = ptheta(samplepts, mat, g, L)

##Find approximate algebraic curve by finding 6 Weierstrass points
Wpts = [PointsinPg[j][1]/PointsinPg[j][2] for j in 1:6]
return Wpts
end

Genus2_WP (generic function with 1 method)

[6]:

####INPUT
𝜂 = pi /12  #Pick a positive number less than 𝜃
𝜃 =pi/4 # Pick a positive number less than 𝜋/3
L = 8 # L is the length of words that we generate in the free group

#####OUTPUT
p = Genus2_WP(𝜂,𝜃, L)

Initialized circles
Sampled 6 points on the curve
Computed Matrices

6-element Vector{ComplexF64}:
-11.474487171228489 + 1.030089577387785e-12im
-0.08714986431005209 + 1.1554187097143076e-14im
4.084600904724572 - 8.763125896606477e-13im
-11.787692697355707 + 3.887475415761668e-12im
0.24482196016832608 - 1.3653789500384812e-14im
-0.08483424412857071 + 1.9297359926505143e-15im

[7]:

##Verify conjugate pairs
p[1]*p[2] , p[3]*p[5], p[4]*p[6]

(0.9999999999999962 - 2.2235053851668632e-13im, 0.9999999999999878 - 2.7031084686709243e-13im, 1.0000000000000442 - 3.525381733329332e-13im)

[8]:

####Plot graph using Plots and Implicit Equations
f(x,y) = y^2 - ((x-real(p[1]))* (x-real(p[2]))*(x-real(p[3]))* (x-real(p[4]))*(x-real(p[5]))* (x-real(p[6])))

plot(f ⩵ 0, xlims = (-20,10), ylims=(-1000,1000), M=10, N=10, linewidth=2)
#savefig("realcurve_nearerzero.png")