Skip to content

[WIP] Rework NamedTensorOperator around output/input pairing#222

Draft
mtfishman wants to merge 3 commits into
mainfrom
mf/operator-input-output
Draft

[WIP] Rework NamedTensorOperator around output/input pairing#222
mtfishman wants to merge 3 commits into
mainfrom
mf/operator-input-output

Conversation

@mtfishman

@mtfishman mtfishman commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

Reworks NamedTensorOperator to describe an operator as a wrapped tensor plus a pairing of its dimension names into an output side and an input side, renaming the codomainnames/domainnames accessors to outputnames/inputnames. The rename frees codomain/domain for 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 linear findfirst, which is faster than hashing for the handful of paired legs an operator carries and drops the OrderedCollections dependency. outputname/inputname look up a wire's other end, with a three-argument get-style form that returns a supplied default when a name is unpaired (so a caller can write inputname(op, i, i) for "the other end of the wire, or i itself") and a two-argument form that throws instead.

apply(x, y) applies x to y, landing x's inputs on y's outputs (or a plain state's legs) and relabeling each consumed output of x back to its input, so the result sits on x'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 of x tensored in. check_apply rejects landing an input of x on an input of y. apply_dag is removed, since the dagger application is apply(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 into check_product: a wire of a and a wire of b must 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/noprime survive only as name generators for constructing operators, and any pair of distinct names describes a wire equally well.

TODO

  • Check for and migrate downstream users of the renamed codomainnames/domainnames accessors.

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.
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.25000% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.67%. Comparing base (a0e9e98) to head (28ae714).

Files with missing lines Patch % Lines
src/namedtensoroperator.jl 81.25% 18 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #222      +/-   ##
==========================================
- Coverage   76.13%   73.67%   -2.46%     
==========================================
  Files          29       28       -1     
  Lines        1697     1683      -14     
==========================================
- Hits         1292     1240      -52     
- Misses        405      443      +38     
Flag Coverage Δ
docs 26.26% <23.15%> (-0.49%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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)`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant