FeynmanDiagram
FeynmanDiagram
class FeynmanDiagramA generated or imported Feynman diagram, with particles, momenta and Feynman rules.
Obtain diagrams from Model.process(...).generate_diagrams().diagrams; use from_json or from_dot to restore a saved diagram with its model. There is no direct Python constructor. internal_edges are propagators, whereas external_edges carry the scattering or decay states.
Use numerator_expression() for symbolic algebra, integral_family() for loop-integral preparation, and render() for an SVG. Graph selections from subgraph and filter retain the original routing and identities. Routing changes return new diagrams. A diagram alone does not perform loop integration or supply a cross section.
Examples
Generate a one-loop scalar scattering diagram, inspect its propagators, and prepare its integral family. In a notebook, displaying diagram renders the graph. The methods below reuse this setup.
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]
diagram.validate()
assert diagram.loop_count == 1
propagators = [(edge.id, edge.particle_name) for edge in diagram.internal_edges]
numerator = diagram.numerator_expression()
family = diagram.integral_family()
assert family.is_completeAttributes
| Name | Description |
|---|---|
cuts |
Return physical final-state cuts selected during generation. |
edges |
Return every particle line, including dangling and sewn external carriers. |
external_edges |
Return incoming or outgoing external-state momentum carriers. |
half_edges |
Return native Linnet half-edge views; data records their native diagram IDs. |
id |
Return the stable content-derived hexadecimal diagram ID. |
internal_edges |
Return propagators excluding external momentum carriers and dummy edges. |
linnet_selection |
Return the canonical Linnet selection representing this physics region. |
loop_count |
Return the number of independent loops in the diagram topology. |
loop_momentum_basis |
Return the loop-momentum routing selected during generation. |
name |
Return the deterministic name assigned during diagram generation. |
numerator |
Return the diagram numerator annotation as source text. |
overall_factor |
Return the diagram-wide multiplicative factor as Symbolica source text |
symmetry_factor |
Return the positive integer denominator of the graph symmetry factor. |
topology_threshold_candidates |
Return topology threshold candidates separately from physical cuts. |
vertices |
Return the diagram’s interaction vertices with stable integer identifiers. |
cuts
FeynmanDiagram.cuts: builtins.list[DiagramCut]Return physical final-state cuts selected during generation.
Examples
Using the setup in the FeynmanDiagram class example:
physical_cuts = [cut.edges for cut in diagram.cuts]
assert physical_cuts == [] # ordinary amplitude, not a sewn cross sectionedges
FeynmanDiagram.edges: builtins.list[DiagramEdge]Return every particle line, including dangling and sewn external carriers.
Examples
Using the setup in the FeynmanDiagram class example:
particles_by_edge = {edge.id: edge.particle_name for edge in diagram.edges}external_edges
FeynmanDiagram.external_edges: builtins.list[DiagramEdge]Return incoming or outgoing external-state momentum carriers.
Examples
Using the setup in the FeynmanDiagram class example:
external_particles = [edge.particle_name for edge in diagram.external_edges]half_edges
FeynmanDiagram.half_edges: list[linnet.HalfEdge]Return native Linnet half-edge views; data records their native diagram IDs.
Examples
Using the setup in the FeynmanDiagram class example:
half_edge_payloads = [half_edge.data for half_edge in diagram.half_edges]id
FeynmanDiagram.id: builtins.strReturn the stable content-derived hexadecimal diagram ID.
Examples
Using the setup in the FeynmanDiagram class example:
selected = process.generate_diagrams(loops=1, select_diagrams=[diagram.id])
assert len(selected.diagrams) == 1internal_edges
FeynmanDiagram.internal_edges: builtins.list[DiagramEdge]Return propagators excluding external momentum carriers and dummy edges.
Examples
Using the setup in the FeynmanDiagram class example:
propagators = [(edge.id, edge.particle_name) for edge in diagram.internal_edges]
assert len(propagators) == 2linnet_selection
FeynmanDiagram.linnet_selection: linnet.SubgraphReturn the canonical Linnet selection representing this physics region.
Examples
Using the setup in the FeynmanDiagram class example:
region = diagram.subgraph(diagram.linnet_selection)
assert region.n_half_edges == len(diagram.half_edges)loop_count
FeynmanDiagram.loop_count: builtins.intReturn the number of independent loops in the diagram topology.
Examples
Using the setup in the FeynmanDiagram class example:
basis = diagram.loop_momentum_bases(limit=1)[0]
len(basis.loop_edges) == diagram.loop_count
Trueloop_momentum_basis
FeynmanDiagram.loop_momentum_basis: LoopMomentumBasisReturn the loop-momentum routing selected during generation.
Examples
Using the setup in the FeynmanDiagram class example:
basis = diagram.loop_momentum_basis
assert len(basis.loop_edges) == diagram.loop_countname
FeynmanDiagram.name: builtins.strReturn the deterministic name assigned during diagram generation.
Examples
Using the setup in the FeynmanDiagram class example:
by_name = {item.name: item for item in result.diagrams}numerator
FeynmanDiagram.numerator: builtins.strReturn the diagram numerator annotation as source text.
Examples
Using the setup in the FeynmanDiagram class example:
source_text = diagram.numerator
numerator = diagram.numerator_expression()overall_factor
FeynmanDiagram.overall_factor: builtins.strReturn the diagram-wide multiplicative factor as Symbolica source text.
This string form is useful for serialization. For algebra or notebook display, prefer overall_factor_expression() so Symbolica’s native rich formatting is preserved.
Examples
Using the setup in the FeynmanDiagram class example:
source = diagram.overall_factor
factor = diagram.overall_factor_expression()
factor # rich Symbolica output in a notebooksymmetry_factor
FeynmanDiagram.symmetry_factor: builtins.intReturn the positive integer denominator of the graph symmetry factor.
Examples
Using the setup in the FeynmanDiagram class example:
graph_weight = 1 / diagram.symmetry_factortopology_threshold_candidates
FeynmanDiagram.topology_threshold_candidates: builtins.list[DiagramThresholdCandidate]Return topology threshold candidates separately from physical cuts.
Examples
Using the setup in the FeynmanDiagram class example:
partitions = [candidate.edges for candidate in diagram.topology_threshold_candidates]vertices
FeynmanDiagram.vertices: builtins.list[DiagramVertex]Return the diagram’s interaction vertices with stable integer identifiers.
Examples
Using the setup in the FeynmanDiagram class example:
interactions = [model.vertex_rule(vertex.interaction) for vertex in diagram.vertices]Methods
| Name | Description |
|---|---|
__repr__ |
Return a concise description of the diagram and its loop count. |
_repr_html_ |
Render the diagram as HTML in Marimo, Jupyter, and IPython. |
_repr_pretty_ |
Write a concise summary to an IPython pretty printer. |
_repr_svg_ |
Return the raw SVG representation used by rich notebook frontends. |
all_bonds |
Enumerate minimal cutsets, independently of physical final-state cuts. |
all_cuts |
Enumerate separating partitions between disjoint interaction vertex groups. |
all_spanning_forests |
Enumerate spanning forests within the selected topology. |
boundary |
Return boundaries around the selected interaction region |
breadth_first_traverse |
Traverse a selected interaction region in breadth-first order. |
bridges |
Return lines whose removal disconnects the selection. |
build_cff |
Build the diagram’s Cross-Free Family representation |
compatible_momentum_basis |
Reuse a parent basis’s loop coordinates wherever the selected topology permits it. |
connected_components |
Return connected interaction regions as reusable selections. |
contracted_momentum_basis |
Route the selected region after contracting complete internal edges. |
cycle_basis |
Return a cycle basis and its covered half-edges. |
denominator_expression |
Return the product of internal propagator denominators as a scalar TensorExpression |
depth_first_traverse |
Traverse a selected interaction region in depth-first order. |
filter |
Select by predicates on Linnet views; their data is a physics object. |
from_dot |
Parse a Feynman diagram from Graphviz DOT text. |
from_json |
Deserialize a Feynman diagram from its JSON representation. |
integral_family |
Build a complete integral family with preferred or automatic ISPs |
is_connected |
Test connectivity of the current diagram or selected region. |
loop_momentum_bases |
Enumerate valid loop-momentum bases for this diagram. |
momentum_basis |
Construct the canonical routing of the selected interaction region. |
numerator_expression |
Return the diagram numerator as a Spenso TensorExpression. |
numerator_prefactor_expression |
Return the request-wide numerator multiplier as a Symbolica expression. |
overall_factor_expression |
Return the diagram-wide multiplicative factor as a Symbolica expression |
projector_expression |
Return the external-state projector as a Symbolica expression. |
propagator_family |
Extract the physical propagators using the diagram’s stored momentum routing |
reduce_tensor_graphs |
Split the tensor numerator into scalar contributions on this topology |
reduce_tensor_numerator |
Reduce the finalized numerator and projector with a tensor reducer |
render |
Render an interactive, transparent SVG using the shared physics renderer |
subgraph |
Select graph elements using canonical Linnet IDs, or import a graph-bound selection |
superficial_degree_of_divergence |
Return the local superficial UV degree of divergence |
tensor_reduce |
Reduce the numerator and projector using the diagram’s internal edge momenta |
to_dot |
Serialize the diagram topology and annotations to Graphviz DOT text. |
to_html |
Render an HTML figure with the same options and hover information as render. |
to_json |
Serialize the complete diagram to JSON text. |
to_linnest |
Export a self-contained Typst document embedding the rendered SVG |
to_linnet |
Return the canonical installed Linnet graph with physics objects as payloads |
uv_counterterm |
Return the additive local UV counterterm, the negative of uv_expansion |
uv_expansion |
Expand the local integrand through its UV degree of divergence |
validate |
Validate particle and interaction references against a physics model. |
with_loop_momentum_edges |
Return a diagram using the specified loop-edge coordinates, in the supplied order. |
with_loop_momentum_tree_edges |
Return a diagram whose momentum routing uses the specified spanning forest. |
__repr__
FeynmanDiagram.__repr__() -> builtins.strReturn a concise description of the diagram and its loop count.
Examples
Using the setup in the FeynmanDiagram class example:
print(diagram)_repr_html_
FeynmanDiagram._repr_html_() -> builtins.strRender the diagram as HTML in Marimo, Jupyter, and IPython.
Examples
Using the setup in the FeynmanDiagram class example:
from IPython.display import display
display(diagram)_repr_pretty_
FeynmanDiagram._repr_pretty_(pretty: typing.Any, cycle: builtins.bool) -> NoneWrite a concise summary to an IPython pretty printer.
Examples
Using the setup in the FeynmanDiagram class example:
from IPython.lib.pretty import pretty
text = pretty(diagram)Parameters
pretty(Any) The IPython pretty-printer object.cycle(bool) Whether this object is part of a recursive formatting cycle.
_repr_svg_
FeynmanDiagram._repr_svg_() -> builtins.strReturn the raw SVG representation used by rich notebook frontends.
Examples
Using the setup in the FeynmanDiagram class example:
from IPython.display import display
display(diagram)all_bonds
FeynmanDiagram.all_bonds(
*,
min_size: typing.Optional[builtins.int] = None,
max_size: typing.Optional[builtins.int] = None,
) -> builtins.list[Subgraph]Enumerate minimal cutsets, independently of physical final-state cuts.
Examples
Using the setup in the FeynmanDiagram class example:
bonds = diagram.all_bonds(min_size=2, max_size=3)Parameters
min_size(int or None, optional) Minimum number of crossing edges.max_size(int or None, optional) Maximum number of crossing edges.
all_cuts
FeynmanDiagram.all_cuts(
source: typing.Sequence[builtins.int],
target: typing.Sequence[builtins.int],
) -> list[linnet.CutPartition]Enumerate separating partitions between disjoint interaction vertex groups.
Examples
Using the setup in the FeynmanDiagram class example:
partitions = diagram.all_cuts([0], [1])Parameters
source(list[int]) Canonical Linnet vertices required on the first side.target(list[int]) Canonical Linnet vertices required on the opposite side.
all_spanning_forests
FeynmanDiagram.all_spanning_forests() -> builtins.list[Subgraph]Enumerate spanning forests within the selected topology.
Examples
Using the setup in the FeynmanDiagram class example:
forests = diagram.all_spanning_forests()boundary
FeynmanDiagram.boundary() -> SubgraphReturn boundaries around the selected interaction region.
The current region determines which interaction boundaries are returned.
Examples
Using the setup in the FeynmanDiagram class example:
region = diagram.subgraph(nodes=[0])
boundary = region.boundary()breadth_first_traverse
FeynmanDiagram.breadth_first_traverse(
root: builtins.int,
*,
include: typing.Optional[builtins.int] = None,
) -> linnet.TraversalTreeTraverse a selected interaction region in breadth-first order.
Examples
Using the setup in the FeynmanDiagram class example:
tree = diagram.breadth_first_traverse(0)Parameters
root(int) Canonical Linnet vertex ID at which traversal starts.include(int or None, optional) Canonical Linnet half-edge ID to prioritize at the root.
bridges
FeynmanDiagram.bridges() -> SubgraphReturn lines whose removal disconnects the selection.
Examples
Using the setup in the FeynmanDiagram class example:
bridges = diagram.bridges()build_cff
FeynmanDiagram.build_cff(
*,
max_orientations: typing.Optional[builtins.int] = None,
fixed_orientations: typing.Optional[typing.Mapping[builtins.int, builtins.bool]] = None,
contracted_edges: typing.Optional[typing.Sequence[builtins.int]] = None,
initial_state_edges: typing.Optional[typing.Sequence[builtins.int]] = None,
) -> CffResultBuild the diagram’s Cross-Free Family representation.
Edge constraints use the stable integer IDs exposed by diagram.edges. False fixes an edge in its stored direction and True reverses it.
Examples
Using the setup in the FeynmanDiagram class example:
Construct and display the causal denominators of a one-loop diagram:
cff = diagram.build_cff(max_orientations=10_000)
cff.to_expression() # native Symbolica display in a notebookParameters
max_orientations(int or None, optional) Maximum number of candidate orientations to inspect.fixed_orientations(mapping[int, bool] or None, optional) Edge IDs mapped to stored (false) or reversed (true) directions.contracted_edges(iterable[int], optional) Edge IDs to contract before constructing denominator surfaces.initial_state_edges(iterable[int], optional) Edge IDs to classify as incoming external lines.
compatible_momentum_basis
FeynmanDiagram.compatible_momentum_basis(parent: LoopMomentumBasis) -> LoopMomentumBasisReuse a parent basis’s loop coordinates wherever the selected topology permits it.
Examples
Using the setup in the FeynmanDiagram class example:
basis = diagram.compatible_momentum_basis(diagram.loop_momentum_basis)Parameters
parent(LoopMomentumBasis) Parent coordinates belonging to this same diagram instance.
connected_components
FeynmanDiagram.connected_components() -> builtins.list[Subgraph]Return connected interaction regions as reusable selections.
Examples
Using the setup in the FeynmanDiagram class example:
components = diagram.connected_components()contracted_momentum_basis
FeynmanDiagram.contracted_momentum_basis(contracted: Subgraph | linnet.Subgraph) -> LoopMomentumBasisRoute the selected region after contracting complete internal edges.
Examples
Using the setup in the FeynmanDiagram class example:
contracted = diagram.filter(edge=lambda edge: edge.data.is_dummy)
basis = diagram.contracted_momentum_basis(contracted)Parameters
contracted(Subgraph or linnet.Subgraph) Complete internal edges to contract, selected from this diagram.
cycle_basis
FeynmanDiagram.cycle_basis() -> tuple[list[linnet.Cycle], Subgraph]Return a cycle basis and its covered half-edges.
Examples
Using the setup in the FeynmanDiagram class example:
cycles, covered = diagram.cycle_basis()denominator_expression
FeynmanDiagram.denominator_expression(
*,
edge_powers: typing.Optional[typing.Mapping[builtins.int, builtins.int]] = None,
dimension: typing.Optional[Expression | int | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | ComplexFloat | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | builtins.complex | tuple[Float | builtins.int | builtins.float | builtins.str | decimal.Decimal, Float | builtins.int | builtins.float | builtins.str | decimal.Decimal]] = None,
in_lmb: builtins.bool = False,
lmb: typing.Optional[LoopMomentumBasis] = None,
) -> TensorExpressionReturn the product of internal propagator denominators as a scalar TensorExpression.
Each factor retains GammaLoop’s four-argument denom annotation around q_e² - m_e², with matching momentum labels and symbolic masses. Dimension defaults to GammaLoop’s symbolic dimension; powers may be signed. The default region excludes external carriers and dummy edges. An explicit region follows GammaLoop and includes every complete selected edge. Widths, an imaginary prescription, and custom UFO denominator formulas are excluded. A selection without internal edges returns one.
Examples
Using the setup in the FeynmanDiagram class example:
denominator = diagram.denominator_expression(in_lmb=True)
integrand = diagram.numerator_expression(in_lmb=True) / denominator
basis = diagram.loop_momentum_bases()[0]
denominator = diagram.denominator_expression(lmb=basis)Parameters
A complete diagram defaults to internal propagators; a Subgraph uses its region.edge_powers(mapping[int, int] or None, optional) Signed propagator powers by diagram edge ID; omitted edges have power one.dimension(Expression or int or None, optional) Lorentz dimension; defaults to the shared symbolic dimension.in_lmb(bool, optional) Express edge momenta in the diagram’s stored loop-momentum basis.lmb(LoopMomentumBasis or None, optional) Basis from this diagram instance. Supplying it enables routing and takes precedence overin_lmb, including for a selected region.
depth_first_traverse
FeynmanDiagram.depth_first_traverse(
root: builtins.int,
*,
include: typing.Optional[builtins.int] = None,
) -> linnet.TraversalTreeTraverse a selected interaction region in depth-first order.
Examples
Using the setup in the FeynmanDiagram class example:
tree = diagram.depth_first_traverse(0)Parameters
root(int) Canonical Linnet vertex ID at which traversal starts.include(int or None, optional) Canonical Linnet half-edge ID to prioritize at the root.
filter
FeynmanDiagram.filter(
*,
node: typing.Callable[[linnet.Node], bool] | None = None,
edge: typing.Callable[[linnet.Edge], bool] | None = None,
half_edge: typing.Callable[[linnet.HalfEdge], bool] | None = None,
) -> SubgraphSelect by predicates on Linnet views; their data is a physics object.
Examples
Using the setup in the FeynmanDiagram class example:
region = diagram.filter(edge=lambda edge: edge.data.particle_name == "g")Parameters
node(callable or None, optional) Predicate on canonical Linnet node views.edge(callable or None, optional) Predicate on canonical Linnet edge views.half_edge(callable or None, optional) Predicate on canonical Linnet half-edge views.
from_dot
FeynmanDiagram.from_dot(model: Model, dot: builtins.str) -> FeynmanDiagramParse a Feynman diagram from Graphviz DOT text.
Examples
Using the setup in the FeynmanDiagram class example:
dot = diagram.to_dot()
restored = hep.FeynmanDiagram.from_dot(model, dot)
restored.validate()
restored # preserve topology through a Graphviz workflowParameters
model(Model) Model used to resolve particles and interactions or validate annotated IDs.dot(str) Compact physics DOT or annotated HEP DOT. Compact cross-sections pair initial-state legs with is_cut and specify comma-separated final_state particles.
from_json
FeynmanDiagram.from_json(model: Model, json: builtins.str) -> FeynmanDiagramDeserialize a Feynman diagram from its JSON representation.
Examples
Using the setup in the FeynmanDiagram class example:
encoded = diagram.to_json()
restored = hep.FeynmanDiagram.from_json(model, encoded)
restored.validate()
restored # render the recovered graph in a notebookParameters
model(Model) Model whose stable IDs and fingerprint are referenced by the diagram.json(str) JSON text produced by :meth:FeynmanDiagram.to_jsonor another schema-compatible producer.
integral_family
FeynmanDiagram.integral_family(
independent_dot_products: typing.Optional[typing.Sequence[Expression]] = None,
*,
kinematics: typing.Optional[Kinematics] = None,
) -> IntegralFamilyBuild a complete integral family with preferred or automatic ISPs.
Physical propagators retain their edge order and model masses. Preferred independent dot products are appended when they increase the rank; automatic scalar products fill any remaining directions. Auxiliary entries have zero powers in the original scalar integral. Equivalent to IntegralFamily.from_diagram(self, independent_dot_products, kinematics=kinematics). Tree diagrams and dependent propagators raise DiagramError. Use propagator_family() to extract dependent propagators for partial fractioning before completing their families.
Examples
Using the setup in the FeynmanDiagram class example:
family = diagram.integral_family()Parameters
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.
is_connected
FeynmanDiagram.is_connected() -> builtins.boolTest connectivity of the current diagram or selected region.
Examples
Using the setup in the FeynmanDiagram class example:
connected = diagram.is_connected()loop_momentum_bases
FeynmanDiagram.loop_momentum_bases(limit: typing.Optional[builtins.int] = None) -> builtins.list[LoopMomentumBasis]Enumerate valid loop-momentum bases for this diagram.
Examples
Using the setup in the FeynmanDiagram class example:
Limit exploratory calculations to the first basis:
basis = diagram.loop_momentum_bases(limit=1)[0]
routing = {
edge_id: signature.format_momentum()
for edge_id, signature in basis.edge_signatures.items()
}Parameters
limit(int or None) Maximum number of bases to return. PassNoneto enumerate every valid basis.
momentum_basis
FeynmanDiagram.momentum_basis() -> LoopMomentumBasisConstruct the canonical routing of the selected interaction region.
Examples
Using the setup in the FeynmanDiagram class example:
basis = diagram.momentum_basis()
routed = basis.route_expression(diagram.numerator_expression())numerator_expression
FeynmanDiagram.numerator_expression(
*,
without: Subgraph | linnet.Subgraph | None = None,
in_lmb: builtins.bool = False,
lmb: typing.Optional[LoopMomentumBasis] = None,
) -> TensorExpressionReturn the diagram numerator as a Spenso TensorExpression.
Examples
Using the setup in the FeynmanDiagram class example:
numerator = diagram.numerator_expression(in_lmb=True)
basis = diagram.loop_momentum_bases()[0]
numerator = diagram.numerator_expression(lmb=basis)
integrand_numerator = diagram.overall_factor_expression() * numerator
integrand_numerator # native Symbolica algebra and rich displayParameters
without(Subgraph or linnet.Subgraph or None, optional) Ignored region, using GammaLoop boundary and local-factor selection semantics.in_lmb(bool, optional) Express edge momenta in the diagram’s stored loop-momentum basis.lmb(LoopMomentumBasis or None, optional) Basis from this diagram instance. Supplying it enables routing and takes precedence overin_lmb, including for a selected region.
numerator_prefactor_expression
FeynmanDiagram.numerator_prefactor_expression() -> ExpressionReturn the request-wide numerator multiplier as a Symbolica expression.
Examples
Using the setup in the FeynmanDiagram class example:
prefactor = diagram.numerator_prefactor_expression()
weighted_numerator = prefactor * diagram.numerator_expression()
weighted_numeratoroverall_factor_expression
FeynmanDiagram.overall_factor_expression(*, evaluate: builtins.bool = False) -> ExpressionReturn the diagram-wide multiplicative factor as a Symbolica expression.
evaluate=True evaluates the generator’s sign, multiplicity and symmetry annotations using the shared graph-factor evaluator. Other symbolic factors remain unchanged.
Examples
Using the setup in the FeynmanDiagram class example:
factor = diagram.overall_factor_expression()
weighted_numerator = factor * diagram.numerator_expression()
weighted_numeratorParameters
evaluate(bool) Evaluate known graph-factor annotations while preserving other symbols.
projector_expression
FeynmanDiagram.projector_expression() -> ExpressionReturn the external-state projector as a Symbolica expression.
Examples
Using the setup in the FeynmanDiagram class example:
projector = diagram.projector_expression()
projected_numerator = projector * diagram.numerator_expression()
projected_numeratorpropagator_family
FeynmanDiagram.propagator_family(
*,
kinematics: typing.Optional[Kinematics] = None,
) -> IntegralFamilyExtract the physical propagators using the diagram’s stored momentum routing.
Reuses the shared propagator builder and model masses. Denominators follow ascending internal edge IDs, as in internal_edges, retaining bridges and repeated propagators. Dependent external coordinates are eliminated; external carriers and dummy edges are excluded. Widths, prescriptions and custom UFO denominator formulas are not inferred. Tree diagrams raise DiagramError because they contain no loop integral. Use diagram.integral_family() to also complete the basis with automatic or explicitly chosen auxiliary scalar products.
Examples
Using the setup in the FeynmanDiagram class example:
family = diagram.propagator_family()
assert len(family.denominators) == len(diagram.internal_edges)Parameters
kinematics(Kinematics or None, optional) Assumptions on routed momentum names and the Lorentz dimension. None uses the shared symbolic dimension with no on-shell assumptions.
reduce_tensor_graphs
FeynmanDiagram.reduce_tensor_graphs(reducer: TensorReducer) -> builtins.list[FeynmanDiagram]Split the tensor numerator into scalar contributions on this topology.
Each returned diagram has one compact reduction term as its numerator, including that term’s exact projector coefficient. The graph topology, model, denominator data, and topology ID are preserved; deterministic .tensor[index] name suffixes distinguish the derived contributions. The external-state projector is consumed and reset to one, while the scalar numerator prefactor is retained. The projection must be fully contracted: any residual indexed Minkowski slot raises TensorReductionError. Use :meth:reduce_tensor_numerator when residual free Lorentz indices are intentional.
Examples
Construct scalar numerator graphs for a vacuum diagram:
from symbolica import S, E
from symbolica.community import hepkit as hep
model = hep.Model.phi4()
vacuum_diagram = model.process([], []).generate_diagrams(loops=2, factorized_loop_topologies_count_range=None).diagrams[0]
reducer = hep.TensorReducer(E("4"), integrated=[E("gammalooprs::Q")])
scalar_graphs = vacuum_diagram.reduce_tensor_graphs(reducer)Parameters
reducer(TensorReducer) Tensor projector and integrated-momentum selection to apply.
reduce_tensor_numerator
FeynmanDiagram.reduce_tensor_numerator(reducer: TensorReducer) -> ExpressionReduce the finalized numerator and projector with a tensor reducer.
The result is a native Symbolica expression using spenso::dot and spenso::g. For a fully projected vacuum numerator, all Lorentz indices disappear and only scalar invariants remain. Residual free projector indices are preserved as metric tensors; use :meth:reduce_tensor_graphs when scalar graph contributions are required. The scalar numerator prefactor remains separate and is not included in this expression.
Examples
Reduce a vacuum graph after explicitly selecting its integrated momentum head:
from symbolica import S, E
from symbolica.community import hepkit as hep
model = hep.Model.phi4()
vacuum_diagram = model.process([], []).generate_diagrams(loops=2, factorized_loop_topologies_count_range=None).diagrams[0]
reducer = hep.TensorReducer(E("4"), integrated=[E("gammalooprs::Q")])
scalar_numerator = vacuum_diagram.reduce_tensor_numerator(reducer)Parameters
reducer(TensorReducer) Tensor projector and integrated-momentum selection to apply.
render
FeynmanDiagram.render(
*,
config: builtins.dict[builtins.str, typing.Any] | None = None,
momenta: builtins.bool = False,
lmb: typing.Optional[LoopMomentumBasis] = None,
highlight: Subgraph | linnet.Subgraph | None = None,
) -> builtins.strRender an interactive, transparent SVG using the shared physics renderer.
All graph geometry is drawn in Rust; the embedded Typst compiler typesets labels and titles. layouts={"impred_labels": True} refines the layout around the drawn labels. No Python renderer or Typst graph package is needed.
Examples
Using the setup in the FeynmanDiagram class example:
svg = diagram.render(momenta=True, config={
"layouts": {"impred_steps": 100},
"template_options": {"show-particle": False},
})
svg = diagram.render(lmb=next(iter(diagram.loop_momentum_bases())))Parameters
config(dict or None, optional) Nativelayouts,drawingandstyledictionaries. Boolean physics controls intemplate_optionsincludeshow-particle,show-momentum,show-edge-index,show-node-index,debug, andmomentum-arrows. Cross sections open their initial-state connections by default; setsplit-initial-statetoFalseto draw the sewn graph.momenta(bool, optional) Show momentum arrows and labels routed in the diagram’s stored basis. Explicit physics settings inconfigoverride these display defaults.lmb(LoopMomentumBasis or None, optional) Explicit routing from this diagram; also enables momentum display. Rendering never changes the diagram’s stored loop-momentum basis.highlight(Subgraph or linnet.Subgraph or None, optional) Highlight a region while preserving the full diagram as muted context. A Subgraph highlights its own region by default.
subgraph
FeynmanDiagram.subgraph(
selection: Subgraph | linnet.Subgraph | None = None,
*,
nodes: typing.Optional[typing.Sequence[builtins.int]] = None,
edges: typing.Optional[typing.Sequence[builtins.int]] = None,
half_edges: typing.Optional[typing.Sequence[builtins.int]] = None,
) -> SubgraphSelect graph elements using canonical Linnet IDs, or import a graph-bound selection. Nested selections intersect this region and retain its immutable original diagram.
Examples
Using the setup in the FeynmanDiagram class example:
region = diagram.subgraph(edges=[0, 1])
numerator = region.numerator_expression()Parameters
selection(Subgraph or linnet.Subgraph or None, optional) Existing selection from the same original diagram; exclusive with element IDs.nodes(list[int] or None, optional) Canonical Linnet nodes IDs to include.edges(list[int] or None, optional) Canonical Linnet edges IDs to include.half_edges(list[int] or None, optional) Canonical Linnet half-edges IDs to include.
superficial_degree_of_divergence
FeynmanDiagram.superficial_degree_of_divergence(*, dimension: builtins.int = 4) -> builtins.intReturn the local superficial UV degree of divergence.
Counts dimension * loops plus vertex momentum powers and internal propagator numerator powers minus two per internal propagator. Uses the stored local numerators; excludes external legs, projectors, and global prefactors. Vertex momenta scale together, before tensor cancellations. Zero is logarithmic, positive is power divergent, and negative is superficially convergent. Subdivergences are not tested.
Examples
Using the setup in the FeynmanDiagram class example:
degree = diagram.superficial_degree_of_divergence()
degree_in_six_dimensions = diagram.superficial_degree_of_divergence(dimension=6)Parameters
dimension(int, optional) Spacetime dimension for each loop integration measure; defaults to four.
tensor_reduce
FeynmanDiagram.tensor_reduce(
dimension: Expression | int | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | ComplexFloat | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | builtins.complex | tuple[Float | builtins.int | builtins.float | builtins.str | decimal.Decimal, Float | builtins.int | builtins.float | builtins.str | decimal.Decimal],
*,
expression: symbolica.Expression | symbolica.community.tensor.TensorExpression | None = None,
projector: typing.Optional[Expression | int | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | ComplexFloat | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | builtins.complex | tuple[Float | builtins.int | builtins.float | builtins.str | decimal.Decimal, Float | builtins.int | builtins.float | builtins.str | decimal.Decimal]] = None,
) -> TensorExpressionReduce the numerator and projector using the diagram’s internal edge momenta.
Four-dimensional Lorentz slots are promoted to D before reduction. External momenta remain projector vectors, and the scalar numerator prefactor remains separate. Requires at least one internal edge. A supplied expression replaces the numerator and projector, for example after a UV expansion; it must use the diagram’s edge momentum names.
Examples
Using the setup in the FeynmanDiagram class example:
from symbolica import E
reduced = diagram.tensor_reduce(E("D"))Parameters
dimension(Expression or int) Lorentz dimension used for the reduction and four-dimensional input slots.expression(Expression or TensorExpression, optional) Complete prepared input to reduce instead of the numerator and projector. Cannot be combined with an explicit projector.projector(Expression or None, optional) Explicit external tensor projector, required for partial regions unless expression is supplied.
to_dot
FeynmanDiagram.to_dot() -> builtins.strSerialize the diagram topology and annotations to Graphviz DOT text.
Examples
Using the setup in the FeynmanDiagram class example:
dot = diagram.to_dot()
restored = hep.FeynmanDiagram.from_dot(model, dot)
restored.validate()to_html
FeynmanDiagram.to_html(
*,
config: builtins.dict[builtins.str, typing.Any] | None = None,
momenta: builtins.bool = False,
lmb: typing.Optional[LoopMomentumBasis] = None,
highlight: Subgraph | linnet.Subgraph | None = None,
) -> builtins.strRender an HTML figure with the same options and hover information as render.
Examples
Using the setup in the FeynmanDiagram class example:
import marimo as mo
mo.iframe(diagram.to_html(momenta=True))Parameters
config(dict or None, optional) Layout, drawing, style and physics settings, as inrender.momenta(bool, optional) Draw momentum arrows and labels in the stored basis.lmb(LoopMomentumBasis or None, optional) Routing from this diagram; also enables momentum display.highlight(Subgraph or linnet.Subgraph or None, optional) Region to highlight in the complete diagram.
to_json
FeynmanDiagram.to_json() -> builtins.strSerialize the complete diagram to JSON text.
Examples
Using the setup in the FeynmanDiagram class example:
encoded = diagram.to_json()
restored = hep.FeynmanDiagram.from_json(model, encoded)
restored.validate()to_linnest
FeynmanDiagram.to_linnest(
*,
config: builtins.dict[builtins.str, typing.Any] | None = None,
momenta: builtins.bool = False,
lmb: typing.Optional[LoopMomentumBasis] = None,
highlight: Subgraph | linnet.Subgraph | None = None,
) -> builtins.strExport a self-contained Typst document embedding the rendered SVG.
Uses the same config, momenta, lmb and highlight settings as render. Labels are already typeset; compiling the exported source needs no Linnest, Kurvst, MiTeX, or model assets.
Examples
Using the setup in the FeynmanDiagram class example:
from pathlib import Path
Path("diagram.typ").write_text(diagram.to_linnest(momenta=True))Parameters
config(dict or None, optional) Layout, drawing, style and physics settings, as inrender.momenta(bool, optional) Draw momentum arrows and labels in the stored basis.lmb(LoopMomentumBasis or None, optional) Routing from this diagram; also enables momentum display.highlight(Subgraph or linnet.Subgraph or None, optional) Region to highlight in the complete diagram.
to_linnet
FeynmanDiagram.to_linnet() -> linnet.GraphReturn the canonical installed Linnet graph with physics objects as payloads.
Node, edge, and half-edge identities are mapped explicitly. Structural edits affect this analysis graph only; the next export starts a fresh graph, and selections from the modified topology cannot be used here.
Examples
Using the setup in the FeynmanDiagram class example:
graph = diagram.to_linnet()
gluons = graph.filter(edge=lambda edge: edge.data.particle_name == "g")uv_counterterm
FeynmanDiagram.uv_counterterm(
uv_mass: Expression | int | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | ComplexFloat | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | builtins.complex | tuple[Float | builtins.int | builtins.float | builtins.str | decimal.Decimal, Float | builtins.int | builtins.float | builtins.str | decimal.Decimal],
*,
dimension: builtins.int = 4,
numerator: symbolica.Expression | symbolica.community.tensor.TensorExpression | None = None,
edge_powers: typing.Optional[typing.Mapping[builtins.int, builtins.int]] = None,
) -> TensorExpressionReturn the additive local UV counterterm, the negative of uv_expansion.
Arguments and selection semantics are those of :meth:uv_expansion. Add this unintegrated expression to the selected integrand to subtract its simultaneous UV limit. Subdivergences require separate forest terms.
Examples
Using the setup in the FeynmanDiagram class example:
from symbolica import S
mass = S("mUV", is_scalar=True)
counterterm = diagram.uv_counterterm(mass)Parameters
uv_mass(Expression or int) Auxiliary mass used for the propagator expansion.dimension(int, optional) Positive spacetime dimension for UV power counting; defaults to four.numerator(Expression or TensorExpression or None, optional) Prepared numerator in edge momenta; None uses the selected local numerator.edge_powers(mapping[int, int] or None, optional) Signed propagator powers by diagram edge ID; omitted edges have power one. Zero omits the denominator; negative powers put it in the numerator. Entries outside the selected internal edges are ignored.
uv_expansion
FeynmanDiagram.uv_expansion(
uv_mass: Expression | int | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | ComplexFloat | Float | builtins.int | builtins.float | builtins.str | decimal.Decimal | builtins.complex | tuple[Float | builtins.int | builtins.float | builtins.str | decimal.Decimal, Float | builtins.int | builtins.float | builtins.str | decimal.Decimal],
*,
dimension: builtins.int = 4,
numerator: symbolica.Expression | symbolica.community.tensor.TensorExpression | None = None,
edge_powers: typing.Optional[typing.Mapping[builtins.int, builtins.int]] = None,
) -> TensorExpressionExpand the local integrand through its UV degree of divergence.
The selected region’s loop momenta are scaled together. Propagators are expanded about the auxiliary mass uv_mass, retaining every power through logarithmic divergence in dimension spacetime dimensions. The result uses edge momenta and the same tagged denom convention as :meth:denominator_expression; the diagram is unchanged.
numerator optionally replaces the local numerator (in edge momenta), for example after contracting a projector. Overall factors, numerator prefactors and projectors remain separate unless supplied in it. edge_powers uses the signed powers of :meth:denominator_expression. Move rational propagator factors out of a prepared numerator into these powers so they receive the same auxiliary-mass expansion. Powers do not change the selected region or its loop integration measure. Empty, tree and UV-convergent regions return zero. This performs one UV limit; it does not enumerate forests or integrate the counterterm.
Examples
Using the setup in the FeynmanDiagram class example:
expanded = diagram.uv_expansion(0)
expansion = expanded # symbolic Taylor-expanded integrandParameters
uv_mass(Expression or int) Auxiliary mass used for the propagator expansion.dimension(int, optional) Positive spacetime dimension for UV power counting; defaults to four.numerator(Expression or TensorExpression or None, optional) Prepared numerator in edge momenta; None uses the selected local numerator.edge_powers(mapping[int, int] or None, optional) Signed propagator powers by diagram edge ID; omitted edges have power one. Zero omits the denominator; negative powers put it in the numerator. Entries outside the selected internal edges are ignored.
validate
FeynmanDiagram.validate() -> NoneValidate particle and interaction references against a physics model.
Examples
Using the setup in the FeynmanDiagram class example:
Validation raises DiagramError for invalid particle or interaction references:
diagram.validate()with_loop_momentum_edges
FeynmanDiagram.with_loop_momentum_edges(edges: typing.Sequence[builtins.int]) -> FeynmanDiagramReturn a diagram using the specified loop-edge coordinates, in the supplied order.
Examples
Using the setup in the FeynmanDiagram class example:
rerouted = diagram.with_loop_momentum_edges(diagram.loop_momentum_basis.loop_edges)Parameters
edges(list[int]) Diagram edge IDs specifying the requested routing coordinates.
with_loop_momentum_tree_edges
FeynmanDiagram.with_loop_momentum_tree_edges(edges: typing.Sequence[builtins.int]) -> FeynmanDiagramReturn a diagram whose momentum routing uses the specified spanning forest.
Examples
Using the setup in the FeynmanDiagram class example:
rerouted = diagram.with_loop_momentum_tree_edges(diagram.loop_momentum_basis.tree_edges)Parameters
edges(list[int]) Diagram edge IDs specifying the requested routing coordinates.