Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
#################################################################################
2
#
3
# (c) Copyright 2010 William Stein
4
#
5
# This file is part of PSAGE
6
#
7
# PSAGE is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# PSAGE is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#
20
#################################################################################
21
22
23
"""
24
Highly optimized computation of the modular symbols map associated to
25
a simple new space of modular symbols.
26
27
AUTHOR:
28
- William Stein
29
"""
30
31
from sage.matrix.all import matrix
32
from sage.rings.all import QQ, ZZ, Integer
33
34
include 'stdsage.pxi'
35
36
def test_contfrac_q(a, b):
37
"""
38
EXAMPLES::
39
40
sage: import psage.modform.rational.modular_symbol_map
41
sage: psage.modform.rational.modular_symbol_map.test_contfrac_q(7, 97)
42
[1, 13, 14, 97]
43
sage: continued_fraction(7/97).convergents()
44
[0, 1/13, 1/14, 7/97]
45
sage: psage.modform.rational.modular_symbol_map.test_contfrac_q(137, 93997)
46
[1, 686, 6175, 43911, 93997]
47
sage: continued_fraction(137/93997).convergents()
48
[0, 1/686, 9/6175, 64/43911, 137/93997]
49
"""
50
cdef long qi[MAX_CONTFRAC]
51
cdef int n = contfrac_q(qi, a, b)
52
return [qi[i] for i in range(n)]
53
54
cdef long contfrac_q(long qi[MAX_CONTFRAC], long a, long b) except -1:
55
"""
56
Given coprime integers `a`, `b`, compute the sequence `q_i` of
57
denominators in the continued fraction expansion of `a/b`, storing
58
the results in the array `q`.
59
60
Returns the number of `q_i`. The rest of the `q` array is
61
garbage.
62
"""
63
cdef long c
64
65
qi[0] = 1
66
if a == 0:
67
return 1
68
if b == 0:
69
raise ZeroDivisionError
70
71
# one iteration isn't needed, since we are only computing the q_i.
72
a,b = b, a%b
73
cdef int i=1
74
while b:
75
if i >= 2:
76
qi[i] = qi[i-1]*(a//b) + qi[i-2]
77
else:
78
qi[1] = a//b
79
a,b = b, a%b
80
i += 1
81
82
return i
83
84
cdef class ModularSymbolMap:
85
def __cinit__(self):
86
self.X = NULL
87
88
def __repr__(self):
89
return "Modular symbols map for modular symbols factor of dimension %s and level %s"%(self.d, self.N)
90
91
def __init__(self, A):
92
"""
93
EXAMPLES::
94
95
We illustrate a few ways to construct the modular symbol map for 389a.
96
97
sage: from psage.modform.rational.modular_symbol_map import ModularSymbolMap
98
sage: A = ModularSymbols(389,sign=1).cuspidal_subspace().new_subspace().decomposition()[0]
99
sage: f = ModularSymbolMap(A)
100
sage: f._eval1(-3,7)
101
[-2]
102
sage: f.denom
103
2
104
105
sage: E = EllipticCurve('389a'); g = E.modular_symbol()
106
sage: h = ModularSymbolMap(g)
107
sage: h._eval1(-3,7)
108
[-2]
109
sage: h.denom
110
1
111
sage: g(-3/7)
112
-2
113
114
sage: f.denom*f.C == h.denom*h.C
115
True
116
"""
117
import sage.schemes.elliptic_curves.ell_modular_symbols as ell_modular_symbols
118
from sage.modular.modsym.space import ModularSymbolsSpace
119
120
if isinstance(A, ell_modular_symbols.ModularSymbol):
121
C = self._init_using_ell_modular_symbol(A)
122
123
elif isinstance(A, ModularSymbolsSpace):
124
C = self._init_using_modsym_space(A)
125
126
else:
127
128
raise NotImplementedError, "Creating modular symbols from object of type %s not implemented"%type(A)
129
130
# useful for debugging only -- otherwise is a waste of memory/space
131
self.C = C
132
133
X, self.denom = C._clear_denom()
134
# Now store in a C data structure the entries of X (as long's)
135
self.X = <long*>sage_malloc(sizeof(long*)*X.nrows()*X.ncols())
136
cdef Py_ssize_t i, j, n
137
n = 0
138
for a in X.list():
139
self.X[n] = a
140
n += 1
141
142
def _init_using_ell_modular_symbol(self, f):
143
# Input f is an elliptic curve modular symbol map
144
assert f.sign() != 0
145
self.d = 1 # the dimension
146
147
E = f.elliptic_curve()
148
self.N = E.conductor()
149
self.P1 = P1List(self.N)
150
151
# Make a matrix whose rows are the images of the Manin symbols
152
# corresponding to the elements of P^1 under f.
153
n = len(self.P1)
154
C = matrix(QQ, n, 1)
155
for i in range(n):
156
# If the ith element of P1 is (u,v) for some u,v modulo N.
157
# We need to turn this into something we can evaluate f on.
158
# 1. Lift to a 2x2 SL2Z matrix M=(a,b;c,d) with c=u, d=v (mod N).
159
# 2. The modular symbol is M{0,oo} = {b/d,a/c}.
160
# 3. So {b/d, a/c} = {b/d,oo} + {oo,a/c} = -{oo,b/d} + {oo,a/c} = f(a/c)-f(b/d).
161
# 4. Thus x |--> f(a/c)-f(b/d).
162
a,b,c,d = self.P1.lift_to_sl2z(i) # output are Python ints, so careful!
163
C[i,0] = (f(Integer(a)/c) if c else 0) - (f(Integer(b)/d) if d else 0)
164
return C
165
166
def _init_using_modsym_space(self, A):
167
# Very slow generic setup code. This is "O(1)" in that we
168
# care mainly about evaluation time being fast, at least in
169
# this code.
170
if A.sign() == 0:
171
raise ValueError, "A must have sign +1 or -1"
172
self.d = A.dimension()
173
174
self.N = A.level()
175
self.P1 = P1List(self.N)
176
177
# The key data we need from the modular symbols space is the
178
# map that assigns to an element of P1 the corresponding
179
# element of ZZ^n. That's it. We forget everything else.
180
M = A.ambient_module()
181
W = matrix([M.manin_symbol(x).element() for x in self.P1])
182
B = A.dual_free_module().basis_matrix().transpose()
183
184
# Return matrix whose rows are the images of the Manin symbols
185
# corresponding to the elements of P^1 under the modular
186
# symbol map.
187
return W*B
188
189
190
def __dealloc__(self):
191
if self.X:
192
sage_free(self.X)
193
194
cdef int evaluate(self, long v[MAX_DEG], long a, long b) except -1:
195
cdef long q[MAX_CONTFRAC]
196
cdef int i, j, k, n, sign=1
197
cdef long* x
198
199
# initialize answer vector to 0
200
for i in range(self.d):
201
v[i] = 0
202
203
# compute continued fraction
204
n = contfrac_q(q, a, b)
205
206
# compute corresponding modular symbols, mapping over...
207
for i in range(1,n):
208
j = self.P1.index((sign*q[i])%self.N, q[i-1]%self.N)
209
# map over, adding a row of the matrix self.X
210
# to the answer vector v.
211
x = self.X + j*self.d
212
for k in range(self.d):
213
v[k] += x[k]
214
# change sign, so q[i] is multiplied by (-1)^(i-1)
215
sign *= -1
216
217
def dimension(self):
218
return self.d
219
220
def _eval0(self, a, b):
221
cdef long v[MAX_DEG]
222
self.evaluate(v, a, b)
223
224
def _eval1(self, a, b):
225
"""
226
EXAMPLE::
227
228
sage: from psage.modform.rational.modular_symbol_map import ModularSymbolMap
229
sage: A = ModularSymbols(188,sign=1).cuspidal_subspace().new_subspace().decomposition()[-1]
230
sage: f = ModularSymbolMap(A)
231
sage: f._eval1(-3,7)
232
[-3, 0]
233
234
"""
235
cdef long v[MAX_DEG]
236
self.evaluate(v, a, b)
237
cdef int i
238
return [v[i] for i in range(self.d)]
239
240
241
242
243
244
245