Contraction Semantics¶
This document describes the label-based contraction model used in Tenax.
Overview¶
Tenax contracts tensors using shared string labels rather than explicit einsum subscript strings. Two tensors that carry the same label on one of their legs are automatically contracted over that pair of legs. This is identical in spirit to the Cytnx / ITensor interface.
Label Rules¶
Rule |
Description |
|---|---|
Shared label → contraction |
Any label that appears on exactly two tensors (or twice within one tensor) is contracted. |
Free label → output leg |
A label that appears on exactly one tensor leg in the full set of operands becomes a free (open) index in the result. |
Label multiplicity > 2 → error |
A label appearing on three or more legs raises |
contract(*tensors, output_labels, optimize)¶
from tenax import contract
result = contract(t1, t2, t3, output_labels=["a", "c"], optimize="auto")
Arguments
*tensors— One or moreTensorobjects (DenseTensororSymmetricTensor).output_labels— Optional list of free labels that determines the leg order of the result tensor. IfNone, free labels appear in the order they are first encountered while scanning tensor indices left-to-right.optimize— opt_einsum path optimizer ("auto","greedy","optimal", etc.). Defaults to"auto".
Return value — A single DenseTensor whose legs correspond to all free labels.
How labels become subscripts¶
Internally, _labels_to_subscripts() in contraction/contractor.py assigns a
unique single-character symbol to each distinct label, then builds the standard
opt_einsum expression. The mapping is ephemeral (not exposed to users) and
changes each call.
t1 labels: ["a", "b"] → subscript "ab"
t2 labels: ["b", "c"] → subscript "bc"
shared: {"b"} → contracted
free: {"a", "c"} → output "ac" (or "ca" if output_labels=["c","a"])
opt_einsum finds the optimal pairwise contraction order for the given operands before JAX executes any computation.
TensorNetwork.contract(nodes, output_labels, optimize, cache)¶
When tensors are stored in a TensorNetwork, contraction is done via the
network object:
tn = TensorNetwork()
tn.add_node("A", t1)
tn.add_node("B", t2)
result = tn.contract(nodes=["A", "B"], output_labels=["a", "c"])
Cache behaviour
Results are cached by the key (tuple(nodes), tuple(output_labels), optimize).
Node order matters: when output_labels is None, the output leg order depends
on the order nodes are listed. The cache is invalidated automatically whenever the
graph structure changes (node added/removed, edge added/removed, tensor replaced).
Two calls with the same nodes but different output_labels or different optimize
strings receive independent cache entries.
truncated_svd(tensor, left_labels, right_labels, ...)¶
SVD splits a tensor into U, S, Vh, S_full with an optional truncation of
singular values:
U, S, Vh, S_full = truncated_svd(
theta,
left_labels=["v0_1", "p0"],
right_labels=["p1", "v1_2"],
new_bond_label="v0_2",
max_singular_values=chi,
)
left_labels— Legs ofthetathat go ontoU.right_labels— Legs ofthetathat go ontoVh.new_bond_label— Label for the new shared bond betweenUandVh.max_singular_values— Hard cap on bond dimension (discards smallest singular values).max_truncation_err— Discard singular values until cumulative truncation error exceeds this threshold (whichever is more restrictive withmax_singular_values).
S contains the truncated singular values in descending order. S_full
contains all singular values before truncation, useful for computing truncation
error without a second SVD.
qr_decompose(tensor, left_labels, right_labels, new_bond_label)¶
Thin QR decomposition. The orthogonality column of Q corresponds to
left_labels; R carries right_labels. Used in MPS right-canonicalization.
Label Conventions in DMRG¶
Object |
Label pattern |
|---|---|
MPS virtual bond between sites i and i+1 |
|
MPS physical leg at site i |
|
MPO virtual bond between sites i and i+1 |
|
MPO physical ket leg at site i |
|
MPO physical bra leg at site i |
|
Left environment legs |
|
Right environment legs |
|
Design Rationale¶
Why label-based? Explicit einsum subscript management becomes error-prone as
networks grow. Labels self-document which physical degrees of freedom are being
contracted (virtual bond vs. physical leg vs. MPO bond), and the label-to-subscript
translation is handled once inside _labels_to_subscripts().
Why opt_einsum? For networks with more than two tensors, the contraction order dominates the computational cost. opt_einsum finds an order that minimises the intermediate tensor size (flops), whereas naive left-to-right pairwise contraction can be exponentially worse.
Pairwise-only enforcement (no trace mode): labels appearing more than twice raise an error immediately. This prevents silent incorrect results when a label is accidentally reused.