SubTropica (external)

The content on this page was written by AI under human supervision.

SubTropica and its integration engine HyperFLINT are public software by Sebastian Mizera, Mathieu Giroux and Giulio Salvatori for computing Feynman-type parametric integrals symbolically. You give it an integrand that is a product of powers of polynomials over positive variables, with exponents linear in the dimensional regulator $\varepsilon$. It returns the exact coefficients of the $\varepsilon$-expansion as rational combinations of multiple zeta values and, when kinematic variables are present, logarithms and polylogarithms of them, with nothing fitted numerically. Upstream SubTropica is a Mathematica package; BootLoops runs the engine through a Julia driver of the same name that needs no Mathematica and adds the handling of divergent integrals, a reducibility screen, a graph front end and verification tools.

What it does

After Feynman parametrization a loop integral becomes an integral over $[0,\infty)^n$ of a product of polynomial powers; for a graph the polynomials are the Symanzik polynomials $\mathcal U$ and $\mathcal F$. SubTropica's input is this "Euler integrand",

$$ I(\varepsilon)= c(\varepsilon)\int_0^\infty d^n x\,\prod_i x_i^{\nu_i(\varepsilon)}\prod_j P_j(x,s)^{a_j+b_j\varepsilon}, $$

with every polynomial coefficient positive, which restricts the kinematic invariants $s$ to the Euclidean region. The driver expands in $\varepsilon$ and integrates each order one variable at a time, keeping every intermediate result as a hyperlogarithman iterated integral whose kernels are dx/(x − letter) for rational "letters"; logarithms and polylogarithms are the simplest cases. After the last variable the remaining constants are reduced to a fixed basis of multiple zeta valuesthe nested sums ζ(s₁,…,s_k) that appear as the constants of multiloop integrals; ζ(2) = π²/6 and ζ(3) are the first two. The result is a Laurent series in $\varepsilon$ with exact symbolic coefficients, plus a record of the integration order used, the engine version and timings.

The method needs the integrand to be linearly reduciblethere is an order of the integration variables in which, after each integration, all new singularities are again linear in the next variable. The driver has the engine search for such an order, saves it under a run directory and replays it on later calls; when none exists it raises NoLROrderError. A built-in retry admits quadratic letters, and a coefficient that would depend on the resulting algebraic constants is refused unless you pass strict_periods=false. A separate screen, lr_refine (the functions refine_letters and blocking_certificate), uses exact polynomial algebra and makes no engine calls. Given the polynomials and a "blocking" letter from a failed search, it decides in seconds whether that letter is certified spurious (an artifact of the search path) or survives the sharper compatibility-graph bound of Brown and Panzer.

Divergent integrals are classified before any integration. The driver builds the Newton polytope of the polynomials and classifies every ray of its normal fan as convergent, logarithmically divergent or power divergent. Convergent integrands go straight to the engine with its divergence check on. For logarithmic divergences it subtracts exact counterterms read off the divergent facets and integrates the finite remainders, so pole coefficients come out exactly. Power divergences, and rays that need a second regulator, stop with a specific exception (PowerDivergentRefusal, GeometricPropertyViolated) whose message says what to change. Calling again with allow_continuation=true rewrites the integral by Nilsson–Passare analytic continuation into pieces that are at most logarithmically divergent, each sent back through the same entry point.

The driver's defaults guard against two engine pitfalls. With its divergence check off, the engine returns zero on a divergent input, so the driver keeps the check on and decides from the response fields instead of the exit code, which is 0 even on failure. On an input that is not linearly reducible the engine can return a clean-looking result that drops algebraic branches, and nothing in the response flags this. The package's rule is therefore to run the lr_refine screen first and to check every new result to at least 30 digits against an independent numerical evaluation (verify.jl compares at an exact rational point). Numerators, physical-region kinematics and integrands with no admissible order are refused with a message; those cases belong to a numerical method.

Examples

Run the self-tests. From tools/subtropica/ in BootLoops' bootloops-dev repository (GitHub organization BootLoops-ai):

python3 selftest.py

Stage R checks the vendored upstream files against their recorded checksums. Stage F runs scripts/fibrate/fibrate.py --selfcheck: an integer-relation search that must recover a known four-term combination and must fail to identify the number $e$, a series check against the exact identity $\mathrm{ZIP}_{\rm reg}([-9/26])=\log(26/9)$, and a cross-check of its two polylogarithm evaluators. Stage E runs the Julia suite only if SUBTROPICA_HF_BIN points at a built engine, and otherwise prints a SKIP line naming what is missing. Exit code 0 means R and F passed and E passed or was skipped for that reason.

A five-variable integral. The package includes a convergent five-variable example of Smirnov's as fixtures/smirnov_tst2_5var.json (the integrand only; fixture files hold no result values). With scripts/env.sh sourced and the Julia project active:

using SubTropica
E = euler_integrand("fixtures/smirnov_tst2_5var.json")
L = subtropica_integrate(E; order=0)
SubTropica.canonical_text(L.coeffs[1])

subtropica_integrate checks the engine version, classifies the rays (all convergent here), finds and saves an integration order under ./subtropica_runs/, integrates, and reduces the constants. L is a LaurentSeries{HlogExpr} with L.minorder == 0, and L.evidence["lr_order"] records the order used. Its first coefficient is $1-\tfrac45\zeta(2)^2+\zeta(3)=1-2\zeta(4)+\zeta(3)$, printed with the engine's names mzv_2, mzv_3 for $\zeta(2)$, $\zeta(3)$. order=2 also returns the $\varepsilon^1$ and $\varepsilon^2$ coefficients. A single integration step can also be called directly, as test/test_bridge.jl does with cfg = SubTropica.HFConfig(): SubTropica.hf_integrate("Log[1+x]/(x(1+x))", [:x], [:x]; cfg=cfg) followed by SubTropica.resolve_periods(terms; cfg=cfg) gives mzv_2, and the integrand "1/((1+x)(2+x))" gives Log2.

Deciding whether a blocking letter is real. Panzer's HyperInt paper (arXiv:1403.3385, Example 4.2) reduces the pair $\{(1+x)^2+y,\;y+z^2\}$ with $z$ a parameter. test/test_lr_refine.jl reproduces it without the engine (the test reaches the functions through a module alias; with using SubTropica they are exported):

using SubTropica, Nemo
R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z])
polys = [(1 + x)^2 + y, y + z^2]
vars = [:x, :y]                                    # z = kinematic
cert, removed, log = refine_letters(polys, vars, [:y, :x])
c = blocking_certificate(polys, vars, x + 1 + z)

log["order_walkable"] is true, and log["stages"] lists the letters $\{x+1,\,x+1+z,\,x+1-z\}$ after integrating $y$ and $\{1+z,\,z-1\}$ after both variables, as published; removed is empty because the naive and refined bounds agree here. With the order [:x, :y] instead, order_walkable is false, since the starting set is not linear in $x$. c["status"] is "SURVIVES" and c["real"] is true: the letter lies in the refined bound and cannot be certified spurious. A letter present in the naive bound but absent from every refined stage comes back "SPURIOUS_REMOVED", a proof that it cannot block the integration. is_blocking_real(polys, vars, letter) returns only the boolean.

Routines

Driver and input

Engine bridge and order search

Building blocks (called by the driver; exported except where written with the module prefix)

Verification (src/verify.jl)

Scripts

Used on this site

Requirements and source

Julia 1.11 with Nemo, Oscar and JSON (pinned in Project.toml; the first instantiate compiles Oscar and is slow), and Python 3 with mpmath and sympy for the scripts. The HyperFLINT engine is not included. Obtain SubTropica and HyperFLINT upstream (github.com/SubTropica/SubTropica, MIT license; paper arXiv:2604.20954) and build the stand-alone command-line engine (C++17, FLINT 3.4 or newer, OpenMP) following the upstream README, a copy of which is in reference/; deps/BUILD.md covers only the optional in-process library. Then set SUBTROPICA_HF_BIN to the engine wrapper and SUBTROPICA_MZV_DATA to its zeta-value reduction table. Every engine call runs under ulimit -v 32505856 (about 31 GB); parallel work uses one process per worker, since threads sharing an engine handle crash. eval_symbolic and the zeta-value table check evaluate constants and polylogarithms with the independent ginac_gpl program of tools/gpl-eval/ in the same repository. That program needs g++ and the GiNaC/CLN libraries and is compiled from source there; set SUBTROPICA_GINAC_GPL if it lives elsewhere. Self-tests: python3 selftest.py inside tools/subtropica/; full suite: ulimit -v 32505856; julia --project=tools/subtropica tools/subtropica/test/runtests.jl (a few tests need SUBTROPICA_PROBES_DIR or SUBTROPICA_RAYCHECK_DIR and say so when unset). Code: tools/subtropica/ in the bootloops-dev repository, released under the MIT license; the vendored upstream files under reference/ and the external libraries the package calls (Oscar, GiNaC, FLINT) keep their own licenses. The algorithms are Brown's (arXiv:0804.1660, arXiv:0910.0114) and Panzer's HyperInt (arXiv:1403.3385).

← back to the tools index