Skip to content

[BREAKING] Drop unused methods and reshape basic ITensorNetwork constructor surface#354

Merged
mtfishman merged 7 commits into
mainfrom
mf/drop-itn-ctors
May 7, 2026
Merged

[BREAKING] Drop unused methods and reshape basic ITensorNetwork constructor surface#354
mtfishman merged 7 commits into
mainfrom
mf/drop-itn-ctors

Conversation

@mtfishman
Copy link
Copy Markdown
Member

@mtfishman mtfishman commented May 7, 2026

Summary

  • Reshape the basic ITensorNetwork constructor surface around two forms:

    • ITensorNetwork(tensors) — collection of tensors, edges inferred from shared indices.
    • ITensorNetwork(tensors, graph::NamedGraph) — tensors placed at the vertices of a given graph, no edge inference.

    tensors is any collection where keys(tensors) are vertex labels and values(tensors) are the ITensors at those vertices (e.g. a Dict, a Dictionary, or a Vector{ITensor} with linear-index vertex labels). The legacy single-ITensor wrap, Vector{ITensorNetwork} (Kronecker product), default-empty (ITensorNetwork{V}() / ITensorNetwork()), pair-vector, and two-vector forms are removed; construct via Dict or Dictionary instead.

  • Drop unused or trivially-replaceable helpers:

    • _gate_vertices, _contract_gate (whole helpers, zero callers).
    • neighbor_tensors, eachtensor(tn, vertices) 2-arg form, site_combiners (had a # TODO: will be broken marker), flatten_linkinds, the lowercase indsnetwork alias.
    • The siteinds(tn, vertex) aliases — the method is kept but is now implemented natively via setdiff over neighbors (matching ITensorNetworksNext.jl) rather than aliased to uniqueinds. The underlying uniqueinds(tn::AbstractITensorNetwork, vertex) method is removed.
    • The whole src/graphs.jl (just SimpleGraphs.SimpleGraph(::Vector{ITensor}), unused).
    • The whole src/update_observer.jl (update_observer!, compose_observers, ComposedObservers, ValuesObserver; no callers in src/).
  • Sync docs/src/deprecated_methods.md and docs/src/experimental_methods.md to reflect the deletions.

The IndsNetwork-, AbstractNamedGraph-, and AbstractSimpleGraph-based constructor families (ITensorNetwork(is::IndsNetwork), ITensorNetwork(::Function, is::IndsNetwork), ITensorNetwork(value, is::IndsNetwork), ITensorNetwork(eltype, undef, is::IndsNetwork), etc.) are not touched in this PR; their removal is being staged separately so it can be reviewed on its own. The same applies to the deprecated per-edge wrappers linkinds(tn, edge) / commoninds(tn, edge) / uniqueinds(tn, edge), which are still used by internal call sites and are being deferred for replacement with explicit set-function calls (e.g. intersect(inds(tn[src(e)]), inds(tn[dst(e)]))).

Release notes:

Breaking. Removed public methods include ITensorNetwork(::ITensor), ITensorNetwork(::Vector{ITensorNetwork}), ITensorNetwork{V}() and ITensorNetwork(), ITensorNetwork(::AbstractVector{<:Pair{<:Any, ITensor}}), ITensorNetwork(vs::AbstractVector, ts::AbstractVector{ITensor}), uniqueinds(tn::AbstractITensorNetwork, vertex), neighbor_tensors, eachtensor(tn, vertices) 2-arg form, flatten_linkinds, indsnetwork (lowercase alias), site_combiners, SimpleGraphs.SimpleGraph(::Vector{ITensor}), and the contents of update_observer.jl. The siteinds(tn, vertex) accessor is preserved with a re-implemented body. Construct an ITensorNetwork from collections via ITensorNetwork(tensors) or ITensorNetwork(tensors, graph::NamedGraph).

mtfishman and others added 3 commits May 7, 2026 09:41
…ructor surface

Continuing the legacy ITensorNetworks.jl simplification ahead of the
ITensorNetworksNext.jl migration. Pure-deletion changes for methods
that aren't used by BP / `apply` / DMRG / TDVP, plus a constructor
reshape around two basic forms — `ITensorNetwork(tensors)` (collection
of tensors, edges inferred from shared indices) and
`ITensorNetwork(tensors, graph::NamedGraph)` (collection of tensors
placed at the vertices of a given graph, no edge inference).

## Deletions

- `_gate_vertices` and `_contract_gate` from `apply.jl` — zero callers.
- `neighbor_tensors`, `eachtensor(tn, vertices)` 2-arg form, and
  `site_combiners` (which had a `# TODO: will be broken` marker) from
  `abstractitensornetwork.jl`.
- `siteinds(tn, vertex)` is reimplemented natively via `setdiff` (matching
  ITensorNetworksNext.jl) instead of as an alias for
  `uniqueinds(tn, vertex)`. The underlying `uniqueinds(tn, vertex)`
  method is removed; the two internal callers (`IndsNetwork(tn)` and
  the 1-arg `siteinds(tn)`) switch to `siteinds(tn, v)`.
- `graphs.jl` (just `SimpleGraphs.SimpleGraph(::Vector{ITensor})`) and
  `update_observer.jl` (`update_observer!` / `compose_observers` /
  `ComposedObservers` / `ValuesObserver`) — both whole files, zero
  callers across `src/`.
- Constructors: `ITensorNetwork(::ITensor)`, `ITensorNetwork(::Vector{ITensorNetwork})`
  (Kronecker; users can call `reduce(⊗, itns)`), `ITensorNetwork{V}()` and
  `ITensorNetwork()` (default empty), `ITensorNetwork(::AbstractVector{<:Pair})`,
  `ITensorNetwork(vs, ts)`. The `(::Pair)` and `(vs, ts)` forms are
  subsumed by `ITensorNetwork(Dict(...))` or `ITensorNetwork(Dictionary(...))`.

## Constructor reshape

The struct now has a single inner constructor — `ITensorNetwork{V}(tensors,
graph::NamedGraph)` — that places tensors at given vertices without edge
inference. The user-facing `ITensorNetwork(tensors)` form derives the
graph from `keys(tensors)` and runs edge inference (O(n²) until the
reverse-index map design lands). Both forms accept any
`AbstractVector{<:ITensor}` / `AbstractDict{<:Any, <:ITensor}` /
`AbstractDictionary{<:Any, <:ITensor}` (a private `_ITensorCollection`
Union, restricted to avoid a dispatch ambiguity with the function-callback
`ITensorNetwork(f, graph::AbstractNamedGraph)` Group-C form). The
`_ITensorNetwork` internal wrap is deleted; `copy`, `convert_vertextype`,
`similar_graph`, `rename_vertices`, and `union` all route through the
public `(tensors, graph)` inner.

## Doc sync

Removes the corresponding entries from `docs/src/deprecated_methods.md`
that #346 introduced. The Group-C constructor families
(`AbstractNamedGraph`, `AbstractSimpleGraph`, `IndsNetwork` shapes) and
the deferred BP `linkinds(::PartitionedGraph, ::QuotientEdge)` stay in
the deprecated doc — they wait for the reverse-index map design and a
BP refactor respectively.

## Version bump

`0.19.7 → 0.20.0` (breaking, since some of the deletions are public-API).
The `ITensorNetworks` pin in `test/`, `examples/`, and `docs/`
`Project.toml` is bumped from `"0.19"` to `"0.20"` to match.

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

Latent breakage from the previous commit: the else-branch of
`simple_update_bp_full` (the full-update apply path) called
`uniqueinds(ψ, v⃗[1])` and `uniqueinds(ψ, v⃗[2])`, but the underlying
`uniqueinds(::AbstractITensorNetwork, vertex)` method was deleted. No
test exercises this branch today, but it would error at runtime.
Switching to `siteinds(ψ, v⃗[1])` / `siteinds(ψ, v⃗[2])` matches the
other simple-update path's call sites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-up cleanup surfaced by the dangling-functions audit on top of the
prior commits:

- Delete `flatten_linkinds(tn::AbstractITensorNetwork)` from
  `abstractitensornetwork.jl`. Only used in tests; no algorithm callers.
  Symmetric `flatten_siteinds` is kept (used by
  `formnetworks/bilinearformnetwork.jl`). Remove the corresponding test
  and import, and the `experimental_methods.md` entry.
- Delete `indsnetwork(tn::AbstractITensorNetwork)` lowercase alias for
  `IndsNetwork(tn)`. Zero callers anywhere.
- Rewrite the full-update `factorize` Q/R call in `apply.jl` to use
  `setdiff` directly on `inds(...)` and `siteinds(tn, vertex)` instead
  of nested `uniqueinds`. Same semantics, fewer wrapper hops.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

❌ Patch coverage is 93.10345% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.36%. Comparing base (c0fecc0) to head (baf7cf1).

Files with missing lines Patch % Lines
src/abstractitensornetwork.jl 90.00% 2 Missing ⚠️
src/itensornetwork.jl 94.11% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #354      +/-   ##
==========================================
+ Coverage   73.26%   74.36%   +1.10%     
==========================================
  Files          66       64       -2     
  Lines        3183     3133      -50     
==========================================
- Hits         2332     2330       -2     
+ Misses        851      803      -48     
Flag Coverage Δ
docs 48.09% <85.96%> (+0.92%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 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 May 7, 2026 10:11
…sor}` in copy / conversion paths

Follow-up cleanup on top of the prior commits:

- Delete `flatten_siteinds(tn::AbstractITensorNetwork)` from
  `abstractitensornetwork.jl`. The two `src/` call sites in
  `formnetworks/bilinearformnetwork.jl` (an `@assert issetequal(...)`
  check and an `isempty(...)` check inside the `BilinearFormNetwork`
  ctor) inline trivially as
  `mapreduce(v -> siteinds(tn, v), vcat, vertices(tn); init = Index[])`.
  Update tests and `experimental_methods.md` accordingly.
- Type-annotate the `Dict(...)` literals built inside the parametric
  `ITensorNetwork{V}(tensors)` ctor and the `copy` / `convert_vertextype` /
  `similar_graph` / `rename_vertices` / `union` paths as
  `Dict{V, ITensor}(...)`, locking the dict value type to `ITensor`
  regardless of how the comprehension would otherwise infer.
- Add `Base.keys(tn::AbstractITensorNetwork) = vertices(tn)` alongside
  the existing `Base.iterate` / `Base.eltype`. With this, an
  `AbstractITensorNetwork` is a `keys`/`values`-shaped collection of
  tensors keyed by vertex, useful in its own right and a prerequisite
  for merging the `ITensorNetwork{V}(tn::ITensorNetwork)` specialization
  into the generic `ITensorNetwork{V}(tensors)` once edge inference
  becomes cheap (with the reverse index map).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nput vertex list

Two small simplifications + one bug fix on top of the prior commits:

- Delete `eachtensor(tn::AbstractITensorNetwork)` and the concrete
  `eachtensor(ψ::ITensorNetwork)`; inline the three internal call sites
  (`promote_indtypeof`, `scalartype`, the `visualize` method) as
  `mapreduce(v -> ...(tn[v]), ..., vertices(tn))` /
  `[tn[v] for v in vertices(tn)]`. Remove `eachtensor` from the
  `test_belief_propagation.jl` import list (unused).
- Drop the redundant `Dict{V, ITensor}(...)` and `ITensorNetwork{V}(...)`
  parametric annotations from `union`, `rename_vertices`, `Base.copy`,
  `convert_vertextype`, `similar_graph`, and the parametric
  `ITensorNetwork{V}(tensors)` form. The non-parametric delegate already
  extracts `V` via `vertextype(graph)`, and the inner ctor builds
  `DataGraph(g; vertex_data_type = ITensor, ...)` regardless of the
  input Dict's value type, so the explicit annotations were doing no
  work.
- Fix an empty-input bug surfaced by the above. `NamedGraph{V}(Int[])`
  with `V = Tuple{Int64}` returns `NamedGraph{Int64}` (vertex type gets
  inferred from the empty input element type, overriding the explicit
  parametric). The parametric `ITensorNetwork{V}(tensors)` form now
  builds the vertex list as `V[v for v in keys(tensors)]` so an empty
  `tensors` (e.g. `ITensor[]`, used internally by the IndsNetwork
  function-callback ctor when bootstrapping) doesn't drop the parametric
  vertex type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n docs

CI surfaced two issues:

1. Stack overflow in `test/solvers/test_applyexp.jl`. Root cause: when
   the parametric `ITensorNetwork{V}(tensors)` form bootstraps an empty
   `ITensorNetwork{Any}` (via the IndsNetwork function-callback ctor's
   `tn = ITensorNetwork{vertextype(is)}(ITensor[])` for an
   `IndsNetwork{Any, Index}`), Julia's type inference gives
   `Dict{Any, Any}` for the empty default-tensor comprehension, not
   `Dict{Any, ITensor}`. `Dict{Any, Any}` is outside the
   `_ITensorCollection` Union, so the next dispatch (`ITensorNetwork(default, g)`)
   misses the new `(tensors, graph::NamedGraph)` form and falls through
   to the function-callback `ITensorNetwork(f, ::AbstractNamedGraph)`
   Group C ctor, which routes back through the IndsNetwork
   function-callback ctor — infinite recursion.

   Fix: re-add the `Dict{V, ITensor}` annotation at every site where
   we build a Dict from a comprehension that may be empty (parametric
   `(tensors)` form, `convert_vertextype`, `Base.copy`, `similar_graph`,
   `union`, `rename_vertices`). The annotation locks the value type so
   the resulting Dict matches `_ITensorCollection` regardless of `V`.

2. Documentation build failed on the `@example` block in
   `docs/src/itensor_networks.md:49–56` which used the dropped
   `ITensorNetwork(["A", "B", "C"], [A, B, C])` and
   `ITensorNetwork(["A" => A, "B" => B, "C" => C])` forms. Replaced
   with `ITensorNetwork(Dict("A" => A, "B" => B, "C" => C))` and
   `ITensorNetwork(Dictionary(...))` to match the new constructor surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The docs `Project.toml` doesn't include `Dictionaries.jl`, so the
`using Dictionaries: Dictionary` line in the previous fix made the
documentation build fail with "Package Dictionaries not found in
current path." Just use `Dict` for the named-vertex example — the
example only constructs the network, doesn't assert edge order, so
`Dict`'s non-deterministic iteration order doesn't matter here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mtfishman mtfishman merged commit fb1d04f into main May 7, 2026
18 checks passed
@mtfishman mtfishman deleted the mf/drop-itn-ctors branch May 7, 2026 18:37
mtfishman added a commit that referenced this pull request May 8, 2026
## Summary

- PR #354 removed `update_observer!` from ITensorNetworks but left the
`ITensorNetworksObserversExt` weak-dependency extension still wired up.
Since v0.20.0, any environment that loads ITensorNetworks alongside
Observers fails to precompile with `UndefVarError: \`update_observer!\`
not defined in \`ITensorNetworks\``. This blocks downstream packages
that depend on Observers (e.g. Tennis.jl).
- Drop the orphaned `ext/ITensorNetworksObserversExt/` directory, the
`Observers` weakdep, the corresponding `[extensions]` entry, and the
`Observers` compat bound. Also drop `Observers` from `test/Project.toml`
(no test files reference it).
- Bump version to `0.21.1` (patch — no public API change beyond the
dead-code extension).
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