11using Compat: Compat
2- using Dictionaries: Dictionary, set!
3- using Graphs: dst, src, vertices
2+ using Graphs: vertices
43using ITensorNetworks: ITensorNetworks, BeliefPropagationCache, QuadraticFormNetwork,
5- contract, contraction_sequence, environment, identity_messages, inner_network, message,
6- message_diff, partitioned_tensornetwork, scalar, siteinds, tensornetwork, update,
7- update_factor, updated_message, ⊗
4+ bra_vertex, contract, contraction_sequence, default_partitioned_vertices, environment,
5+ identity_messages, ket_vertex, message, message_diff, norm_sqr_network, operator_vertex,
6+ partitioned_tensornetwork, scalar, siteinds, tensornetwork, update, update_factor,
7+ updated_message
88include (" utils.jl" )
99using ITensors. NDTensors: array
10- using ITensors: ITensors, Algorithm, ITensor, Index, combiner, commoninds, dag, inds, inner,
11- op, prime, random_itensor
10+ using ITensors: ITensors, ITensor, combiner, dag, inds, inner, prime, random_itensor
1211using LinearAlgebra: eigvals, tr
13- using NamedGraphs. NamedGraphGenerators: named_comb_tree, named_grid
14- using NamedGraphs. PartitionedGraphs: PartitionedGraph, QuotientEdge, quotientedges
15- using NamedGraphs: NamedEdge, NamedGraph
16- using SplitApplyCombine: group
12+ using NamedGraphs. NamedGraphGenerators: named_grid
13+ using NamedGraphs. PartitionedGraphs: PartitionedGraph, quotientedges
1714using StableRNGs: StableRNG
1815using TensorOperations: TensorOperations
1916using Test: @test , @testset
@@ -28,38 +25,19 @@ using Test: @test, @testset
2825 χ = 2
2926 rng = StableRNG (1234 )
3027 ψ = random_tensornetwork (rng, elt, s; link_space = χ)
31- ψψ = ψ ⊗ prime (dag (ψ); sites = [])
32- pv = group (v -> first (v), vertices (ψψ))
33- ptn = PartitionedGraph (ψψ, pv)
34- # Build identity initial messages by hand: layer 1 is the ket
35- # (original ψ) and layer 2 is the bra (`dag(prime(ψ; sites = []))`).
36- # Pair the bra/ket link inds ordinally on each quotient edge so the
37- # resulting `delta(b, dag(k))` has opposite QN flow.
38- pairings = Dictionary {QuotientEdge, Pair{Vector{Index}, Vector{Index}}} ()
39- for pe in quotientedges (ptn)
40- v_src, v_dst = parent (src (pe)), parent (dst (pe))
41- for (v_from, v_to, e) in (
42- (v_src, v_dst, pe),
43- (v_dst, v_src, reverse (pe)),
44- )
45- # ψψ layer 2 is `dag(prime(ψ; sites = []))`, so each bra
46- # link Index is `dag(prime(k))` for the matching ket k.
47- # Build the pair explicitly to avoid relying on
48- # `commoninds` ordering across the two layers.
49- kets = collect (commoninds (ψψ[(v_from, 1 )], ψψ[(v_to, 1 )]))
50- bras = dag .(prime .(kets))
51- set! (pairings, e, bras => kets)
52- end
53- end
54- bpc = BeliefPropagationCache (ptn; messages = identity_messages (elt, pairings))
28+ ψψ = norm_sqr_network (ψ)
29+ ptn = PartitionedGraph (ψψ, default_partitioned_vertices (ψψ))
30+ bpc = BeliefPropagationCache (ptn; messages = identity_messages (ψψ, ptn))
5531
56- # Test updating the tensors in the cache
57- vket, vbra = ((1 , 1 ), 1 ), ((1 , 1 ), 2 )
32+ # Test updating the tensors in the cache. QFN bra has both site
33+ # and link inds primed (relative to the ket), so the bra-side
34+ # tensor is constructed as `dag(prime(new_A))` directly.
35+ v = (1 , 1 )
36+ vket = ket_vertex (ψψ, v)
37+ vbra = bra_vertex (ψψ, v)
5838 A = bpc[vket]
5939 new_A = random_itensor (elt, inds (A))
60- new_A_dag = ITensors. replaceind (
61- dag (prime (new_A)), only (s[first (vket)])' , only (s[first (vket)])
62- )
40+ new_A_dag = dag (prime (new_A))
6341 bpc[vket] = new_A
6442 bpc[vbra] = new_A_dag
6543 @test bpc[vket] == new_A
@@ -73,28 +51,31 @@ using Test: @test, @testset
7351 @test eltype (only (message (bpc, pe))) == elt
7452 end
7553 # Test updating the underlying tensornetwork in the cache
76- v = first (vertices (ψψ))
54+ v_any = first (vertices (ψψ))
7755 rng = StableRNG (1234 )
78- new_tensor = random_itensor (rng, inds (ψψ[v ]))
79- bpc_updated = update_factor (bpc, v , new_tensor)
56+ new_tensor = random_itensor (rng, inds (ψψ[v_any ]))
57+ bpc_updated = update_factor (bpc, v_any , new_tensor)
8058 ψψ_updated = tensornetwork (bpc_updated)
81- @test ψψ_updated[v ] == new_tensor
59+ @test ψψ_updated[v_any ] == new_tensor
8260
83- # Test forming a two-site RDM. Check it has the correct size, trace 1 and is PSD
61+ # Two-site RDM at `vs`: ask for the environment around all three
62+ # layers (bra/ket/operator) at `vs` so the BP env is just incoming
63+ # messages, then contract with only the bra and ket tensors at
64+ # `vs` — dropping the per-site identity operator at those
65+ # vertices leaves the bra (primed) and ket (unprimed) site inds
66+ # open, which is exactly the RDM.
8467 vs = [(2 , 2 ), (2 , 3 )]
85-
86- # Prime the bra-ket shared site indices on the ket side at the
87- # selected vertices, so the contracted RDM has open primed/unprimed
88- # legs there. Mutates a copy of `ψψ` in place; no graph edits.
89- ψψsplit = copy (ψψ)
90- for v in vs
91- common = commoninds (ψψsplit[(v, 1 )], ψψsplit[(v, 2 )])
92- ψψsplit[(v, 2 )] = prime (ψψsplit[(v, 2 )], common)
93- end
94- env_tensors = environment (bpc, [(v, 2 ) for v in vs])
95- rdm =
96- contract (vcat (env_tensors, ITensor[ψψsplit[vp] for vp in [(v, 2 ) for v in vs]]))
97-
68+ env_vs = vcat (
69+ [bra_vertex (ψψ, v) for v in vs],
70+ [ket_vertex (ψψ, v) for v in vs],
71+ [operator_vertex (ψψ, v) for v in vs]
72+ )
73+ env_tensors = environment (bpc, env_vs)
74+ local_tensors = vcat (
75+ ITensor[ψψ[bra_vertex (ψψ, v)] for v in vs],
76+ ITensor[ψψ[ket_vertex (ψψ, v)] for v in vs]
77+ )
78+ rdm = contract (vcat (env_tensors, local_tensors))
9879 rdm = array (
9980 (rdm * combiner (inds (rdm; plev = 0 )... )) * combiner (inds (rdm; plev = 1 )... )
10081 )
0 commit comments