IBPFamily

Symbolica documentation for getting started, symbolic expressions, numerical evaluation, pattern matching, and APIs in Python and Rust.

IBPFamily

class IBPFamily

Find exact integration-by-parts (IBP) relations for a complete integral family.

Wrap a hep.IntegralFamily after checking is_complete and is_independent. The denominator order, signs, masses, dimension and external scalar products are preserved. Supply a symbolic dimension through Kinematics. Missing scalar-product coordinates must be added explicitly with family.complete(); auxiliary denominators normally have nonpositive powers.

Choose solve_parametric for a reusable symbolic recurrence in a sector, or reduce_laporta for a finite set of integer-power targets. Inspect the returned rules and residual integrals before using a reduction. Searches are bounded: they do not certify a complete master-integral basis.

Searches use the compiled runtime arity registry (by default 1–16 denominators) and integer powers from -64 through 63. Applying a discovered rule accepts signed 64-bit powers. Booleans are not powers.

Examples

from symbolica import S, E
from symbolica.community import hepkit as hep
d, k, m2 = S("d", "k", "m2")
kin = hep.Kinematics(d, momenta=[k])
family = hep.IntegralFamily([k], [], [kin.scalar_product(k, k) - m2], kinematics=kin)
ibp = hep.IBPFamily(family, name="T")
solution = ibp.solve_parametric([True])
terms = solution.reduce([2])
assert terms[0][0] == [1]
assert (terms[0][1] - (d-2)/(2*m2)).together() == E("0")

Parameters

  • family (IntegralFamily) Complete, independent denominator basis with symbolic dimension.
  • name (str, optional) Family label used in diagnostic output; default “F”.
  • cut (list[bool] or None, optional) Reverse-unitarity flags in denominator order; None leaves all lines uncut.

Attributes

Name Description
cut Reverse-unitarity flags in denominator order; nonpositive cut powers vanish.
denominator_count Number of entries required in every sector, target and fixed-power vector.
index_symbols Formal integral-index symbols, one per denominator in family order
parameter_bindings Internal polynomial parameters paired with original HEPKit atoms

cut

IBPFamily.cut: list[bool]

Reverse-unitarity flags in denominator order; nonpositive cut powers vanish.

Examples

Using the setup in the IBPFamily class example:

assert ibp.cut == [False]

denominator_count

IBPFamily.denominator_count: int

Number of entries required in every sector, target and fixed-power vector.

Examples

Using the setup in the IBPFamily class example:

assert ibp.denominator_count == len(family.denominators)

index_symbols

IBPFamily.index_symbols: list[Expression]

Formal integral-index symbols, one per denominator in family order.

These symbols occur in ibp_identities and parametric rules. Use the returned symbols for substitutions: freshly creating a symbol named n1 does not identify this family’s privately scoped index.

Examples

Using the setup in the IBPFamily class example:

n = ibp.index_symbols[0]
assert len(ibp.index_symbols) == ibp.denominator_count

parameter_bindings

IBPFamily.parameter_bindings: list[tuple[Expression, Expression]]

Internal polynomial parameters paired with original HEPKit atoms.

A presentation legend, not a replacement of serialized artifact names.

Examples

Using the setup in the IBPFamily class example:

bindings = ibp.parameter_bindings
assert {original for internal, original in bindings} == {d, m2}

Methods

Name Description
__init__ Prepare a complete denominator basis for exact IBP searches
__repr__ Summarize this IBPFamily for interactive inspection.
compiled_runtime_arities Solver entry points compiled into this host, not a mathematical bound.
ibp_identities Generate the L*(L+E) ordinary IBP equations with symbolic indices
normalize_candidate_terminals Explicit exact normalization of saved finite residuals in this family
reduce_laporta Reduce requested integer-power integrals by exact finite-target elimination
solve_parametric Search for symbolic recurrences within one positive/nonpositive power sector
start_generation Start native generation from this exact routed family, without re-parsing

__init__

IBPFamily.__init__(
    family: IntegralFamily,
    *,
    name: str = 'F',
    cut: list[bool] | None = None,
) -> None

Prepare a complete denominator basis for exact IBP searches.

Raises ValueError for an incomplete/dependent basis, unsupported kinematics, or too many denominators. Complete missing coordinates before constructing this object; dependent propagators require partial fractions.

Examples

from symbolica import S, E
from symbolica.community import hepkit as hep
d, k, m2 = S("d", "k", "m2")
kin = hep.Kinematics(d, momenta=[k])
family = hep.IntegralFamily([k], [], [kin.scalar_product(k, k) - m2], kinematics=kin)
ibp = hep.IBPFamily(family, name="T")
assert ibp.denominator_count == 1

Parameters

  • family (IntegralFamily) Complete, independent family; its denominator order is retained.
  • name (str, optional) Diagnostic family label; default “F”.
  • cut (list[bool] or None, optional) One reverse-unitarity flag per denominator. Nonpositive powers of a cut denominator vanish; None leaves all denominators uncut.

__repr__

IBPFamily.__repr__() -> str

Summarize this IBPFamily for interactive inspection.

Examples

Using the setup in the IBPFamily class example:

summary = repr(ibp)

compiled_runtime_arities

IBPFamily.compiled_runtime_arities() -> list[int]

Solver entry points compiled into this host, not a mathematical bound.

Examples

from symbolica.community import hepkit as hep
arities = hep.IBPFamily.compiled_runtime_arities()
assert arities == sorted(set(arities))

ibp_identities

IBPFamily.ibp_identities() -> list[list[tuple[list[Expression], Expression]]]

Generate the L*(L+E) ordinary IBP equations with symbolic indices.

Each row is a list of (powers, coefficient) pairs representing sum(coefficient * I(*powers)) = 0. Powers contain index symbols and integer shifts, not just shifts. Coefficients retain the family’s kinematics. This method generates equations without solving them.

Examples

Using the setup in the IBPFamily class example:

I = S("I")
equations = [sum((coefficient * I(*powers) for powers, coefficient in row), E("0"))
             for row in ibp.ibp_identities()]
assert len(equations) == 1  # one loop, no external momenta

normalize_candidate_terminals

IBPFamily.normalize_candidate_terminals(
    artifact: rustred.CandidateArtifact,
    *,
    max_terminals: int = 1000000,
    max_supports: int = 100000,
    max_matrix_cells: int = 1000000,
    max_output_terms: int = 4000000,
) -> rustred.TerminalNormalization

Explicit exact normalization of saved finite residuals in this family.

Uses native unit aliases and weighted polynomial-numerator relations; it does not regenerate candidates, solve ordinary IBPs, certify closure, or prove master independence. Native family identity must match.

Examples

Using the setup in the IBPFamily class example:

session = ibp.start_generation(n_cores=1, numerical_depth=1)
assert session.wait(timeout=120)
artifact = session.result().artifact()
normalized = ibp.normalize_candidate_terminals(artifact)
assert normalized.metadata()["exact_within_family"]

Parameters

  • artifact (rustred.CandidateArtifact) Generated candidate artifact belonging to this exact native family.
  • max_terminals (int, optional) Maximum number of input or output terminal keys; default 1000000.
  • max_supports (int, optional) Maximum number of normalization supports; default 100000.
  • max_matrix_cells (int, optional) Maximum number of cells in normalization matrices; default 1000000.
  • max_output_terms (int, optional) Maximum number of terms in the normalized output; default 4000000.

reduce_laporta

IBPFamily.reduce_laporta(
    targets: list[list[int]],
    *,
    max_depth: int = 2,
    include_lorentz: bool = False,
    max_targets: int = 1024,
    preferred_masters: list[list[int]] | None = None,
    until_stable: bool = False,
) -> IBPSolution

Reduce requested integer-power integrals by exact finite-target elimination.

The solver searches seed neighborhoods and back-substitutes solved targets. solution.residuals lists the basis left at this search depth, which is not a certified set of independent master integrals. Increase max_depth when more relations are needed. Exceeding max_targets raises ValueError rather than silently truncating the search.

Examples

Using the setup in the IBPFamily class example:

solution = ibp.reduce_laporta([[3]], max_depth=1)
terms = solution.reduce([3])
assert terms[0][0] == [1]  # solved intermediate powers are back-substituted

Parameters

  • targets (list[list[int]]) Power vectors, one integer in -64..63 per denominator.
  • max_depth (int, optional) Nonnegative signed L1 seed radius; default 2.
  • include_lorentz (bool, optional) Add Lorentz-invariance identities; default False.
  • max_targets (int, optional) Limit on distinct integrals searched, including discovered targets; default 1024.
  • preferred_masters (list[list[int]] or None, optional) Requested residual basis, used where the discovered equations permit replacement. None retains the solver’s residual basis.
  • until_stable (bool, optional) Check two further depths for an unchanged residual set, within max_depth. This heuristic does not certify a complete basis.

solve_parametric

IBPFamily.solve_parametric(
    sector: list[bool],
    *,
    fixed: list[int | None] | None = None,
    max_depth: int = 2,
    include_lorentz: bool = False,
) -> IBPSolution

Search for symbolic recurrences within one positive/nonpositive power sector.

True means a strictly positive denominator power; False means zero or negative. The sector and optional fixed vector must each have one entry per denominator. None leaves an index symbolic; an integer fixes its absolute power and must agree with the sector.

Returns an IBPSolution whose rules carry explicit nonzero conditions and exceptional branches. reduce performs one recurrence step per call. Increasing max_depth searches more seeds but does not guarantee closure.

Examples

Using the setup in the IBPFamily class example:

solution = ibp.solve_parametric([True], fixed=[None], max_depth=1)
assert solution.rules
lowered = solution.reduce([3])
assert lowered[0][0] == [2]  # one recurrence step

Parameters

  • sector (list[bool]) Positive/nonpositive support, in denominator order.
  • fixed (list[int | None] or None, optional) Fixed absolute powers in -64..63; default all symbolic.
  • max_depth (int, optional) Nonnegative seed-search depth; default 2.
  • include_lorentz (bool, optional) Add Lorentz-invariance identities; default False.

start_generation

IBPFamily.start_generation(
    *,
    event_capacity: int = 256,
    **options: object,
) -> rustred.CandidateGenerationSession

Start native generation from this exact routed family, without re-parsing.

Poll the bounded stream for progress; cancellation drains at native safe boundaries. Output is a generated candidate, not a closure certificate. nonpositive_indices identifies auxiliary scalar-product slots. Cut families currently use the existing cut-aware finite/parametric APIs.

Examples

Using the setup in the IBPFamily class example:

session = ibp.start_generation(n_cores=1, numerical_depth=1)
assert session.wait(timeout=120)
artifact = session.result().artifact()
assert artifact.metadata()["arity"] == ibp.denominator_count

Parameters

  • event_capacity (int, optional) Maximum number of retained progress events; default 256.
  • options (object) Native candidate-generation keyword options, including n_cores, numerical_depth, and nonpositive_indices for auxiliary slots.