Skip to content

Name-based index-set algebra, whole-tensor index ops, and the id/uuid rename#213

Merged
mtfishman merged 15 commits into
mainfrom
mf/nextgen-followups-round1
Jul 10, 2026
Merged

Name-based index-set algebra, whole-tensor index ops, and the id/uuid rename#213
mtfishman merged 15 commits into
mainfrom
mf/nextgen-followups-round1

Conversation

@mtfishman

@mtfishman mtfishman commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

A batch of next-generation index and identity utilities for AbstractNamedTensor, plus one breaking rename. Builds on the TensorAlgebra additions in ITensor/TensorAlgebra.jl#205 (TensorAlgebra 0.17.1).

  • Name-based index-set algebra: commoninds/uniqueinds/unioninds/noncommoninds/hascommoninds, the singular commonind/uniqueind, and the non-erroring trycommonind/trynoncommonind. Indices match by name, and NamedUnitRange equality is now dual-insensitive, so a shared bond matches even when one tensor carries its dual.
  • Whole-tensor index ops: prime, noprime, and sim relabel every index of a tensor.
  • Identity and trace: id(elt, codomain, domain) builds the identity operator from indices and an element type alone, and tr traces a named tensor viewed as a codomain/domain map. Both rest on a map-shaped similar(a, codomain, domain) that follows the tensor's backend and takes its axes as any iterable.
  • Matricize: the positional matricize(a, codomain, domain) fuses two dimension groups into a matrix and generates fresh names for the fused dimensions, next to the pair form that takes explicit names. Both forms accept any iterable of dimensions per group.
  • svd_trunc now returns the truncation error as a fourth output, matching the matrix-level primitive.
  • Smaller fixes: a clearer error when building a tensor from a single named range, index-keyed pairs in replacedimnames, and trivialrange for a NamedUnitRange.

Breaking: the unique-identifier accessor on an index or index name is renamed from id to uuid, freeing id for the identity constructor.

mtfishman added 6 commits July 8, 2026 14:34
…runc ϵ, trivialrange for named ranges

Bugfixes and additive index utilities. `ITensor(array, Index-tuple)` now throws
with guidance toward `array[i, j]` and `ITensor(array, name.((i, j)))` instead of
silently mis-constructing. `replacedimnames` accepts `Index` keys by stripping to
the dimname. `svd_trunc` returns the truncation error `ϵ` as a fourth output. And
`trivialrange(::NamedUnitRange)` mints a fresh trivial named range on the same
backend.
…replaceinds, rank-0 similar/one

Whole-tensor index manipulation on `AbstractNamedTensor`. `mapinds(f, t)` relabels
every index name-only (leaving the space untouched), with `prime(t)`, `noprime(t)`,
and `sim(t)` built on it. `replaceinds` becomes a name-only relabel, a synonym for
`replacedimnames`, and `sim(i)` mints a fresh id preserving tags and prime level.
`similar(a, ())` and `one(a)` give a rank-0 scalar tensor on `a`'s backend.
Adds `commoninds`, `uniqueinds`, `unioninds`, `noncommoninds`, and `hascommoninds` on `AbstractNamedTensor`, along with the singular `commonind`/`uniqueind` and their non-erroring `trycommonind`/`trynoncommonind` counterparts. Indices are compared by name, so a shared bond matches even when the two tensors carry it as an index on one and its dual on the other.
The function form of `replaceinds`/`mapinds` forwarded straight to `replacedimnames`, so its `f` received a dimension name rather than the index its docstring describes. Apply `f` to each index instead, relabeling name-only through the pair form, so `replaceinds`/`mapinds` are the index-level counterpart of the name-level `replacedimnames`/`mapdimnames`.
…ity constructor

Rename the unique-identifier accessor `id` on `IndexName`/`Index` to `uuid` (along with the struct field, the constructor keyword, and the `setuuid` setter), freeing the `id` name for the identity-tensor constructor. Add `id(elt, codomain, domain)`, the from-scratch identity operator over the given codomain and domain indices, a sibling of `one(a, codomain, domain)` that needs only the indices and an element type rather than a prototype tensor. `id` is exported.

Breaking: `ITensorBase.id` on an index or index name is now `ITensorBase.uuid`.
`name` already strips an index to its dimension name and passes a bare name through unchanged, so `to_dimname` duplicated it. Call `name` directly when normalizing relabel pairs, which handles either an index or a bare name on either side of the pair.
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.98131% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.65%. Comparing base (daa7646) to head (eb6d837).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/abstractnamedtensor.jl 78.57% 9 Missing ⚠️
src/tensoralgebra.jl 86.20% 4 Missing ⚠️
src/index.jl 88.88% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #213      +/-   ##
==========================================
+ Coverage   74.40%   74.65%   +0.24%     
==========================================
  Files          30       30              
  Lines        1567     1653      +86     
==========================================
+ Hits         1166     1234      +68     
- Misses        401      419      +18     
Flag Coverage Δ
docs 25.94% <55.14%> (+2.81%) ⬆️

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.

mtfishman and others added 4 commits July 9, 2026 09:50
Adds `LinearAlgebra.tr(a, codomain, domain)` for an `AbstractNamedTensor`, plus a `NamedTensorOperator` method, the trace of a named tensor viewed as a map. It pairs each codomain index with the domain index in the same position and sums the diagonal. The contracting identity is built over the dual axes with `similar` and `one!`, so the trace follows the backend (dense, graded, or TensorMap).

Adds a map-shaped `Base.similar(a, codomain, domain)` carrying a nontrivial domain, so a graded or TensorMap backend allocates the correct codomain-to-domain block structure. The existing single-axis-tuple forms are all-codomain.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rAlgebra.tr

Equality, isequal, and hash on NamedUnitRange now key on the name plus the axis's ungraded extent (via TensorAlgebra.ungrade) rather than the full range. Conjugation preserves the name and the ungraded extent while flipping arrows and charge labels, so an index compares equal to its dual and stock Base set-ops, Dict, and Set treat the two as the same leg. isequal delegates to ==.

tr on a named tensor now forwards to TensorAlgebra.tr on the unnamed data, which matricizes into the square matrix and takes the matrix trace, replacing the earlier identity contraction. The two agree for bosons and differ for fermions by the twist sign, and the matricized trace is the plain operator trace.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The map-shaped `similar(a, [elt,] codomain, domain)` now takes its axis lists as any iterable, so a vector or a tuple of named axes both work. The body is already generic over the collection (broadcast plus splat, and `TensorAlgebra.similar_map` accepts either), so the previous `Tuple{Vararg{NamedUnitRange}}` restriction only forced callers to pre-wrap their axes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a `datatype` method for `AbstractNamedTensor` that returns the underlying
storage array type by delegating to `TensorAlgebra.datatype` through `unnamed`,
so downstream code can get an ITensor's storage type through the shared
`TensorAlgebra.datatype` interface rather than a bespoke accessor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mtfishman added a commit to mtfishman/TensorNetworkQuantumSimulator.jl that referenced this pull request Jul 9, 2026
…jl wrappers

Continues shrinking `src/itensors.jl` by deleting thin compat wrappers and
calling the upstream ITensorBase / TensorAlgebra functions at the call sites
instead. Index relabeling uses ITensorBase's `replaceinds` directly (in place of
the vendored `replaceind`/`replaceinds` shims, with collection relabels spelled
`(from .=> to)...`), storage access uses `unnamed`/`Array` and a `datatype` that
now delegates to `TensorAlgebra.datatype`
(ITensor/ITensorBase.jl#213), and in-place scaling goes
through ITensorBase's `rmul!` for `AbstractNamedTensor`. The list-contraction
verb `contract` is renamed to `contract_network`, and tag construction passes a
`key => value` pair now that the comma-string `settags` form is gone
(`site_tag` returns the site-type tag). `hasqns` stays for contraction-optimizer
selection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mtfishman added a commit to mtfishman/TensorNetworkQuantumSimulator.jl that referenced this pull request Jul 9, 2026
`simple_update` and `full_update` now take the truncation error from
`svd_trunc`'s `ϵ` (the 2-norm of the discarded singular values, exposed in
ITensor/ITensorBase.jl#213) as `(ϵ / ‖M‖)^2`. This is the
same relative squared error the code reported before, but computed directly
instead of by the `1 - ‖S‖²/‖M‖²` subtraction, which lost all precision when
little was discarded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mtfishman and others added 4 commits July 9, 2026 15:57
Remove the `TensorAlgebra.datatype(a::AbstractNamedTensor)` method. The generic
in TensorAlgebra now reaches the storage through `parent`, and
`Base.parent(::NamedTensor)` already returns the unnamed backing, so named
tensors resolve through it without a dedicated method.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Give the name-based index-set functions, `replaceinds`, and `mapinds` runnable
doctests, and simplify the `replaceinds`/`mapinds` docstrings to describe the
relabel directly. Credit the TensorKit functions that `id` and `one` are modeled
on, and simplify the `id`/`one`/`tr` examples to use `Index` and demonstrate the
identity through `tr`. Fix the `tr` doctest so it brings `tr` into scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a positional `matricize` form that fuses the two dimension groups into a
matrix and mints fresh unique names for the fused row and column dimensions,
next to the pair form that takes explicit output names. Both forms now accept
any iterable of dimensions per group, so a `Vector` works without wrapping in
`Tuple`. Documents both forms with a shared docstring and doctest, and adds
tests covering the positional form and vector groups.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TensorAlgebra 0.17.1 is registered, so drop the branch `[sources]` pin and set
the compat floor to 0.17.1, the version that provides the `data`/`datatype` and
`matricize` additions this PR builds on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mtfishman mtfishman changed the title [WIP] Name-based index-set algebra, whole-tensor index ops, and the id/uuid rename Name-based index-set algebra, whole-tensor index ops, and the id/uuid rename Jul 9, 2026
@mtfishman
mtfishman marked this pull request as ready for review July 9, 2026 22:40
@mtfishman
mtfishman enabled auto-merge (squash) July 9, 2026 22:41
The dual-insensitive `NamedUnitRange` hash bypassed `hash_named`, dropping the
`:NamedArray` typetag and reordering the fields, so a named range no longer
hashed equal to a named array of the same values despite comparing `==` to it,
breaking Julia's `a == b` implies `hash(a) == hash(b)` contract. Add `ungrade`
on `NamedUnitRange` (strip the grading, keep the name) and hash through
`hash_named(:NamedArray, ungrade(r), h)`, matching the named-array hash while
keeping the dual-insensitivity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mtfishman
mtfishman merged commit 1917dea into main Jul 10, 2026
18 checks passed
@mtfishman
mtfishman deleted the mf/nextgen-followups-round1 branch July 10, 2026 00:05
mtfishman added a commit to mtfishman/TensorNetworkQuantumSimulator.jl that referenced this pull request Jul 10, 2026
…upstream API (#2)

## Summary

Removes the `ITensorsITensorBaseCompat` submodule and shrinks the
remaining legacy shim onto the upstream `ITensorBase` / `TensorAlgebra`
/ `MatrixAlgebraKit` API.

The operator and named-state system, which has no upstream equivalent,
becomes a TNQS-owned `Ops` submodule (custom gates extend `Ops.op`, and
`state` is called qualified as `Ops.state` so it does not collide with
`ITensorBase.state`). The remaining legacy tensor helpers move into an
`itensors.jl` shim that this PR then trims:

- **Index and tensor ops** move to the upstream versions:
`prime`/`noprime` (including the whole-tensor forms), `id`, `sim`,
`scalartype`, and the name-based index-set algebra
(`commoninds`/`uniqueinds`/`trycommonind`/`trynoncommonind`). `Index`
equality is name-based (dual-insensitive), so plain `Base` set-ops work
directly on index collections and the local `small`/`name` set helpers
and the `commonind`/`noncommonind`/`similar_map` wrappers are gone.
- **More index and storage helpers move to the upstream API too:** index
relabeling uses ITensorBase's `replaceinds` directly (dropping the
vendored `replaceind`/`replaceinds`/`swapind` wrappers, with collection
relabels spelled `(from .=> to)...`), storage access uses
`unnamed`/`Array` and a `datatype` that delegates to
`TensorAlgebra.datatype`
(ITensor/ITensorBase.jl#213), and in-place
scaling uses ITensorBase's `rmul!`. The `matricize(a::ITensor)` helper
is dropped for the upstream `matricize(a, codomain, domain)`, which
generates the fused output names itself, so no fresh-name minting
remains at the TNQS call sites. The list-contraction verb `contract` is
renamed to `contract_network`, and tags are set through `key => value`
pairs now that the comma-string `settags` form is gone (`settags`
accepts any iterable of pairs).
- **Factorizations** at the call sites go straight through
MatrixAlgebraKit
(`qr_compact`/`svd_compact`/`svd_trunc`/`left_orth`/`right_orth`), and
the operator trace is `tr(a, operator_inds(a)...)`. The compat
`factorize` and `eigen` wrappers are removed, keeping `itensor_trunc`
for the `cutoff`/`maxdim` to `trunc` translation. A call that names the
new bond inlines the relabel until tag support lands in the upstream
factorizations. The apply routines report their truncation error from
`svd_trunc`'s returned `ϵ` instead of a cancellation-prone norm
subtraction.
- Because `Index` equality is name-based, the contraction-sequence
optimizers, the graph index-set operations, and `directsum` take `Index`
objects directly, dropping the `name.(...)` labels and comparisons that
only worked around dual-mismatched indices. `directsum` now aligns each
tensor with `unname`, and gains a first test through the `+`/`add` path.
- Legacy no-ops (`disable_warn_order`, `denseblocks`, `dense`) and the
first-shrink shims (`random_itensor`, `itensor`, `algorithm_name`,
`dim`, `dag`, filtered-`inds`) are dropped for `randn`,
`TensorAlgebra.scalar`, `length`, `conj`, and inline `filter` at the
call sites.

Builds on the ITensorBase and TensorAlgebra API additions in
ITensor/ITensorBase.jl#213 and
ITensor/TensorAlgebra.jl#205. The `[compat]`
floors are ITensorBase 0.11.2 and TensorAlgebra 0.17.2, since those
releases additionally carry the `Array(::ITensor)` densification,
`namedunitrange(::ElementarySpace)`, and `data` / `datatype` over
TensorMap storage that the TensorKit-backed path relies on.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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