Dear Colleagues, Here is the latest version of the L-function c++ class library and, the command line program lcalc. To compile: gunzip it: gunzip L-1.22.tar.gz untar it: tar -xvf L-1.22.tar This creates a directory called L-1.22 go to the src directory: cd L-1.22/src compile: make this creates the command line interface: lcalc and also a library to which you can link if you want to write your own c programs: libLfunction.a If you have root powers, you can do: sudo make install to install lcalc in /usr/local/bin and libLfunction.a in /usr/local/lib Please read the INSTALL file for more detailed info about compiling to use this package along with pari's elliptic curve routines. ====================================================================================== You probably will only use the command line interface. To learn usage: ./lcalc --help |more The default L-function is the Riemann zeta function. First I'll explain how to use some basic options with zeta. Then I'll explain the options that allow you to do other L-function computations. To compute zeros of zeta use the --zeros or -z option: ./lcalc -z 1000 computes the first 1000 zeros of zeta while also checking for RH and making sure no zeros are missed. This is the option I use when I collect tables of zeros of L-functions. The numbers outputed are the imaginary parts of the zeros of zeta. If you aren't concerned about verifying RH, or if RH doesn't hold (for instance, if you plan to study Dirichlet series without Euler products) you should look for zeros using the --zeros-interval option. For example ./lcalc --zeros-interval -x 10 -y 100 --stepsize .1 searches for zeros of zeta in the interval from 1/2+10i to 1/2+100i, checking for sign changes advancing in steps of size .1. The first column outputs the imaginary part of the zero, the second column a quantity related to S(T) (it increases roughly by 2 whenever a sign change, i.e. pair of zeros, is missed). Higher up the critical strip you should use a smaller stepsize so as not to miss zeros. The --zeros-interval options makes sense if you want to output zeros as they are found. The -z option, which verifies RH, looks for several dozen zeros to make sure none have been missed before outputting any zeros at all, so takes longer than --zeros-interval to output just the first few zeros. For collecting more than just a handful of zeros, one should use the -z option. To compute values: ./lcalc -v -x .5 -y 100 computes the value of zeta at s=.5+100i, outputting the real and imaginary parts of the result. You can also compute values along a line segment at equally spaced points: ./lcalc --value-line-segment -x .5 -y 0 -X .5 -Y 100 --number-samples 10000 computes zeta from s=.5+0i to .5+100i at 1000 equally spaced sample points, outputting the real and imaginary parts of the sample points and the corresponding zeta values. There are some built in L-functions: twists by Dirichlet characters (this currently works for zeta and cusp form L-functions). So for example ./lcalc -v -x .5 -y 0 --twist-quadratic --start -100 --finish 100 will give you L(1/2, chi_d) with -100 <= d <= 100. The short form would be ./lcalc -v -x .5 -y 0 -q -s -100 -f 100 Other twisting options are available, for example ./lcalc -z 10 --twist-primitive --start 3 --finish 100 gives the first 10 zeros of all primitive L(s,chi) with 3 <= conductor <= 100. Notice that with the --twist-quadratic option one is specifying the discriminant which can be negative, while with the --twist-primitive option one is specifying the conductor which should be positive. When using the various twisting options, other than --twist-quadratic, the second column outputted is a label for the character mod n. It is an integer between 1 and phi(n). If one is restricting to primitive charcters, then only a subset of these integers appear in the second column. One can obtain a table of characters using the --output-character, or -C, option. This doesn't work with the --twist-quadratic option, but does with the other twisting options. The --output-character option requires either a '1' or '2'. 1 is to print a comprehensive table of chi(n) for all (n,conductor)=1. ./lcalc -z 10 --twist-primitive --start 3 --finish 100 --output-character 1 will also output a table for each character before outputting the zeros of the corresponding L-function. The characters are constructed multiplicatively in terms of generators of the cyclic groups mod the prime powers that divide n, and there's no simple formula to go from the label to the character. That's why I have the -C 1 option ouputs a table for each character (use in conjunction with the -p, -g, -a, -A, or -c option, but not with the -q option). This ouputs a table of the character before outputting say the zeros requested. There are 6 columns. column 1: n column 2: a label for the character, an integer between 1 and phi(n). column 3: the conductor of the inducing character (same as column 1 if primitive). column 4: m, integer that is coprime with n column 5: Re(chi(m)) column 6: Im(chi(m)) The '2' option is to print just the value of chi(-1), i.e. whether chi is even or odd, and also whether chi is primitive or not. There's also the Ramanujan tau L-function. You can use the --tau option For instance ./lcalc -z 1000 --tau gives the first 1000 zeros of L_tau(s). You can combine it with twisting options. If you have pari and wish to compute the L-function of an elliptic curve, you can modify the Makefile and uncomment the line #PARI_DEFINE = -DINCLUDE_PARI That allows you (after doing a 'make clean' and 'make') to use the -e option successfully. The --help option explains usage. It can be combined with twists. For example ./lcalc -z 30 -e --a1 1 --a2 0 --a3 0 --a4 0 --a6 1 computes the first thirty zeros of the L_function associated to the elliptic curve y^2 = x^3 + 1. The above is consistent with the unix convention that has a '-' for single letter options and '--' for options that are longer, for example '--a1'. The naming convention here will be changed in a future version to be more elegant. If you have a long run you can add nohup at the start of the line and an & at the end to run in the background (do I need to tell you that?). You can also use the > to direct output to a file: For example nohup ./lcalc -z 1000 --tau > my_tau_zeros & will compute, in the background, the first 1000 zeros of L_tau(s) and send the output to the file my_tau_zeros. Other useful options: --rank-compute Computes the analytic rank (short form: -r) --derivative=INT Compute derivative (short form -d INT). Presently the derivative option uses numeric differentiation, and one loses about half the working precision for each successive derivative. Multiprecision is still being implemented, so, for now, the derivative option only gives moderately reasonable output for the first derivative (about 6-7 digits), and less for the second derivative (about 3 digits). Beyond this, one needs to use the USE_LONG_DOUBLE compile option in the MAkefile or higher precision. Analytic rank works well even for high rank since the method used does not compute derivatives, but rather looks at the behaviour of the L-function near the critical point. ----------------------------------------------------------------------------- Finally, you can read in an L-function from a file. The file should contain functional equation data, Dirichlet coefficients and some other useful quantities. To read in the file you use the -F option. For example, say you have a datafile called example_data_files/data_tau containing data for the Ramanujan tau L-function. Then, for instance, ./lcalc --zeros-interval -x 0 -y 100 --stepsize .1 -F example_data_files/data_tau computes the zeros on the critical line, from .5+0i to .5+100i, of the L-function in the file example_data_files/data_tau, by looking in steps of size .1 You could also use the -z option as explained earlier. (The Ramanjuan tau L-function is also available as a built in L-function, using the --tau option rather than the -F option). You can also grab the file if it resides on a webpage by using --url or -u option instead of -F and specifying the url of the file. For the -F or -u options to work, you must have enough Dirichlet coefficients in your file. The program should complain if you don't. Here is the format for the datafile. At the end of the explanation I'll give you an example. The explanation is a bit long, but basically you need to specify the functional equation, Dirichlet coefficients, and some helpful info. The first line should contain an integer, either 1,2, or 3 1 specifies that the Dirichlet coefficients are to be given as integers (up to 32 bits long), 2 that they are floating point numbers, 3 that they are complex numbers. So, for example, the first line would be a 2 for cusp form or Maass form L-function (we normalize the L-functional so that the functional equation is s<->1-s, so the normalized Dirichlet coefficients for a cusp form L-function are not integers). The second line specifies info that the calculator can exploit (or will exploit at some future date). It is an integer that is assigned to different types of L-functions. Currently: -1 for zeta 0 for unknown 1 for periodic including L(s,chi) -2 for L(s,chi) but where the # coeffs computed is < period. 2 for cusp form (in S_K(Gamma_0(N)) 3 for Maass form for SL_2(Z) other integers reserved for future types. So if you are doing a Maass form L-function , the second line should be a 3. The third line is an integer that specifies how many Dirichlet coefficients to read. There should be at least these many Dirichlet coefficients in the file. This is a useful quantity to specify since sometimes (I might include this as a command line option at some point) the data file might have, say, 100 million coefficients, but one might want to read in, say, just 10000 of them. The fourth line is either 0, if the Dirichlet coefficients are *not* periodic, or a positive integer specifying the period otherwise (this happens in the case of Dirichlet L-functions). For a Maass form it should be 0. The fifth line is a positive integer, the quasi-degree. This is the number of gamma factors of the form Gamma(gamma s + lambda) in the functional equation, where gamma is either .5 or 1, and lambda is a complex number with Re lambda >= 0. For example, it is 1 for Dirichlet L-functions, 1 for cusp form L-functions, 2 for Maass form L-functions, etc. Notice the '1' for cusp form L-functions could be a '2' if you wish to split the gamma factor up using the Legendre duplication formula. But it's better not to. Next come the gamma factors, two lines for each gamma factor. The first of each pair of lines contains gamma (either .5 or 1), and the second line contains a pair of floating point numbers separated by a space specifying the real and imaginary parts of lambda (even if purely real, lambda should be given as a pair of numbers, the second one then being 0). Next you specify the functional equation. Let Lambda(s) = a --------' ' | | s | | Q | | Gamma( gamma_j s + lambda_j) L(s) | | j = 1 __________ _ satisfy Lambda(s) = omega Lambda(1-s), where Q is a real number, and omega is complex. Notice that the functional equation is s into 1-s, i.e. the gamma factors and Dirichlet coefficients of L(s) should be normalized correctly so as to have critical line Re(s)=1/2. The next line in the datafile is Q giving as a floating point number, and the one after that gives omega as a pair x y of floating point numbers, specifying the real and imaginary parts of omega (even if it equals 1 it should be given as a pair of floating points, for example 1 0 to indicate 1 + 0 i). We need to allow for the possibility of poles. For example, if L(s) = zeta(s) then Lambda(s) has simple poles with residue 1 at s=1 and s=0. To take into account such possibilities I assume that Lambda(s) has at most simple poles. So, the next line specifies the number of poles (usually 0) and then, for each pole there are two lines. The first line in each pair gives the pole x+iy as a pair x y of floating point numbers. The second line specifies the residue at that pole, also as a pair of floating point numbers. Finally the Dirichlet coefficients. The remaining lines in the file contain a list of Dirichlet coefficients, at least as many as indicated in line three of the datafile. The coefficients can be integers, real, or complex. If complex they should, as usual, be given as a pair x y of floating point numbers separated by a space. Otherwise they should be given as single column of integers or floating point numbers respectively. The datafile should only contain numbers and no comments. The comments below are for the sake of understanding the structure of the datafile. I'm including a couple of sample datafiles in the src/example_data_files/ directory: data_maass is for the Maass form for SL_2(Z) associated to the eigenvalue with R=13.779751351891. data_L4 contains data for the real quadratic Dirichlet L-function of conductor 4. data_tau is for the Ramanujan tau L-function. (the latter two L-functions are also available as a built in option: the first using the options: --twist-quadratic -s -4 -f -4 the second using the option: --tau). Here are the first few lines of data_maass (by the way, this is just as an example... the Dirichlet coefficients I have for this particular L-function are only accurate to a handful of decimal places, expecially near the tail of the file). 2 the two indicated that the Dirichlet coefficients are real 3 what type of L-function. '3' is for a Maass form L-function 29900 How many Dirichlet coefficients to read in 0 zero since coefficients are not periodic 2 number of gamma factors of the form Gamma(gamma s + lambda) .5 first gamma 0 6.88987567594535 first lambda .5 second gamma 0 -6.88987567594535 second lambda .3183098861837906715 the Q in the functional equation 1 0 the omega in the functional equation, omega = 1 + 0i 0 the number of poles of Lambda(s) 1 the first Dirichlet coefficient 1.549304477941 the second Dirichlet coefficient 0.246899772454 the third Dirichlet coefficient 1.400344365369 the fourth Dirichlet coefficient etc ----------------------------------------------------------------------------- For programmers: If you want to write your own c++ program that makes use of the Lfunction library, rather than just use the command line interface, please look at the directory: example_programs, or, for a more complex example, at the source code for the commandline interface (the files of the form Lcommandline*.cc) For an idea on how to compile, while in the src directory type: make examples The include directory contains the L-function class. The main file is L.h. The comments in that file explain the makeup of the class. ----------------------------------------------------------------------------- Questions, comments, and bug reports can be directed to Michael Rubinstein: mrubinst X1 uwaterloo X2 ca where you replace ' X1 ' with '@' and ' X2 ' with '.'