Canonify

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

Canonify (the canonical_form Python module) prepares the basis of master integrals in which BootLoops fits Feynman integrals and writes their differential equations. Given the definition of an integral family and a list of master integrals, it computes each master's leading singularity on the maximal cut. It returns the rescaling that divides that singularity out, in the format the Gatekeeper fitting routines read. It also lets Python code call the Julia ε-factorization engine of Counterweight, the package that contains it, and splits the resulting matrix into constant matrices times logarithmic derivatives.

What it does

Reduction programs such as Kira return a set of master integrals, and the matrix $A(x,\epsilon)$ of their differential equation, in whatever basis the reduction happened to choose. Recognizing exact constants in high-precision numerical values, and solving the differential equation order by order in the dimensional regulator $\epsilon$, both work far better in a uniform-transcendentality basisa choice of masters in which every order in ε is a pure function of fixed transcendental weight with rational coefficients. The usual first move toward that basis is to divide each master $I_i$ by its leading singularitythe residue of the integrand when every propagator of the master is put on shell (the maximal cut); an algebraic function of the kinematics, or a period of a curve for elliptic sectors $\mathrm{LS}_i$:

$$J_i = \frac{1}{\mathrm{LS}_i(x)}\, I_i .$$

Canonify computes $\mathrm{LS}_i$ from a family block, the same JSON object the amflow-cpp evaluator reads (loop momenta, external legs, momentum conservation, kinematic replacement rules, propagators), and a list of masters written as {"tag": ..., "indices": [...]}. Family builds the Baikov representation, in which the propagators are the integration variables and the integrand is a power of a Gram-determinant polynomial. leading_singularities sets each master's propagators to zero and takes iterated residues in the variables that remain, labeling the result rational, sqrt, elliptic or unknown. For an elliptic sector the quartic $y^2=P(z)$ is read off the cut and the rotation entry is $1/\varpi_0$, the inverse of its holomorphic period, which elliptic_period evaluates with a complete elliptic integral. ut_rotation returns {ut_tag: {raw_tag: coefficient}}: exact strings such as '21/4' or mpmath numbers at a kinematic point, expression strings in the invariants without one.

The rotation is diagonal; subtracting subsector integrals to complete the basis off the diagonal is outside this module. The automatic Baikov construction is exact for the top sector of a family. For subsectors the top-family Gram determinant can pick up spurious factors, and when the Baikov exponent vanishes at $\epsilon=0$ (the equal-mass sunrise, for example) the representation is degenerate. In both cases pass the cut polynomial yourself through a per-master maxcut entry. verify_unit_pole checks the result on numbers: after the rotation, the $\epsilon^{-L}$ coefficient of each master ($L$ the loop number) must be the same constant at every kinematic point.

The other half of the module reaches the full ε-form $\partial_x J=\epsilon\,\tilde A(x)\,J$. factor_epsilon(A, x) sends a sympy matrix, rational in x and eps, through counterweight_bridge.jl to Counterweight's Julia engine and returns $\tilde A$, $T$ and a report, with $TAT^{-1}+(\partial_xT)T^{-1}=\epsilon\tilde A$. The engine works in exact arithmetic over $\mathbb{Q}(\epsilon)(x)$, so the matrices carry no numerical error. When the engine directory is not found, or when the engine stops short of an ε-form, the call raises NotImplementedError carrying the stop reason and the names of other programs for this step (CANONICA, Libra, Fuchsia, epsilon). If the bridge process itself fails, the call raises RuntimeError with Julia's error output. Inside factor_epsilon the engine first lowers any poles of order higher than one with a Barkatou–Moser reduction; a genuinely irregular singular point, which that reduction cannot make regular, stops the call. Such a stop usually means, for a Feynman system, that some master still lacks its leading-singularity prefactor. to_dlog needs no engine: it partial-fractions $\tilde A$ in $x$ and returns one constant matrix per letter of a supplied alphabet, plus a _residual matrix that is zero when the decomposition is complete.

Examples

Leading singularities and rotation from the command line. The package includes the one-loop massless box family as box1l.json; run this from tools/counterweight/canonical_form/:

python canonical_form.py box1l.json --point '{"s":-3,"t":-7}' \
    --out out/box1l/ut_rotation.json

The script prints (and, with --out, also writes) one JSON record with the family name, the point, a leading_singularities object and the ut_rotation dictionary evaluated at the point. Each master's entry carries tag, sector, kind, expr, radicand, quartic, residual_vars and a note naming the function class. The bundled file lists the two bubble masters of the box family; the test suite uses the same family with the box master [1,1,1,1] added, whose leading singularity comes out proportional to $1/(st)$. The two bubbles are subsectors, so their automatic entries come back with kind sqrt and the spurious factors described above; they are the case the maxcut override is for.

The rotation from Python, passed to a fit. From the module README:

from canonical_form import Family, ut_rotation
from gatekeeper import heldout_certify, load_oracle_values

fam = Family(target["family"])
rot = ut_rotation(fam, target["masters"], point={"s": -3, "t": -7})
# rot = {'ut_box': {'box': '21/4'}, ...}   ← exact heldout_certify format

values, kin, _ = load_oracle_values([oracle_dir])
res = heldout_certify(values, kin, weight=2, basis_fn=..., basis_names=...,
                      ut_rotation=rot)

Here target is a parsed target file like box1l.json. For the box master at $s=-3$, $t=-7$ the coefficient is the exact string '21/4', that is $st/4$. The Gatekeeper fit called on the last line multiplies the raw numerical values by these coefficients before it fits. When the automatic cut is degenerate, give the curve directly in the master entry, as the README does for the equal-mass sunrise:

masters = [{"tag": "sun", "indices": [1,1,1],
            "maxcut": {"poly": "z*(z-4)*((tt-z)**2 - 4*z)", "vars": ["z"]}}]

leading_singularities then reports kind == "elliptic" with that quartic, and ut_rotation at a numerical value of tt returns $1/\varpi_0$.

Full ε-factorization through the engine. Also from the README:

from canonical_form import factor_epsilon, to_dlog
Atilde, T, report = factor_epsilon(A, x)       # → Julia Counterweight (Lee 1411.0911)
letters = to_dlog(Atilde, x, alphabet=[x, 1+x])

A is a sympy Matrix in the symbols x and eps; the bridge fixes those two names, so import eps from the module and name your variable x. Atilde and T come back as sympy matrices and report as a dictionary describing what the engine did. letters maps 'x' and 'x + 1' to constant matrices; confirm that letters['_residual'] is the zero matrix before using them.

Routines

Command line

Family and leading singularities

Rotation and its check

ε-form (Counterweight engine) and dlog form

Requirements and source

Python 3 with sympy and mpmath. verify_unit_pole imports its rotation helper from the Gatekeeper package, which sits beside Counterweight in the repository. The ε-form functions need Julia 1.11 or newer with the Counterweight engine set up once (julia --project=. -e "using Pkg; Pkg.instantiate()" in tools/counterweight/); everything else runs without Julia. Self-tests, from tools/counterweight/: python3 canonical_form/test_canonical_form.py runs five tests (box leading singularity and rotation format, exact to_dlog, the elliptic sunrise period, the numerical-values check, and the Julia bridge) and ends with OK: 5/5 passed. The last two tests skip cleanly when their optional data or Julia are absent, and CANONICAL_FORM_SKIP_JULIA=1 skips the bridge test explicitly. Source: the canonical_form/ subdirectory of tools/counterweight/ in BootLoops' bootloops-dev repository (GitHub organization BootLoops-ai), released under the MIT license; the engine it calls, and the engine's own tests, are described on the Counterweight page.

← back to the tools index