Numkin
The content on this page was written by AI under human supervision.
Numkin is for Feynman-integral reductions that stall because two symbolic scales are kept at once. You give it the equation files Kira has already generated, the name of one kinematic invariant, and several rational values for it. Numkin substitutes each value into the files, runs the fast one-variable reduction at every point, and reconstructs the exact dependence on the frozen invariant, checking every entry against points not used in the fit. Three smaller parts cover related cases: a loop-momentum shift search for slow AMFlow reductions, scripts that fix the dimension to a number and rerun, and an exact linear solver for functions known to lie in a given finite-dimensional space.
What it does
An integration-by-parts reductiona large sparse linear solve that writes every Feynman integral of a family as a combination of a few "master" integrals with rational-function coefficients produces coefficients that are rational functions of the dimension $d$ and the kinematic invariants. Kira delegates those functions to FireFlya library that rebuilds an exact rational function from many numerical evaluations over finite fields. With only $d$ symbolic this usually finishes in minutes. With $d$ and one invariant both symbolic, a few high-degree entries can keep the same system running for days, and more memory does not help because the time goes into the two-variable reconstruction.
Numkin's main route has three steps. numkin_sweep.sh stage copies a finished Kira generation directory and writes a rational value for the chosen invariant, say $m^2=101$, into every compressed SYSTEM_*.gz file by word-boundary text substitution, so equation generation is never repeated. It also strips the invariant from the copied kinematics.yaml and substitutes the value in integralfamilies.yaml, because a leftover symbol anywhere in the configuration puts FireFly back in two-variable mode. numkin_sweep.sh run runs Kira with run_initiate: false and FireFly on that directory. Repeated at several points, this yields coefficients that are exact rational functions of $d$ alone. numkin_harvest.py then reconstructs each coefficient in both variables,
$$c(d,x)=\frac{\sum_b N_b(d)\,x^b}{\sum_b D_b(d)\,x^b},$$
by exact rational (Padé/Thiele) interpolation, first in the frozen variable $x$ and then in $d$, using integer-matrix nullspaces from python-flint so no floating-point number enters. The highest-numbered points (two by default) are kept out of the fit and every entry must reproduce them exactly. An entry that fails, or whose degrees the points do not determine (the code raises DGridInsufficient instead of guessing), is listed under failed_entries and left out; the remedy is more points. Output is a JSON file with the polynomials $N_b$, $D_b$ per entry and a summary of fit points, verification points and failures, plus optionally a .m file in Kira's kira2math format.
The other parts treat neighboring problems. shift_opt.py is for AMFlow's auxiliary-mass ($\eta$) reductions. An affine loop-momentum shift with unit Jacobian leaves an integral without numerators unchanged but can shrink a sector's reduction by a large factor. The script builds shifted family definitions, runs short capped AMFlow probes per shift and sector, and reports which gives the smallest system. The etarerun/ scripts apply the freeze idea to $d$: they take a stalled AMFlow target_reduce/ directory whose equations contain only $d$ and $\eta$, substitute $d=4-2\epsilon$ at a rational $\epsilon$, and relaunch with one-variable FireFly. basisland.py handles a function known to be a combination of given basis functions. It finds the rank and a pivot subset from sample rows, solves the overdetermined exact linear system by modular elimination over many primes, and verifies every row exactly. The number of samples needed scales with the dimension of the space and is independent of the number of variables.
Limits. The sweep needs Kira, FireFly and Fermat and a completed generation pass; it is pointless for a single kinematic point. Do not freeze $d$ with numkin_sweep.sh (use etarerun/), and avoid values where the system degenerates, since a degenerate point returns a valid-looking wrong reduction. shift_opt.py covers only integrals without irreducible numerators. basisland.py needs a known spanning set and exact rational rows; without a basis use the Padé route or Ratfit.
Examples
Run the self-test suite. From the root of BootLoops' bootloops-dev repository (GitHub organization BootLoops-ai); no Kira needed:
python3 tools/numkin/selftest.py
The script exercises basisland.py on a synthetic system with a known answer. rank on five sample rows over three symbols must report rank 3 with pivots b1, b2, b3, agreeing across primes. solve on the 5-by-3 system must return exactly 2, -3/7, 5 with all 5 rows verified. solve on a system with no support for b3 must exit with code 2, printing RANK DEFICIT and the column name. Three [PASS] lines and OVERALL: PASS in a few seconds mean the install is good. The sweep, harvest and shift parts are skipped because they need Kira, FireFly and Fermat.
Freeze a mass and sweep. The usage text of numkin_sweep.sh stages point 0 of a sweep in $m^2$ for a family box3L, reducing two sectors, then runs it on 8 threads:
cat > reduce.yaml <<'EOF'
- {topologies: [box3L], sectors: [1023], r: 13, s: 1, d: 3}
- {topologies: [box3L], sectors: [170], r: 10, s: 1}
EOF
numkin_sweep.sh stage box3L /scratch/gen_pass_dir \
m2 101 /scratch/sec1023_numkin 0 \
preferred_masters de_targets_top30 reduce.yaml
numkin_sweep.sh run /scratch/sec1023_numkin 0 8
stage leaves a ready-to-run Kira job in /scratch/sec1023_numkin/pt_0: jobs.yaml, the substituted equation files, a config/ with m2 removed, a link to the source sectormappings/, and m2val recording the value. run writes run.log and prints the elapsed seconds and the resulting results/box3L/*.m. Repeat with point identifiers 1, 2, ... at other values (p/q is accepted; keep the identifiers numeric, since numkin_harvest.py reads pt_<number> directories), then reconstruct:
python3 tools/numkin/numkin_harvest.py --family FAM --targets-file F --pts-dir DIR --var m2 --held-out 2 --out OUT.json [--out-m OUT.m] [--min-fit-pts N]
with FAM = box3L, F the target list de_targets_top30, DIR the sweep directory; bracketed arguments are optional. The log names the fit and verification points and ends with counts of entries reconstructed, failed and skipped, with the first failure reasons. Called before any point has finished it writes a JSON with no entries and exits, so it is safe to run during the sweep.
Search loop-momentum shifts for a slow AMFlow sector. From the usage text of shift_opt.py: build one named shift for sector 510 of a template AMFlow input, or probe the standard catalog on sector 1022:
shift_opt.py build TEMPLATE.json --shift 'k2sh:k2=l+p1-k2' \
--sec 510:0,2,1,1,1,1,1,1,1,0 --out DIR
shift_opt.py probe TEMPLATE.json --sec 1022:0,1,2,1,1,1,1,1,1,1 \
--catalog --out DIR --amf /path/to/amflow_cli
build writes one AMFlow input in_<tag>_sec<sector>.json per shift and sector, with the physical propagators shifted and the auxiliary numerators re-chosen to complete the set. probe also launches each input, polls every 20 seconds, and stops anything still running at --cap seconds (480 by default). It writes SHIFT_PROBE.json giving per shift and sector the number of $\eta$ masters, the equation count and the first Fermat item count. Beside each probe log it also writes <log>.memfence.json, recording the memory-limit settings the launched AMFlow process actually received; if they differ from what was requested, the probe stops that process and exits with an error. The smallest numbers mark the shift to use for that sector; different sectors may prefer different shifts.
Routines
Freeze one invariant and reconstruct
numkin_sweep.sh stage FAM SYS_DIR VAR VALUE OUT_DIR PT_ID PREFERRED_MASTERS TARGETS_FILE REDUCE_YAML— stage one point: substituteVAR=(VALUE)into the generatedSYSTEM_*.gz, stripVARfrom the copied config, writejobs.yaml;NUMKIN_STAGE_PARsets the substitution parallelism (default 12).numkin_sweep.sh run OUT_DIR PT_ID NTHREADS [KIRA_BIN] [FERMATPATH]— run Kira with FireFly on a staged point and time it.numkin_harvest.py --family --targets-file --pts-dir [--var] [--held-out] --out [--out-m] [--min-fit-pts]— reconstruct every coefficient exactly in (d, var), verify on the points kept out of the fit, write JSON and optionally akira2math.mfile.DGridInsufficient(innumkin_harvest.py) — the exception raised when the points do not determine an entry (nullity zero, a denominator vanishing at a $d$ node, or degrees disagreeing across the $d$ grid).
Loop-momentum shifts for AMFlow
shift_opt.py build TEMPLATE.json --sec ... [--shift tag:loop=expr] [--catalog] [--n-phys] [--out]— write shifted-family AMFlow inputs per shift and sector.shift_opt.py probe ... [--amf] [--wrap] [--cap]— build, launch capped probes, writeSHIFT_PROBE.jsonand one<log>.memfence.jsonper probe.shift_opt.py harvest ...— re-read existing probe directories intoSHIFT_PROBE.jsonwithout launching.
Numeric-dimension rerun (etarerun/; the launch scripts need Linux)
etanumd_convert.sh SRC DST EPS_PQ [PARALLEL] [MEM_GB] [--nolaunch]— copy an AMFlowtarget_reduce/directory, substitute $d=4-2\epsilon$ at $\epsilon=$P/Q, rewritejobs.yamlfor FireFly, launch Kira detached.etanumd_2varff.sh SRC DST [PARALLEL] [MEM_GB] [--nolaunch]— the same relaunch with no substitution, both $d$ and $\eta$ symbolic.check_degd.py— estimate the degree in $d$ from two or more finished slices (ETANUMD_DIR,ETANUMD_FAM) and print how many slices a reconstruction needs.inject_ibpcache.sh KIRA_TARGET_M AMFLOW_LOG IN_JSON OUT_JSON— place a reconstructedkira_target.min AMFlow's reduction cache (AMFLOW_IBP_CACHE_DIR) under the key the stalled run missed, so a relaunch finds it.FARM_LAUNCHERS.sh— detached-launch templates for these routes; inputs come fromETANUMD_*variables with no defaults.inject/extract_shared_rows.py,inject/rebase_invert.py— reuse rows already reduced in one slice inside another, after exactly inverting the change of master basis;inject/build_M1_injected.sh,merge_M1_injected.sh,FARM_M1_INJECTED.share the matching build, splice and launch templates.
Exact solve in a known basis (basisland.py, importable as numkin.basisland)
basisland.py rank IN.json OUT.json [nprimes=3]/rank_verb— rank and pivot symbols of sample rows, required to agree across primes.basisland.py solve IN.json OUT.json [nprimes=96]/solve_verb— exact solution vectors (several right-hand sides allowed), every row verified; exits 2 on rank deficit naming the columns, 3 when more primes are needed, 4 on any verification miss.
Tests
selftest.py— the self-test suite of the first example.
Used on this site
- Three-loop light-by-light — exact reconstruction of differential-equation entries for the crossed box that a fully symbolic FireFly run could not finish.
- The crossed light-by-light box — the same entries, each verified at two kinematic points not used in its fit.
Requirements and source
Bash and Python 3. numkin_harvest.py needs python-flint and the kira_parse module from tools/frobenius-boundary/ in the same repository (found automatically when the packages sit side by side). basisland.py needs NumPy and SymPy. shift_opt.py needs SymPy and an AMFlow command-line build with its launch wrapper (--amf/--wrap or AMFLOW_CLI/AMFLOW_WRAP). It also imports the memfence module from tools/amflow-kit/ in the same repository (amflow_kit.memfence, see AMFlow), which uses only the standard library and needs Linux, since it reads /proc and cgroup v2. The sweep and etarerun/ scripts need Kira, FireFly and Fermat; the etarerun/ launch scripts preload jemalloc (library path from JEMALLOC) and take the Fermat binary from FERMATPATH, falling back to the usual Debian/Ubuntu install paths. Run the tests with python3 tools/numkin/selftest.py. The code is in tools/numkin/ in the bootloops-dev repository, released under the MIT license; tools/numkin_sweep.sh, tools/numkin_harvest.py and tools/shift_opt.py forward to it. Upstream: Kira, FireFly.