Skip to content

Commit 0df8051

Browse files
authored
Output eigenvalue from DMRG and DMRG-X (#167)
1 parent 8c43155 commit 0df8051

File tree

8 files changed

+81
-28
lines changed

8 files changed

+81
-28
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ITensorNetworks"
22
uuid = "2919e153-833c-4bdc-8836-1ea460a35fc7"
33
authors = ["Matthew Fishman <[email protected]>, Joseph Tindall <[email protected]> and contributors"]
4-
version = "0.10.4"
4+
version = "0.11.0"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -63,7 +63,7 @@ IterTools = "1.4.0"
6363
KrylovKit = "0.6, 0.7"
6464
NamedGraphs = "0.6.0"
6565
NDTensors = "0.3"
66-
Observers = "0.2"
66+
Observers = "0.2.4"
6767
OMEinsumContractionOrders = "0.8.3"
6868
PackageExtensionCompat = "1"
6969
SerializedElementArrays = "0.1"

src/solvers/dmrg.jl

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,24 @@ using KrylovKit: KrylovKit
44
"""
55
Overload of `ITensors.ITensorMPS.dmrg`.
66
"""
7-
87
function ITensorMPS.dmrg(
9-
operator, init_state; nsweeps, nsites=2, updater=eigsolve_updater, kwargs...
8+
operator,
9+
init_state;
10+
nsweeps,
11+
nsites=2,
12+
updater=eigsolve_updater,
13+
(region_observer!)=nothing,
14+
kwargs...,
1015
)
11-
return alternating_update(operator, init_state; nsweeps, nsites, updater, kwargs...)
16+
eigvals_ref = Ref{Any}()
17+
region_observer! = compose_observers(
18+
region_observer!, ValuesObserver((; eigvals=eigvals_ref))
19+
)
20+
state = alternating_update(
21+
operator, init_state; nsweeps, nsites, updater, region_observer!, kwargs...
22+
)
23+
eigval = only(eigvals_ref[])
24+
return eigval, state
1225
end
1326

1427
"""

src/solvers/dmrg_x.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
function dmrg_x(
2-
operator, init_state::AbstractTTN; nsweeps, nsites=2, updater=dmrg_x_updater, kwargs...
2+
operator,
3+
init_state::AbstractTTN;
4+
nsweeps,
5+
nsites=2,
6+
updater=dmrg_x_updater,
7+
(region_observer!)=nothing,
8+
kwargs...,
39
)
4-
return alternating_update(operator, init_state; nsweeps, nsites, updater, kwargs...)
10+
eigvals_ref = Ref{Any}()
11+
region_observer! = compose_observers(
12+
region_observer!, ValuesObserver((; eigvals=eigvals_ref))
13+
)
14+
state = alternating_update(
15+
operator, init_state; nsweeps, nsites, updater, region_observer!, kwargs...
16+
)
17+
eigval = only(eigvals_ref[])
18+
return eigval, state
519
end

src/solvers/local_solvers/dmrg_x.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ function dmrg_x_updater(
1212
which_region_update,
1313
internal_kwargs,
1414
)
15-
#ToDo: Implement this via KrylovKit or similar for better scaling
1615
H = contract(projected_operator![], ITensor(true))
1716
D, U = eigen(H; ishermitian=true)
1817
u = uniqueind(U, H)
1918
max_overlap, max_ind = findmax(abs, array(dag(init) * U))
2019
U_max = U * dag(onehot(u => max_ind))
21-
# TODO: improve this to return the energy estimate too
22-
return U_max, (;)
20+
eigvals = [((onehot(u => max_ind)' * D) * dag(onehot(u => max_ind)))[]]
21+
return U_max, (; eigvals)
2322
end

src/update_observer.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,24 @@ end
99
function update_observer!(observer::Nothing; kwargs...)
1010
return nothing
1111
end
12+
13+
struct ComposedObservers{Observers<:Tuple}
14+
observers::Observers
15+
end
16+
compose_observers(observers...) = ComposedObservers(observers)
17+
function update_observer!(observer::ComposedObservers; kwargs...)
18+
for observerᵢ in observer.observers
19+
update_observer!(observerᵢ; kwargs...)
20+
end
21+
return observer
22+
end
23+
24+
struct ValuesObserver{Values<:NamedTuple}
25+
values::Values
26+
end
27+
function update_observer!(observer::ValuesObserver; kwargs...)
28+
for key in keys(observer.values)
29+
observer.values[key][] = kwargs[key]
30+
end
31+
return observer
32+
end

test/test_treetensornetworks/test_solvers/test_contract.jl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ using Test: @test, @test_broken, @testset
4444
@test inner(psi, Hpsi) inner(psi', H, psi) rtol = 1e-5
4545
# Test variational compression via DMRG
4646
Hfit = ProjOuterProdTTN(psi', H)
47-
Hpsi_via_dmrg = dmrg(Hfit, psi; updater_kwargs=(; which_eigval=:LR,), nsweeps=1)
47+
e, Hpsi_via_dmrg = dmrg(Hfit, psi; updater_kwargs=(; which_eigval=:LR,), nsweeps=1)
4848
@test abs(inner(Hpsi_via_dmrg, Hpsi / norm(Hpsi))) 1 rtol = 1e-4
4949
# Test whether the interface works for ProjTTNSum with factors
5050
Hfit = ProjTTNSum([ProjOuterProdTTN(psi', H), ProjOuterProdTTN(psi', H)], [-0.2, -0.8])
51-
Hpsi_via_dmrg = dmrg(Hfit, psi; nsweeps=1, updater_kwargs=(; which_eigval=:SR,))
51+
e, Hpsi_via_dmrg = dmrg(Hfit, psi; nsweeps=1, updater_kwargs=(; which_eigval=:SR,))
5252
@test abs(inner(Hpsi_via_dmrg, Hpsi / norm(Hpsi))) 1 rtol = 1e-4
5353

5454
# Test basic usage for use with multiple ProjOuterProdTTN with default parameters
@@ -66,9 +66,7 @@ using Test: @test, @test_broken, @testset
6666
# Test the above via DMRG
6767
# ToDo: Investigate why this is broken
6868
Hfit = ProjTTNSum([ProjOuterProdTTN(psi', H), ProjOuterProdTTN(psi', identity)], [-1, 1])
69-
Hpsi_normalized = ITensorNetworks.dmrg(
70-
Hfit, psi; nsweeps=3, updater_kwargs=(; which_eigval=:SR)
71-
)
69+
e, Hpsi_normalized = dmrg(Hfit, psi; nsweeps=3, updater_kwargs=(; which_eigval=:SR))
7270
@test_broken abs(inner(Hpsi, (Hpsi_normalized) / norm(Hpsi))) 1 rtol = 1e-5
7371

7472
#

test/test_treetensornetworks/test_solvers/test_dmrg.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,24 @@ ITensors.disable_auto_fermion()
5353
psi_mps = ITensorMPS.MPS([psi[v] for v in 1:nv(psi)])
5454
e2, psi2 = dmrg(H_mpo, psi_mps; nsweeps, maxdim, outputlevel=0)
5555

56-
psi = dmrg(
56+
e, psi = dmrg(
5757
H, psi; nsweeps, maxdim, cutoff, nsites, updater_kwargs=(; krylovdim=3, maxiter=1)
5858
)
59+
@test inner(psi', H, psi) e
5960
@test inner(psi', H, psi) inner(psi2', H_mpo, psi2)
6061

6162
# Alias for `ITensorNetworks.dmrg`
62-
psi = eigsolve(
63+
e, psi = eigsolve(
6364
H, psi; nsweeps, maxdim, cutoff, nsites, updater_kwargs=(; krylovdim=3, maxiter=1)
6465
)
66+
@test inner(psi', H, psi) e
6567
@test inner(psi', H, psi) inner(psi2', H_mpo, psi2)
6668

6769
# Test custom sweep regions #BROKEN, ToDo: Make proper custom sweep regions for test
6870
#=
6971
orig_E = inner(psi', H, psi)
7072
sweep_regions = [[1], [2], [3], [3], [2], [1]]
71-
psi = dmrg(H, psi; nsweeps, maxdim, cutoff, sweep_regions)
73+
e, psi = dmrg(H, psi; nsweeps, maxdim, cutoff, sweep_regions)
7274
new_E = inner(psi', H, psi)
7375
@test new_E ≈ orig_E
7476
=#
@@ -101,13 +103,14 @@ end
101103
energy(; eigvals, kw...) = eigvals[1]
102104
region_observer! = observer(region, sweep, energy)
103105

104-
psi = dmrg(H, psi; nsweeps, maxdim, cutoff, sweep_observer!, region_observer!)
106+
e, psi = dmrg(H, psi; nsweeps, maxdim, cutoff, sweep_observer!, region_observer!)
105107

106108
#
107109
# Test out certain values
108110
#
109111
@test region_observer![9, :region] == [2, 1]
110112
@test region_observer![30, :energy] < -4.25
113+
@test region_observer![30, :energy] e rtol = 1e-6
111114
end
112115

113116
@testset "Cache to Disk" begin
@@ -126,7 +129,7 @@ end
126129
nsweeps = 4
127130
maxdim = [10, 20, 40, 80]
128131

129-
@test_broken psi = dmrg(
132+
@test_broken e, psi = dmrg(
130133
H,
131134
psi;
132135
nsweeps,
@@ -160,7 +163,7 @@ end
160163
maxdim = [200, 250, 400, 600, 800, 1200, 2000, 2400, 2600, 3000]
161164
cutoff = [1e-10, 1e-10, 1e-12, 1e-12, 1e-12, 1e-12, 1e-14, 1e-14, 1e-14, 1e-14]
162165

163-
psi = dmrg(H, psi; nsweeps, maxdim, cutoff)
166+
e, psi = dmrg(H, psi; nsweeps, maxdim, cutoff)
164167
end
165168

166169
@testset "Tree DMRG" for nsites in [2]
@@ -195,7 +198,7 @@ end
195198
nsweeps = 10
196199
maxdim = [10, 20, 40, 100]
197200
@show use_qns
198-
psi = dmrg(
201+
e, psi = dmrg(
199202
H, psi; nsweeps, maxdim, cutoff, nsites, updater_kwargs=(; krylovdim=3, maxiter=1)
200203
)
201204

@@ -252,7 +255,7 @@ end
252255
end
253256
states = v -> d[v]
254257
psi = ttn(states, s)
255-
psi = dmrg(
258+
e, psi = dmrg(
256259
H, psi; nsweeps, maxdim, cutoff, nsites, updater_kwargs=(; krylovdim=3, maxiter=1)
257260
)
258261

@@ -280,7 +283,7 @@ end
280283
os = ModelHamiltonians.heisenberg(c)
281284
H = ttn(os, s)
282285
psi = random_ttn(s; link_space=5)
283-
psi = dmrg(H, psi; nsweeps, maxdim, nsites)
286+
e, psi = dmrg(H, psi; nsweeps, maxdim, nsites)
284287

285288
@test all(edge_data(linkdims(psi)) .<= maxdim)
286289
end

test/test_treetensornetworks/test_solvers/test_dmrg_x.jl

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ using NamedGraphs.NamedGraphGenerators: named_comb_tree
1010
using Random: Random
1111
using Test: @test, @testset
1212

13+
# TODO: Combine MPS and TTN tests.
1314
@testset "MPS DMRG-X" for conserve_qns in (false, true)
1415
n = 10
1516
s = siteinds("S=1/2", n; conserve_qns)
@@ -25,14 +26,16 @@ using Test: @test, @testset
2526

2627
dmrg_x_kwargs = (nsweeps=20, normalize=true, maxdim=20, cutoff=1e-10, outputlevel=0)
2728

28-
ϕ = dmrg_x(H, ψ; nsites=2, dmrg_x_kwargs...)
29+
e, ϕ = dmrg_x(H, ψ; nsites=2, dmrg_x_kwargs...)
2930

31+
@test inner', H, ϕ) / inner(ϕ, ϕ) e
3032
@test inner', H, ψ) / inner(ψ, ψ) inner', H, ϕ) / inner(ϕ, ϕ) rtol = 1e-1
3133
@test inner(H, ψ, H, ψ) inner', H, ψ)^2 rtol = 1e-7
3234
@test inner(H, ϕ, H, ϕ) inner', H, ϕ)^2 rtol = 1e-7
3335

34-
ϕ̃ = dmrg_x(H, ϕ; nsites=1, dmrg_x_kwargs...)
36+
e, ϕ̃ = dmrg_x(H, ϕ; nsites=1, dmrg_x_kwargs...)
3537

38+
@test inner(ϕ̃', H, ϕ̃) / inner(ϕ̃, ϕ̃) e
3639
@test inner', H, ψ) / inner(ψ, ψ) inner(ϕ̃', H, ϕ̃) / inner(ϕ̃, ϕ̃) rtol = 1e-1
3740
@test inner(H, ϕ̃, H, ϕ̃) inner(ϕ̃', H, ϕ̃)^2 rtol = 1e-3
3841
# Sometimes broken, sometimes not
@@ -56,14 +59,16 @@ end
5659

5760
dmrg_x_kwargs = (nsweeps=20, normalize=true, maxdim=20, cutoff=1e-10, outputlevel=0)
5861

59-
ϕ = dmrg_x(H, ψ; nsites=2, dmrg_x_kwargs...)
62+
e, ϕ = dmrg_x(H, ψ; nsites=2, dmrg_x_kwargs...)
6063

64+
@test inner', H, ϕ) / inner(ϕ, ϕ) e
6165
@test inner', H, ψ) / inner(ψ, ψ) inner', H, ϕ) / inner(ϕ, ϕ) rtol = 1e-1
6266
@test inner(H, ψ, H, ψ) inner', H, ψ)^2 rtol = 1e-2
6367
@test inner(H, ϕ, H, ϕ) inner', H, ϕ)^2 rtol = 1e-7
6468

65-
ϕ̃ = dmrg_x(H, ϕ; nsites=1, dmrg_x_kwargs...)
69+
e, ϕ̃ = dmrg_x(H, ϕ; nsites=1, dmrg_x_kwargs...)
6670

71+
@test inner(ϕ̃', H, ϕ̃) / inner(ϕ̃, ϕ̃) e
6772
@test inner', H, ψ) / inner(ψ, ψ) inner(ϕ̃', H, ϕ̃) / inner(ϕ̃, ϕ̃) rtol = 1e-1
6873
@test inner(H, ϕ̃, H, ϕ̃) inner(ϕ̃', H, ϕ̃)^2 rtol = 1e-6
6974
# Sometimes broken, sometimes not

0 commit comments

Comments
 (0)