On this page

For developers

Vakint implementation architecture

Implemented · reviewed 2026-10-04System architecturecurrent

Topology construction, canonicalization and tensor-reduction flow, backend selection, external-process ownership, persistence boundaries, invariants, and tests.

View the source note

Lifecycle
current
Owner
Ownership decision required
Review
2026-10-04 · jj:twxxuvmo
Freshness
reviewed
Evidence
Not an evidence record
Verified scopes
  • vakint::Vakint
    crates/vakint/src/lib.rs · digest 7766f7350df0
    entire file
  • vakint::topologies::Topologies::match_topologies_to_user_input
    crates/vakint/src/topologies.rs · digest f4efb1593e4f
    entire file
  • vakint::graph::Graph::new_from_atom
    crates/vakint/src/graph.rs · digest 39e48cf8f2a5
    entire file
  • vakint::symbolica_community_module::VakintWrapper
    crates/vakint/src/symbolica_community_module/mod.rs · digest d2483b4ed0df
    entire file

Status: Current implementation architecture, audited against the Vakint source on 2026-10-04.

This note describes the Rust engine and its optional Symbolica community-module wrapper. Backend availability and numerical coverage depend on the selected topology, epsilon depth, and installed external tools.

Boundaries

Vakint is an in-process Symbolica transformation engine for single-scale vacuum integrals. The Rust crate owns five boundaries:

  • Vakint and Topologies: construction of the known topology library and entry points for canonicalization, tensor reduction, parametric evaluation, and numerical evaluation;
  • VakintExpression and VakintTerm: the structured numerator/topology representation used between stages;
  • VakintSettings, EvaluationOrder, and EvaluationMethod: precision, normalization, dependency, and backend-selection policy;
  • FORM and pySecDec adapters: template rendering, subprocess execution, and result decoding;
  • the optional symbolica.community.vakint module: Python classes that own a Rust engine and settings while exchanging Symbolica expressions.

The modules alphaloop_numerics, matad, matad_numerics, fmft, and fmft_numerics contain backend-specific reductions and master-integral substitutions. symbols owns the namespaced Symbolica symbols. graph is a small vacuum-topology graph used for validation, contraction, and loop-momentum-basis work; it is not Linnet’s generic half-edge graph.

Core representation

Vakint::new initializes the symbol registry and generates an in-memory Topologies collection. The collection contains canonical one- through four-loop families and selected contractions, followed by an Unknown matcher whose allowed evaluation method is pySecDec. Each Integral stores its canonical and optional short expressions, match patterns and conditions, graph, loop/propagator counts, and applicable backend set.

Input is represented as a Symbolica Atom. VakintExpression::split_integrals separates a sum into VakintTerm values, each containing:

  • one topo(...) expression;
  • its coefficient as the numerator;
  • the loop and external vectors discovered in that numerator.

ReplacementRules is the result of matching one input topology. It carries the selected canonical topology, the canonical-to-input edge map, substitutions for masses, powers, momenta, and nodes, and the substitutions required to rewrite the numerator consistently. It is an ephemeral transformation plan, not a persisted cache.

VakintSettings controls epsilon and scale symbols, executable paths, input rationalization and runtime precision, numerator verification, normalization, unknown-integral policy, temporary files, epsilon depth, dot-product notation, and EvaluationOrder. A Vakint engine is reusable; settings are passed explicitly to Rust operations. The Python Vakint wrapper stores the engine and settings together for convenience.

Main control flow

The complete Rust entry point is Vakint::evaluate:

AtomView
  -> validate selected settings and external dependencies
  -> split into VakintExpression terms
  -> match and canonicalize topology plus numerator
  -> tensor-reduce each numerator through FORM
  -> choose the first supported EvaluationMethod for each term
  -> run the backend and decode its Symbolica expression
  -> combine the transformed terms into an Atom

to_canonical, tensor_reduce, and evaluate_integral expose narrower stages. Canonicalization tries registered topologies in order, derives replacement rules, normalizes momentum routing, and can emit the short topology form. Tensor reduction converts compact dot notation if needed, maps vectors and indices into FORM syntax, runs the embedded reduction program, and maps the result back to Symbolica.

Integral evaluation matches again so that it has the canonical topology and numerator mapping. It then walks settings.evaluation_order and selects the first method whose topology, loop count, and requested epsilon depth are supported. AlphaLoop is limited to its registered topologies, at most three loops, and at most four requested terms; MATAD covers its registered topologies up to three loops and normally five terms; FMFT covers registered four-loop topologies up to five terms; pySecDec covers topologies registered for that numerical path. Failure to find a method is an explicit NoEvaluationMethodFound error, not an implicit fallback.

MATAD also accepts exactly six terms for a certified product of at most three independent tadpoles with the same nonzero mass. Each line must be a self-loop carrying a distinct loop momentum with coefficient +1 or -1. These products need only the existing Gamma series through epsilon degree five. Connected master tables retain their original depth limit; mixed masses, scaled loop momenta and seven-term requests do not qualify. The FORM remainder check still rejects unavailable coefficients.

The registered one-scale two-loop sunsets include the MM0 and M00 mass patterns. Canonical masses accept either zero or msq(index), and scale extraction chooses a nonzero mass. These partially massless topologies use MATAD: AlphaLoop’s uvprop representation has no mass slot and cannot preserve which lines are massless, so that representation is withheld for any topology with a zero mass.

Numerical evaluation is a later boundary. Parametric backend output remains a Symbolica expression. Numerical parameters and optional external momenta are converted to the configured binary precision, and NumericalEvaluationResult represents the result and optional error as Laurent coefficients (epsilon power, complex value). Laurent extraction reads the actual epsilon atom and its integer powers, preserving its namespace and display registrations. A malformed monomial or a coefficient that still depends on epsilon returns an evaluation error.

External tools and feature boundaries

AlphaLoop, MATAD, and FMFT invoke FORM. The pySecDec method invokes both FORM and pySecDec through the configured Python executable. validate_settings checks only dependencies required by the selected evaluation order, validates the loop-normalization expression, and enforces FORM >= 4.2.1 and pySecDec >= 1.6.4 when those tools are selected.

Backend expression serialization follows the exact atom tree and symbol identities, independently of display callbacks. A complex numeric atom is written from its explicit real and imaginary coefficients, including a unit imaginary numerator; the FORM adapter then maps the imaginary unit to i_. This preserves valid syntax for coefficients such as i/16 without changing their value.

FORM programs, headers, and run templates are embedded in the Rust binary with include_str!. For each run, Vakint renders those resources into a uniquely named temporary directory, launches the configured process, reads out.txt, and removes the directory when clean_tmp_dir is true. pySecDec can reuse a caller-selected output directory; the implementation labels this unsafe for normal operation because stale generated sources or results can be mistaken for the current calculation.

The Cargo build script has one platform-specific boundary: on macOS, setting EXTRA_MACOS_LIBS_FOR_GNU_GCC opts into linking gcc_s.1.1 from MacPorts’ libgcc directory when that library exists. This affects native linking only; it does not select an evaluation backend.

The core Rust API has no feature requirement. python enables the PyO3 wrapper and registers Vakint, VakintExpression, VakintEvaluationMethod, and VakintNumericalResult on symbolica.community.vakint. python-stubs adds stub metadata and implies python, including Symbolica’s Python export. The wrapper delegates transformations to the Rust engine and converts VakintError into Python ValueError; it does not implement a second evaluation pipeline.

Persistence and reproducibility

Vakint does not serialize its topology library or settings. Known topologies are regenerated by Vakint::new, which is why one engine should be reused for multiple operations. Durable values cross the API as Symbolica expressions or Laurent-coefficient lists. Temporary FORM/pySecDec workspaces are implementation artifacts unless cleanup is disabled or a reuse directory is explicitly supplied.

A reproducible result therefore depends on more than the input expression: record the topology form, numerator, normalization convention, epsilon depth, decimal precision, backend order and options, numerical masses and external momenta, executable versions, and whether a pySecDec workspace was reused.

Maintained invariants

  • Each input term contains exactly one first-power topo(...) factor; scalar-only terms and powers of a topology are rejected by the structured-expression boundary.
  • Propagator ids are contiguous from one, and loop-momentum ids are contiguous from one through the detected loop count. Vacuum-graph nodes must have degree greater than one.
  • Canonical topology substitutions and numerator substitutions are applied as one mapping; sequential replacement is avoided because one replacement target can be another source.
  • When verify_numerator_identification is enabled, no unrecognized loop-momentum dependence may remain after canonical mapping.
  • EvaluationOrder is policy: the first supported method wins. Unsupported methods are skipped, but execution errors from the selected method are returned.
  • Loop normalization may reference only the documented symbols and is expanded to the requested epsilon order before backend results are normalized.
  • Runtime numerical precision is converted to a binary precision of at least the equivalent of 17 decimal digits; Python convenience inputs are converted at that boundary.

The integration-test modules separate topology/input matching, tensor reduction, analytic evaluation, free-form evaluation, backend comparisons, and direct pySecDec evaluation. Analytic cross-checks compare AlphaLoop with MATAD, while numerical suites compare supported analytic results with pySecDec. Tests that need pySecDec detect or explicitly skip that dependency; FORM and backend-enabled coverage still requires the corresponding external tools. The crate also has focused unit tests for expression encoding and numerical-result behavior.

For supported workflows, see the matching tutorial, evaluation and reproducibility guide, Rust/Python interface guide, and generated topology table. Exact Rust signatures are in the native Vakint Rustdoc.

Factorized tensor projection and epsilon coefficients

The default tensor-projection path reduces universal loop-momentum kernels while preserving graph coefficients as factorized expressions. Temporary coefficient aliases are restored after analytic integration. project_onto_tensor_integrals = false instead reduces each complete numerator through FORM. Both modes retain separate denominator topologies and validate Lorentz domains.

Opaque spin tensors declare their Lorentz slots with vakint::tensor(body, slot, ...). Projection may introduce vakint::tensor_index slots, which the caller translates before completing spin algebra. Vakint does not evaluate that algebra. Numerator and normalization poles increase the required epsilon order; positive powers do not reduce the conservative depth. Opaque epsilon-dependent functions error.

The Python adapter accepts complex mass/numerator substitutions as numerical_parameters; the PySecDec boundary requires real pole masses and external momenta, with complex numerator coefficients allowed. Physical PySecDec integration tests remain explicit manual checks. The commands and detailed contracts are in the evaluation guide.

Developer architecture · documented revision ff533fcd91d8