-
Notifications
You must be signed in to change notification settings - Fork 1
/
slices.py
148 lines (119 loc) · 7.24 KB
/
slices.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
""" Functions for generating slice exteriors.
"""
from . import farey, riley
from mpmath import mp
from numpy.polynomial import Polynomial as P
import pandas as pd
import math
class ConvergenceFailedException(Exception):
""" Thrown if a polynomial solution fails to converge. """
def __init__(self, r, s, m, n, poly):
self.r = r
self.s = s
self.m = m
self.n = n
self.poly = poly
super().__init__()
def __str__(self):
return f"Convergence failed at r/s = {self.r}/{self.s}, gen powers {self.m} {self.n}, polynomial {self.poly}"
def primitive_exterior(θ, η, pow_X, pow_Y, depth, maxsteps=500, extraprec=1000, level_set = -2):
""" Compute points of the Riley slice exterior on generator angles θ and η.
Parameters:
`θ`, `η` -- parameters of the slice
`powX`, `powY` -- what powers of X and Y to take in the Farey words
`depth` -- maximal denominator of Farey polynomial to use
`maxsteps`, `extraprec` -- passed directly to mpmath.polyroots().
`level_set` -- level set of the Farey polynomials to compute (-2 for cusp points).
Generates: a dataframe with columns `[ x, y, pow_x, pow_y, method, level_set ]` where `x+y*j` is an element
of the `level_set` level set of some Farey polynomial, where `pow_x` and `pow_y` are
respectively `pow_X` and `pow_Y`, where `method = "farey"`, and where `level_set` is the same as the eponynous parameter.
"""
# Note that the trace of an elliptic element is 2cos(t), where t is the rotation
# angle. Thus the trace of powers of X and Y are as follows:
trX = P([2*mp.cos(pow_X*θ)])
trY = P([2*mp.cos(pow_Y*η)])
# For X^powX Y^powY we need to compute for a bit, but we get the following. The
# z coefficient of the trace polynomial might involve a 0/0 if θ or η is a multiple
# of pi, so we need to specifically take 1 in those cases.
z_coefficient_X_contribution = 1 if mp.sin(θ) == 0 else mp.sin(pow_X*θ)/mp.sin(θ)
z_coefficient_Y_contribution = 1 if mp.sin(η) == 0 else mp.sin(pow_Y*η)/mp.sin(η)
trXY = P([ 2*mp.cos(pow_X*θ + pow_Y*η), z_coefficient_X_contribution*z_coefficient_Y_contribution ])
# We can now compute the Farey polynomials after substitution.
def _internal_generator():
for (r,s) in farey.walk_tree_bfs(depth):
try:
poly = farey.farey_polynomial(r,s,trX,trY,trXY) - level_set
yield from farey.solve_polynomial(poly, maxsteps, extraprec)
except mp.NoConvergence:
raise ConvergenceFailedException(r,s,pow_X,pow_Y,poly)
return pd.DataFrame.from_records(([float(pt.real), float(pt.imag), pow_X, pow_Y, 'farey', level_set] for pt in _internal_generator()), columns=['x','y','pow_x','pow_y', 'method', 'level_set'])
def parabolic_exterior_from_farey(depth, maxsteps=500,extraprec=1000,level_set=-2):
""" Compute points of the parabolic Riley slice exterior.
Parameters:
depth -- maximal denominator of Farey polynomial to use
maxsteps, extraprec -- passed directly to mpmath.polyroots().
level_set -- level set of the Farey polynomials to compute (-2 for cusp points).
Generates: a dataframe with columns [ x, y, pow_x, pow_y ] where x+yi is an element
of the `level_set` level set of some Farey polynomial and where pow_x = pow_y = 1, method = "farey",
and level_set is the value passed in.
"""
return primitive_exterior(0,0,1,1,depth,maxsteps,extraprec,level_set)
def parabolic_exterior_from_riley(depth, maxsteps=500,extraprec=1000):
""" Compute points of the parabolic Riley slice exterior using Riley polynomials.
Parameters:
depth -- maximal denominator of Riley polynomial to use
maxsteps, extraprec -- passed directly to mpmath.polyroots().
Generates: a dataframe with columns [ x, y, pow_x, pow_y, method, level_set ] where x+yi is a zero
of some Riley polynomial and where pow_x = pow_y = 1, method = "riley", and level_set = 0.
"""
def _internal_generator():
for (r,s) in farey.walk_tree_bfs(depth):
poly = farey.riley_polynomial(r,s)
yield from farey.solve_polynomial(poly, maxsteps, extraprec)
return pd.DataFrame.from_records(([float(pt.real), float(pt.imag), 1, 1, 'riley', 0] for pt in _internal_generator()), columns=['x','y','pow_x','pow_y', 'method', 'level_set'])
def elliptic_exterior(p, q, depth, maxsteps=500, extraprec=1000, level_set = -2):
""" Compute points of the elliptic Riley slice exterior with holonomies π/p, π/q.
Parameters:
p, q -- orders of X and Y (possibly np.inf)
depth -- maximal denominator of Farey polynomial to use
maxsteps, extraprec -- passed directly to mpmath.polyroots().
level_set -- level set of the Farey polynomials to compute (-2 for cusp points).
Generates: a dataframe with columns [ x, y, pow_x, pow_y, method, level_set ] where:
* x+yi is an element of the `level_set` level set of some substituted Farey polynomial---namely the Farey
polynomial with X -> X^pow_x and Y -> Y^pow_y; and
* method = "farey".
"""
θ = mp.pi/p
η = mp.pi/q
frames = []
# If either p or q is infinite, we only want to compute m or n = 1, otherwise m or n is all numbers up to p or q.
top_p_power = p if p != mp.inf else 2
top_q_power = q if q != mp.inf else 2
for m in range(1, top_p_power):
for n in range(1, top_q_power):
if math.gcd(m, top_p_power) * math.gcd(n, top_q_power) == 1:
frames.append(primitive_exterior(θ, η, m, n, depth, maxsteps, extraprec, level_set))
return pd.concat(frames)
def maskit_slice_exterior(depth, maxsteps=500, extraprec=1000, level_set = -2, translates = 4):
""" Compute points of the Maskit slice exterior.
Note that the Maskit polynomial levelsets will have real part in [0,2]. This function produces
`translates` translates of this set left and right to see the whole picture.
Parameters:
`depth` -- maximal denominator of Farey polynomial to use
`maxsteps`, `extraprec` -- passed directly to mpmath.polyroots().
`level_set` -- level set of the Farey polynomials to compute (-2 for cusp points).
`translates` -- number of translates to produce
Generates: a dataframe with columns `[ x, y, pow_x, pow_y, method, level_set ]` where `x+y*j` is an element
of the `level_set` level set of some Farey polynomial, where `pow_x` and `pow_y` are
respectively `pow_X` and `pow_Y`, where `method = "farey"`, and where `level_set` is the same as the eponynous parameter.
"""
def _internal_generator():
for (r,s) in farey.walk_tree_bfs(depth):
try:
poly = farey.maskit_polynomial(r,s) - level_set
yield from farey.solve_polynomial(poly, maxsteps, extraprec)
except mp.NoConvergence:
raise ConvergenceFailedException(r,s,pow_X,pow_Y,poly)
points = [[pt.real, pt.imag, level_set] for pt in _internal_generator()]
t = 2
return pd.DataFrame.from_records([[float(p[0] + t*by), float(p[1]), p[2]] for p in points for by in range(-translates,translates)], columns=['x','y', 'level_set'])