Skip to content

Commit b108f68

Browse files
authored
Add square root BP and BP-based simple update gate evolution (#100)
1 parent 84807b1 commit b108f68

File tree

15 files changed

+744
-41
lines changed

15 files changed

+744
-41
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using ITensorNetworks
2+
using ITensorNetworks:
3+
approx_network_region,
4+
belief_propagation,
5+
get_environment,
6+
contract_inner,
7+
find_subgraph,
8+
message_tensors,
9+
neighbor_vertices,
10+
nested_graph_leaf_vertices,
11+
symmetric_gauge,
12+
vidal_gauge,
13+
vidal_to_symmetric_gauge,
14+
norm_network
15+
using Test
16+
using Compat
17+
using Dictionaries
18+
using ITensors
19+
using Metis
20+
using NamedGraphs
21+
using Observers
22+
using Random
23+
using LinearAlgebra
24+
using SplitApplyCombine
25+
using OMEinsumContractionOrders
26+
27+
function expect_bp(opname, v, ψ, mts)
28+
s = siteinds(ψ)
29+
ψψ = norm_network(ψ)
30+
numerator_network = approx_network_region(
31+
ψψ, mts, [(v, 1)]; verts_tn=ITensorNetwork(ITensor[apply(op(opname, s[v]), ψ[v])])
32+
)
33+
denominator_network = approx_network_region(ψψ, mts, [(v, 1)])
34+
return contract(numerator_network)[] / contract(denominator_network)[]
35+
end
36+
37+
function vertex_array(ψ, v, v⃗ⱼ)
38+
indsᵥ = unioninds((linkinds(ψ, v => vⱼ) for vⱼ in v⃗ⱼ)...)
39+
indsᵥ = unioninds(siteinds(ψ, v), indsᵥ)
40+
ψᵥ = ψ[v]
41+
ψᵥ /= norm(ψᵥ)
42+
return array(permute(ψᵥ, indsᵥ))
43+
end
44+
45+
function simple_update_bp(
46+
os,
47+
ψ::ITensorNetwork;
48+
maxdim,
49+
variational_optimization_only=false,
50+
regauge=false,
51+
reduced=true,
52+
)
53+
println("Simple update, BP")
54+
ψψ = norm_network(ψ)
55+
mts = message_tensors(partition(ψψ, group(v -> v[1], vertices(ψψ))))
56+
mts = belief_propagation(
57+
ψψ, mts; contract_kwargs=(; alg="exact"), niters=50, target_precision=1e-5
58+
)
59+
for layer in eachindex(os)
60+
@show layer
61+
o⃗ = os[layer]
62+
for o in o⃗
63+
v⃗ = neighbor_vertices(ψ, o)
64+
for e in edges(mts)
65+
@assert order(only(mts[e])) == 2
66+
@assert order(only(mts[reverse(e)])) == 2
67+
end
68+
69+
@assert length(v⃗) == 2
70+
v1, v2 = v⃗
71+
72+
s1 = find_subgraph((v1, 1), mts)
73+
s2 = find_subgraph((v2, 1), mts)
74+
envs = get_environment(ψψ, mts, [(v1, 1), (v1, 2), (v2, 1), (v2, 2)])
75+
obs = observer()
76+
# TODO: Make a version of `apply` that accepts message tensors,
77+
# and computes the environment and does the message tensor update of the bond internally.
78+
ψ = apply(
79+
o,
80+
ψ;
81+
envs,
82+
(observer!)=obs,
83+
maxdim,
84+
normalize=true,
85+
variational_optimization_only,
86+
nfullupdatesweeps=20,
87+
symmetrize=true,
88+
reduced,
89+
)
90+
S = only(obs.singular_values)
91+
S /= norm(S)
92+
93+
# Update message tensor
94+
ψψ = norm_network(ψ)
95+
mts[s1] = ITensorNetwork(dictionary([(v1, 1) => ψψ[v1, 1], (v1, 2) => ψψ[v1, 2]]))
96+
mts[s2] = ITensorNetwork(dictionary([(v2, 1) => ψψ[v2, 1], (v2, 2) => ψψ[v2, 2]]))
97+
mts[s1 => s2] = ITensorNetwork(obs.singular_values)
98+
mts[s2 => s1] = ITensorNetwork(obs.singular_values)
99+
end
100+
if regauge
101+
println("regauge")
102+
mts = belief_propagation(
103+
ψψ, mts; contract_kwargs=(; alg="exact"), niters=50, target_precision=1e-5
104+
)
105+
end
106+
end
107+
return ψ, mts
108+
end
109+
110+
function simple_update_vidal(os, ψ::ITensorNetwork; maxdim, regauge=false)
111+
println("Simple update, Vidal gauge")
112+
ψψ = norm_network(ψ)
113+
mts = message_tensors(partition(ψψ, group(v -> v[1], vertices(ψψ))))
114+
mts = belief_propagation(
115+
ψψ, mts; contract_kwargs=(; alg="exact"), niters=50, target_precision=1e-5
116+
)
117+
ψ, bond_tensors = vidal_gauge(ψ, mts)
118+
for layer in eachindex(os)
119+
@show layer
120+
o⃗ = os[layer]
121+
for o in o⃗
122+
v⃗ = neighbor_vertices(ψ, o)
123+
ψ, bond_tensors = apply(o, ψ, bond_tensors; maxdim, normalize=true)
124+
end
125+
if regauge
126+
println("regauge")
127+
ψ_symmetric, mts = vidal_to_symmetric_gauge(ψ, bond_tensors)
128+
ψψ = norm_network(ψ_symmetric)
129+
mts = belief_propagation(
130+
ψψ, mts; contract_kwargs=(; alg="exact"), niters=50, target_precision=1e-5
131+
)
132+
ψ, bond_tensors = vidal_gauge(ψ_symmetric, mts)
133+
end
134+
end
135+
return ψ, bond_tensors
136+
end
137+
138+
function main(;
139+
seed=5623,
140+
graph,
141+
opname,
142+
dims,
143+
χ,
144+
nlayers,
145+
variational_optimization_only=false,
146+
regauge=false,
147+
reduced=true,
148+
)
149+
Random.seed!(seed)
150+
n = prod(dims)
151+
g = graph(dims)
152+
s = siteinds("S=1/2", g)
153+
ψ = randomITensorNetwork(s; link_space=χ)
154+
es = edges(g)
155+
os = [
156+
[op(opname, s[src(e)]..., s[dst(e)]...; eltype=Float64) for e in es] for _ in 1:nlayers
157+
]
158+
159+
# BP SU
160+
ψ_bp, mts = simple_update_bp(
161+
os, ψ; maxdim=χ, variational_optimization_only, regauge, reduced
162+
)
163+
# ψ_bp, mts = vidal_to_symmetric_gauge(vidal_gauge(ψ_bp, mts)...)
164+
165+
# Vidal SU
166+
ψ_vidal, bond_tensors = simple_update_vidal(os, ψ; maxdim=χ, regauge)
167+
ψ_vidal, mts_vidal = vidal_to_symmetric_gauge(ψ_vidal, bond_tensors)
168+
169+
return ψ_bp, mts, ψ_vidal, mts_vidal
170+
end
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
include("apply_bp.jl")
2+
3+
# opname = "Id"
4+
opname = "RandomUnitary"
5+
6+
@show opname
7+
8+
# graph = named_comb_tree
9+
graph = named_grid
10+
11+
dims = (6, 6)
12+
13+
ψ_bp, mts_bp, ψ_vidal, mts_vidal = main(;
14+
seed=1234,
15+
opname,
16+
graph,
17+
dims,
18+
χ=2,
19+
nlayers=2,
20+
variational_optimization_only=false,
21+
regauge=false,
22+
reduced=true,
23+
)
24+
25+
v = dims 2
26+
27+
sz_bp = @show expect_bp("Sz", v, ψ_bp, mts_bp)
28+
sz_vidal = @show expect_bp("Sz", v, ψ_vidal, mts_vidal)
29+
@show abs(sz_bp - sz_vidal) / abs(sz_vidal)
30+
31+
# Run BP again
32+
mts_bp = belief_propagation(
33+
norm_network(ψ_bp),
34+
mts_bp;
35+
contract_kwargs=(; alg="exact"),
36+
niters=50,
37+
target_precision=1e-5,
38+
)
39+
mts_vidal = belief_propagation(
40+
norm_network(ψ_vidal),
41+
mts_vidal;
42+
contract_kwargs=(; alg="exact"),
43+
niters=50,
44+
target_precision=1e-5,
45+
)
46+
47+
sz_bp = @show expect_bp("Sz", v, ψ_bp, mts_bp)
48+
sz_vidal = @show expect_bp("Sz", v, ψ_vidal, mts_vidal)
49+
@show abs(sz_bp - sz_vidal) / abs(sz_vidal)
50+
51+
ψ_symmetric, _ = symmetric_gauge(ψ_bp)
52+
53+
v⃗ⱼ = [v .+ (1, 0), v .- (1, 0), v .+ (0, 1), v .- (0, 1)]
54+
ψ_bp_v = vertex_array(ψ_bp, v, v⃗ⱼ)
55+
ψ_vidal_v = vertex_array(ψ_vidal, v, v⃗ⱼ)
56+
ψ_symmetric_v = vertex_array(ψ_symmetric, v, v⃗ⱼ)
57+
58+
@show norm(abs.(ψ_bp_v) - abs.(ψ_vidal_v))
59+
@show norm(abs.(ψ_bp_v) - abs.(ψ_symmetric_v))
60+
@show norm(abs.(ψ_vidal_v) - abs.(ψ_symmetric_v))
61+
62+
# inner_ψ_net = inner_network(ψ_bp, ψ_vidal)
63+
# norm_ψ_bp_net = norm_network(ψ_bp)
64+
# norm_ψ_vidal_net = norm_network(ψ_vidal)
65+
# seq = contraction_sequence(inner_ψ_net; alg="sa_bipartite")
66+
# @disable_warn_order begin
67+
# inner_ψ = contract(inner_ψ_net; sequence=seq)[]
68+
# norm_sqr_ψ_bp = contract(norm_ψ_bp_net; sequence=seq)[]
69+
# norm_sqr_ψ_vidal = contract(norm_ψ_vidal_net; sequence=seq)[]
70+
# end
71+
# @show 1 - inner_ψ / (sqrt(norm_sqr_ψ_bp) * sqrt(norm_sqr_ψ_vidal))
72+
# @show log(inner_ψ) - (log(norm_sqr_ψ_bp) / 2 + log(norm_sqr_ψ_vidal) / 2)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using ITensors
2+
using ITensorNetworks
3+
using Random
4+
using SplitApplyCombine
5+
6+
using ITensorNetworks:
7+
approx_network_region,
8+
belief_propagation,
9+
sqrt_belief_propagation,
10+
ising_network_state,
11+
message_tensors
12+
13+
function main(; n, niters, network="ising", β=nothing, h=nothing, χ=nothing)
14+
g_dims = (n, n)
15+
@show g_dims
16+
g = named_grid(g_dims)
17+
s = siteinds("S=1/2", g)
18+
19+
Random.seed!(5467)
20+
21+
ψ = if network == "ising"
22+
ising_network_state(s, β; h)
23+
elseif network == "random"
24+
randomITensorNetwork(s; link_space=χ)
25+
else
26+
error("Network type $network not supported.")
27+
end
28+
29+
ψψ = norm_network(ψ)
30+
31+
# Site to take expectation value on
32+
v = (n ÷ 2, n ÷ 2)
33+
@show v
34+
35+
#Now do Simple Belief Propagation to Measure Sz on Site v
36+
mts = message_tensors(
37+
ψψ; subgraph_vertices=collect(values(group(v -> v[1], vertices(ψψ))))
38+
)
39+
40+
mts = @time belief_propagation(ψψ, mts; niters, contract_kwargs=(; alg="exact"))
41+
numerator_network = approx_network_region(
42+
ψψ, mts, [(v, 1)]; verts_tn=ITensorNetwork([apply(op("Sz", s[v]), ψ[v])])
43+
)
44+
denominator_network = approx_network_region(ψψ, mts, [(v, 1)])
45+
sz_bp =
46+
contract(
47+
numerator_network; sequence=contraction_sequence(numerator_network; alg="optimal")
48+
)[] / contract(
49+
denominator_network; sequence=contraction_sequence(denominator_network; alg="optimal")
50+
)[]
51+
52+
println(
53+
"Simple Belief Propagation Gives Sz on Site " * string(v) * " as " * string(sz_bp)
54+
)
55+
56+
mts_sqrt = message_tensors(
57+
ψψ; subgraph_vertices=collect(values(group(v -> v[1], vertices(ψψ))))
58+
)
59+
60+
mts_sqrt = @time sqrt_belief_propagation(ψ, mts_sqrt; niters)
61+
62+
numerator_network = approx_network_region(
63+
ψψ, mts_sqrt, [(v, 1)]; verts_tn=ITensorNetwork([apply(op("Sz", s[v]), ψ[v])])
64+
)
65+
denominator_network = approx_network_region(ψψ, mts_sqrt, [(v, 1)])
66+
sz_sqrt_bp =
67+
contract(
68+
numerator_network; sequence=contraction_sequence(numerator_network; alg="optimal")
69+
)[] / contract(
70+
denominator_network; sequence=contraction_sequence(denominator_network; alg="optimal")
71+
)[]
72+
73+
println(
74+
"Sqrt Belief Propagation Gives Sz on Site " * string(v) * " as " * string(sz_sqrt_bp)
75+
)
76+
77+
return (; sz_bp, sz_sqrt_bp)
78+
end

src/ITensorNetworks.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ using ITensors.ITensorVisualizationCore
1818
using ITensors.LazyApply
1919
using IterTools
2020
using KrylovKit: KrylovKit
21+
using LinearAlgebra
2122
using NamedGraphs
2223
using Observers
2324
using Observers.DataFrames: select!
@@ -36,6 +37,7 @@ using ITensors:
3637
@Algorithm_str,
3738
@debug_check,
3839
@timeit_debug,
40+
δ,
3941
AbstractMPS,
4042
Algorithm,
4143
OneITensor,
@@ -94,7 +96,8 @@ include("utility.jl")
9496
include("specialitensornetworks.jl")
9597
include("renameitensornetwork.jl")
9698
include("boundarymps.jl")
97-
include("beliefpropagation.jl")
99+
include(joinpath("beliefpropagation", "beliefpropagation.jl"))
100+
include(joinpath("beliefpropagation", "sqrt_beliefpropagation.jl"))
98101
include("contraction_tree_to_graph.jl")
99102
include("gauging.jl")
100103
include("utils.jl")

src/ITensorsExt/itensorutils.jl

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
1-
using ITensors.NDTensors: Tensor, diaglength, getdiagindex, setdiagindex!, tensor
1+
using ITensors.NDTensors:
2+
Tensor,
3+
diaglength,
4+
getdiagindex,
5+
setdiagindex!,
6+
tensor,
7+
DiagBlockSparseTensor,
8+
DenseTensor,
9+
BlockOffsets
10+
11+
function NDTensors.blockoffsets(dense::DenseTensor)
12+
return BlockOffsets{ndims(dense)}([Block(ntuple(Returns(1), ndims(dense)))], [0])
13+
end
14+
function NDTensors.nzblocks(dense::DenseTensor)
15+
return nzblocks(blockoffsets(dense))
16+
end
17+
NDTensors.blockdim(ind::Int, ::Block{1}) = ind
18+
NDTensors.blockdim(i::Index{Int}, b::Integer) = blockdim(i, Block(b))
19+
NDTensors.blockdim(i::Index{Int}, b::Block) = blockdim(space(i), b)
20+
21+
LinearAlgebra.isdiag(it::ITensor) = isdiag(tensor(it))
222

323
function map_diag!(f::Function, it_destination::ITensor, it_source::ITensor)
424
return itensor(map_diag!(f, tensor(it_destination), tensor(it_source)))
@@ -20,6 +40,21 @@ invsqrt_diag(it::ITensor) = map_diag(inv ∘ sqrt, it)
2040
pinv_diag(it::ITensor) = map_diag(pinv, it)
2141
pinvsqrt_diag(it::ITensor) = map_diag(pinv sqrt, it)
2242

43+
# Analagous to `denseblocks`.
44+
# Extract the diagonal entries into a diagonal tensor.
45+
function diagblocks(D::Tensor)
46+
nzblocksD = nzblocks(D)
47+
T = DiagBlockSparseTensor(eltype(D), nzblocksD, inds(D))
48+
for b in nzblocksD
49+
for n in 1:diaglength(D)
50+
setdiagindex!(T, getdiagindex(D, n), n)
51+
end
52+
end
53+
return T
54+
end
55+
56+
diagblocks(it::ITensor) = itensor(diagblocks(tensor(it)))
57+
2358
"""Given a vector of ITensors, separate them into groups of commuting itensors (i.e. itensors in the same group do not share any common indices)"""
2459
function group_commuting_itensors(its::Vector{ITensor})
2560
remaining_its = copy(its)

0 commit comments

Comments
 (0)