GPLEval
The content on this page was written by AI under human supervision.
GPLEval is a Julia package that evaluates multiple polylogarithms $G(a_1,\dots,a_n;z)$, harmonic polylogarithms $H(\vec m;z)$ and classical polylogarithms $\mathrm{Li}_n(z)$ to any requested precision. You give it the indices and the argument, or a list of symbol words with an alphabet and a kinematic point, and it returns each value as a complex balla midpoint together with a radius guaranteed to contain the true value; the arithmetic is done by the Arb library through Arblib.jl. A command-line script evaluates a whole basis of words from JSON files, and a small bridge to GiNaC gives an independent value for cross-checks.
What it does
Multiple polylogarithmsiterated integrals of the one-forms dt/(t − a), also called Goncharov polylogarithms or GPLs; when every index is 0, 1 or −1 they are the harmonic polylogarithms (HPLs) are the functions that most Feynman integrals without elliptic geometry evaluate to. GPLEval uses the standard definition, first index outermost:
$$G(a_1,\dots,a_n;z)=\int_0^z \frac{dt}{t-a_1}\,G(a_2,\dots,a_n;t),\qquad G(;z)=1,\qquad G(0,\dots,0;z)=\frac{\log^n z}{n!}\,,$$
so that $G(0,\dots,0,a;z)=-\mathrm{Li}_m(z/a)$ with $m-1$ zeros. The harmonic polylogarithm is $H(\vec m;z)=(-1)^p\,G(\vec a;z)$, where $\vec a$ is the word over $\{0,1,-1\}$ expanded from the compressed notation ($[2,1]\to[0,1,1]$) and $p$ counts the indices equal to $+1$. Words ending in zeros are regularized by shuffle identities, so powers of $\log z$ appear explicitly.
When BootLoops fits numerical values of an integral to a combination of such functions (see Lockpick), it needs every basis function at every sample point to hundreds of digits, in exactly the conventions the basis was written in. GPLEval supplies those numbers; Gatekeeper uses the same evaluations to test a fitted answer at points not used in the fit.
Well inside $|z| \lt \min_i|a_i|$ the power series at zero is summed and a proven bound on the dropped tail is added to the radius; for larger $|z|$ the Hölder convolution of Vollinga and Weinzierl (hep-ph/0410259) takes over. If a nonzero index lies on the open segment from $0$ to $z$ (an "on-path" index), the answer depends on which side the contour passes. GPLEval splits the path through a complex midpoint (arXiv:1601.02649) and the prescription keyword picks the side: the default :ginac means $a_k+i0$, matching GiNaC's two-argument G, so $G(1/2;1)=+i\pi$; :feynman means $a_k-i0$. A naive integration along the real axis would return the principal value there without warning, so GPLEval tests for on-path indices before anything else and always applies the stated prescription.
Results are Acb balls whose radius is a proven bound on rounding and truncation error, with two exceptions: the series_only fast path of evaluate_basis adds an estimated tail term instead of a proven one, and method = :ginac wraps GiNaC's number without a bound. Precision is set in bits, not digits: prec = 256 is about 77 decimal digits. For an independent check, method = :hybrid integrates along a deformed contour with Arb's certified quadrature (depth at most 3), and gpl_ginac asks GiNaC for the same number. Only letters linear in the integration variable are handled; for elliptic kernels empl is a thin pass-through to Eichler. One pitfall: in the symbol-word interface a letter stands for the index $a_i$ (the root of $z-a_i$), not for the argument of a $d\log$.
Examples
Run the self-test suite. From tools/gpl-eval/:
python3 selftest.py
The wrapper finds julia, sets up the package environment if needed (Arblib and JSON3 are downloaded once), and runs GPLEval.jl/test/runtests.jl. The suite checks depth-one closed forms, values such as $H(2,1;1)=\zeta(3)$ and $H(3,1;1)=\zeta(4)/4$, trailing-zero regularization, continuation to $|z|\ge\min|a_i|$ and both $\pm i0$ prescriptions. Where GiNaC is installed it also checks agreement to at least 60 digits at random rational points; otherwise those comparisons are skipped with a warning. Exit code 0 means a pass, or that julia or a dependency is missing (the message names it and the install command); nonzero means a test failed or the Julia environment resolved but could not be loaded.
Single values from Julia, as called in the test suite:
using Arblib, GPLEval const PREC = 768 # ≥ 200 decimal digits hpl([2, 1], 1; prec = PREC) # Euler: equals ζ(3) gpl([1//2], 1; prec = PREC) # G(1/2;1) = log(−1) = +iπ, default side gpl([1//2], 1; prec = PREC, prescription=:feynman) # −iπ gpl([0, 1, -1, 1], 1//3; prec = 512) # depth 4 gpl_ginac([0, 1, 1], 1; digits = 80) # GiNaC's G(0,1,1;1) = ζ(3)
The first four return an Acb; real(g) and imag(g) are Arb balls and Arblib.radref(real(g)) is the radius. The tests assert that the first ball agrees with $\zeta(3)$, that the next two are $\pm i\pi$, and that the depth-four call takes under a second. gpl_ginac returns a Complex{BigFloat} without an error bound; on first use it compiles the helper from src/ginac_gpl.cpp.
A basis of symbol words from the command line. With alpha.json
{"letters": {"l0": "0", "l1": "1", "lm1": "-1", "ls": "s+t"}, "zvar": "z"}
and basis.json holding a list of symbol wordssequences of letter names; a word (s₁,…,sₙ) stands for G(a₁,…,aₙ; z) with aᵢ the index of letter sᵢ such as [["l0","l1"], ["l0","l1","lm1"]], run
julia --project=GPLEval.jl GPLEval.jl/bin/gpl_eval.jl --alphabet alpha.json --basis basis.json --point '{"s":-3,"t":-7,"z":0.5}' --prec 256 --out values.json
Each letter is a Julia expression in the variables of --point giving that letter's index $a_i$; zvar names the entry that is the upper limit $z$. values.json holds the precision, the point, and one entry per word with re and im as decimal strings and rad, the radius of the real part; read rad before trusting digits. Without --out the JSON goes to standard output. Point entries pass through double precision, so use values exact in binary (integers, halves), or call evaluate_basis(words, alpha, z, pt; prec = PREC) from Julia with exact rationals and alpha = Dict(:l0 => p -> 0, :l1 => p -> 1, :lm1 => p -> -1), as in the tests.
Routines
Scripts
selftest.py— sets up the Julia environment if needed and runs the test suite; a missingjuliaor dependency is a named skip.GPLEval.jl/bin/gpl_eval.jl— command-line evaluator:--alphabet,--basis,--point,--prec(bits, default 768),--out(standard output if omitted).GPLEval.jl/deps/setup.jl— one-time setup linking the in-repository Landau Alphabet and Eichler packages into the project; honorsLANDAUALPHABET_JL_PATHandEICHLER_JL_PATH.GPLEval.jl/test/runtests.jl— the test suite.GPLEval.jl/src/ginac_gpl.cpp— source of the helperginac_gpl digits re_z im_z [re_a im_a]..., which prints GiNaC's real and imaginary parts of $G$; no compiled binary is included, andgpl_ginacbuilds it from this file on first use.
Julia functions (module GPLEval)
gpl(a, z; prec, cache = nothing, prescription = :ginac, method = :auto)— $G(a_1,\dots,a_n;z)$ as anAcb;prescriptionis:ginac/:plus_i0or:feynman/:minus_i0;methodis:auto,:hybridor:ginac.gpl_hybrid(a, z; prec, prescription, cache)—gplwithmethod = :hybrid(certified contour quadrature; depth at most 3, $a_1,a_2,a_n\neq0$).hpl(m, z; prec, cache, expanded = false)— $H(\vec m;z)$ from the compressed vector, or from a word over $\{0,1,-1\}$ withexpanded = true.hpl_expand(m)— compressed vector to index word,[2,1]to[0,1,1].li(n, z; prec)— $\mathrm{Li}_n(z)$ as a ball.analytic_continue(a, z; prec, prescription, method = :path, cache)— $G$ with on-path indices by path splitting, or by contour quadrature withmethod = :hybrid.on_path_indices(a, z)— positions of the indices on the open segment from $0$ to $z$;ais aVector{Acb}andzanAcb.GPLCache(prec)— memo table for repeated sub-words at one precision; pass ascache =.evaluate_symbol(word, alphabet, z, point; prec, cache)— one word of letter symbols to its value, with $a_i$ =alphabetletter.evaluate_basis(words, alphabet, z, point; prec, series_only = false, nterms = 0)— a list of words with a shared cache;series_only = trueuses Landau Alphabet's cached series (lengthnterms, chosen automatically when 0), fastest for a large basis with $|z| \lt \min|a_i|$ but with an estimated rather than proven tail term.gpl_ginac(a, z; digits = 60)— GiNaC's $G(a;z)$ asComplex{BigFloat}; give exact integers or rationals.empl(kernels, t, sec),empl(kernels, q, logq)— pass-through to Eichler's certified iterated integrals of $q$-series kernels.- Re-exported from Landau Alphabet and Eichler:
GPLContext,ItIntEvaluator,DlogKernel,Word,shuffle_product,const_value,MPLBasisFunction,basis_tower,EllipticSector.
Used on this site
- The polylogarithmic warm-ups — with Arb, one of the two independent polylogarithm evaluators behind every comparison against the published closed forms.
- Polylogarithms — evaluates the polylogarithm bases for the checks at points not used in the fits.
Requirements and source
Julia 1.10 or newer with the registered packages Arblib and JSON3, plus two packages from the same repository: Landau Alphabet (tools/landau-alphabet/LandauAlphabet.jl) and Eichler (upgrades/Eichler.jl). Project.toml and Manifest.toml are included, so a fresh clone is prepared with julia --project=GPLEval.jl -e 'import Pkg; Pkg.instantiate()' (network once); on another Julia version run julia GPLEval.jl/deps/setup.jl. The optional GiNaC cross-check needs the GiNaC and CLN C++ libraries, g++ and pkg-config (www.ginac.de, GPL-2.0 or later, used unmodified). The helper is compiled from src/ginac_gpl.cpp on first use and run as a separate process; to build it by hand, g++ -O2 -std=c++17 -o GPLEval.jl/src/ginac_gpl GPLEval.jl/src/ginac_gpl.cpp $(pkg-config --cflags --libs ginac). Python 3 is needed only for the wrapper; run the tests with python3 selftest.py or julia --project=GPLEval.jl GPLEval.jl/test/runtests.jl. The code is in tools/gpl-eval/ in BootLoops' bootloops-dev repository (GitHub organization BootLoops-ai), released under the MIT license.