Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
/*
2
* rankbound.cc
3
*
4
* Code to analytically bound the rank of an elliptic curve (assuming BSD
5
* + RH). More specifically, this program computes
6
*
7
* sum f(\gamma)
8
*
9
* where 1/2 + i\gamma runs over the nontrivial zeros of the L function
10
* of an elliptic curve (using the "analytic" normalization here). We use
11
*
12
* f = (sin(delta pi x)/(delta pi x))^2
13
*
14
* so that f(0) = 1 and f(x) > 0 if x is real. So if all of the
15
* gammas are real, then the resulting sum is an upper bound for
16
* the number of zeros of L(s, E) at s = 1/2.
17
*
18
*/
19
20
21
/*
22
* Basic workings of the program:
23
*
24
* We compute the sum over zeros using the explicit formula, which does not
25
* require us to actually find the zeros. The main() function initializes
26
* some variables, computes some quantities that are independent of the
27
* curve or that only rely on the conductor, and then creates the curve
28
* as a smalljac object.
29
*
30
* We register a callback with smalljac to compute successive terms in the
31
* "sum over primes" part of the explicit formula as smalljac computes
32
* each ap for us. Since smalljac doesn't compute ap when E has bad reduction
33
* at p, these p and ap need to be specified in advance.
34
*
35
*/
36
37
38
#include <iostream>
39
#include <cstdlib>
40
#include <iomanip>
41
#include <fstream>
42
#include <string>
43
#include <vector>
44
#include "precomputation.h"
45
#include "mathlib.h"
46
47
#include <complex>
48
using namespace std;
49
50
extern "C" {
51
#include "smalljac.h"
52
}
53
54
// We are only going to be doing one curve at a time,
55
// so we don't mind making the following global variables.
56
57
long * bad_primes;
58
int * bad_prime_aps;
59
int number_of_bad_primes;
60
61
double delta = 3.6;
62
double endpoint;
63
volatile double sum;
64
long _count;
65
const complex<double> I = complex<double>(0.0, 1.0);
66
67
int verbose = 0;
68
69
inline complex<double> digamma(complex<double> z) {
70
return log_GAMMA(z, 1);
71
}
72
/*
73
int smalljac_callback(smalljac_Qcurve_t curve, unsigned long p, int good, long a[], int n, void *arg) {
74
_count++;
75
76
double p_endpoint = log(endpoint)/log(p);
77
if(!good) {
78
long ap = 2;
79
for(int n = 0; n < number_of_bad_primes; n++) {
80
if(p == bad_primes[n])
81
ap = bad_prime_aps[n];
82
continue;
83
}
84
if(ap == 2) {
85
cerr << "warning: missing or bad ap for bad prime " << p << endl;
86
}
87
for(int k = 1; k <= p_endpoint; k++) {
88
sum -= log(p) * ap/pow((double)p, k) * triangle(k * log(p)/(2.0 * M_PI), delta)/M_PI;
89
}
90
}
91
else {
92
double ap = -a[0]/sqrt(p);
93
complex<double> alpha = ap/2.0 + I * sqrt(1 - ap/2.0);
94
complex<double> beta = ap/2.0 - I * sqrt(1 - ap/2.0);
95
96
97
for(int k = 1; k <= p_endpoint; k++) {
98
double cn = (pow(alpha, k) + pow(beta, k)).real();
99
double z = log(p) * ((pow(alpha, k) + pow(beta, k)).real()/pow(p, k/2.0) *
100
triangle(k * log(p)/(2.0 * M_PI), delta)/M_PI);
101
sum -= z;
102
}
103
104
if( verbose && ((_count % 100000 == 0) || (_count < 10000 && _count % 1000 == 0)))
105
cout << p << " " << (double)p/(double)endpoint << " " << sum << " " << endl;
106
}
107
return 1;
108
}
109
*/
110
111
int smalljac_callback(smalljac_Qcurve_t curve, unsigned long p, int good, long a[], int n, void *arg) {
112
_count++;
113
114
double p_endpoint = log(endpoint)/log(p);
115
116
complex<double> alpha;
117
complex<double> beta;
118
119
if(!good) {
120
long ap = 2;
121
for(int n = 0; n < number_of_bad_primes; n++) {
122
if(p == bad_primes[n])
123
ap = bad_prime_aps[n];
124
continue;
125
}
126
if(ap == 2) {
127
cerr << "warning: missing or bad ap for bad prime " << p << endl;
128
}
129
alpha = ap/sqrt(p);
130
beta = 0.0;
131
}
132
else {
133
double ap = -a[0]/sqrt(p);
134
alpha = ap/2.0 + I * sqrt(1 - ap*ap/4.0);
135
beta = ap/2.0 - I * sqrt(1 - ap*ap/4.0);
136
}
137
138
double x = 0;
139
140
for(int k = 1; k <= p_endpoint; k++) {
141
double cn = (pow(alpha, k) + pow(beta, k)).real();
142
double z = cn/pow(p, k/2.0) * triangle(k * log(p)/(2.0 * M_PI), delta);
143
x += z;
144
}
145
146
sum = sum - log(p) * x/M_PI;
147
148
if( verbose && ((_count % 100000 == 0) || (_count < 10000 && _count % 1000 == 0)))
149
cout << p << " " << (double)p/(double)endpoint << " " << sum << " " << endl;
150
151
return 1;
152
153
}
154
155
extern "C"
156
double rankbound(char * curve_string, double logN, long * bad_primes_, int * ap_, int len_bad_primes_, double delta_, int verbose_) {
157
verbose = verbose_;
158
delta = delta_;
159
bad_primes = bad_primes_;
160
bad_prime_aps = ap_;
161
number_of_bad_primes = len_bad_primes_;
162
163
endpoint = exp(2 * M_PI * delta);
164
double conductor_term = triangle(0, delta)/(2 * M_PI) * logN;
165
if(verbose) {
166
cout << "conductor term: " << conductor_term << endl;
167
cout << "gamma terms: " << gamma_terms(delta) << endl;
168
cout << "logpi term: " << -triangle(0, delta) * log(M_PI)/M_PI << endl;
169
}
170
//sum = gamma_terms(delta) - triangle(0, delta) * log(M_PI)/M_PI + conductor_term;
171
sum = gamma_terms(delta) - triangle(0, delta) * log(2 * M_PI)/M_PI + conductor_term;
172
173
smalljac_Qcurve_t curve;
174
175
long result;
176
int err;
177
long maxp = endpoint;
178
179
_count = 0;
180
181
curve = smalljac_Qcurve_init(curve_string, &err);
182
183
result = smalljac_Lpolys(curve, 1, maxp, 0, smalljac_callback, (void * )NULL);
184
smalljac_Qcurve_clear(curve);
185
186
return sum;
187
}
188
189
int main(int argc, char *argv[]) {
190
if(argc < 3) {
191
cout << "Usage: rankbound input_file delta" << endl;
192
cout << "Example: rankbound rank20_example 2.5" << endl;
193
return 1;
194
}
195
196
double delta;
197
198
delta = strtod(argv[2], NULL);
199
200
cout << setprecision(17);
201
202
ifstream infile(argv[1]);
203
204
//
205
// we expect infile to contain one line, which looks like
206
//
207
// [a1,a2,a3,a4,a6] logN p ap p ap ...
208
//
209
210
string curve_string;
211
infile >> curve_string;
212
213
double logN;
214
infile >> logN;
215
216
vector<long> bad_primes;
217
vector<int> bad_prime_aps;
218
219
while(!infile.eof()) {
220
unsigned long p;
221
int ap;
222
infile >> p;
223
bad_primes.push_back(p);
224
infile >> ap;
225
bad_prime_aps.push_back(ap);
226
227
}
228
229
verbose = 1;
230
231
double bound = rankbound(const_cast<char *>(curve_string.c_str()),
232
logN,
233
&bad_primes[0],
234
&bad_prime_aps[0],
235
bad_primes.size(),
236
delta,
237
verbose);
238
239
cout << curve_string << " " << bound << endl;
240
241
242
}
243
244