This project delves into the Riemann zeta function, a cornerstone of number theory due to the remarkable connection between its zeros and the distribution of prime numbers. The exact location of its zeros constitutes the renowned Riemann hypothesis.
This project focuses on a sequence of complex functions conceived by Y. Matiyasevich as efficient approximations of
The code in this repository –written in Python and Julia– generates the numerical data that defines Matiyasevich's approximations of the Riemann zeta function, as introduced in the references 1 and 2, and then computes the approximation errors. The next section of this README introduces the mathematical objects involved in this code, and the subsequent one gives an overview of the various scripts in the repository.
To handle computational instability in our calculations, we maintain high precision in our floating-point numbers, generally requiring around mpmath package, and in Julia through its native BigFloat type.
The need for arbitrary precision resulted in significant performance issues, which we addressed by (i) implementing the most computationally intensive parts of the code in Julia, and (ii) parallelizing whenever feasible.
The Python function mpmath.zetazero, which has no equivalent in Julia, calculates the critical-line zeros of PyCall, it does not appear possible to parallelize a function in this context. This explains our choice of Python for this specific part of the code.
The Riemann zeta function
for every complex number
Matiyasevich's approximations of
The approximations3 are defined in the references 1 and 2 by the formula
where
Despite being defined only from a finite number of zeros, Matiyasevich observed that the approximations
In this project, we focus on the quotient
By the Möbius inversion formula, the quotient
(see Eq. 93 in 1) where the coefficients
and
of
Through our data-driven approach, we aim to describe the dependencies of the functions
Before executing any of the scripts described below, the parameters must be adjusted in their main functions. Individual functions are documented inside the scripts.
Remark on multithreading in Julia. Julia runs by default in single-thread mode. To enable multithreading in Julia, one must add the command -t (which stands for "threads") when executing it. For example, julia -t 4 starts Julia with four threads,
julia -t 4 coef_delta.jl
runs the script coef_delta.jl with four threads, and julia -t auto detects automatically the maximum number of threads available in the machine.
This script returns a list of the imaginary parts of the first mpmath.zetazero.
Parameters
-
max_M(int). Maximal index$M$ of the critical-line zeros to be computed. -
n_dps(int). Precision in number of digits. -
n_cores(int). Number of cores used for multithreading.
Output file.
TXT file containing the imaginary parts of the first max_M critical-line zeros with a precision of n_dps number of digits, ordered increasingly and separated by new-line characters \n. Its path will be ~/Data/p[n_dps]/ImZetaZero_M[max_M]_p[n_dps].txt.
This script computes the coefficients max_M, by solving the linear systems corresponding to all of the approximations simultaneously. It is a multi-thread implementation in Julia of the Gauss algorithm without pivots, based on an algorithm due to Beliakov and Matiyasevich (see the reference 4).
Parameters
-
max_M(int). Maximal index of$M$ for the approximations$\Omega_M$ to be computed. -
max_computed_M(int). Maximal index of the zeros listed in the input file (see "Input file" below). -
n_dps(int). Precision in number of digits. It must coincide with the precision specified in the input file path (see "Input file" below). -
chunk_size(int). Upper bound in bytes for the size of output JSON files (see "Output files" below).
Input file.
TXT file (as output by zeta_zeros.py) with path ~/Data/p[n_dps]/ImZetaZero_M[max_computed_M]_p[n_dps].txt listing the critical-line zeros of zeta up to index max_computed_M with precision n_dps.
Output files.
Dictionary whose keys are integers from 1 to max_M and the value at key chunk_size. The path of the JSON files will be ~/Data/p[n_dps]/CoefDelta_M[start]-[end]_p[n_dps].json, where start and end denote the key range for the dictionary entries stored in the file.
This script computes the multiplicative error function range_M, range_K, range_s of the parameters
Parameters.
-
range_M(StepRange of int). Range of integer values of$M$ for the computation of$\nu_{M, K}(s)$ . -
range_K(StepRange of int). Range of integer values of$K$ for the computation of$\nu_{M, K}(s)$ . -
range_s(StepRange of numbers). Range of values of$s$ for the computation of$\nu_{M, K}(s)$ (they may be integers or float). -
n_dps(int). Precision in number of digits. It must coincide with the precision specified in the input file paths (see "Input files" below). -
chunk_size(int). Upper bound in bytes for the size of output JSON files (see "Output files" below).
Input files.
JSON files (as output by coef_delta.jl) listing the coefficients range_M with precision n_dps. Their path should be ~/Data/p[n_dps]/CoefDelta_M[start]-[end]_p[n_dps].json.
Output files.
Dictionary whose keys are tuples (M,K,s) in the Cartesian product of the ranges range_M, range_K and range_s. The value at key (M,K,s) is the value of the function chunk_size. The path of the JSON files is
~/Data/p[n_dps]/nu_M[range_M]_K[range_K]_s[range_s]_p[n_dps]_part_[i].json
where the parameter i indexes the parts in which the dictionary is divided. If the whole dictionary has size less than chunk_size, then it is stored as
~/Data/p[n_dps]/nu_M[range_M]_K[range_K]_s[range_s]_p[n_dps].json
without i parameter. The ranges are written in the format [start]-[step]-[end].
Footnotes
-
Y. Matiyasevich. Calculation of Riemann's zeta function via interpolating determinants. Preprints of MPIM in Bonn, 2013. ↩ ↩2 ↩3 ↩4
-
Y. Matiyasevich. Riemann’s zeta function and finite Dirichlet series. St. Petersburg Math. J. 27 (2016), 985-1002. ↩ ↩2
-
Our notation differs from Matiyasevich's in that our Ω_M(s) functions correspond to the functions Δ_{2M+1}(s) in his articles. ↩
-
G. Beliakov and Y. Matiyasevich. A parallel algorithm for calculation of determinants and minors using arbitrary precision arithmetic. BIM Numerical Mathematics 56 (2016), 33–50. ↩
