IntegralFamily
IntegralFamily
class IntegralFamilyAn ordered set of inverse propagators sharing loop momenta and external kinematics.
Pass denominators such as k.k - m2, not their reciprocals. An integral with powers [a1, a2, ...] has integrand 1/(D1**a1 * D2**a2 * ...): zero powers omit a denominator and negative powers put it in the numerator. All power vectors and denominator labels follow the original input order.
Declare independent external momenta and their scalar products through Kinematics. is_independent checks the denominator basis for linear dependence; is_complete checks whether it spans every loop scalar product. For L loops and E independent external momenta this space has L(L+1)/2 + LE coordinates. complete() returns a new family with missing coordinates appended; give these auxiliary slots nonpositive integral powers. Use partial_fraction() before completion when denominators are dependent.
Use this class to rewrite scalar numerators, compare momentum routings, test scalelessness, and construct Symanzik polynomials. Reduction is provided by hep.IBPFamily or, for one loop, hep.oneloop.reduce. No integration prescription or loop-measure normalization is inferred by this container.
Examples
Build a massless bubble with external virtuality p.p = s. The method examples below reuse this family and its symbols.
from symbolica import S, E
from symbolica.community import hepkit as hep
D, k, p, s = S("D", "k", "p", "s")
d1, d2, x1, x2 = S("d1", "d2", "x1", "x2")
kin = hep.Kinematics(D, momenta=[k, p]).with_scalar_product(p, p, s)
denominators = [kin.scalar_product(k, k), kin.scalar_product(k-p, k-p)]
family = hep.IntegralFamily([k], [p], denominators, kinematics=kin)
assert family.rank == 2 and family.is_complete and family.is_independent
rewritten = family.rewrite_numerator(kin.scalar_product(k, p), [d1, d2])
assert (rewritten - (d1 - d2 + s)/2).expand() == E("0")
U, F = family.symanzik([x1, x2])
assert U == x1 + x2Attributes
| Name | Description |
|---|---|
denominators |
Ordered inverse propagators, including any auxiliary completion terms. |
external_momenta |
Independent external momentum names in their original order. |
is_complete |
Whether the inverse propagators span every loop scalar product. |
is_independent |
Whether no denominator can be eliminated by an affine relation. |
kinematics |
Scoped kinematics, including the family momentum declarations. |
loop_momenta |
Integrated momentum names in their original order. |
rank |
Number of independent affine forms in the loop scalar products. |
scalar_products |
Loop-loop and loop-external products spanning the numerator space. |
denominators
IntegralFamily.denominators: builtins.list[Expression]Ordered inverse propagators, including any auxiliary completion terms.
Examples
Using the setup in the IntegralFamily class example:
assert family.denominators == denominators
weighted = list(zip(family.denominators, [1, 2]))external_momenta
IntegralFamily.external_momenta: builtins.list[Expression]Independent external momentum names in their original order.
Examples
Using the setup in the IntegralFamily class example:
assert family.external_momenta == [p]is_complete
IntegralFamily.is_complete: builtins.boolWhether the inverse propagators span every loop scalar product.
Examples
Using the setup in the IntegralFamily class example:
assert family.is_complete
assert family.rank == len(family.scalar_products)is_independent
IntegralFamily.is_independent: builtins.boolWhether no denominator can be eliminated by an affine relation.
Examples
Using the setup in the IntegralFamily class example:
assert family.is_independent
assert family.rank == len(family.denominators)kinematics
IntegralFamily.kinematics: KinematicsScoped kinematics, including the family momentum declarations.
Examples
Using the setup in the IntegralFamily class example:
assert family.kinematics.scalar_product(p, p) == sloop_momenta
IntegralFamily.loop_momenta: builtins.list[Expression]Integrated momentum names in their original order.
Examples
Using the setup in the IntegralFamily class example:
assert family.loop_momenta == [k]rank
IntegralFamily.rank: builtins.intNumber of independent affine forms in the loop scalar products.
Examples
Using the setup in the IntegralFamily class example:
assert family.rank == 2scalar_products
IntegralFamily.scalar_products: builtins.list[Expression]Loop-loop and loop-external products spanning the numerator space.
Examples
Using the setup in the IntegralFamily class example:
assert len(family.scalar_products) == 2Methods
| Name | Description |
|---|---|
__new__ |
Compute the independent loop scalar products and denominator rank. |
__repr__ |
Return a compact summary of the family and its scalar-product rank. |
_repr_html_ |
Display ordered inverse propagators and family metadata in a notebook |
_repr_pretty_ |
Write the summary and ordered denominators using Symbolica’s text printer. |
complete |
Complete a basis, preferring supplied inverse propagators |
find_mapping |
Find a verified affine loop-momentum shift into the target family |
find_mappings |
Group families and return verified maps to their representatives |
from_diagram |
Build a complete family from the diagram’s routed internal propagators |
mapping_to |
Verify explicit source-loop images in another family’s coordinates |
parametric_mapping |
Find a parameter permutation identifying both Symanzik polynomials |
partial_fraction |
Partial-fraction dependent propagators while preserving family order |
rewrite_numerator |
Rewrite a numerator in inverse-propagator variables and expand it. |
scalar_product_rules |
Solve loop scalar products in terms of inverse-propagator labels. |
scaleless_scaling |
Find parameter weights proving a sector scaleless in dimensional regularization |
scaleless_transverse_direction |
Find an unconstrained transverse loop direction proving scalelessness |
sector |
Select the positive-power propagators of an integral’s sector |
symanzik |
Compute the Symanzik polynomials U and F in propagator order |
__new__
IntegralFamily.__new__(
loop_momenta: typing.Sequence[Expression],
external_momenta: typing.Sequence[Expression],
denominators: typing.Sequence[Expression],
*,
kinematics: typing.Optional[Kinematics] = None,
) -> IntegralFamilyCompute the independent loop scalar products and denominator rank.
Examples
from symbolica import S, E
from symbolica.community import hepkit as hep
D, k, p, s = S("D", "k", "p", "s")
d1, d2, x1, x2 = S("d1", "d2", "x1", "x2")
kin = hep.Kinematics(D, momenta=[k, p]).with_scalar_product(p, p, s)
denominators = [kin.scalar_product(k, k), kin.scalar_product(k-p, k-p)]
family = hep.IntegralFamily([k], [p], denominators, kinematics=kin)
assert family.rank == 2Parameters
loop_momenta(list[Expression]) Distinct unindexed integrated momentum names.external_momenta(list[Expression]) Independent unindexed external momentum names.denominators(list[Expression]) Ordered inverse propagators, not their reciprocals.kinematics(Kinematics | None) External assumptions and dimension; defaults to unconstrained 4D.
__repr__
IntegralFamily.__repr__() -> builtins.strReturn a compact summary of the family and its scalar-product rank.
Examples
Using the setup in the IntegralFamily class example:
print(family)_repr_html_
IntegralFamily._repr_html_() -> builtins.strDisplay ordered inverse propagators and family metadata in a notebook.
Expressions use Symbolica’s native HTML printer.
Examples
Using the setup in the IntegralFamily class example:
from IPython.display import display
display(family)_repr_pretty_
IntegralFamily._repr_pretty_(pretty: typing.Any, cycle: builtins.bool) -> NoneWrite the summary and ordered denominators using Symbolica’s text printer.
Examples
Using the setup in the IntegralFamily class example:
from IPython.lib.pretty import pretty
text = pretty(family)Parameters
pretty(object) IPython’s pretty printer, providing atextmethod.cycle(bool) Whether this family is part of a recursive formatting cycle.
complete
IntegralFamily.complete(
*,
candidates: typing.Optional[typing.Sequence[Expression]] = None,
) -> IntegralFamilyComplete a basis, preferring supplied inverse propagators.
Original propagators retain their positions. Dependent families must first be partial-fractioned. Added propagators carry nonpositive powers when used to represent numerator factors in an IBP integral list. Candidates are tried in order after applying this family’s kinematics. Redundant candidates are skipped; bare scalar products fill any missing directions. All candidates must be affine in the loop scalar products.
Examples
Using the bubble setup in IntegralFamily:
incomplete = hep.IntegralFamily([k], [p], denominators[:1], kinematics=kin)
completed = incomplete.complete()
assert not incomplete.is_complete and completed.is_complete
assert completed.denominators[0] == denominators[0]
powers = [1, 0] # the appended slot is absent from the original integralParameters
candidates(list[Expression] | None) Preferred auxiliary inverse propagators in this family’s momentum coordinates. Defaults to using only bare scalar products.
find_mapping
IntegralFamily.find_mapping(
target: IntegralFamily,
*,
max_candidates: builtins.int = 100000,
) -> typing.Optional[IntegralMapping]Find a verified affine loop-momentum shift into the target family.
Search derives candidates from independent quadratic propagators, then checks every propagator, including eikonal and auxiliary entries. It includes loop mixtures, reversals and external shifts. It does not test parametric identities that have no affine loop-momentum map.
Examples
Using the bubble setup in IntegralFamily:
target = hep.IntegralFamily([k], [p], list(reversed(denominators)), kinematics=kin)
mapping = family.find_mapping(target)
assert mapping is not None
transformed = mapping.apply(kin.scalar_product(k, p))Parameters
target(IntegralFamily) Target family with the same external kinematics and loop count.max_candidates(int) Candidate budget; exhaustion raises IntegralFamilyError.
Returns
IntegralMapping | NoneVerified mapping, or None if no supported candidate matches.
find_mappings
IntegralFamily.find_mappings(
families: typing.Sequence[IntegralFamily],
*,
max_candidates: builtins.int = 100000,
) -> builtins.list[tuple[builtins.int, IntegralMapping]]Group families and return verified maps to their representatives.
Returns one (target_index, mapping) per input family in input order. Indices refer to the original list. Representatives map to themselves; every other mapping goes directly to a retained representative. The first compatible representative wins. Symbolica canonizes each Symanzik pair once, then native affine-shift search verifies all merges. A parametric equivalence without a verified loop map remains separate.
Families need compatible external kinematics and nonsingular quadratic forms. Unsupported shift searches and exhausted budgets raise errors. Different propagator counts stay separate. Select sectors and remove certified scaleless integrals before grouping; complete bases afterwards. This does not exchange external momenta or infer integration prescriptions.
Examples
Using the bubble setup in IntegralFamily:
families = [family, family]
mappings = hep.IntegralFamily.find_mappings(families)
assert [target for target, mapping in mappings] == [0, 0]Parameters
families(list[IntegralFamily]) Ordered families; earlier entries are preferred as representatives.max_candidates(int) Affine-shift candidate budget per pair; exhaustion raises an error.
Returns
list[tuple[int, IntegralMapping]]Target index and verified map for each input, including representatives.
from_diagram
IntegralFamily.from_diagram(
diagram: FeynmanDiagram,
independent_dot_products: typing.Optional[typing.Sequence[Expression]] = None,
*,
kinematics: typing.Optional[Kinematics] = None,
) -> IntegralFamilyBuild a complete family from the diagram’s routed internal propagators.
Graph propagators retain their edge order and model masses. Preferred independent dot products are appended in order when they increase the rank; automatic scalar products fill any remaining directions. Auxiliary denominators have nonpositive powers when representing the original integral. Tree diagrams and dependent graph propagators raise DiagramError. Use diagram.propagator_family() to extract dependent propagators for partial fractioning before completing the resulting families.
Examples
from symbolica import S, E
from symbolica.community import hepkit as hep
model = hep.Model.phi4()
process = model.process(["phi", "phi"], ["phi", "phi"])
result = process.generate_diagrams(loops=1)
diagram = result.diagrams[0]
family = hep.IntegralFamily.from_diagram(diagram)
assert family.is_completeParameters
diagram(FeynmanDiagram) A complete diagram with its chosen loop-momentum routing.independent_dot_products(list[Expression] or None, optional) Preferred auxiliary inverse propagators in the routed momenta. None selects a suitable basis automatically.kinematics(Kinematics or None, optional) External assumptions and dimension; defaults to the diagram’s symbolic dimension with no on-shell assumptions.
mapping_to
IntegralFamily.mapping_to(
target: IntegralFamily,
loop_images: typing.Sequence[Expression],
) -> typing.Optional[IntegralMapping]Verify explicit source-loop images in another family’s coordinates.
Real affine images must have loop determinant +1 or -1 and map every source propagator to a distinct equal target propagator. External names, dimensions and scalar-product assumptions must agree. Additional target propagators are allowed for subtopology embeddings.
Examples
Using the bubble setup in IntegralFamily:
mapping = family.mapping_to(family, [k])
assert mapping.map_powers([1, 2]) == [1, 2]Parameters
target(IntegralFamily) Family in whose coordinates the images are expressed.loop_images(list[Expression]) One image per source loop momentum, in source order.
Returns
IntegralMapping | NoneVerified mapping, or None when the images fail the equivalence checks.
parametric_mapping
IntegralFamily.parametric_mapping(
target: IntegralFamily,
parameters: typing.Sequence[Expression],
) -> typing.Optional[PropagatorMapping]Find a parameter permutation identifying both Symanzik polynomials.
Symbolica canonizes polynomial incidence graphs, preserving coefficients, powers and the distinction between U and F. This can identify families without a loop shift at fixed external momenta. The result supplies no momentum or tensor-numerator substitution and does not check contours or propagator prescriptions. Both families must have equal denominator counts and the same external kinematics. Singular quadratic forms are rejected because their U/F polynomials can discard physical parameters.
Examples
Using the bubble setup in IntegralFamily:
target = hep.IntegralFamily([k], [p], list(reversed(denominators)), kinematics=kin)
mapping = family.parametric_mapping(target, [x1, x2])
assert mapping is not None
mapped_powers = mapping.map_powers([1, 2])Parameters
target(IntegralFamily) Family whose U and F polynomials are compared.parameters(list[Expression]) One distinct new symbol or labeled call per source denominator.
Returns
PropagatorMapping | NoneFormal parameter permutation, or None if the polynomials differ.
partial_fraction
IntegralFamily.partial_fraction(
powers: typing.Sequence[builtins.int],
*,
max_states: builtins.int = 100000,
) -> builtins.list[tuple[Expression, builtins.list[builtins.int]]]Partial-fraction dependent propagators while preserving family order.
Both affine mass shifts and homogeneous dependencies are supported. The identity is algebraic: no momentum shifts or scaleless-term removal are applied. Impose exceptional kinematics before building the family; generic external invariants may appear in the returned coefficients.
Examples
Using the symbols and kinematics in IntegralFamily:
m2 = S("m2")
dependent = hep.IntegralFamily([k], [], [kin.scalar_product(k, k),
kin.scalar_product(k, k) - m2], kinematics=kin)
terms = dependent.partial_fraction([1, 1])
assert all(sum(power > 0 for power in powers) == 1 for coefficient, powers in terms)Parameters
powers(list[int]) Signed powers in family order; negative powers are numerator factors.max_states(int) Maximum number of intermediate exponent vectors; defaults to 100000.
Returns
list[tuple[Expression, list[int]]]Coefficients and powers whose positive-power denominators are independent.
rewrite_numerator
IntegralFamily.rewrite_numerator(
numerator: Expression,
labels: typing.Sequence[Expression],
) -> ExpressionRewrite a numerator in inverse-propagator variables and expand it.
Examples
Using the setup in the IntegralFamily class example:
numerator = kin.scalar_product(k, p)**2
reduced = family.rewrite_numerator(numerator, [d1, d2])Parameters
numerator(Expression) Scalar numerator after tensor reduction and momentum routing.labels(list[Expression]) One distinct symbol or labeled call per denominator, in family order.
scalar_product_rules
IntegralFamily.scalar_product_rules(labels: typing.Sequence[Expression]) -> builtins.list[tuple[Expression, Expression]]Solve loop scalar products in terms of inverse-propagator labels.
Examples
Using the setup in the IntegralFamily class example:
rules = family.scalar_product_rules([d1, d2])
assert len(rules) == 2Parameters
labels(list[Expression]) One distinct symbol or labeled call per denominator, in family order.
Returns
list[tuple[Expression, Expression]]Simultaneous replacement pairs for an independent, complete family.
scaleless_scaling
IntegralFamily.scaleless_scaling(parameters: typing.Sequence[Expression]) -> typing.Optional[builtins.list[Expression]]Find parameter weights proving a sector scaleless in dimensional regularization.
For G=U+F, the returned weights satisfy sum(w_ix_idG/dx_i)=G. None means this criterion did not detect scalelessness, not that the integral is nonzero. Every denominator is treated as present; use sector(powers) first to select positive-power entries. Singular quadratic loop forms raise IntegralFamilyError: their algebraic U/F polynomials do not establish this parametric scaling certificate.
Examples
Using the bubble setup in IntegralFamily:
tadpole = family.sector([1, 0])
weights = tadpole.scaleless_scaling([x1])
assert weights is not None # massless tadpole vanishes in dimensional regularizationParameters
parameters(list[Expression]) One distinct new symbol or labeled call per sector denominator.
Returns
list[Expression] | NoneExact scaling weights in parameter order, or no certificate.
scaleless_transverse_direction
IntegralFamily.scaleless_transverse_direction() -> typing.Optional[builtins.list[Expression]]Find an unconstrained transverse loop direction proving scalelessness.
Returns a nonzero real list w in loop order such that each inverse propagator is invariant under k_i -> k_i + w_i*r_perp for any vector orthogonal to the external span. The corresponding unrestricted transverse integral vanishes in dimensional regularization, including polynomial numerators. Apply sector(powers) first to exclude numerator-only entries.
Requires a nonsingular external Gram matrix. Symbolic dimension is interpreted generically; a concrete dimension must exceed the external basis size. None means no certificate was found. A vanishing Symanzik U alone is not sufficient, and complex loop directions are not accepted.
Examples
Using the bubble setup in IntegralFamily:
empty_sector = family.sector([0, 0])
direction = empty_sector.scaleless_transverse_direction()
assert direction is not None # no denominators constrain the loop momentumReturns
list[Expression] | NoneVerified real loop direction, or no certificate.
sector
IntegralFamily.sector(powers: typing.Sequence[builtins.int]) -> IntegralFamilySelect the positive-power propagators of an integral’s sector.
Zero and negative powers are omitted. Loop variables and external kinematics are retained. This selects sector support; it does not remove numerator factors algebraically from the original integrand.
Examples
Using the bubble setup in IntegralFamily:
sector = family.sector([1, 0])
assert sector.denominators == denominators[:1]Parameters
powers(list[int]) One signed propagator power per family denominator.
symanzik
IntegralFamily.symanzik(parameters: typing.Sequence[Expression]) -> tuple[Expression, Expression]Compute the Symanzik polynomials U and F in propagator order.
Uses Minkowski inverse propagators: k2-m2 gives U=x and F=m2*x2. For a weighted denominator k.M.k + 2 k.Q + J, this returns U=det(M) and F=Q.adj(M).Q-U*J, using Symbolica determinants and cofactors. Singular quadratic forms are accepted as algebraic polynomial data; they do not establish a Gaussian integration formula or scalelessness. This prepares polynomials without performing integration.
Examples
Using the setup in the IntegralFamily class example:
U, F = family.symanzik([x1, x2])
assert U == x1 + x2 # two standard one-loop propagatorsParameters
parameters(list[Expression]) One distinct new symbol or labeled call per inverse propagator.
Returns
tuple[Expression, Expression]First and second Symanzik polynomials, respectively.