hilbert-modular-group 0.1.3__cp312-cp312-macosx_15_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hilbert-modular-group might be problematic. Click here for more details.
- hilbert_modgroup/__init__.py +1 -0
- hilbert_modgroup/all.py +9 -0
- hilbert_modgroup/hilbert_modular_group_class.py +987 -0
- hilbert_modgroup/hilbert_modular_group_element.cpython-312-darwin.so +0 -0
- hilbert_modgroup/hilbert_modular_group_element.pyx +623 -0
- hilbert_modgroup/pullback.py +2256 -0
- hilbert_modgroup/pullback_cython.cpython-312-darwin.so +0 -0
- hilbert_modgroup/pullback_cython.pyx +411 -0
- hilbert_modgroup/upper_half_plane.cpython-312-darwin.so +0 -0
- hilbert_modgroup/upper_half_plane.pxd +59 -0
- hilbert_modgroup/upper_half_plane.pyx +1828 -0
- hilbert_modgroup/utils.py +66 -0
- hilbert_modgroup/version.py +21 -0
- hilbert_modular_group-0.1.3.dist-info/METADATA +891 -0
- hilbert_modular_group-0.1.3.dist-info/RECORD +18 -0
- hilbert_modular_group-0.1.3.dist-info/WHEEL +5 -0
- hilbert_modular_group-0.1.3.dist-info/licenses/LICENSE +674 -0
- hilbert_modular_group-0.1.3.dist-info/top_level.txt +1 -0
|
Binary file
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
#cython: profile=True
|
|
2
|
+
"""
|
|
3
|
+
Cython versions of Pullback algorithms.
|
|
4
|
+
|
|
5
|
+
Note: These are the algorithms that needs optimizing to make it all faster.
|
|
6
|
+
"""
|
|
7
|
+
from sage.functions.other import ceil
|
|
8
|
+
from sage.functions.other import floor
|
|
9
|
+
from sage.categories.sets_cat import cartesian_product
|
|
10
|
+
from sage.arith.misc import gcd
|
|
11
|
+
from sage.structure.sage_object cimport SageObject
|
|
12
|
+
from hilbert_modgroup.upper_half_plane cimport UpperHalfPlaneProductElement__class
|
|
13
|
+
from sage.rings.number_field.number_field_element cimport NumberFieldElement
|
|
14
|
+
|
|
15
|
+
cpdef integral_coordinates_in_box(bounds):
|
|
16
|
+
"""
|
|
17
|
+
Find all integral points inside a box in R^n.
|
|
18
|
+
|
|
19
|
+
INPUT:
|
|
20
|
+
- `bounds` -- a list of upper and lower bounds defining a parallelepiped of positive volume.
|
|
21
|
+
|
|
22
|
+
EXAMPLES::
|
|
23
|
+
|
|
24
|
+
sage: from hilbert_modgroup.pullback_cython import integral_coordinates_in_box
|
|
25
|
+
sage: integral_coordinates_in_box([(-1,1),(-1,1)])
|
|
26
|
+
[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)]
|
|
27
|
+
sage: integral_coordinates_in_box([(-1,1),(-1.5,1.5)])
|
|
28
|
+
[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)]
|
|
29
|
+
sage: integral_coordinates_in_box([(-1,1),(-1,1),(-0.5,0.5)])
|
|
30
|
+
[(-1, -1, 0),
|
|
31
|
+
(-1, 0, 0),
|
|
32
|
+
(-1, 1, 0),
|
|
33
|
+
(0, -1, 0),
|
|
34
|
+
(0, 0, 0),
|
|
35
|
+
(0, 1, 0),
|
|
36
|
+
(1, -1, 0),
|
|
37
|
+
(1, 0, 0),
|
|
38
|
+
(1, 1, 0)]
|
|
39
|
+
sage: integral_coordinates_in_box([(-1,1),(-1,1),(-0.5,0.5)])
|
|
40
|
+
[(-1, -1, 0),
|
|
41
|
+
(-1, 0, 0),
|
|
42
|
+
(-1, 1, 0),
|
|
43
|
+
(0, -1, 0),
|
|
44
|
+
(0, 0, 0),
|
|
45
|
+
(0, 1, 0),
|
|
46
|
+
(1, -1, 0),
|
|
47
|
+
(1, 0, 0),
|
|
48
|
+
(1, 1, 0)]
|
|
49
|
+
"""
|
|
50
|
+
if not isinstance(bounds, list):
|
|
51
|
+
raise ValueError
|
|
52
|
+
n = len(bounds)
|
|
53
|
+
coordinates = []
|
|
54
|
+
for i in range(n):
|
|
55
|
+
lower = ceil(bounds[i][0])
|
|
56
|
+
upper = floor(bounds[i][1])
|
|
57
|
+
if lower > upper:
|
|
58
|
+
raise ValueError("Bounds must give interval of positive length.")
|
|
59
|
+
coordinates.append(range(lower, upper + 1))
|
|
60
|
+
# result = [tuple(x) for x in cartesian_product(coordinates)]
|
|
61
|
+
# return result
|
|
62
|
+
return list(cartesian_product(coordinates))
|
|
63
|
+
|
|
64
|
+
cpdef lattice_elements_in_box(lattice_basis, lattice_bounds, coordinate_bounds, norm_bound=None):
|
|
65
|
+
"""
|
|
66
|
+
Return all coordinates of elements in a lattice in R^n restricted to a specific box and with
|
|
67
|
+
coordinates in another box.
|
|
68
|
+
|
|
69
|
+
INPUT:
|
|
70
|
+
- ``lattice_basis`` -- a list of lists of a basis of the embedded lattice
|
|
71
|
+
- ``lattice_bounds`` -- the bounds for the embeddings
|
|
72
|
+
- ``coordinate_bounds`` -- the bounds for the coordinates
|
|
73
|
+
- ``norm_bound`` -- bounds for the norm (default None - meaning that no bounds are applied)
|
|
74
|
+
|
|
75
|
+
EXAMPLES::
|
|
76
|
+
|
|
77
|
+
sage: from hilbert_modgroup.pullback_cython import lattice_elements_in_box
|
|
78
|
+
sage: lattice_elements_in_box([[0,1],[1,0]],[(-1,1),(-1,1)],[(-1,1),(-1,1)])
|
|
79
|
+
[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)]
|
|
80
|
+
sage: lattice_elements_in_box([[2,0],[0,2]],[(-2,2),(-1,1)],[(-1,1),(-1,1)])
|
|
81
|
+
[(-1, 0), (0, 0), (1, 0)]
|
|
82
|
+
sage: from hilbert_modgroup.all import *
|
|
83
|
+
sage: P1 = HilbertPullback(HilbertModularGroup(5))
|
|
84
|
+
sage: lb, ib = P1._get_lattice_and_ideal_basis()
|
|
85
|
+
sage: lattice_elements_in_box(lb,[(-2,2),(-2,2)],[(-1,1),(-1,1)])
|
|
86
|
+
[(-1, -1), (-1, 0), (0, -1), (0, 0), (0, 1), (1, 0), (1, 1)]
|
|
87
|
+
sage: lattice_elements_in_box(lb,[(-2,2),(-2,2)],[(-1,1),(0,1)])
|
|
88
|
+
[(-1, 0), (0, 0), (0, 1), (1, 0), (1, 1)]
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
coordinates = integral_coordinates_in_box(coordinate_bounds)
|
|
92
|
+
result = []
|
|
93
|
+
n = len(lattice_basis[0])
|
|
94
|
+
for coordinate_vector in coordinates:
|
|
95
|
+
is_within_bounds = True
|
|
96
|
+
if norm_bound:
|
|
97
|
+
norm = 1
|
|
98
|
+
for i in range(n):
|
|
99
|
+
alpha_i = 0.0
|
|
100
|
+
for j in range(n):
|
|
101
|
+
alpha_i = alpha_i + lattice_basis[i][j] * coordinate_vector[j]
|
|
102
|
+
if alpha_i < lattice_bounds[i][0] or alpha_i > lattice_bounds[i][1]:
|
|
103
|
+
# We need to discard this
|
|
104
|
+
is_within_bounds = False
|
|
105
|
+
break
|
|
106
|
+
if norm_bound:
|
|
107
|
+
norm = norm*alpha_i
|
|
108
|
+
if norm_bound and abs(norm) > norm_bound:
|
|
109
|
+
is_within_bounds = False
|
|
110
|
+
# If we are within the bounds we add the number field element.
|
|
111
|
+
if is_within_bounds:
|
|
112
|
+
result.append(coordinate_vector)
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
cpdef coordinates_to_ideal_elements(coordinates,ideal_basis):
|
|
116
|
+
r"""
|
|
117
|
+
Return elements of an ideal given by coordinates and a basis.
|
|
118
|
+
|
|
119
|
+
INPUT:
|
|
120
|
+
- `coordinates` -- a list of coordinates (as tuples or lists) of the same length as the basis.
|
|
121
|
+
- `ideal_basis` -- the basis of an ideal.
|
|
122
|
+
|
|
123
|
+
EXAMPLES::
|
|
124
|
+
|
|
125
|
+
sage: from hilbert_modgroup.pullback_cython import coordinates_to_ideal_elements
|
|
126
|
+
sage: from hilbert_modgroup.all import *
|
|
127
|
+
sage: P1 = HilbertPullback(HilbertModularGroup(5))
|
|
128
|
+
sage: lb, ib = P1._get_lattice_and_ideal_basis()
|
|
129
|
+
sage: coordinates_to_ideal_elements([[1,1],(2,3)],ib)
|
|
130
|
+
[1/2*a + 1/2, 3/2*a + 1/2]
|
|
131
|
+
|
|
132
|
+
TESTS::
|
|
133
|
+
|
|
134
|
+
sage: coordinates_to_ideal_elements([[1,1],(2,2,1)],ib)
|
|
135
|
+
Traceback (most recent call last):
|
|
136
|
+
...
|
|
137
|
+
ValueError: Coordinate need to have same length as basis!
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
result = []
|
|
141
|
+
n = len(ideal_basis)
|
|
142
|
+
for coordinate_vector in coordinates:
|
|
143
|
+
if len(coordinate_vector) != n:
|
|
144
|
+
raise ValueError("Coordinate need to have same length as basis!")
|
|
145
|
+
element = 0
|
|
146
|
+
for i,b in enumerate(ideal_basis):
|
|
147
|
+
element += b * coordinate_vector[i]
|
|
148
|
+
result.append(element)
|
|
149
|
+
return result
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
cpdef find_candidate_cusps(p, z, use_lll=True, use_norm_bound=True, return_sigma_candidates=False,
|
|
153
|
+
initial_bd_d=None,
|
|
154
|
+
use_initial_bd_d=True):
|
|
155
|
+
r"""
|
|
156
|
+
Return candidates for closest cusp to the point ``z`` in the upper half-plane.
|
|
157
|
+
|
|
158
|
+
INPUT:
|
|
159
|
+
|
|
160
|
+
- ``p`` -- object of type HilbertPullback
|
|
161
|
+
- ``z`` -- point in the upper half-plane
|
|
162
|
+
- ``use_lll`` -- boolean (default: `True`) Use the LLL method to find a preliminary bounds
|
|
163
|
+
- ``use_norm_bound`` -- boolean (default: `True`) Use the norm bound together ith the embedding bounds
|
|
164
|
+
- ``return_sigma_candidates`` -- boolean (default: `False`) Return a list of sigma candidates only
|
|
165
|
+
- ``initial_bd_d`` -- positive number (default: `None`) - an initial bound for the distance to nearest cusp.
|
|
166
|
+
- ``use_initial_bd_d`` -- boolean (default: `False`) Use the initial bound
|
|
167
|
+
|
|
168
|
+
OUTPUT:
|
|
169
|
+
- list of tuples (sigma,rho) representing cusps
|
|
170
|
+
|
|
171
|
+
EXAMPLES::
|
|
172
|
+
|
|
173
|
+
sage: from hilbert_modgroup.all import *
|
|
174
|
+
sage: from hilbert_modgroup.pullback_cython import find_candidate_cusps
|
|
175
|
+
sage: H1 = HilbertModularGroup(5)
|
|
176
|
+
sage: P1 = HilbertPullback(H1)
|
|
177
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,1),CC(0,1)])
|
|
178
|
+
sage: find_candidate_cusps(P1,z)
|
|
179
|
+
[(1, 0), (-1, -1), (0, 1), (1, -1)]
|
|
180
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,0.5),CC(0,1)])
|
|
181
|
+
sage: find_candidate_cusps(P1,z)
|
|
182
|
+
[(0, 1)]
|
|
183
|
+
sage: H2 = HilbertModularGroup(10)
|
|
184
|
+
sage: P2 = HilbertPullback(H2)
|
|
185
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,1),CC(0,1)])
|
|
186
|
+
sage: find_candidate_cusps(P2,z)
|
|
187
|
+
[(1, 0),
|
|
188
|
+
...
|
|
189
|
+
sage: len(_)
|
|
190
|
+
10
|
|
191
|
+
sage: z=UpperHalfPlaneProductElement([CC(2.58,0.5),CC(0.5,0.5)]) # long time (1 second)
|
|
192
|
+
sage: len(find_candidate_cusps(P2,z)) # long time (1 second)
|
|
193
|
+
271
|
|
194
|
+
|
|
195
|
+
"""
|
|
196
|
+
ideal_basis = p._construct_ideal(1).integral_basis()
|
|
197
|
+
lattice_basis = p.basis_matrix_ideal()
|
|
198
|
+
n = len(lattice_basis[0])
|
|
199
|
+
# Make lattice basis to a nested list to avoid creation of FreeModule elements
|
|
200
|
+
lattice_basis = [[lattice_basis[i][j] for j in range(n)] for i in range(n)]
|
|
201
|
+
## Initial bound:
|
|
202
|
+
if use_lll:
|
|
203
|
+
candidate_cusp = p.get_heuristic_closest_cusp(z)
|
|
204
|
+
else:
|
|
205
|
+
candidate_cusp = None
|
|
206
|
+
if candidate_cusp and use_initial_bd_d:
|
|
207
|
+
dist = distance_to_cusp(p, candidate_cusp[0], candidate_cusp[1], z)
|
|
208
|
+
else:
|
|
209
|
+
dist = None
|
|
210
|
+
if use_norm_bound:
|
|
211
|
+
norm_bound_sigma = p._bound_for_sigma_norm(z, dist)
|
|
212
|
+
norm_bound_sigma = norm_bound_sigma*(1+2**(-z[0].prec()/2)) # correct for numerical errors
|
|
213
|
+
else:
|
|
214
|
+
norm_bound_sigma = None
|
|
215
|
+
if use_initial_bd_d and initial_bd_d and (not dist or dist > initial_bd_d):
|
|
216
|
+
dist = initial_bd_d
|
|
217
|
+
# norm_bound_rho = p._bound_for_rho_norm(z, dist)
|
|
218
|
+
one = p.number_field()(1)
|
|
219
|
+
coordinate_bounds = p._bound_for_sigma_coordinates(z, initial_bd_d=dist,use_initial_bd_d=use_initial_bd_d)
|
|
220
|
+
embedding_bounds = p._bound_for_sigma_embeddings(z, initial_bd_d=dist,use_initial_bd_d=use_initial_bd_d)
|
|
221
|
+
coordinate_bounds = [(-b,b) for b in coordinate_bounds]
|
|
222
|
+
embedding_bounds = [(-b,b) for b in embedding_bounds]
|
|
223
|
+
sigma_candidates_coordinates = lattice_elements_in_box(lattice_basis,
|
|
224
|
+
embedding_bounds,
|
|
225
|
+
coordinate_bounds, norm_bound=norm_bound_sigma)
|
|
226
|
+
sigma_candidates = coordinates_to_ideal_elements(sigma_candidates_coordinates,
|
|
227
|
+
ideal_basis)
|
|
228
|
+
if return_sigma_candidates:
|
|
229
|
+
return sigma_candidates
|
|
230
|
+
# To remove duplicates we keep track of the quotients rho/sigma (for sigma !=0)
|
|
231
|
+
quotients = {}
|
|
232
|
+
if not candidate_cusp or candidate_cusp[1] == 0:
|
|
233
|
+
result = [(p.number_field()(1), p.number_field()(0))]
|
|
234
|
+
elif candidate_cusp[0] == 0:
|
|
235
|
+
result = [(p.number_field()(0), p.number_field()(1))]
|
|
236
|
+
else:
|
|
237
|
+
# We always have infinity since sigma=0 is always within the bounds.
|
|
238
|
+
result = [candidate_cusp,(p.number_field()(1), p.number_field()(0))]
|
|
239
|
+
q = candidate_cusp[0]/candidate_cusp[1]
|
|
240
|
+
ngcd = gcd(candidate_cusp[0].norm(),candidate_cusp[1].norm())
|
|
241
|
+
quotients = {q: (ngcd,(candidate_cusp[0],candidate_cusp[1]))}
|
|
242
|
+
for s in sigma_candidates:
|
|
243
|
+
if s == 0:
|
|
244
|
+
continue
|
|
245
|
+
rho_coordinate_bounds = p._bound_for_rho_coordinates(z, s, initial_bd_d=dist, use_initial_bd_d=use_initial_bd_d)
|
|
246
|
+
rho_coordinate_bounds = [(-b,b) for b in rho_coordinate_bounds]
|
|
247
|
+
rho_embedding_bounds = p._bound_for_rho_embeddings(z, s, initial_bd_d=dist, use_initial_bd_d=use_initial_bd_d)
|
|
248
|
+
|
|
249
|
+
rho_candidates_coordinates = lattice_elements_in_box(lattice_basis,
|
|
250
|
+
rho_embedding_bounds,
|
|
251
|
+
rho_coordinate_bounds)
|
|
252
|
+
rho_candidates = coordinates_to_ideal_elements(rho_candidates_coordinates,
|
|
253
|
+
ideal_basis)
|
|
254
|
+
|
|
255
|
+
for r in rho_candidates:
|
|
256
|
+
if r == 0 and (r,one) not in result:
|
|
257
|
+
result.append((r,one))
|
|
258
|
+
if r == 0:
|
|
259
|
+
continue
|
|
260
|
+
quo = r/s
|
|
261
|
+
ngcd = gcd(r.norm(), s.norm())
|
|
262
|
+
if quo in quotients:
|
|
263
|
+
# We try to pick the representative cusp that has the smallest norm gcd
|
|
264
|
+
if ngcd < quotients[quo][0]:
|
|
265
|
+
result.remove(quotients[quo][1])
|
|
266
|
+
else:
|
|
267
|
+
continue
|
|
268
|
+
result.append((r,s))
|
|
269
|
+
quotients[quo] = (ngcd,(r,s))
|
|
270
|
+
return result
|
|
271
|
+
|
|
272
|
+
cpdef find_closest_cusp(p, z, return_multiple=False, use_lll=True, use_norm_bound=True):
|
|
273
|
+
r"""
|
|
274
|
+
Return the closest cusp(s) to z
|
|
275
|
+
|
|
276
|
+
INPUT:
|
|
277
|
+
- ``p`` -- A HilbertPullback object
|
|
278
|
+
- ``z`` -- point in the upper half-plane
|
|
279
|
+
- ``return_multiple`` -- boolean (default False), set to True to return multiple closest cusp if it is no unique.
|
|
280
|
+
- ``use_lll`` -- boolean (default True) if True uses the LLL method to obtain an initial bound
|
|
281
|
+
- ``use_norm_bound`` -- boolean (default True) if True uses the norm bound as well as the embedding bounds
|
|
282
|
+
|
|
283
|
+
OUTPUT:
|
|
284
|
+
- tuple representing a cusp (if return_multiple == False)
|
|
285
|
+
- list of tuples representing cusps (if return_multiple == True)
|
|
286
|
+
|
|
287
|
+
EXAMPLES::
|
|
288
|
+
|
|
289
|
+
sage: from hilbert_modgroup.all import *
|
|
290
|
+
sage: from hilbert_modgroup.pullback_cython import find_closest_cusp
|
|
291
|
+
sage: H1 = HilbertModularGroup(5)
|
|
292
|
+
sage: P1 = HilbertPullback(H1)
|
|
293
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,1),CC(0,1)])
|
|
294
|
+
sage: find_closest_cusp(P1,z)
|
|
295
|
+
(1, 0)
|
|
296
|
+
sage: find_closest_cusp(P1,z,return_multiple=True)
|
|
297
|
+
[(1, 0), (0, 1)]
|
|
298
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,0.5),CC(0,1)])
|
|
299
|
+
sage: find_closest_cusp(P1,z)
|
|
300
|
+
(0, 1)
|
|
301
|
+
sage: find_closest_cusp(P1,z,return_multiple=True)
|
|
302
|
+
[(0, 1)]
|
|
303
|
+
|
|
304
|
+
sage: H2 = HilbertModularGroup(10)
|
|
305
|
+
sage: P2 = HilbertPullback(H2)
|
|
306
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,1),CC(0,1)])
|
|
307
|
+
sage: find_closest_cusp(P2,z)
|
|
308
|
+
(1, 0)
|
|
309
|
+
sage: find_closest_cusp(P2,z,return_multiple=True)
|
|
310
|
+
[(1, 0), (0, 1)]
|
|
311
|
+
sage: z=UpperHalfPlaneProductElement([CC(-2.58,0.5),CC(0.5,0.5)])
|
|
312
|
+
sage: find_closest_cusp(P2,z,return_multiple=True)
|
|
313
|
+
[(-a + 2, -2)]
|
|
314
|
+
|
|
315
|
+
"""
|
|
316
|
+
cusp_candidates = find_candidate_cusps(p, z, use_lll=use_lll, use_norm_bound=use_norm_bound)
|
|
317
|
+
min_cusp = cusp_candidates[0]
|
|
318
|
+
min_d = distance_to_cusp(p,min_cusp[0], min_cusp[1], z)
|
|
319
|
+
if return_multiple:
|
|
320
|
+
min_cusp = [min_cusp]
|
|
321
|
+
min_cusp_bound = p._bound_for_closest_cusp()
|
|
322
|
+
eps = 2.0**(4-53) # Numerical precision for when we consider cusps to be equally close.
|
|
323
|
+
# There may be many identical cusps in this list.
|
|
324
|
+
# In particular there might be many
|
|
325
|
+
for c in cusp_candidates[1:]:
|
|
326
|
+
d = distance_to_cusp(p, c[0],c[1], z)
|
|
327
|
+
if abs(d-min_d)<eps and return_multiple:
|
|
328
|
+
min_cusp.append(c)
|
|
329
|
+
if d < min_d - 2*eps:
|
|
330
|
+
if return_multiple:
|
|
331
|
+
min_cusp = [c]
|
|
332
|
+
else:
|
|
333
|
+
min_cusp = c
|
|
334
|
+
min_d = d
|
|
335
|
+
if d < min_cusp_bound:
|
|
336
|
+
break
|
|
337
|
+
# We have already filtered away identical cusps but as a final stage
|
|
338
|
+
# we also check if the minimal cusps are equal to any of the fixed representatives.
|
|
339
|
+
# other than infinity which is already taken care of
|
|
340
|
+
if p.group().ncusps() == 1:
|
|
341
|
+
return min_cusp
|
|
342
|
+
result = []
|
|
343
|
+
for cusp in p.group().cusps()[1:]:
|
|
344
|
+
c, d = cusp.numerator(),cusp.denominator()
|
|
345
|
+
quo = c/d
|
|
346
|
+
if return_multiple:
|
|
347
|
+
for r,s in min_cusp:
|
|
348
|
+
if s == 0:
|
|
349
|
+
result.append((r, s))
|
|
350
|
+
elif r == 0 and (0,1) not in result:
|
|
351
|
+
result.append((0,1))
|
|
352
|
+
elif r == 0:
|
|
353
|
+
continue
|
|
354
|
+
elif r/s == quo and (c,d) not in result:
|
|
355
|
+
result.append((c,d))
|
|
356
|
+
elif r/s != quo:
|
|
357
|
+
result.append((r,s))
|
|
358
|
+
elif min_cusp[1] != 0 and min_cusp[0]/min_cusp[1] == quo:
|
|
359
|
+
result = (c,d)
|
|
360
|
+
else:
|
|
361
|
+
result = min_cusp
|
|
362
|
+
return result
|
|
363
|
+
|
|
364
|
+
cpdef distance_to_cusp(SageObject p, NumberFieldElement r, NumberFieldElement s,
|
|
365
|
+
UpperHalfPlaneProductElement__class z):
|
|
366
|
+
r"""
|
|
367
|
+
Return the distance from an element in the upper half-plane to a cusp.
|
|
368
|
+
|
|
369
|
+
INPUT:
|
|
370
|
+
- ``p`` - Should be an object of type HilbertPullback (but this is not recognized by Cython so I use SageObject instead)
|
|
371
|
+
- ``r`` - Number field element, numerator of cusp
|
|
372
|
+
- ``s`` - Number field element, denomnator of cusp
|
|
373
|
+
- ``z`` - Point in the upper half-plane
|
|
374
|
+
|
|
375
|
+
EXAMPLES::
|
|
376
|
+
|
|
377
|
+
sage: from hilbert_modgroup.all import *
|
|
378
|
+
sage: from hilbert_modgroup.pullback_cython import distance_to_cusp
|
|
379
|
+
sage: H1 = HilbertModularGroup(5)
|
|
380
|
+
sage: P1 = HilbertPullback(H1)
|
|
381
|
+
sage: K = P1.number_field()
|
|
382
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,1),CC(0,1)])
|
|
383
|
+
sage: distance_to_cusp(P1,K(0),K(1),z) # abs tol 1e-10
|
|
384
|
+
1.0
|
|
385
|
+
sage: distance_to_cusp(P1,K(1),K(1),z) # abs tol 1e-10
|
|
386
|
+
2.0
|
|
387
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,0.5),CC(0,1)])
|
|
388
|
+
sage: distance_to_cusp(P1,K(0),K(1),z) # abs tol 1e-10
|
|
389
|
+
0.707106781186548
|
|
390
|
+
sage: H2 = HilbertModularGroup(10)
|
|
391
|
+
sage: P2 = HilbertPullback(H2)
|
|
392
|
+
sage: K = P2.number_field()
|
|
393
|
+
sage: z=UpperHalfPlaneProductElement([CC(0,1),CC(0,1)])
|
|
394
|
+
sage: distance_to_cusp(P2,K(0),K(1),z) # abs tol 1e-10
|
|
395
|
+
1.0
|
|
396
|
+
sage: z=UpperHalfPlaneProductElement([CC(-2.58,0.5),CC(0.5,0.5)])
|
|
397
|
+
sage: a = K.gen()
|
|
398
|
+
sage: distance_to_cusp(P2,a-5,-a,z) # abs tol 1e-10
|
|
399
|
+
1.01308408502928
|
|
400
|
+
|
|
401
|
+
"""
|
|
402
|
+
cdef list rlist,slist
|
|
403
|
+
ideal_rs = r.parent().fractional_ideal(r,s)
|
|
404
|
+
rlist = r.complex_embeddings()
|
|
405
|
+
slist = s.complex_embeddings()
|
|
406
|
+
n = len(slist)
|
|
407
|
+
d = 1
|
|
408
|
+
for i in range(n):
|
|
409
|
+
d = d* ((-z._x[i] * slist[i] + rlist[i]) ** 2 * z._y[i] ** -1 + slist[i] ** 2 * z._y[i])
|
|
410
|
+
d = ideal_rs.norm()**-1*d.sqrt()
|
|
411
|
+
return d
|
|
Binary file
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from sage.structure.element cimport Element
|
|
2
|
+
from sage.structure.parent cimport Parent
|
|
3
|
+
from sage.rings.complex_mpc cimport MPComplexField_class, MPComplexNumber
|
|
4
|
+
from sage.rings.real_mpfr cimport RealNumber
|
|
5
|
+
from sage.categories.map cimport Map
|
|
6
|
+
|
|
7
|
+
cdef class ComplexPlaneProduct__class(Parent):
|
|
8
|
+
cdef int _degree
|
|
9
|
+
cdef int _prec
|
|
10
|
+
|
|
11
|
+
cdef class UpperHalfPlaneProduct__class(ComplexPlaneProduct__class):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
cdef class AnytoCPP(Map):
|
|
15
|
+
pass
|
|
16
|
+
cdef class ComplexPlaneProductElement__class(Element):
|
|
17
|
+
# cdef double *_x
|
|
18
|
+
# cdef double *_y
|
|
19
|
+
cdef int _degree
|
|
20
|
+
cdef list _x
|
|
21
|
+
cdef list _y
|
|
22
|
+
cdef list _z
|
|
23
|
+
cdef int _prec
|
|
24
|
+
cdef int _verbose
|
|
25
|
+
cdef MPComplexField_class _base_ring
|
|
26
|
+
|
|
27
|
+
cdef MPComplexNumber _norm
|
|
28
|
+
cdef RealNumber _imag_norm
|
|
29
|
+
cdef RealNumber _real_norm
|
|
30
|
+
cdef RealNumber _abs_square_norm
|
|
31
|
+
cdef int _norm_set
|
|
32
|
+
cdef int _imag_norm_set
|
|
33
|
+
cdef int _real_norm_set
|
|
34
|
+
cdef int _abs_square_norm_set
|
|
35
|
+
cdef int _is_in_upper_half_plane
|
|
36
|
+
cpdef imag(self)
|
|
37
|
+
cpdef real(self)
|
|
38
|
+
cpdef _is_equal(self, ComplexPlaneProductElement__class other)
|
|
39
|
+
cpdef __copy__(self)
|
|
40
|
+
cpdef z(self)
|
|
41
|
+
cpdef set_prec(self,prec)
|
|
42
|
+
cpdef abs(self)
|
|
43
|
+
cpdef imag_norm(self)
|
|
44
|
+
cpdef real_norm(self)
|
|
45
|
+
cpdef abs_square_norm(self)
|
|
46
|
+
cpdef imag_trace(self)
|
|
47
|
+
cpdef real_trace(self)
|
|
48
|
+
cpdef trace(self)
|
|
49
|
+
cpdef reflect(self)
|
|
50
|
+
|
|
51
|
+
cpdef prec(self)
|
|
52
|
+
cpdef norm(self)
|
|
53
|
+
cpdef vector(self)
|
|
54
|
+
cpdef vector_norm(self, p=?)
|
|
55
|
+
cpdef apply(self, m)
|
|
56
|
+
|
|
57
|
+
cdef class UpperHalfPlaneProductElement__class(ComplexPlaneProductElement__class):
|
|
58
|
+
pass
|
|
59
|
+
|