ETH Zürich ← FAIR

FAIR tutorial

A hands-on walk-through, from a fresh checkout to reading reduced integrals in your CAS. Every command below is copy-pasteable and matches the shipped examples. For the reference description of options and file formats, see README.md; for the algorithm, see doc/fair.tex.

FAIR (Fast Automatic Integral Reduction) is a self-contained C++/FLINT realization of the A.I.R. IBP-reduction algorithm (hep-ph/0404258). It needs no external computer-algebra system — only FLINT/GMP/MPFR at build time.


0. Prerequisites

You need a C++17 compiler and FLINT 3.1 or later (tested with 3.1.3 and 3.5.0; the 3.0.x series does not work) with GMP and MPFR. The easiest way to get them on any platform is conda-forge:

micromamba create -n fair flint gmp mpfr cxx-compiler   # or: conda / mamba
micromamba activate fair

(System packages also work: Debian/Ubuntu libflint-dev libgmp-dev libmpfr-dev, Homebrew brew install flint. FAIR uses the fmpz_mpoly_q API, so make sure your FLINT is 3.1 or newer; the 3.0.x series is too old.)

1. Build and self-check

./build.sh            # auto-detects FLINT; bundles libs into ./lib (portable)
./test/run_tests.sh   # runs 4 known reductions, diffs against golden output

If you see ALL TESTS PASSED, your build is correct. build.sh works on Linux ($ORIGIN rpath, bundled .so) and macOS (@loader_path, bundled .dylib, ad-hoc codesign); the binaries plus ./lib are portable as a unit.

If FLINT lives somewhere unusual: FLINT_PREFIX=/path/to/prefix ./build.sh.

2. Your first reduction (one-loop box)

You describe the physics in a runcard; fair-run derives the scalar products, writes the low-level topology, seeds, and runs the reduction. Here is the shipped two-mass-easy box, examples/box2me.run:

name      Box2me
loops     k1
legs      p1 p2 p3 p4           # all incoming, sum = 0 (p4 dependent)
onshell   p2 p4                 # the two massless legs
invariant s  = (p1+p2)^2
invariant t  = (p2+p3)^2
invariant m1 = p1^2             # off-shell virtuality of leg 1
invariant m2 = p3^2             # off-shell virtuality of leg 3
prop      k1
prop      k1+p1
prop      k1+p1+p2
prop      k1+p1+p2+p3
maxtensor [2, +1]               # targets tensor 0..2 ; seed +1 above for closure
maxdots   [0,  0]               # targets dots 0..0 ; no extra dotted seeds

Run it:

./fair-run examples/box2me.run -o out/ --format mathematica

fair-run prints the scalar products it derived (you never hand-compute a dot product) and the seeding scope, then writes into out/:

out/masters.m         MASTERS = { ... }
out/reductions.m      red = { target -> Σ cᵢ masterᵢ, ... }
out/manifest.txt       human summary: masters, target counts by rank, closure
out/Box2me.topo        the generated low-level topology (for reference)
out/Box2me.fair        the generated problem file (templates + seeds)

The manifest.txt tells you at a glance what happened:

masters (5): Box2me(0,0,1,1) ... Box2me(1,1,1,1)
targets melted: 32   (not closed/unreduced: 0)
by numerator rank:  rank 0: 4   rank 1: 12   rank 2: 16

not closed: 0 is what you want — every target was fully reduced to masters.

3. Reading the result

The integral Box2me(a,b,c,d) is the scalar integral with propagator powers a,b,c,d (negative = numerator, i.e. an inverse propagator / dot product). A line of reductions.m looks like:

Box2me[1,0,1,-2] -> ((d*m2^2-2*d*m2*s+d*s^2)/(4*d-4))*Box2me[1,0,1,0],

Use it in Mathematica:

Get["out/masters.m"]       (* -> MASTERS *)
Get["out/reductions.m"]    (* -> red = { target -> rhs, ... } *)
myexpr2 = myexpr /. red;    (* rewrite onto masters *)

Want a different format? Add format form (or sympy) to the runcard, or pass --format on the command line:

./fair-run examples/box2me.run -o out_mma/ --format mathematica   # out_mma/reductions.m
./fair-run examples/box2me.run -o out_frm/ --format form          # out_frm/reductions.h
formatfilesload with
maple (default).mplread "...":
mathematica.mGet["..."] → red, MASTERS
form.h#include reductions.h (sparse Table/Fill)
sympy.pyfrom reductions import reductions (dict)

4. A two-loop example, and controlling the seeding

The planar double box, examples/pbox.run, is a genuine two-loop topology. You list only the 7 genuine propagators; FAIR auto-completes the 2 irreducible numerators it needs:

./fair-run examples/pbox.run -o pbox_out/

The two knobs that matter most:

maxtensor [max, offset]   # reduce numerator rank 0..max ; also SEED offset above max
maxdots   [max, offset]   # reduce up to max dots        ; also SEED offset above max

So maxtensor [3, +1] means: *give me rank 0–3, seed up to rank 4.* You can also override on the CLI: --seed-tensor, --seed-dots, --format, --factor, --gzip.

The shipped runcards mbox, pentagon, xbox, pentabox, and the one-off-shell xbox1m follow the same pattern. (The 3-loop *.topo files — ladder3, tetra3 — are low-level topology demos; see §7.)

5. Going further

These are documented fully in the README; here is when you reach for each.

``sh ./fair --problem p.fair --out base --tenmax 3 --save state.fairstate ./fair --problem p.fair --out ext --tenmax 4 --resume state.fairstate # only new seeds ``

The simplest cut family: NLO real emission

examples/dy_real.run is a one-loop reverse-unitarity family: p1 + p2 → V(M) + parton, with the radiated parton and the massive boson line as cut lines and the t-channel propagator as the only uncut line. FAIR finds one master (the two-body phase space DYreal(1,1,0)) and reduces the 27 targets to it in a fraction of a second, e.g. DYreal(1,1,1) = 2(d-3)/((d-4)(M-s)) * DYreal(1,1,0). A cut line is written prop mom | mass2 | cut (or prop mom | cut when massless).

A worked reverse-unitarity example

examples/higgs_rr.run is an NNLO double-real phase-space topology — gg → H + 2 partons — with the Higgs and the two radiated partons entering as cut lines. Because the incoming momenta p1, p2 are independent (their sum carries s into the final state), it uses external rather than legs:

name      HiggsRR
loops     k1 k2
external  p1 p2                   # independent incoming momenta (no conservation)
onshell   p1 p2
invariant s = (p1+p2)^2
prop      k1            | 0  | cut    # radiated parton 1
prop      k2            | 0  | cut    # radiated parton 2
prop      k1+k2+p1+p2   | Mh | cut    # the Higgs (mass^2 = Mh)
prop      k1+p1
prop      k1+k2+p1
prop      k1+p2
prop      k1+k2+p2
maxtensor [2, 1]
maxdots   [0, 0]

Run it the same way as the box:

./fair-run examples/higgs_rr.run -o out/

The three cut lines are pinned — any integral missing one is set to zero — and FAIR reduces the phase-space integrals by IBP exactly as for a virtual topology:

masters: 4 ...  MELTED 100 targets ...  (0 not closed)

4 masters, all 100 rank-0..2 targets closed in well under a second. Read the result just as in §3. The three-loop N³LO triple-real analogue (the Higgs plus three cut partons) is examples/higgs_n3lo.run.

6. Huge reductions

When the output is too large for a CAS to parse, combine these (see README → *Huge reductions* for measured numbers):

./fair-run examples/pbox.run -o pbox_out/ --factor --gzip

Those control the output size. A different bottleneck is the melt-time memory peak (many long coefficients normalized at once); split the melt into two stages with --partial-melt (on fair):

7. The low-level tools (optional)

fair-run is just a friendly front end over two binaries you can call directly:

./fairgen --spec examples/pbox3.topo --out pbox.fair          # .topo -> problem file
./fair    --problem pbox.fair --out pbox_out --tenmax 3 --dotmax 0

A .topo file states the topology directly (loop momenta, external legs, propagators with | mass² | cut, scalar-product values, seed ranks). This is the right level for exotic kinematics or three-loop topologies (ladder3.topo, tetra3.topo), where you may prefer to write the scalar products yourself. The full .topo grammar is in the README.

8. Troubleshooting

symptomfix
ERROR: FLINT not foundinstall FLINT/GMP/MPFR; FLINT_PREFIX=/path ./build.sh
build OK but ./fair can't find a libraryre-run ./build.sh (it bundles libs into ./lib); keep lib/ next to the binary
not closed > 0 in the manifestraise the seed offset (e.g. maxtensor [N, +1])
results look wrongrun ./test/run_tests.sh — if that fails, the build is broken
huge output won't loadsee §6 (--gzip, --split, --format form)

9. Citing FAIR

If FAIR is useful in your work, please cite the A.I.R. paper it implements (Anastasiou & Lazopoulos, JHEP 07 (2004) 046, hep-ph/0404258) and this software — see CITATION.cff.