Ansatzer
The content on this page was written by AI under human supervision.
Ansatzer tells you, before any expensive numerical work, how many unknown coefficients are left in the symbol ansatz of a polylogarithmic Feynman integral once the standard linear constraints are imposed. It reads the integral's letter alphabet from a small JSON file, optionally with channel tags on the letters and the connection matrix of the family's differential equation. The output is the surviving dimension weight by weight and the number of high-precision numerical values a fit will need.
What it does
A polylogarithmic Feynman integral is largely determined by its symbola sum of "words", ordered strings of letters drawn from a finite alphabet of functions of the kinematics, encoding the branch cuts. An alphabet of $n$ letters gives $n^w$ possible words at weightthe number of letters per word; it grows with the loop order $w$. A bootstrap calculation writes the answer as an unknown combination of words and fixes the coefficients against numerical values of the integral, each of which is expensive to compute at high precision. How many unknowns survive the constraints decides whether that is affordable, and Ansatzer counts them without evaluating anything.
Six families of linear conditions are imposed in order and the dimension is reported after each. Integrability keeps combinations that are the symbol of an actual function; first entry restricts the first letter to those that vanish at a physical threshold (an invariant or a mass); last entry restricts the final letter to a declared set. The Steinmann condition applies when the alphabet file tags letters with the scattering channel whose discontinuity they carry (an optional channel block): two adjacent letters whose tag sets have nothing in common are forbidden, letters sharing a tag may follow each other, and untagged letters are unconstrained. Parity keeps the requested sign under square-root sign flips. The coproduct condition needs the connection matrix: for each master integral (one of the finite basis of integrals the family reduces to), a final letter is allowed only if that letter's matrix has a non-zero entry in that master's row.
Conditions whose input is missing are skipped and labeled in the report header, and the rest still runs: without channel tags it says steinmann=vacuous (no channel tags) (or SKIPPED (disabled) under --no-steinmann), without a connection file it says coproduct=SKIPPED (no connection supplied), and a skipped column repeats the count before it. RESIDUAL is the number of unknowns, pts_needed is 1.3 times that rounded up, and a one-line verdict reads COLLAPSES (at most 12 at every weight), FULL (60 or more at some weight) or INTERMEDIATE.
By default (--method auto), when $n^w \le 500$ everything is solved exactly over the rationals and every column is a true subspace dimension. Otherwise the cheaper conditions filter the word list first and integrability is solved modulo a large prime; for alphabets in more than three variables the equations are sampled at random kinematic points, added until the rank stops changing. Only RESIDUAL is then a dimension; the other columns are word counts. The report names the back end per weight (rank_method), says whether sampling converged, and marks a weight that exceeded --timeout with bound: ≥N, an upper limit not to be used for planning.
The --per-orbit mode instead builds the integrable space recursively, one weight at a time, keeping only survivors, so it stays fast when $n^w$ is far too large to list. It applies integrability and the two entry conditions only (no Steinmann, parity or coproduct condition) and takes one alphabet at a time, typically that of a single subsector. Two limits apply to the whole tool: letters containing square roots must be given in variables that make every letter rational (for example $O_{A3}=((1+y)/(1-y))^2$ with $t=4/(1+y^2)$, as in alphabets/p4_J25.json), or the counts are wrong; and Ansatzer only sizes the fit, it evaluates nothing.
Examples
Run the self-tests. The alphabets/ folder holds small example inputs with known counts; the test script checks four of them and ends with ALL PASS.
python3 test_ansatzer.py
Each test prints an [OK ] line per checked count, and tests T2 to T4 also print the full table. For the three-letter alphabet $\{s,\,t,\,s+t\}$ with first entries $\{s,\,s+t\}$ (alphabets/p4_J23.json) the table is (columns narrowed to fit):
=== P4_J23 (3 letters; rank=exact_Q; steinmann=vacuous (no channel tags); coproduct=SKIPPED (no connection supplied)) ===
weight | raw | integrability | first | last | steinmann | parity | coproduct | RESIDUAL | pts_needed
-----------------------------------------------------------------------------------------------
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2
1 | 3 | 3 | 2 | 2 | 2 | 2 | 2 | 2 | 3
2 | 9 | 7 | 4 | 4 | 4 | 4 | 4 | 4 | 6
3 | 27 | 15 | 8 | 8 | 8 | 8 | 8 | 8 | 11
4 | 81 | 31 | 16 | 16 | 16 | 16 | 16 | 16 | 21
VERDICT: INTERMEDIATE (16/weight; ~21 pts) (max RESIDUAL = 16, pts_needed ≈ 21)
On the weight-four line, 31 independent combinations of the 81 words are integrable, the first-entry condition leaves 16, and nothing cuts further (no channel tags, no parity data, no connection); a weight-four fit would need about 21 numerical values. The tests make the same call from Python:
from ansatzer import predict_collapse, format_table
rep = predict_collapse("alphabets/p4_J23.json", weight_max=4, method="exact_Q")
print(format_table(rep))
Add a connection matrix for per-master counts. In the toy connection alphabets/p4_J23_conn.json, master m1 couples only through $s$ and $s+t$ and m2 only through $t$ and $s+t$.
python3 ansatzer.py --alphabet alphabets/p4_J23.json --connection alphabets/p4_J23_conn.json \
--wmax 4 --out report.json
The header now says coproduct=applied, the coproduct column drops from (2, 4, 8, 16) to (2, 3, 5, 9), and the verdict becomes COLLAPSES (≤9/weight; few-point fit). report.json holds the table under per_weight, the residual for each master under per_master (m1: 2, 3, 5, 9; m2: 1, 2, 4, 8) and, under honesty, the back end and whether the Steinmann and coproduct conditions ran. --compare B.json prints a second alphabet's table beside the first.
Count recursively. The per-orbit mode takes the same alphabet file.
python3 ansatzer.py --per-orbit --alphabet alphabets/p4_J23.json --wmax 4 --npts 96 --out r.json
The output JSON has Kw_LE, the count per weight with the last-entry condition (here 1, 2, 4, 8, 16, matching the table above); Kw_full_noLE, the count before it, skipped at the top weight; and converged, which records per weight whether the modular rank stabilized and at how many points, for example [true, 12]. A false means the --npts cap was hit first and the count is not yet final.
Routines
Command line
ansatzer.py— the predictor:--alphabet(required),--connection,--wmax(default 4),--method auto|exact_Q|modp,--no-steinmann,--timeoutseconds per weight (default 120),--out,--compare,--per-orbitwith--npts(default 96),-v.test_ansatzer.py— self-tests T1 to T7 (T6 covers the Steinmann condition, T7 the per-orbit input adapter); T5 checks the Landau Alphabet adapter and skips unlessCOLLAPSE_T5_ALPHABETpoints at such a file.
Python functions (import from ansatzer)
load_alphabet(path_or_dict)— parse an alphabet JSON (native schema, or Landau Alphabet output, adapted automatically) into anAlphabetobject.load_connection(path_or_dict, letter_names)— parse a connection JSON (sparse[[i,j,"q"],...]or dense rows) into aConnectionobject; only the non-zero pattern is kept.symbol_space_dims(alpha, weight_max)— the raw counts $n^w$.integrability_cut(alpha, w, method=..., timeout_s=...)— the integrable subspace at weightw; returns the word list, a basis (exact mode only), the dimension and the method used.entry_cut(basis, words, allowed_first, allowed_last)— first-entry then last-entry condition.steinmann_cut(basis, words, alpha)— remove words with adjacent letters from non-overlapping channels; does nothing when the alphabet has no channel tags.parity_cut(basis, words, alpha)— project onto the requested parity sector.coproduct_cut(basis, words, alpha, conn, master)— restrict the last letter for one master from the connection.predict_collapse(alphabet_json, connection=None, weight_max=4, masters=None, method="auto", steinmann=True, timeout_s=120, verbose=False)— run the whole cascade; returns the report dictionary.format_table(rep)— render a report as the text table above.compare(report_A, report_B)— two reports side by side.recursive_Kw(alpha_json, wmax=4, npts_max=96)— the recursive builder behind--per-orbit.per_orbit_report(alphabet_json, wmax=4, npts=96)—recursive_Kwplus elapsed time; what--per-orbitprints.main(argv=None)— command-line entry point.
Data files
alphabets/— six test fixtures (trivial_2var,p4_J23,p4_J25,p4_J23_conn,synth_7letter,5pt_2mass_nonplanar), from a hand-checkable two-letter case to a 19-letter two-mass five-point alphabet;synth_7lettercarries parity and channel tags and exercises every condition except the coproduct.p4_J25_collapse.json— a sample output report.
Used on this site
- Non-planar hexa-box — counted the residual free constants before any fitting, cross-checked against an independent counter.
- The polylogarithmic warm-ups — supplied the integrability, branch-cut and parity filters that reduced each candidate word space to a fittable basis.
Requirements and source
Pure Python 3 with numpy and sympy. Self-tests: python3 test_ansatzer.py in the package directory. Setting COLLAPSE_NPTS_MAX above its default of 12 lets the modular back end use more sample points when it reports that sampling did not converge. The alphabet file usually comes from Landau Alphabet, and the point count is what a coefficient fit with Lockpick will consume. Code: tools/ansatzer/ in BootLoops' bootloops-dev repository (GitHub organization BootLoops-ai), released under the MIT license. Older material refers to the same tool as Collapse Predictor.