Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
include 'interrupt.pxi'
2
3
cdef extern from "rankbound.h":
4
double rankbound(char * curve_string,
5
double logN,
6
long * bad_primes_,
7
int * ap_,
8
int len_bad_primes_,
9
double delta_,
10
int verbose_)
11
12
cdef extern from "math.h":
13
double log(double)
14
15
cdef extern from "stdlib.h":
16
void free(void* ptr)
17
void* malloc(size_t size)
18
void* realloc(void* ptr, size_t size)
19
20
from sage.schemes.elliptic_curves.ell_rational_field import EllipticCurve_rational_field
21
22
def xxx_rankbound(E, float delta, bad_primes = None, verbose = 0):
23
r"""
24
Assuming the Riemann hypothesis for `L(s, E)` and the BSD conjecture,
25
this function computes and returns an upper bound for the rank of `E`,
26
which must be defined over `Q`.
27
28
More precisely, we compute the sum
29
30
`\sum_\gamma f(\gamma, \Delta)`
31
32
where `1/2 + i\gamma` runs over the nontrivial zeros of `L(s, E)`
33
(counted with multiplicity) and
34
35
`f(t, \delta) = (sin(\pi \Delta t)/(\pi \Delta t))^2`.
36
37
If all of the `\gamma` are real, then this is an upper bound for the
38
analytic rank of `E`, and so if the BSD conjecture is true, it is an
39
upper bound for the rank of `E`.
40
41
42
INPUT:
43
44
- ``E`` - An Elliptic Curve, whose rank is to be bounded.
45
46
- ``delta`` - a real number between 1 and 5; the `\Delta` described above.
47
48
- ``verbose`` - if > 0, print out some progress information.
49
50
OUTPUT:
51
52
- The sum described above, which happens to be a bound for the rank if
53
RH+BSD holds, expected to be accurate to about `5e-5`.
54
55
56
EXAMPLES:
57
58
This method works well on some high rank curves. Under BSD, the parity
59
of the rank of the following curve is known, so the bound computed
60
is tight.
61
62
::
63
64
sage: from psage.ellcurve.xxx.rankbound import xxx_rankbound
65
sage: E = EllipticCurve([1,0,0,-431092980766333677958362095891166,5156283555366643659035652799871176909391533088196]) # rank >= 20
66
sage: xxx_rankbound(E, 2.1)
67
21.48...
68
69
It is also possible to specify a list of the bad primes, so that computing
70
the conductor is fast. (In the following example, a larger value of Delta
71
would give a better bound, but a tight bound seems unattainable at the
72
moment.)
73
74
::
75
76
sage: from psage.ellcurve.xxx.rankbound import xxx_rankbound
77
sage: E = EllipticCurve([1, -1, 1, -20067762415575526585033208209338542750930230312178956502, 34481611795030556467032985690390720374855944359319180361266008296291939448732243429]) # rank >= 28
78
sage: xxx_rankbound(E, 2.0, bad_primes = [2, 3, 5, 7, 11, 13, 17, 19, 48463, 20650099, 315574902691581877528345013999136728634663121, 376018840263193489397987439236873583997122096511452343225772113000611087671413])
79
36.13...
80
81
82
It also sometimes works well on some not so high rank curves.
83
84
::
85
86
sage: from psage.ellcurve.xxx.rankbound import xxx_rankbound
87
sage: E = EllipticCurve([0, -1, 1, 109792, 10201568]) # rank 0
88
sage: xxx_rankbound(E, 2.0)
89
0.53...
90
91
We test the accuracy with some curves where we can actually
92
compute the zeros. In both of the following cases, it is
93
likely (but not certain) that the value computed by xxx_rankbound()
94
is more accurate than the value computed by summing over zeros,
95
since we are not finding enough zeros for high accuracy.
96
97
::
98
99
sage: from psage.ellcurve.xxx.rankbound import xxx_rankbound
100
sage: E = EllipticCurve('11a1') # rank 0
101
sage: a = xxx_rankbound(E, 2.0); # answer is around .0027
102
sage: abs(a - .0027) < 1e-5
103
True
104
sage: f = lambda t : (sin(RR(t * 2.0 * pi))/RR(t * pi * 2.0))^2 # long time
105
sage: zeros = lcalc.zeros(1000, E) # long time
106
sage: b = 2 * sum( (f(z) for z in zeros) ) # long time
107
sage: abs(a - b) < 1e-4 # long time
108
True
109
sage: E = EllipticCurve('389a1') # rank 2
110
sage: a = xxx_rankbound(E, 1.1); # the answer is around 2.03
111
sage: abs(a - 2.03) < 1e-4
112
True
113
sage: f = lambda t : (sin(RR(t * 1.1 * pi))/RR(t * pi * 1.1))^2 # long time
114
sage: zeros = lcalc.zeros(4000, E) # long time
115
sage: b = 2 * sum( (f(z) for z in zeros[2:]) ) + 2 # long time
116
sage: abs(a - b) < 5e-4 # long time
117
True
118
119
Often it doesn't work so well for curves of small rank and
120
large conductor, but I'm not going to write down an example
121
of that right now.
122
123
NOTES:
124
125
We use the explicit formula to compute the sum over zeros. (So
126
we don't actually find the zeros.) As such, the complexity grows
127
exponentially with delta (while, unfortunately, giving only slightly
128
better bounds). Guidelines on a fast machine: delta = 2.0 is fast,
129
delta = 2.5 is a little slower, delta = 3.0 takes a few minutes,
130
delta = 3.5 takes at least a few hours, delta = 4.0 takes over a
131
day (a few days?).
132
133
"""
134
135
if not isinstance(E, EllipticCurve_rational_field):
136
raise NotImplementedError("Only elliptic curves over Q are implemented for now.")
137
138
L = str(list(E.ainvs()))
139
140
if bad_primes is not None:
141
N = 1
142
for p in bad_primes:
143
e = E.local_data(p).conductor_valuation()
144
a = p**e
145
N = N * a
146
logN = float(log(N))
147
else:
148
logN = float(log(E.conductor()))
149
bad_primes = [x.prime().gen() for x in E.local_data()]
150
151
bad_primes = [x for x in bad_primes if x < 2**63]
152
cdef long* bad_primes_array = <long*>malloc(sizeof(long) * len(bad_primes))
153
cdef int* bad_ap = <int*>malloc(sizeof(int) * len(bad_primes))
154
155
for n in range(len(bad_primes)):
156
p = bad_primes[n]
157
bad_primes_array[n] = p
158
bad_ap[n] = E.ap(p)
159
160
sig_on()
161
#
162
# We make no attempt to cleanup nicely if there is a keyboard interrupt.
163
# Oh well, only a few bytes will be lost...
164
#
165
bound = rankbound(L, logN, bad_primes_array, bad_ap, len(bad_primes), delta, verbose)
166
sig_off()
167
free(bad_primes_array)
168
free(bad_ap)
169
return bound
170
171