/*1* rankbound.cc2*3* Code to analytically bound the rank of an elliptic curve (assuming BSD4* + RH). More specifically, this program computes5*6* sum f(\gamma)7*8* where 1/2 + i\gamma runs over the nontrivial zeros of the L function9* of an elliptic curve (using the "analytic" normalization here). We use10*11* f = (sin(delta pi x)/(delta pi x))^212*13* so that f(0) = 1 and f(x) > 0 if x is real. So if all of the14* gammas are real, then the resulting sum is an upper bound for15* the number of zeros of L(s, E) at s = 1/2.16*17*/181920/*21* Basic workings of the program:22*23* We compute the sum over zeros using the explicit formula, which does not24* require us to actually find the zeros. The main() function initializes25* some variables, computes some quantities that are independent of the26* curve or that only rely on the conductor, and then creates the curve27* as a smalljac object.28*29* We register a callback with smalljac to compute successive terms in the30* "sum over primes" part of the explicit formula as smalljac computes31* each ap for us. Since smalljac doesn't compute ap when E has bad reduction32* at p, these p and ap need to be specified in advance.33*34*/353637#include <iostream>38#include <cstdlib>39#include <iomanip>40#include <fstream>41#include <string>42#include <vector>43#include "precomputation.h"44#include "mathlib.h"4546#include <complex>47using namespace std;4849extern "C" {50#include "smalljac.h"51}5253// We are only going to be doing one curve at a time,54// so we don't mind making the following global variables.5556long * bad_primes;57int * bad_prime_aps;58int number_of_bad_primes;5960double delta = 3.6;61double endpoint;62volatile double sum;63long _count;64const complex<double> I = complex<double>(0.0, 1.0);6566int verbose = 0;6768inline complex<double> digamma(complex<double> z) {69return log_GAMMA(z, 1);70}71/*72int smalljac_callback(smalljac_Qcurve_t curve, unsigned long p, int good, long a[], int n, void *arg) {73_count++;7475double p_endpoint = log(endpoint)/log(p);76if(!good) {77long ap = 2;78for(int n = 0; n < number_of_bad_primes; n++) {79if(p == bad_primes[n])80ap = bad_prime_aps[n];81continue;82}83if(ap == 2) {84cerr << "warning: missing or bad ap for bad prime " << p << endl;85}86for(int k = 1; k <= p_endpoint; k++) {87sum -= log(p) * ap/pow((double)p, k) * triangle(k * log(p)/(2.0 * M_PI), delta)/M_PI;88}89}90else {91double ap = -a[0]/sqrt(p);92complex<double> alpha = ap/2.0 + I * sqrt(1 - ap/2.0);93complex<double> beta = ap/2.0 - I * sqrt(1 - ap/2.0);949596for(int k = 1; k <= p_endpoint; k++) {97double cn = (pow(alpha, k) + pow(beta, k)).real();98double z = log(p) * ((pow(alpha, k) + pow(beta, k)).real()/pow(p, k/2.0) *99triangle(k * log(p)/(2.0 * M_PI), delta)/M_PI);100sum -= z;101}102103if( verbose && ((_count % 100000 == 0) || (_count < 10000 && _count % 1000 == 0)))104cout << p << " " << (double)p/(double)endpoint << " " << sum << " " << endl;105}106return 1;107}108*/109110int smalljac_callback(smalljac_Qcurve_t curve, unsigned long p, int good, long a[], int n, void *arg) {111_count++;112113double p_endpoint = log(endpoint)/log(p);114115complex<double> alpha;116complex<double> beta;117118if(!good) {119long ap = 2;120for(int n = 0; n < number_of_bad_primes; n++) {121if(p == bad_primes[n])122ap = bad_prime_aps[n];123continue;124}125if(ap == 2) {126cerr << "warning: missing or bad ap for bad prime " << p << endl;127}128alpha = ap/sqrt(p);129beta = 0.0;130}131else {132double ap = -a[0]/sqrt(p);133alpha = ap/2.0 + I * sqrt(1 - ap*ap/4.0);134beta = ap/2.0 - I * sqrt(1 - ap*ap/4.0);135}136137double x = 0;138139for(int k = 1; k <= p_endpoint; k++) {140double cn = (pow(alpha, k) + pow(beta, k)).real();141double z = cn/pow(p, k/2.0) * triangle(k * log(p)/(2.0 * M_PI), delta);142x += z;143}144145sum = sum - log(p) * x/M_PI;146147if( verbose && ((_count % 100000 == 0) || (_count < 10000 && _count % 1000 == 0)))148cout << p << " " << (double)p/(double)endpoint << " " << sum << " " << endl;149150return 1;151152}153154extern "C"155double rankbound(char * curve_string, double logN, long * bad_primes_, int * ap_, int len_bad_primes_, double delta_, int verbose_) {156verbose = verbose_;157delta = delta_;158bad_primes = bad_primes_;159bad_prime_aps = ap_;160number_of_bad_primes = len_bad_primes_;161162endpoint = exp(2 * M_PI * delta);163double conductor_term = triangle(0, delta)/(2 * M_PI) * logN;164if(verbose) {165cout << "conductor term: " << conductor_term << endl;166cout << "gamma terms: " << gamma_terms(delta) << endl;167cout << "logpi term: " << -triangle(0, delta) * log(M_PI)/M_PI << endl;168}169//sum = gamma_terms(delta) - triangle(0, delta) * log(M_PI)/M_PI + conductor_term;170sum = gamma_terms(delta) - triangle(0, delta) * log(2 * M_PI)/M_PI + conductor_term;171172smalljac_Qcurve_t curve;173174long result;175int err;176long maxp = endpoint;177178_count = 0;179180curve = smalljac_Qcurve_init(curve_string, &err);181182result = smalljac_Lpolys(curve, 1, maxp, 0, smalljac_callback, (void * )NULL);183smalljac_Qcurve_clear(curve);184185return sum;186}187188int main(int argc, char *argv[]) {189if(argc < 3) {190cout << "Usage: rankbound input_file delta" << endl;191cout << "Example: rankbound rank20_example 2.5" << endl;192return 1;193}194195double delta;196197delta = strtod(argv[2], NULL);198199cout << setprecision(17);200201ifstream infile(argv[1]);202203//204// we expect infile to contain one line, which looks like205//206// [a1,a2,a3,a4,a6] logN p ap p ap ...207//208209string curve_string;210infile >> curve_string;211212double logN;213infile >> logN;214215vector<long> bad_primes;216vector<int> bad_prime_aps;217218while(!infile.eof()) {219unsigned long p;220int ap;221infile >> p;222bad_primes.push_back(p);223infile >> ap;224bad_prime_aps.push_back(ap);225226}227228verbose = 1;229230double bound = rankbound(const_cast<char *>(curve_string.c_str()),231logN,232&bad_primes[0],233&bad_prime_aps[0],234bad_primes.size(),235delta,236verbose);237238cout << curve_string << " " << bound << endl;239240241}242243244