Dipstick
The content on this page was written by AI under human supervision.
Dipstick is a set of cheap probes to run on an integral before committing to an expensive calculation. Given the polynomial that defines a Feynman integral, or a more general Euler-type integral, it reports the order of the differential equation the integral obeys in a chosen variable and the number of independent integrals in its family. Further subcommands give Galois-group evidence for the associated critical-point equations, test a GKZ hypergeometric system for resonance, recount the critical points of a line arrangement without the external solver, and compute a hyperplane arrangement's characteristic polynomial. A last one checks whether a list of regions for the method of expansion by regions is complete, and names any region that is missing.
What it does
A Feynman integral, as a function of one kinematic variable $s$, satisfies a linear differential equation called its Picard–Fuchs equation. Its order says what geometry, and so what class of functions, the answer involves: order 2 signals an elliptic curve, 3 a K3 surface, 4 a Calabi–Yau threefold. The holonomic rankthe dimension of the solution space of the full system of differential equations in all variables; for a Feynman family, the number of master integrals says how large the full system of differential equations will be. Both are available before any reduction has run; GeoTriage reads the order from this package.
dipstick order computes both from the Lee–Pomeransky polynomialthe single polynomial G = U + F built from the two Symanzik graph polynomials of the diagram $G$, given as a string. It uses Griffiths–Dwork reduction modulo a prime below $2^{29}$, with the other kinematic variables set to random values. The run is repeated at a second prime and the two orders must agree (fields pf_order_2p, stable). The rank comes from an Euler-characteristic count done by Leviathan. An order equal to Lmax+1, where Lmax is the highest derivative tried, means the search ran out of room and is not an answer: raise Lmax, or use pf_probe_esc, which does so automatically. A $G$ nonlinear in $s$ is detected and handled by an exact recursion for the derivatives. reducible is true when the order is below the rank (the maximal cut does not generate the whole family); the operator is never factored. The method is comfortable up to four integration variables. Integrals known only as a series belong to Annihilator.
For many-variable Euler integrals $\int \prod_i p_i(x)^{s_i}\,dx$ that linear algebra is too large, and dipstick count uses another fact: at generic exponents the holonomic rank equals the number of critical points of $\sum_i s_i \log p_i$ (the maximum-likelihood degree of algebraic statistics). It writes the sparse Lagrange system
$$\lambda_i\, p_i(x) = u_i \ \ (\text{one per factor}), \qquad \sum_i \lambda_i\, \partial p_i/\partial x_j = 0 \ \ (\text{one per variable}),$$
with random integer $u_i$, as an input file for the polynomial-system solver msolve. You run msolve through run_msolve_capped.sh, which refuses to start without a memory cap because msolve's matrix allocation has no internal limit, and read off the number of solutions: that is the rank. The built-in generator covers $X(3,n)$, $n$ points in the projective plane with the non-constant $3\times3$ minors as factors. count counts; it solves nothing.
dipstick cycletype re-solves such a system modulo six primes and factors the eliminating polynomial at each with FLINT. The factor degrees at a prime form the cycle type of a Frobenius element in the Galois group permuting the critical points; the script prints them with a transitivity test, each permutation's parity, and Jordan's criterion for the full symmetric group. The output is evidence, valid when the reduction at each prime is squarefree (discard a prime showing a repeated factor). dipstick nonres checks the GKZ system of the $X(3,6)$ integral stored in GKZ36.json. It enumerates the facets of the cone over the columns of the $A$-matrix (qhull in floating point, each normal then made integral and verified exactly, unverifiable facets dropped). It then builds the parameter vector $\beta$ from the exponents in w5_seed_base.json and pairs every facet normal with $\beta$ exactly. An integer pairing is a resonance; none means $\beta$ is nonresonant and the GKZ module irreducible there. The certificate holds at that point only.
Two more subcommands serve arrangements of lines or hyperplanes, where every factor $p_i$ is linear. dipstick audit recounts the critical points of a two-variable system without msolve. It reads a .ms file whose first line names the variables, whose second line gives the field characteristic (0), and whose remaining rows, one for each line $i$ of the arrangement, are the expanded form of $m_i(a_i x_1+b_i x_2+c_i)-u_i$. It eliminates one variable with an exact resultant modulo a large prime and subtracts the spurious roots at the points where lines cross; the remainder is the count. msolve has returned wrong counts on systems of this class that stayed the same across many primes, so a two-variable count should always be cross-checked this way; --fast selects an evaluate-and-interpolate variant for about twenty lines or more. dipstick flatchi computes the characteristic polynomial $\chi_A(q)$ of a hyperplane arrangement exactly, from its lattice of intersections and the Möbius function, in any dimension $k$. Given a .ms file it treats the rows as affine hyperplanes and prints $\chi_A(q)$, the number of bounded regions $|\chi_A(1)|$ and the number of regions $(-1)^k\chi_A(-1)$ (Zaslavsky's theorem). At generic weights the bounded-region count equals the number of critical points (Varchenko's theorem), an independent check on audit. With no file it runs built-in projective examples and prints the Euler characteristic of the complement. Point counts over small finite fields interpolate badly for arrangements of this size, which is why flatchi uses the exact lattice.
dipstick regions checks the input to an expansion by regions. That method expands a Feynman integral in a small parameter, such as a small mass, the distance to a threshold or the inverse of a heavy mass, as a sum of simpler integrals, one per region. A region is one way the integration variables can scale with the parameter. If a region is left out, the series in the small parameter still converges, but to a wrong value, and nothing in the series itself says so. The regions can be read off the polynomial $G=U+F$. Give each monomial one extra coordinate, the power of the small parameter it carries, and take the Newton polytope, the convex hull of the exponent vectors, in that higher dimension: its lower facets are the regions. Each facet's normal gives a region's scaling vector $v_R$, the power of the small parameter by which each integration variable scales (components may be negative), and the monomials on the facet form that region's polynomial $G_R$. The subcommand enumerates the facets with Oscar and tests the enumeration with two sums. The normalized volumes $n!\,\mathrm{Vol}$ of the projected facets must add up to that of the Newton polytope of $G$ without its extra coordinate, an exact tiling identity, and the master-integral counts $\chi(G_R)$, computed by Leviathan, must add up to $\chi(G)$. When the input file also lists the regions you intend to use, as scaling vectors, the list is compared with the enumeration. The run then ends with VERDICT: PASS (region list complete) or VERDICT: FAIL (region list INCOMPLETE), naming each missing region by its scaling vector and printing the volume and $\chi$ deficits.
The check certifies that a list is complete; it does not build or resum the series. Regions of Glauber type need not show up as facets of $G$ alone, and for such families a failed $\chi$ sum is the only sign, so do not rely on the volume sum by itself there. A failed $\chi$ sum together with a complete list means instead that some $G_R$ is degenerate (it factors, or sits on a Landau singularity), a property of that region and not a missing one; the included large-mass example is such a case, passing the volume test while its $\chi$ values sum to 4 against 5. For large families the $\chi$ computation dominates the run time, and DIPSTICK_SKIP_CHI=1 skips it, leaving the volume certificate and printing NA for every $\chi$; treat a skipped or mismatched $\chi$ as unverified and check the expanded result against a numerical value before using it.
Examples
Run the self-tests. From the package directory, tools/dipstick/:
python3 battery.py julia --project=<your Oscar project> regress_order.jl pf_rank.jl python3 regions/selftest.py
The first command reruns each subcommand against the reference outputs in fixtures/ and prints PASS, FAIL, or SKIP with the reason when an engine is missing (Julia with Oscar, msolve, scipy, sympy); --legs count,cycletype,nonres,regions selects parts. The Julia line runs the seven order cases and ends RESULT: 7/7 PASS, printing order=2 2p=(2, 2) hr=7 for the equal-mass sunrise and order=3 2p=(3, 3) hr=15 for the three-loop banana, each in seconds once Julia has compiled. The third runs the regions check (regions/regions.jl) on three of its included inputs in one Julia process (about 50 seconds) and must end dipstick regions selftest PASS (bubble + positive + negative control); without Julia, or without the Oscar and JSON packages, it prints SKIP, says which package is missing, gives the one-time install command and exits 0. The same check is the regions part of battery.py.
Picard–Fuchs order of the sunrise. The arguments are the polynomial, the kinematic variable names, the integration variables, the variable to differentiate in, and optionally Lmax (default 6):
dipstick order 'x1*x2+x1*x3+x2*x3 + s*x1*x2*x3 - (x1+x2+x3)*(x1*x2+x1*x3+x2*x3)' s x1,x2,x3 s 3
The command prints a named tuple with holonomic_rank = 7, pf_order = 2, pf_order_2p = (2, 2), stable = true, reducible = true, Lmax = 3 and timings. In Julia the same call is include("pf_rank.jl"); pf_probe(Gstr, kin, xvars, "s"; Lmax=6). For an Oscar polynomial, here the regression suite's Legendre family in $s^2$:
R3, (w,z,s3) = Oscar.polynomial_ring(Oscar.QQ, ["w","z","s"]) G3 = w^2 - z*(z-1)*(z-s3^2) r3 = pf_probe_gen(G3, R3, ["w","z"], ["s"], "s"; Lmax=3)
r3.pf_order is 2 and r3.stable is true; pf_probe_gen does not compute the rank.
Rank, Galois evidence and resonance for $X(3,6)$.
dipstick count 6 MSOLVE_CAP_GB=30 ./run_msolve_capped.sh -f crit36.ms -o crit36.out -t 8 dipstick cycletype crit36.ms dipstick nonres
The first prints X(3,6): 14 factors, 18 vars, 18 eqs, max deg 3 and writes crit36.ms. The second runs msolve on 8 threads under a 30 GB cap; the degree opening the parametrization block of crit36.out ([1, [[26, ...) is 26, the rank. The third prints lines such as p=1073741833: cycle type [1, 1, 2, 5, 17] and p=1073741789: cycle type [5, 21], then rational-factor candidate degrees: NONE (irreducible/transitive), the parities (three of six odd) and the Jordan line with n = 26. A transitive group on 26 points containing a 17-cycle and an odd element is the full symmetric group $S_{26}$. The last prints 43 exact-verified distinct facets and RESONANT facets at the physical point: 10 of 43: the exponents in w5_seed_base.json are a special point. The guide records that at generic rational exponents none of the 43 facets is resonant, which certifies the module irreducible with 26 solutions.
Independent count and region numbers for a line arrangement. The package includes a toy system of four generic lines in the plane, fixtures/audit_toy.ms:
dipstick audit fixtures/audit_toy.ms dipstick audit --fast fixtures/audit_toy.ms dipstick flatchi fixtures/audit_toy.ms dipstick flatchi --quick
Each audit call prints one Python dictionary per file: the number of lines, a tally of intersection points by how many lines meet there (census), the resultant's degree (degR), the multiplicity removed at intersection points (arr_val), and crit, here 3; the exact and --fast routes must agree field for field. flatchi on the same file prints chi_A(q) = q**2 - 4*q + 6 and bounded (|chi(1)|): 3 regions: 11: three bounded regions, matching the three critical points, and eleven regions in all. dipstick flatchi --quick runs the built-in projective example, the 15 lines through pairs of 6 generic points in the plane, and prints chi_top = 42 (expect 42); without --quick it continues to the 35 planes through triples of 7 generic points in projective 3-space, which takes minutes.
Is this list of regions complete? Four input files come with the package under regions/tests/. The one-loop massive bubble at large momentum transfer, bubble_largeQ.json, has $Q^2=-1$ and the small parameter $t=m^2$, and lists the textbook three regions (hard and two collinear):
{
"G": "x1+x2 + t*(x1+x2)^2 + x1*x2",
"kin": ["t"],
"x": ["x1","x2"],
"kin_weight": {"t": 1},
"regions": [[0,0],[-1,0],[0,-1]]
}
kin_weight says that t scales like the first power of the small parameter; a heavy squared mass would get weight -1, as M2 does in the two large-mass files, and a fixed scale weight 0. Running the bubble together with the deliberately incomplete large-mass example,
dipstick regions regions/tests/bubble_largeQ.json regions/tests/largemass_toy_incomplete.json
loads Oscar once (about 45 seconds; extra files in the same call add seconds) and prints one report per file, each opening with == dipstick regions: <file> ==. A report gives the number of variables and monomials, n!Vol(Newt(G)) and chi_reg(G), then every region found as R1, R2, ... with its scaling vector v, its n!Vol, its chi and its polynomial G_R (a region of zero volume is marked [scaleless]), then the two sums against the whole, marked [TILES OK] and [CHI ADDITIVITY OK] when they agree. For the bubble the three listed regions are the three facets and the report ends VERDICT: PASS (region list complete). The large-mass file, a one-loop triangle with one heavy internal line, lists the single region [0,0,1]; the enumeration finds a second, and its report ends VERDICT: FAIL (region list INCOMPLETE) with a MISSING facets line naming the scaling vector $(1,1,1)$, a volume deficit of 3 and a $\chi$ deficit of 2. Its companion largemass_toy_complete.json lists both regions and passes; sunrise_threshold.json, the two-loop equal-mass sunrise near its threshold, has no regions entry and is enumerated only.
Routines
Command line
dipstick order '<Gstr>' <kin_csv> <x_csv> <svar> [Lmax]— Picard–Fuchs order insvar, checked at two primes, and the holonomic rank (runspf_rank.jl).dipstick count <npts>— writes the critical-point system of $X(3,n)$, $n$ =npts, tocrit3<n>.msin the current directory for msolve (critcount.py; importable asbuild(npts, seed=11)).dipstick cycletype [file.ms]— re-solves at six primes (8 threads, 30 GB cap each) and prints cycle types with the transitivity, parity and Jordan summary (cycletype.py; defaultcrit36.ms).dipstick nonres— facet enumeration and exact pairing check for the included $X(3,6)$ GKZ system (nonres.py, readingGKZ36.jsonandw5_seed_base.json).dipstick audit [--fast] <file.ms> [more files]— exact critical-point count of a two-variable line-arrangement system by resultant, independent of msolve; prints one dictionary per file (resaudit2.py;--fastruns the evaluate-and-interpolate variantresaudit_fast.py; each importable asaudit(fn, p=999999937)).dipstick flatchi [<file.ms> | --quick]— with a file, the characteristic polynomial, bounded-region count and region count of the affine arrangement in it (flatchi_aff.py, importableaffine_chi(planes, k)); with no file, the built-in projective examples (flatchi.py, importableflats_and_chi(normals, k), which returns the characteristic polynomial, its quotient by $q-1$ and $\chi_{\rm top}$ of the projective complement, andplanes_from_points(C, k));--quickstops after the first example.run_msolve_capped.sh <msolve args>— msolve under a mandatory address-space cap ofMSOLVE_CAP_GBgigabytes (a plain integer;31Gis rejected). Exit code 2 means it refused to start; otherwise msolve's own code, where 139 usually means the cap was hit and should be raised.
Expansion-by-regions check (the regions subcommand, regions/regions.jl)
dipstick regions <in.json> [more.json ...]— enumerates the regions of the family in each input file, tests the enumeration by the volume and $\chi$ sums, and, when a file lists regions, prints the PASS or FAIL verdict with the missing scaling vectors; several files share one Oscar load. The direct call isjulia --project=<your Oscar project> regions/regions.jl <in.json> [more.json ...];DIPSTICK_JULIAandDIPSTICK_JULIA_PROJECTapply as fororder.- Input file — JSON with
"G"(the polynomial $U+F$ as a string),"kin"(kinematic symbol names),"x"(integration variable names),"kin_weight"(symbol to integer power of the small parameter; symbols left out count as 0), and optionally"regions"(the scaling vectors to certify; leave it out to enumerate only) and"seed"(for the random evaluation points of the $\chi$ count). regions/tests/—bubble_largeQ.json,largemass_toy_complete.json,largemass_toy_incomplete.json,sunrise_threshold.json.python3 regions/selftest.py, orjulia selftest.jlfromregions/— runs the first three inputs and requires both sums and PASS for the bubble, PASS for the complete large-mass list, and FAIL with the missing facet named for the incomplete one; exit 0 on success or when Julia or its packages are missing (a skip, with the reason printed), 1 on a failure.DIPSTICK_SKIP_CHI=1— skip all $\chi$ work (volume certificate only,chi=NAin the report);DIPSTICK_LEVIATHAN— path toLeviathan.jl, as fororder. The older namesEBR_SKIP_CHIandEBR_LEVIATHAN, from when this check was the separate ebr-complete tool, are still read.
Julia functions (pf_rank.jl)
pf_probe(Gstr, kinnames, xnames, svar; Lmax=6, p, p2, seed)— string interface; returns(holonomic_rank, pf_order, pf_order_2p, stable, reducible, Lmax, t_chi, t_pf, nW_ncol).pf_probe_gen(GQ, R, xnames, kinnames, svar; Lmax=3, primes, seed)— order probe for an Oscar polynomial of any degree insvar; no rank.pf_probe_esc(GQ, R, xnames, kinnames, svar; Ls=(3,5))— repeatspf_probe_genwith increasingLmaxuntil the order is unsaturated and both primes agree; addssaturated.tools/pf_rank.jl— one-line compatibility file that includestools/dipstick/pf_rank.jlso older include paths work.
Tests
battery.py [--legs a,b] [--tool-dir DIR] [--receipts DIR] [--summary-out FILE]— the self-test suite (partsorder_member,order_shim,count,cycletype,nonres,audit,flatchi,regions), comparing each subcommand against the reference outputs infixtures/and running theregionsself-test;--receiptssays where logs and work directories go (defaultfixtures/);--tool-diraims the same comparison at a modified copy, which must then fail.regress_order.jl <pf_rank file>— sevenordercases: sunrise through both interfaces, Legendre in $s^2$, a constant period, two cases that first eliminate nested quadratic variables, three-loop banana.pf_rank_validate.jl— timedpf_proberun on sunrise, three-loop banana, ice-cream cone and four-loop banana, stopping after any case that takes more than five minutes.
Used on this site
- Sunrise —
dipstick orderon the equal-mass sunrise polynomial gives Picard–Fuchs order 2 (an elliptic curve) and holonomic rank 7, the check that fixes its function class before any reduction. - Banana — the same probe on the three-loop equal-mass banana gives order 3 (a K3 period) and rank 15.
- The Grassmannian string integral —
countgave the rank 26 of $X(3,6)$ andcycletypethe evidence that the Galois group of its critical points is $S_{26}$; those runs are the package's test fixtures.
Requirements and source
Julia with Oscar and Leviathan for order; Julia 1.10 or newer with the Oscar and JSON packages and Leviathan for regions; Python 3 with sympy and numpy (enough for count, audit and flatchi), plus scipy for nonres and python-flint for cycletype; the msolve binary, public software by Berthomieu, Eder and Safey El Din (msolve.lip6.fr), for count and cycletype. Oscar is GPL-licensed software that you install yourself and that Dipstick only imports at run time; from a clone of the repository, julia --project=upgrades/leviathan -e 'import Pkg; Pkg.instantiate()' installs the whole Julia stack once (a large download). Environment variables: DIPSTICK_JULIA (the Julia command, e.g. julia +1.10), DIPSTICK_JULIA_PROJECT (a project providing Oscar), DIPSTICK_LEVIATHAN (path to Leviathan.jl, used by order and regions; default upgrades/leviathan in the repository, unless a copy sits in a sibling leviathan/ folder under tools/, which is tried first), DIPSTICK_SKIP_CHI (regions only), DIPSTICK_MSOLVE, MSOLVE_CAP_GB, MSOLVE_BIN; the old names EBR_LEVIATHAN and EBR_SKIP_CHI are accepted as aliases. Self-tests: python3 battery.py [--legs count,cycletype,nonres,regions], julia --project=<your Oscar project> regress_order.jl pf_rank.jl and python3 regions/selftest.py, run from the package directory. Code and guide: tools/dipstick/ in BootLoops' bootloops-dev repository (GitHub organization BootLoops-ai), with the regions check in its regions/ subfolder, released under the MIT license. Methods credited: Griffiths–Dwork reduction, GKZ holonomic-rank theory, the maximum-likelihood-degree count of critical points, and the expansion by regions of Beneke and Smirnov in its Newton-polytope formulation.