Rework NamedTensorOperator around output/input pairing#222
Merged
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #222 +/- ##
==========================================
+ Coverage 76.90% 77.23% +0.32%
==========================================
Files 29 29
Lines 1706 1713 +7
==========================================
+ Hits 1312 1323 +11
+ Misses 394 390 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Rename the operator's dimension-name accessors from codomainnames/domainnames to outputnames/inputnames, and store the pairing as two equal-length name vectors over the wrapped tensor instead of a Bijection (linear findfirst is faster than hashing for the few paired legs an operator carries, and it drops the OrderedCollections dependency). Add outputname/inputname get-style wire lookups, express apply as a contraction followed by an output-to-input relabel, and define product as composition on matching sites, gated by check_product.
Add two-argument `outputname(a, i)` / `inputname(a, i)` that return the paired name and throw a clear `ArgumentError` when `i` is unpaired, alongside the three-argument get-style forms that return a supplied default.
Rework `apply` so applying an operator to another operator returns an operator: `x`'s inputs land on `y`'s outputs, each consumed output of `x` is relabeled back to its input, and uncontracted structure passes through, with a disjoint part of `x` tensored in. Applying to a bare state still returns a state, and `check_apply` rejects landing an input of `x` on an input of `y`. Remove `apply_dag`, which was unused. The dagger application is `apply(adjoint(x), y)`.
The Hermitian square-root operator forms (`project_hermitian`, `sqrth_safe`, `invsqrth_safe`, `sqrth_invsqrth_safe`) landed on `main` after this branch and still used the old `codomainnames`/`domainnames` accessors. Rename them to `outputnames`/`inputnames` so they resolve against the reworked operator interface.
mtfishman
force-pushed
the
mf/operator-input-output
branch
from
July 20, 2026 22:31
2c39c72 to
f0a11b3
Compare
The operator methods return a `Vector{DimName}`, so the plain-tensor fallback
returning a tuple was inconsistent. Return `DimName[]` so both always give a
Vector, and drop the now-redundant `collect` from the accessor docstrings.
`apply`'s `See also` linked `[`product`](@ref)`, but `product` is internal (unexported and undocumented), so Documenter cannot resolve the reference and the docs build fails. Remove it. The remaining `See also` links all point to documented names.
mtfishman
marked this pull request as ready for review
July 21, 2026 18:21
mtfishman
enabled auto-merge (squash)
July 21, 2026 18:21
mtfishman
added a commit
to ITensor/ITensorNetworksNext.jl
that referenced
this pull request
Jul 21, 2026
## Summary Builds ITensorNetworksNext against ITensorBase v0.13 (ITensor/ITensorBase.jl#222), which reworks `NamedTensorOperator` around an output/input name pairing. Renames the `domainnames` accessor to `inputnames` in the belief-propagation apply path. The Ising-network generator inserted each bond matrix with `apply` on an operator whose shared leg was its output. The reworked `apply` preserves a state's names and only contracts an operator's input, so it now rejects that usage. The old `apply` had degraded to a plain contraction in that case anyway, so this replaces it with the direct named contraction it was really doing, leaving the generated network and the Ising free-energy checks unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks
NamedTensorOperatorto describe an operator as a wrapped tensor plus a pairing of its dimension names into an output side and an input side, renaming thecodomainnames/domainnamesaccessors tooutputnames/inputnames. The rename freescodomain/domainfor the tensor's own structural split, which is separate from the operator's output/input pairing.The pairing is now stored as two equal-length name vectors over the wrapped tensor instead of a
Bijection. Lookups are a linearfindfirst, which is faster than hashing for the handful of paired legs an operator carries and drops theOrderedCollectionsdependency.outputname/inputnamelook up a wire's other end, with a three-argumentget-style form that returns a supplied default when a name is unpaired (so a caller can writeinputname(op, i, i)for "the other end of the wire, oriitself") and a two-argument form that throws instead.apply(x, y)appliesxtoy, landingx's inputs ony's outputs (or a plain state's legs) and relabeling each consumed output ofxback to its input, so the result sits onx's input space. Applying an operator to a state gives a state and applying it to another operator gives an operator, with a disjoint part ofxtensored in.check_applyrejects landing an input ofxon an input ofy.apply_dagis removed, since the dagger application isapply(adjoint(x), y).product(a, b)composes operators on matching sites: a name that is an input of both operands is welded through a fresh bond so the site composes, while dangling names such as batch and Kraus dimensions contract the way*contracts them. The rule that keeps a product well defined is factored intocheck_product: a wire ofaand a wire ofbmust either be the same wire, which welds, or share no name, which stays independent. Connecting two operators end to end through a shared bond is left to*, which already returns the composed operator.Priming is demoted from a pairing mechanism to a naming convenience. The pairing is explicit data, so
prime/noprimesurvive only as name generators for constructing operators, and any pair of distinct names describes a wire equally well.