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
Pkg.add("LinearAlgebra")
Pkg.add("ImplicitEquations")
Pkg.add("Plots")
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")