IBPSolution
IBPSolution
class IBPSolutionRules, unresolved integrals and statistics returned by an IBP search.
Obtain a solution from IBPFamily.solve_parametric or reduce_laporta; there is no public constructor. reduce chooses the first applicable rule. For parametric solutions it takes one recurrence step. Laporta solutions already back-substitute solved targets. Unmatched integrals remain explicit.
Residual integrals are the unresolved basis at the chosen search depth; they are not certified independent masters. Rule conditions still apply when masses, invariants or the dimension are specialized.
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.reduce_laporta([[3]], max_depth=1)
I = S("I")
reduced = solution.reduce([3], integral=I)
expected = (d-2)*(d-4)/(8*m2**2)*I(1)
assert (reduced - expected).together() == E("0")
assert [1] in solution.residualsAttributes
| Name | Description |
|---|---|
residuals |
Integer power vectors left unresolved by the finite-target search |
rules |
Solved identities in application order |
stats |
Search counters: sectors, seeds, rows, and exact_trace_rows |
residuals
IBPSolution.residuals: list[list[int]]Integer power vectors left unresolved by the finite-target search.
The list describes this search’s remaining basis, not a proof of master independence. Parametric searches may have no residual list even though a recurrence leaves boundary cases unsolved.
Examples
Using the setup in the IBPSolution class example:
assert [1] in solution.residuals
I = S("I")
remaining_integrals = [I(*powers) for powers in solution.residuals]rules
IBPSolution.rules: list[IBPRule]Solved identities in application order.
Inspect each rule’s target, sector, nonzero conditions and exceptions before using it at specialized kinematics. An empty list means no solved rules were found.
Examples
Using the setup in the IBPSolution class example:
assert solution.rules
for rule in solution.rules:
identity = (rule.target, rule.terms)stats
IBPSolution.stats: dict[str, int]Search counters: sectors, seeds, rows, and exact_trace_rows.
Use these counts to compare search effort at different depths. They report work performed, not completeness or the number of independent masters.
Examples
Using the setup in the IBPSolution class example:
assert solution.stats["rows"] > 0
seed_count = solution.stats["seeds"]Methods
| Name | Description |
|---|---|
__repr__ |
Summarize this IBPSolution for interactive inspection. |
reduce |
Apply the first valid rule, leaving unmatched integrals unchanged |
__repr__
IBPSolution.__repr__() -> strSummarize this IBPSolution for interactive inspection.
Examples
Using the setup in the IBPSolution class example:
summary = repr(solution)reduce
IBPSolution.reduce(
powers: list[int],
*,
integral: None = None,
) -> list[tuple[list[int], Expression]]
IBPSolution.reduce(powers: list[int], *, integral: Expression) -> ExpressionApply the first valid rule, leaving unmatched integrals unchanged.
Returns (powers, coefficient) terms by default. With a bare Symbolica symbol as integral, returns their symbolic sum; an empty sum is zero. Laporta rules are back-substituted, whereas parametric rules perform one recurrence step. A rule’s symbolic kinematic conditions still apply.
Wrong power-vector length or a non-symbol integral raises ValueError. Unmatched input returns [(powers, 1)] or integral(*powers) rather than an error; inspect the returned powers to see what remains.
Examples
Using the setup in the IBPSolution class example:
I = S("I")
terms = solution.reduce([3])
assert terms[0][0] == [1]
assert solution.reduce([1], integral=I) == I(1)Parameters
powers(list[int]) One signed 64-bit integer per denominator; booleans are rejected.integral(Expression or None, optional) Bare function-head symbol, e.g. S(“I”); None returns structured terms.