Skip to content

Commit fb1d04f

Browse files
mtfishmanclaude
andauthored
[BREAKING] Drop unused methods and reshape basic ITensorNetwork constructor surface (#354)
## 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 `ITensor`s 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)`. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c0fecc0 commit fb1d04f

17 files changed

Lines changed: 148 additions & 331 deletions

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ITensorNetworks"
22
uuid = "2919e153-833c-4bdc-8836-1ea460a35fc7"
3-
version = "0.19.7"
3+
version = "0.20.0"
44
authors = ["Matthew Fishman <mfishman@flatironinstitute.org>, Joseph Tindall <jtindall@flatironinstitute.org> and contributors"]
55

66
[workspace]

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ path = ".."
1616
Documenter = "1.10"
1717
Graphs = "1"
1818
ITensorFormatter = "0.2.27"
19-
ITensorNetworks = "0.19"
19+
ITensorNetworks = "0.20"
2020
ITensors = "0.9"
2121
Literate = "2.20.1"
2222
NamedGraphs = "0.11"

docs/src/deprecated_methods.md

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,6 @@ Suggestions of methods which could be deleted.
66

77
#### ITensorNetwork Constructors
88

9-
* Default constructor (`itensornetwork.jl`).
10-
```julia
11-
ITensorNetwork{V}()
12-
```
13-
14-
* (Only actually deprecate / delete this function if the more generic constructor `ITensorNetwork(tensors)` can also handle this case.)
15-
From a vector of `ITensor`s, with vertex labels auto-assigned to `eachindex(ts)`.
16-
Edges are inferred from shared indices (`itensornetwork.jl`):
17-
```julia
18-
ITensorNetwork(ts::AbstractVector{ITensor})
19-
```
20-
21-
* From a collection of ITensorNetworks. Merges (Kronecker or tensor product) of input networks (`itensornetwork.jl`):
22-
```julia
23-
ITensorNetwork(itns::Vector{ITensorNetwork})
24-
```
25-
269
* From a named graph, forwards to construction from `IndsNetwork` (`itensornetwork.jl`):
2710
```julia
2811
ITensorNetwork{V}(g::NamedGraph)
@@ -47,11 +30,6 @@ Suggestions of methods which could be deleted.
4730
ITensorNetwork(itensor_constructor::Function, is::IndsNetwork; link_space = trivial_space(is), kwargs...)
4831
```
4932

50-
* From a single `ITensor`. Wraps the tensor in a single-vertex network (`itensornetwork.jl`):
51-
```julia
52-
ITensorNetwork(t::ITensor)
53-
```
54-
5533
* Construct an `ITensorNetwork` from an `IndsNetwork`. Initializes ITensors with `undef` storage on each vertex
5634
of the `IndsNetwork` with the corresponding indices (`itensornetwork.jl`):
5735
```julia
@@ -63,58 +41,20 @@ Suggestions of methods which could be deleted.
6341

6442
#### Local Operations on ITensorNetworks
6543

66-
* Versions of `siteinds` taking a `vertex` argument. Each of these is just an alias for `uniqueinds`. Possibly the wrong design / implementation. (`abstractitensornetwork.jl`).
67-
```julia
68-
siteinds(tn::AbstractITensorNetwork, vertex) # abstractitensornetwork.jl:288
69-
siteinds(tn::AbstractITensorNetwork, vertex::Int) # abstractitensornetwork.jl:292
70-
```
71-
72-
73-
* Functions in `apply.jl` which are unused, even inside that file (`apply.jl`):
74-
```julia
75-
_gate_vertices(o::ITensor, ψ)
76-
_gate_vertices(o::AbstractEdge, ψ)
77-
_contract_gate(o::ITensor, ψv1, Λ, ψv2)
78-
_contract_gate(o::AbstractEdge, ψv1, Λ, ψv2)
79-
```
80-
81-
* Collection of tensors neighboring the given vertex (`abstractitensornetwork.jl`):
82-
```julia
83-
neighbor_tensors(tn::AbstractITensorNetwork, vertex)
84-
```
85-
86-
* Iterate over the tensors at the given vertices, default all vertices (`abstractitensornetwork.jl`):
87-
```julia
88-
eachtensor(tn::AbstractITensorNetwork, vertices = vertices(tn))
89-
```
90-
9144
* Indices on the source tensor of `edge` that are not shared with the destination tensor.
9245
(`abstractitensornetwork.jl`):
9346
```julia
9447
uniqueinds(tn::AbstractITensorNetwork, edge::AbstractEdge)
9548
uniqueinds(tn::AbstractITensorNetwork, edge::Pair)
9649
```
9750

98-
* Alias for `uniqueinds` (`abstractitensornetwork.jl`):
99-
```julia
100-
siteinds(tn::AbstractITensorNetwork, vertex)
101-
siteinds(tn::AbstractITensorNetwork, vertex::Int)
102-
```
103-
10451
* Indices common to the ITensors on the vertices connected by the edge (`abstractitensornetwork.jl`):
10552
(Use a set function like `intersection` instead.)
10653
```julia
10754
commoninds(tn::AbstractITensorNetwork, edge)
10855
linkinds(tn::AbstractITensorNetwork, edge)
10956
```
11057

111-
* Indices on `tn[vertex]` that aren't shared with any neighbor, i.e. the external/site
112-
indices of that vertex (`abstractitensornetwork.jl`).
113-
(Use a set function like `setdiff` instead.)
114-
```julia
115-
uniqueinds(tn::AbstractITensorNetwork, vertex)
116-
```
117-
11858
## Global Operations on ITensorNetworks
11959

12060

@@ -138,11 +78,3 @@ Suggestions of methods which could be deleted.
13878
```
13979
To be revisited after Jack's work on NamedGraphs.
14080

141-
* Methods in `graphs.jl`.
142-
Just one methods which constructs a `SimpleGraph` from ITensors (`graphs.jl`).
143-
```julia
144-
SimpleGraphs.SimpleGraph(itensors::Vector{ITensor})
145-
```
146-
Not used anywhere in library.
147-
148-
* Methods in `update_observer.jl`. Not used anywhere in library.

docs/src/experimental_methods.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,6 @@ Methods which still need to be discussed, modified, or deprecated.
4444
dst_ind_map::Function = prime)
4545
```
4646

47-
* Collect all site indices (per-vertex) of a network as a flat vector (`abstractitensornetwork.jl`):
48-
```julia
49-
flatten_siteinds(tn::AbstractITensorNetwork)
50-
```
51-
52-
* Collect all link indices (per-edge) of a network as a flat vector (`abstractitensornetwork.jl`):
53-
```julia
54-
flatten_linkinds(tn::AbstractITensorNetwork)
55-
```
56-
57-
5847
## TreeTensorNetwork Types
5948

6049
#### OpSum Constructors

docs/src/itensor_networks.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ i, j, k = Index(2, "i"), Index(2, "j"), Index(2, "k")
5151
A, B, C = ITensor(i, j), ITensor(j, k), ITensor(k)
5252
5353
tn = ITensorNetwork([A, B, C]) # integer vertices 1, 2, 3
54-
tn = ITensorNetwork(["A", "B", "C"], [A, B, C]) # named vertices
55-
tn = ITensorNetwork(["A" => A, "B" => B, "C" => C]) # from pairs
54+
tn = ITensorNetwork(Dict("A" => A, "B" => B, "C" => C)) # named vertices via a Dict
5655
```
5756

5857
```@docs; canonical=false

examples/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ ITensorNetworks = "2919e153-833c-4bdc-8836-1ea460a35fc7"
55
path = ".."
66

77
[compat]
8-
ITensorNetworks = "0.19"
8+
ITensorNetworks = "0.20"

src/ITensorNetworks.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module ITensorNetworks
33
include("lib/BaseExtensions/src/BaseExtensions.jl")
44
include("lib/ITensorsExtensions/src/ITensorsExtensions.jl")
55
include("visualize.jl")
6-
include("graphs.jl")
76
include("abstractindsnetwork.jl")
87
include("indextags.jl")
98
include("indsnetwork.jl")
@@ -23,7 +22,6 @@ include("formnetworks/bilinearformnetwork.jl")
2322
include("formnetworks/linearformnetwork.jl")
2423
include("formnetworks/quadraticformnetwork.jl")
2524
include("utils.jl")
26-
include("update_observer.jl")
2725

2826
include("treetensornetworks/abstracttreetensornetwork.jl")
2927
include("treetensornetworks/treetensornetwork.jl")

src/abstractitensornetwork.jl

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ Base.copy(tn::AbstractITensorNetwork) = not_implemented()
4343
# Iteration
4444
Base.iterate(tn::AbstractITensorNetwork, args...) = iterate(vertex_data(tn), args...)
4545

46+
# Vertex-keyed access: `keys(tn)` returns the vertex set, `tn[v]` returns the
47+
# tensor at vertex `v`. Together with `Base.iterate` above, this lets `tn`
48+
# stand in as a `keys`/`values`-style collection of tensors keyed by vertex.
49+
Base.keys(tn::AbstractITensorNetwork) = vertices(tn)
50+
4651
# TODO: This contrasts with the `DataGraphs.AbstractDataGraph` definition,
4752
# where it is defined as the `vertextype`. Does that cause problems or should it be changed?
4853
Base.eltype(tn::AbstractITensorNetwork) = eltype(vertex_data(tn))
@@ -167,8 +172,11 @@ end
167172
# TODO: broadcasting
168173

169174
function Base.union(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork; kwargs...)
170-
# TODO: Use a different constructor call here?
171-
tn = _ITensorNetwork(union(data_graph(tn1), data_graph(tn2)); kwargs...)
175+
g = union(underlying_graph(tn1), underlying_graph(tn2); kwargs...)
176+
tensors = Dict{vertextype(g), ITensor}(
177+
v => (v in vertices(tn1) ? tn1[v] : tn2[v]) for v in vertices(g)
178+
)
179+
tn = ITensorNetwork(tensors, g)
172180
# Add any new edges that are introduced during the union
173181
for v1 in vertices(tn1)
174182
for v2 in vertices(tn2)
@@ -181,8 +189,9 @@ function Base.union(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork; kw
181189
end
182190

183191
function NamedGraphs.rename_vertices(f::Function, tn::AbstractITensorNetwork)
184-
# TODO: Use a different constructor call here?
185-
return _ITensorNetwork(rename_vertices(f, data_graph(tn)))
192+
new_g = NamedGraphs.rename_vertices(f, underlying_graph(tn))
193+
tensors = Dict{vertextype(new_g), ITensor}(f(v) => tn[v] for v in vertices(tn))
194+
return ITensorNetwork(tensors, new_g)
186195
end
187196

188197
#
@@ -197,23 +206,16 @@ function ITensors.hascommoninds(tn::AbstractITensorNetwork, edge::AbstractEdge)
197206
return hascommoninds(tn[src(edge)], tn[dst(edge)])
198207
end
199208

200-
# Convenience wrapper
201-
function eachtensor(tn::AbstractITensorNetwork, vertices = vertices(tn))
202-
return map(v -> tn[v], vertices)
203-
end
204-
205209
#
206210
# Promotion and conversion
207211
#
208212

209213
function ITensorsExtensions.promote_indtypeof(tn::AbstractITensorNetwork)
210-
return mapreduce(promote_indtype, eachtensor(tn)) do t
211-
return indtype(t)
212-
end
214+
return mapreduce(v -> indtype(tn[v]), promote_indtype, vertices(tn))
213215
end
214216

215217
function NDTensors.scalartype(tn::AbstractITensorNetwork)
216-
return mapreduce(eltype, promote_type, eachtensor(tn); init = Bool)
218+
return mapreduce(v -> eltype(tn[v]), promote_type, vertices(tn); init = Bool)
217219
end
218220

219221
# TODO: Define `eltype(::AbstractITensorNetwork)` as `ITensor`?
@@ -249,32 +251,24 @@ end
249251
function IndsNetwork(tn::AbstractITensorNetwork)
250252
is = IndsNetwork(underlying_graph(tn))
251253
for v in vertices(tn)
252-
is[v] = uniqueinds(tn, v)
254+
is[v] = siteinds(tn, v)
253255
end
254256
for e in edges(tn)
255257
is[e] = commoninds(tn, e)
256258
end
257259
return is
258260
end
259261

260-
# Alias
261-
indsnetwork(tn::AbstractITensorNetwork) = IndsNetwork(tn)
262-
263262
# TODO: Output a `VertexDataGraph`? Unfortunately
264263
# `IndsNetwork` doesn't allow iterating over vertex data.
265264
function siteinds(tn::AbstractITensorNetwork)
266265
is = IndsNetwork(underlying_graph(tn))
267266
for v in vertices(tn)
268-
is[v] = uniqueinds(tn, v)
267+
is[v] = siteinds(tn, v)
269268
end
270269
return is
271270
end
272271

273-
function flatten_siteinds(tn::AbstractITensorNetwork)
274-
# `identity.(...)` narrows the type, maybe there is a better way.
275-
return identity.(flatten(map(v -> siteinds(tn, v), vertices(tn))))
276-
end
277-
278272
function linkinds(tn::AbstractITensorNetwork)
279273
is = IndsNetwork(underlying_graph(tn))
280274
for e in edges(tn)
@@ -283,23 +277,20 @@ function linkinds(tn::AbstractITensorNetwork)
283277
return is
284278
end
285279

286-
function flatten_linkinds(tn::AbstractITensorNetwork)
287-
# `identity.(...)` narrows the type, maybe there is a better way.
288-
return identity.(flatten(map(e -> linkinds(tn, e), edges(tn))))
289-
end
290-
291280
#
292281
# Index access
293282
#
294283

295-
function neighbor_tensors(tn::AbstractITensorNetwork, vertex)
296-
return eachtensor(tn, neighbors(tn, vertex))
297-
end
298-
299-
function ITensors.uniqueinds(tn::AbstractITensorNetwork, vertex)
300-
tn_vertex = [tn[vertex]; collect(neighbor_tensors(tn, vertex))]
301-
return reduce(setdiff, inds.(tn_vertex))
284+
function _siteinds(tn::AbstractITensorNetwork, vertex)
285+
s = inds(tn[vertex])
286+
for v in neighbors(tn, vertex)
287+
s = setdiff(s, inds(tn[v]))
288+
end
289+
return s
302290
end
291+
siteinds(tn::AbstractITensorNetwork, vertex) = _siteinds(tn, vertex)
292+
# Fix ambiguity with `siteinds(::Type, ::Int)` from `sitetype.jl`.
293+
siteinds(tn::AbstractITensorNetwork, vertex::Int) = _siteinds(tn, vertex)
303294

304295
function ITensors.uniqueinds(tn::AbstractITensorNetwork, edge::AbstractEdge)
305296
return uniqueinds(tn[src(edge)], tn[dst(edge)])
@@ -309,14 +300,6 @@ function ITensors.uniqueinds(tn::AbstractITensorNetwork, edge::Pair)
309300
return uniqueinds(tn, edgetype(tn)(edge))
310301
end
311302

312-
function siteinds(tn::AbstractITensorNetwork, vertex)
313-
return uniqueinds(tn, vertex)
314-
end
315-
# Fix ambiguity error with IndsNetwork constructor.
316-
function siteinds(tn::AbstractITensorNetwork, vertex::Int)
317-
return uniqueinds(tn, vertex)
318-
end
319-
320303
function ITensors.commoninds(tn::AbstractITensorNetwork, edge)
321304
e = edgetype(tn)(edge)
322305
return commoninds(tn[src(e)], tn[dst(e)])
@@ -843,7 +826,7 @@ function ITensorVisualizationCore.visualize(
843826
vertex_labels = [vertex_labels_prefix * string(v) for v in vertices(tn)]
844827
end
845828
# TODO: Use `tokenize_vertex`.
846-
return visualize(collect(eachtensor(tn)), args...; vertex_labels, kwargs...)
829+
return visualize([tn[v] for v in vertices(tn)], args...; vertex_labels, kwargs...)
847830
end
848831

849832
#
@@ -877,20 +860,6 @@ function linkdims(tn::AbstractITensorNetwork{V}) where {V}
877860
return ld
878861
end
879862

880-
#
881-
# Site combiners
882-
#
883-
884-
# TODO: will be broken, fix this
885-
function site_combiners(tn::AbstractITensorNetwork{V}) where {V}
886-
Cs = DataGraph{V, ITensor}(copy(underlying_graph(tn)))
887-
for v in vertices(tn)
888-
s = siteinds(tn, v)
889-
Cs[v] = combiner(s; tags = commontags(s))
890-
end
891-
return Cs
892-
end
893-
894863
function insert_linkinds(
895864
tn::AbstractITensorNetwork, edges = edges(tn); link_space = trivial_space(tn)
896865
)

src/apply.jl

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ function full_update_bp(
2929
Qᵥ₂, Rᵥ₂ = ITensor(true), copy(ψ[v⃗[2]])
3030
else
3131
Qᵥ₁, Rᵥ₁ = factorize(
32-
ψ[v⃗[1]], uniqueinds(uniqueinds(ψ[v⃗[1]], ψ[v⃗[2]]), uniqueinds(ψ, v⃗[1]))
32+
ψ[v⃗[1]],
33+
setdiff(setdiff(inds(ψ[v⃗[1]]), inds(ψ[v⃗[2]])), siteinds(ψ, v⃗[1]))
3334
)
3435
Qᵥ₂, Rᵥ₂ = factorize(
35-
ψ[v⃗[2]], uniqueinds(uniqueinds(ψ[v⃗[2]], ψ[v⃗[1]]), uniqueinds(ψ, v⃗[2]))
36+
ψ[v⃗[2]],
37+
setdiff(setdiff(inds(ψ[v⃗[2]]), inds(ψ[v⃗[1]])), siteinds(ψ, v⃗[2]))
3638
)
3739
end
3840
extended_envs = vcat(envs, Qᵥ₁, prime(dag(Qᵥ₁)), Qᵥ₂, prime(dag(Qᵥ₂)))
@@ -286,25 +288,6 @@ function ITensors.apply(
286288
return apply(ITensor(o, siteinds(ψ)), ψ; normalize, ortho, apply_kwargs...)
287289
end
288290

289-
_gate_vertices(o::ITensor, ψ) = neighbor_vertices(ψ, o)
290-
_gate_vertices(o::AbstractEdge, ψ) = [src(o), dst(o)]
291-
292-
function _contract_gate(o::ITensor, ψv1, Λ, ψv2)
293-
indsᵥ₁ = noprime(noncommoninds(ψv1, Λ))
294-
Qᵥ₁, Rᵥ₁ = qr(ψv1, setdiff(uniqueinds(indsᵥ₁, ψv2), commoninds(indsᵥ₁, o)))
295-
Qᵥ₂, Rᵥ₂ = qr(ψv2, setdiff(uniqueinds(ψv2, indsᵥ₁), commoninds(ψv2, o)))
296-
theta = noprime(noprime(Rᵥ₁ * Λ) * Rᵥ₂ * o)
297-
return Qᵥ₁, Rᵥ₁, Qᵥ₂, Rᵥ₂, theta
298-
end
299-
300-
function _contract_gate(o::AbstractEdge, ψv1, Λ, ψv2)
301-
indsᵥ₁ = noprime(noncommoninds(ψv1, Λ))
302-
Qᵥ₁, Rᵥ₁ = qr(ψv1, uniqueinds(indsᵥ₁, ψv2))
303-
Qᵥ₂, Rᵥ₂ = qr(ψv2, uniqueinds(ψv2, indsᵥ₁))
304-
theta = noprime(Rᵥ₁ * Λ) * Rᵥ₂
305-
return Qᵥ₁, Rᵥ₁, Qᵥ₂, Rᵥ₂, theta
306-
end
307-
308291
### Full Update Routines ###
309292

310293
# Calculate the overlap of the gate acting on the previous p and q versus the new p and q in the presence of environments. This is the cost function that optimise_p_q will minimise

0 commit comments

Comments
 (0)