Skip to content

Commit e312bd5

Browse files
mtfishmanclaude
andauthored
Add apply_operator(s) for gate application with BP simple-update backend (#114)
## Summary Adds `apply_operator` and `apply_operators` for applying gates to a `TensorNetwork`, with a belief-propagation simple-update backend (`BPApplyGate`) and a `MessageCache`-based BP environment for the double-layer norm network `⟨tn|tn⟩`. Built on the operator-construction primitives in ITensor/TensorAlgebra.jl#177 and ITensor/NamedDimsArrays.jl#229. Also renames `insert_trivial_link!` to `insertlink!` and routes its underlying-range construction through `TensorAlgebra.trivialrange`. Adds `randlinknames`, which copies a tensor network, renaming every shared link with a fresh `randname`, used to contract networks such as `⟨ψ|ψ⟩`. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1b5ea47 commit e312bd5

12 files changed

Lines changed: 739 additions & 91 deletions

Project.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ITensorNetworksNext"
22
uuid = "302f2e75-49f0-4526-aef7-d8ba550cb06c"
3-
version = "0.4.3"
3+
version = "0.4.4"
44
authors = ["ITensor developers <support@itensor.org> and contributors"]
55

66
[workspace]
@@ -19,8 +19,10 @@ FunctionImplementations = "7c7cc465-9c6a-495f-bdd1-f42428e86d0c"
1919
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
2020
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2121
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
22+
MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4"
2223
NamedDimsArrays = "60cbd0c0-df58-4cb7-918c-6f5607b73fde"
2324
NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19"
25+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2426
SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
2527
SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66"
2628
TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a"
@@ -47,11 +49,13 @@ FunctionImplementations = "0.4.1"
4749
Graphs = "1.13.1"
4850
LinearAlgebra = "1.10"
4951
MacroTools = "0.5.16"
50-
NamedDimsArrays = "0.14.3, 0.15"
52+
MatrixAlgebraKit = "0.6"
53+
NamedDimsArrays = "0.15.8"
5154
NamedGraphs = "0.11"
55+
Random = "1.10"
5256
SimpleTraits = "0.9.5"
5357
SplitApplyCombine = "1.2.3"
54-
TensorAlgebra = "0.9.2"
58+
TensorAlgebra = "0.9.5"
5559
TensorOperations = "5.3.1"
5660
TermInterface = "2"
5761
TypeParameterAccessors = "0.4.4"

src/AlgorithmsInterfaceExtensions/AlgorithmsInterfaceExtensions.jl

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module AlgorithmsInterfaceExtensions
22

3-
import AlgorithmsInterface as AI
3+
using AlgorithmsInterface: AlgorithmsInterface as AI
44

55
# ============================ NestedAlgorithm =============================================
66

@@ -52,44 +52,6 @@ function Base.propertynames(state::NestedState)
5252
return (fieldnames(typeof(state))..., :iterate)
5353
end
5454

55-
# ============================ select_algorithm / default_algorithm ========================
56-
57-
# Like `MatrixAlgebraKit.select_algorithm` / `default_algorithm`, but
58-
# selection-relevant inputs are packed into an `args` tuple so the value
59-
# and type domains stay disjoint: `(1.2,)` vs `Tuple{Float64}`. Strategy
60-
# types subtype `AbstractAlgorithm` so the passthrough overload is generic.
61-
abstract type AbstractAlgorithm end
62-
63-
function default_algorithm(f, ::Type{Args}; kwargs...) where {Args <: Tuple}
64-
return throw(MethodError(default_algorithm, (f, Args)))
65-
end
66-
function default_algorithm(f, args::Tuple; kwargs...)
67-
return default_algorithm(f, typeof(args); kwargs...)
68-
end
69-
70-
function select_algorithm(f, alg, args::Tuple; kwargs...)
71-
return select_algorithm(f, alg, typeof(args); kwargs...)
72-
end
73-
function select_algorithm(f, ::Nothing, ::Type{Args}; kwargs...) where {Args <: Tuple}
74-
return default_algorithm(f, Args; kwargs...)
75-
end
76-
function select_algorithm(f, alg::NamedTuple, ::Type{Args}; kwargs...) where {Args <: Tuple}
77-
isempty(kwargs) || throw(
78-
ArgumentError(
79-
"Additional keyword arguments are not allowed when `alg` is a `NamedTuple`."
80-
)
81-
)
82-
return default_algorithm(f, Args; alg...)
83-
end
84-
function select_algorithm(f, alg::AbstractAlgorithm, ::Type{<:Tuple}; kwargs...)
85-
isempty(kwargs) || throw(
86-
ArgumentError(
87-
"Additional keyword arguments are not allowed when `alg` is an `AbstractAlgorithm` instance."
88-
)
89-
)
90-
return alg
91-
end
92-
9355
# ============================ StopWhenConverged ===========================================
9456

9557
# Stopping criterion that fires once `iterate_diff(iterate, previous_iterate) < tol`.

src/ITensorNetworksNext.jl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
module ITensorNetworksNext
22

3-
# Imported as a name only so that the `[compat] TensorAlgebra = "0.9.2"` floor
4-
# (needed for a `bipermutedimsopadd!` fix in `TensorAlgebra` 0.9.2 that affects
5-
# `NamedDimsArrays`-mediated tensor multiplication) isn't reported as a stale
6-
# dependency by Aqua.
7-
using TensorAlgebra: TensorAlgebra
3+
if VERSION >= v"1.11.0-DEV.469"
4+
eval(
5+
Meta.parse(
6+
"public apply_operator, apply_operators, beliefpropagation_normnetwork, identity_norm_message_env, normnetwork, norm_message_env, ones_norm_message_env, rand_norm_message_env, randn_norm_message_env, similar_norm_message_env"
7+
)
8+
)
9+
end
810

11+
include("select_algorithm.jl")
912
include("AlgorithmsInterfaceExtensions/AlgorithmsInterfaceExtensions.jl")
1013
include("LazyNamedDimsArrays/LazyNamedDimsArrays.jl")
1114
include("abstracttensornetwork.jl")
@@ -15,5 +18,8 @@ include("contract_network.jl")
1518

1619
include("beliefpropagation/messagecache.jl")
1720
include("beliefpropagation/beliefpropagation.jl")
21+
include("beliefpropagation/normnetwork.jl")
22+
23+
include("apply/apply_operators.jl")
1824

1925
end

src/abstracttensornetwork.jl

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,20 @@ function Adapt.adapt_structure(to, tn::AbstractTensorNetwork)
6363
end
6464

6565
linkinds(tn::AbstractGraph, edge::Pair) = linkinds(tn, edgetype(tn)(edge))
66-
linkinds(tn::AbstractGraph, edge::AbstractEdge) = inds(tn[src(edge)]) inds(tn[dst(edge)])
66+
# Pick the link indices from the `src` side, identified by name match with `dst`.
67+
# A range-strict intersection (`inds(src) ∩ inds(dst)`) would drop graded links
68+
# whose two endpoints carry dual-related ranges.
69+
function linkinds(tn::AbstractGraph, edge::AbstractEdge)
70+
ln = linknames(tn, edge)
71+
return [i for i in inds(tn[src(edge)]) if name(i) in ln]
72+
end
6773

6874
function linkaxes(tn::AbstractGraph, edge::Pair)
6975
return linkaxes(tn, edgetype(tn)(edge))
7076
end
7177
function linkaxes(tn::AbstractGraph, edge::AbstractEdge)
72-
return axes(tn[src(edge)]) axes(tn[dst(edge)])
78+
ln = linknames(tn, edge)
79+
return [ax for ax in axes(tn[src(edge)]) if name(ax) in ln]
7380
end
7481
function linknames(tn::AbstractGraph, edge::Pair)
7582
return linknames(tn, edgetype(tn)(edge))
@@ -143,7 +150,7 @@ function add_missing_edges!(tn::AbstractGraph, v)
143150
for v′ in vertices(tn)
144151
if v v′
145152
e = v => v′
146-
if !isempty(linkinds(tn, e))
153+
if !isempty(linknames(tn, e))
147154
add_edge!(tn, e)
148155
end
149156
end
@@ -162,37 +169,40 @@ end
162169
function fix_edges!(tn::AbstractGraph, v)
163170
for e in incident_edges(tn, v)
164171
# Remove an edge if there is no index on that edge.
165-
if isempty(linkinds(tn, e))
172+
if isempty(linknames(tn, e))
166173
rem_edge!(tn, e)
167174
end
168175
end
169176
add_missing_edges!(tn, v)
170177
return tn
171178
end
172179

173-
# Customization point.
174-
using NamedDimsArrays: AbstractNamedUnitRange, namedunitrange, nametype, randname
175-
function trivial_unitrange(type::Type{<:AbstractUnitRange})
176-
return Base.oneto(one(eltype(type)))
177-
end
178-
function rand_trivial_namedunitrange(
179-
::Type{<:AbstractNamedUnitRange{<:Any, R, N}}
180-
) where {R, N}
181-
return namedunitrange(trivial_unitrange(R), randname(N))
182-
end
183-
184-
dag(x) = x
185-
186-
function insert_trivial_link!(tn, e)
180+
using NamedDimsArrays: denamedtype, named, nametype, randname
181+
using TensorAlgebra: trivialrange
182+
function insertlink!(tn, e)
187183
add_edge!(tn, e)
188-
l = rand_trivial_namedunitrange(eltype(inds(tn[src(e)])))
189-
x = similar(tn[src(e)], (l,))
190-
x[1] = 1
184+
T = eltype(inds(tn[src(e)]))
185+
l = named(trivialrange(denamedtype(T)), randname(nametype(T)))
186+
x = fill!(similar(tn[src(e)], (l,)), one(eltype(tn[src(e)])))
191187
@preserve_graph tn[src(e)] = tn[src(e)] * x
192-
@preserve_graph tn[dst(e)] = tn[dst(e)] * dag(x)
188+
@preserve_graph tn[dst(e)] = tn[dst(e)] * conj(x)
193189
return tn
194190
end
195191

192+
using NamedDimsArrays: replacedimnames
193+
function randlinknames(tn)
194+
new_tn = copy(tn)
195+
for e in edges(new_tn)
196+
u, v = src(e), dst(e)
197+
for n in intersect(dimnames(new_tn[u]), dimnames(new_tn[v]))
198+
n′ = randname(n)
199+
new_tn[u] = replacedimnames(new_tn[u], n => n′)
200+
new_tn[v] = replacedimnames(new_tn[v], n => n′)
201+
end
202+
end
203+
return new_tn
204+
end
205+
196206
function Base.setindex!(tn::AbstractTensorNetwork, value, v)
197207
@preserve_graph tn[v] = value
198208
fix_edges!(tn, v)

0 commit comments

Comments
 (0)