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 accept 1–12 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”.
Attributes
| Name | Description |
|---|---|
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 |
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_countMethods
| Name | Description |
|---|---|
__init__ |
Prepare a complete denominator basis for exact IBP searches |
__repr__ |
Summarize this IBPFamily for interactive inspection. |
ibp_identities |
Generate the L*(L+E) ordinary IBP equations with symbolic indices |
reduce_laporta |
Reduce requested integer-power integrals by exact finite-target elimination |
solve_parametric |
Search for symbolic recurrences within one positive/nonpositive power sector |
__init__
IBPFamily.__init__(family: IntegralFamily, *, name: str = 'F') -> 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”.
__repr__
IBPFamily.__repr__() -> strSummarize this IBPFamily for interactive inspection.
Examples
Using the setup in the IBPFamily class example:
summary = repr(ibp)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 momentareduce_laporta
IBPFamily.reduce_laporta(
targets: list[list[int]],
*,
max_depth: int = 2,
include_lorentz: bool = False,
max_targets: int = 1024,
) -> 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.
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.