IBPFamily
IBPFamily
class IBPFamilyFind 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: intNumber 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_countparameter_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,
) -> NonePrepare 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 == 1Parameters
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__() -> strSummarize 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 momentanormalize_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.TerminalNormalizationExplicit 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,
) -> IBPSolutionReduce 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-substitutedParameters
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, withinmax_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,
) -> IBPSolutionSearch 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 stepParameters
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.CandidateGenerationSessionStart 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_countParameters
event_capacity(int, optional) Maximum number of retained progress events; default 256.options(object) Native candidate-generation keyword options, includingn_cores,numerical_depth, andnonpositive_indicesfor auxiliary slots.