Skip to content

Commit 42e9ce1

Browse files
committed
styles, find_groundstate restructure, local subspace expansion, randperturbexpand
1 parent 57ee602 commit 42e9ce1

16 files changed

Lines changed: 329 additions & 86 deletions

File tree

src/MPSKit.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export FiniteExcited, QuasiparticleAnsatz, ChepigaAnsatz, ChepigaAnsatz2
3737
export time_evolve, timestep, timestep!, make_time_mpo
3838
export TDVP, TDVP2, WI, WII, TaylorCluster
3939
export changebonds, changebonds!
40-
export VUMPSSvdCut, OptimalExpand, SvdCut, RandExpand
40+
export VUMPSSvdCut, OptimalExpand, SvdCut, RandExpand, RandPerturbedExpand
4141
export propagator
4242
export DynamicalDMRG, NaiveInvert, Jeckelmann
4343
export exact_diagonalization, fidelity_susceptibility
@@ -155,6 +155,7 @@ include("algorithms/changebonds/optimalexpand.jl")
155155
include("algorithms/changebonds/vumpssvd.jl")
156156
include("algorithms/changebonds/svdcut.jl")
157157
include("algorithms/changebonds/randexpand.jl")
158+
include("algorithms/changebonds/localexpand.jl")
158159

159160
include("algorithms/timestep/tdvp.jl")
160161
include("algorithms/timestep/taylorcluster.jl")

src/algorithms/approximate/idmrg.jl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,9 @@ function approximate!(
120120

121121
# update error
122122
ϵ = sum(zip(C_current, ψ.C[:, 0])) do (c1, c2)
123-
smallest = infimum(_firstspace(c1), _firstspace(c2))
124-
e1 = isometry(_firstspace(c1), smallest)
125-
e2 = isometry(_firstspace(c2), smallest)
126-
return norm(e2' * c2 * e2 - e1' * c1 * e1)
123+
return bond_error(c1, c2)
127124
end
128-
125+
129126
if ϵ < alg.tol
130127
@infov 2 logfinish!(log, iter, ϵ)
131128
break

src/algorithms/changebonds/changebonds.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function changebonds(
2020
end
2121

2222
_expand(ψ, AL′, AR′) = _expand!(copy(ψ), AL′, AR′)
23-
function _expand!::InfiniteMPS, AL′::PeriodicVector, AR′::PeriodicVector)
23+
function _expand!(ψ, AL′::AbstractVector, AR′::AbstractVector)
2424
for i in 1:length(ψ)
2525
# update AL: add vectors, make room for new vectors:
2626
# AL -> [AL expansion; 0 0]
@@ -46,7 +46,7 @@ function _expand!(ψ::InfiniteMPS, AL′::PeriodicVector, AR′::PeriodicVector)
4646
end
4747
return normalize!(ψ)
4848
end
49-
function _expand!::MultilineMPS, AL′::PeriodicMatrix, AR′::PeriodicMatrix)
49+
function _expand!::MultilineMPS, AL′::AbstractMatrix, AR′::AbstractMatrix)
5050
for i in 1:size(ψ, 1)
5151
_expand!(ψ[i], AL′[i, :], AR′[i, :])
5252
end
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
struct NoExpand <: Algorithm end
2+
3+
function changebonds_left(AL, C, alg::RandPerturbedExpand)
4+
AL = _expand_leftisometry(AL, alg)
5+
C′ = _embed_left_space(AL, C, alg)
6+
return AL, C′
7+
end
8+
function changebonds_left(AL, C1, C2, alg::RandPerturbedExpand)
9+
AL = _expand_leftisometry(AL, alg)
10+
C1′ = _embed_left_space(AL, C1, alg)
11+
C2′ = _embed_left_space(AL, C2, alg)
12+
return AL, C1′, C2′
13+
end
14+
function changebonds_right(C, AR, alg::RandPerturbedExpand)
15+
AR = _expand_rightisometry(AR, alg)
16+
C′ = _embed_right_space(C, AR, alg)
17+
return C′, AR
18+
end
19+
function changebonds_right(C1, C2, AR, alg::RandPerturbedExpand)
20+
AR = _expand_rightisometry(AR, alg)
21+
C1′ = _embed_right_space(C1, AR, alg)
22+
C2′ = _embed_right_space(C2, AR, alg)
23+
return C1′, C2′, AR
24+
end
25+
26+
function changebonds(AL, C, AR, alg::RandPerturbedExpand)
27+
AL = _expand_leftisometry(AL, alg)
28+
C = _embed_left_space(AL, C, alg)
29+
AR = _expand_rightisometry(AR, alg)
30+
C = _embed_right_space(C, AR, alg)
31+
return AL, C, AR
32+
end
33+
34+
function _expand_leftisometry(A::MPSTensor, alg)
35+
VL = left_null(A)
36+
V = sample_space(right_virtualspace(VL), alg.trscheme)
37+
XL = randisometry(scalartype(VL), right_virtualspace(VL) V)
38+
A = catdomain(A, VL * XL)
39+
return A
40+
end
41+
function _expand_rightisometry(A::MPSTensor, alg)
42+
return _transpose_front(_expand_rightisometry(_transpose_tail(A; copy = true), alg))
43+
end
44+
function _expand_rightisometry(AR_tail::AbstractTensorMap, alg)
45+
VR = right_null(AR_tail)
46+
V = sample_space(space(VR, 1), alg.trscheme)
47+
XR = randisometry(scalartype(VR), space(VR, 1) V)
48+
AR_tail = catcodomain(AR_tail, XR' * VR)
49+
return AR_tail
50+
end
51+
52+
function _embed_left_space(A::MPSTensor, C::MPSBondTensor, alg)
53+
C′ = similar(C, right_virtualspace(A) right_virtualspace(C))
54+
scale!(randn!(C′), alg.noisefactor)
55+
C′ = TensorKit.absorb!(C′, C)
56+
return C′
57+
end
58+
function _embed_left_space(A::MPSTensor, Anext::MPSTensor, alg)
59+
Anext′ = similar(Anext, right_virtualspace(A) physicalspace(Anext) right_virtualspace(Anext))
60+
scale!(randn!(Anext′), alg.noisefactor)
61+
Anext′ = TensorKit.absorb!(Anext′, Anext)
62+
return Anext′
63+
end
64+
65+
function _embed_right_space(C::MPSBondTensor, A::AbstractTensorMap, alg)
66+
C′ = similar(C, left_virtualspace(C) space(A, 1))
67+
scale!(randn!(C′), alg.noisefactor)
68+
C′ = TensorKit.absorb!(C′, C)
69+
return C′
70+
end
71+
function _embed_right_space(Anext::MPSTensor, A::AbstractTensorMap, alg)
72+
Anext′ = similar(Anext, left_virtualspace(Anext) physicalspace(Anext) space(A, 1))
73+
scale!(randn!(Anext′), alg.noisefactor)
74+
Anext′ = TensorKit.absorb!(Anext′, Anext)
75+
return Anext′
76+
end

src/algorithms/changebonds/randexpand.jl

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
"""
23
$(TYPEDEF)
34
@@ -6,9 +7,6 @@ orthogonal to the existing state. This means that additional directions are adde
67
`AL` and `AR` that are contained in the nullspace of both. Note that this is happens in
78
parallel, and therefore the expansion will never go beyond the local two-site subspace.
89
9-
The truncation strategy dictates the number of expanded states, by generating uniformly
10-
distributed weights for each state in the two-site space and truncating that.
11-
1210
## Fields
1311
1412
$(TYPEDFIELDS)
@@ -35,8 +33,8 @@ function changebonds!(ψ::InfiniteMPS, alg::RandExpand)
3533
# obtain (orthogonal) directions as isometries in that direction
3634
XL = randisometry(scalartype(VL), right_virtualspace(VL) V)
3735
AL′[i] = VL * XL
38-
XR = randisometry(scalartype(VR), space(VR, 1) V)
39-
AR′[i + 1] = XR' * VR
36+
XR = randisometry(storagetype(VL), space(VR, 1) V)
37+
AR′[i + 1] = XR * VR
4038
end
4139

4240
return _expand!(ψ, AL′, AR′)
@@ -87,3 +85,92 @@ function sample_space(V, strategy)
8785
ind = MatrixAlgebraKit.findtruncated(S, strategy)
8886
return TensorKit.Factorizations.truncate_space(V, ind)
8987
end
88+
89+
90+
91+
"""
92+
$(TYPEDEF)
93+
94+
An algorithm that expands the bond dimension by adding random unitary vectors that are
95+
orthogonal to the existing state, in a sweeping fashion. Additionally, some random noise
96+
is added to the state in order for it to remain gauge-able.
97+
98+
## Fields
99+
100+
$(TYPEDFIELDS)
101+
"""
102+
@kwdef struct RandPerturbedExpand{S} <: Algorithm
103+
"algorithm used for the singular value decomposition"
104+
alg_svd::S = Defaults.alg_svd()
105+
106+
"algorithm used for [truncation](@extref MatrixAlgebraKit.TruncationStrategy] the expanded space"
107+
trscheme::TruncationStrategy
108+
109+
"amount of noise that is added to the current state"
110+
noisefactor::Float64 = eps()^(3 / 4)
111+
112+
"algorithm used for gauging the state"
113+
alg_gauge = Defaults.alg_gauge(; dynamic_tols = false)
114+
end
115+
116+
function changebonds!(ψ, alg::RandPerturbedExpand)
117+
for i in 1:length(ψ)
118+
# obtain space by sampling the support of left nullspace
119+
# add (orthogonal) directions as isometries in that direction
120+
VL = left_null.AL[i])
121+
V = sample_space(right_virtualspace(VL), alg.trscheme)
122+
XL = randisometry(scalartype(VL), right_virtualspace(VL) V)
123+
ψ.AL[i] = catdomain.AL[i], VL * XL)
124+
125+
# make sure the next site fits, by "absorbing" into a larger tensor
126+
# with some random noise to ensure state is still gauge-able
127+
AL = ψ.AL[i + 1]
128+
AL′ = similar(AL, right_virtualspace.AL[i]) physicalspace(AL) right_virtualspace(AL))
129+
scale!(randn!(AL′), alg.noisefactor)
130+
ψ.AL[i + 1] = TensorKit.absorb!(AL′, AL)
131+
end
132+
133+
# properly regauge the state:
134+
makefullrank!.AL)
135+
ψ.AR .= similar.(ψ.AL)
136+
# ψ.AC .= similar.(ψ.AL)
137+
138+
# initial guess for gauge is embedded original C
139+
C₀ = similar.C[0], right_virtualspace.AL[end]) left_virtualspace.AL[1]))
140+
absorb!(id!(C₀), ψ.C[0])
141+
142+
gaugefix!(ψ, ψ.AL, C₀; order = :R, alg.alg_gauge.maxiter, alg.alg_gauge.tol)
143+
144+
for i in reverse(1:length(ψ))
145+
# obtain space by sampling the support of left nullspace
146+
# add (orthogonal) directions as isometries in that direction
147+
AR_tail = _transpose_tail.AR[i]; copy = true)
148+
VR = right_null(AR_tail)
149+
V = sample_space(space(VR, 1), alg.trscheme)
150+
XR = randisometry(scalartype(VR), space(VR, 1) V)
151+
ψ.AR[i] = _transpose_front(catcodomain(AR_tail, XR' * VR))
152+
153+
# make sure the next site fits, by "absorbing" into a larger tensor
154+
# with some random noise to ensure state is still gauge-able
155+
AR = ψ.AR[i - 1]
156+
AR′ = similar(AR, left_virtualspace(AR) physicalspace(AR) left_virtualspace.AR[i]))
157+
scale!(randn!(AR′), alg.noisefactor)
158+
ψ.AR[i - 1] = TensorKit.absorb!(AR′, AR)
159+
end
160+
161+
# properly regauge the state:
162+
makefullrank!.AR)
163+
ψ.AL .= similar.(ψ.AR)
164+
ψ.AC .= similar.(ψ.AR)
165+
166+
# initial guess for gauge is embedded original C
167+
C₀ = similar.C[0], right_virtualspace.AR[end]) left_virtualspace.AR[1]))
168+
absorb!(id!(C₀), ψ.C[0])
169+
170+
gaugefix!(ψ, ψ.AR, C₀; order = :LR, alg.alg_gauge.maxiter, alg.alg_gauge.tol)
171+
mul!.(ψ.AC, ψ.AL, ψ.C)
172+
173+
return ψ
174+
end
175+
176+
changebonds(ψ, alg::RandPerturbedExpand) = changebonds!(copy(ψ), alg)

src/algorithms/groundstate/dmrg.jl

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,30 @@ struct DMRG{A, F} <: Algorithm
1414
"maximal amount of iterations"
1515
maxiter::Int
1616

17+
miniter::Int
18+
1719
"setting for how much information is displayed"
1820
verbosity::Int
1921

2022
"algorithm used for the eigenvalue solvers"
2123
alg_eigsolve::A
2224

25+
expscheme::Algorithm
26+
2327
"callback function applied after each iteration, of signature `finalize(iter, ψ, H, envs) -> ψ, envs`"
2428
finalize::F
2529
end
2630
function DMRG(;
2731
tol = Defaults.tol, maxiter = Defaults.maxiter, alg_eigsolve = (;),
28-
verbosity = Defaults.verbosity, finalize = Defaults._finalize
32+
verbosity = Defaults.verbosity, finalize = Defaults._finalize,
33+
miniter = 0, expscheme = NoExpand()
2934
)
3035
alg_eigsolve′ = alg_eigsolve isa NamedTuple ? Defaults.alg_eigsolve(; alg_eigsolve...) :
3136
alg_eigsolve
32-
return DMRG(tol, maxiter, verbosity, alg_eigsolve′, finalize)
37+
return DMRG(tol, maxiter, miniter, verbosity, alg_eigsolve′, expscheme, finalize)
3338
end
3439

35-
function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG, envs = environments(ψ, H))
40+
function find_groundstate!(::FiniteChainStyle, ψ, H, alg::DMRG, envs = environments(ψ, H))
3641
ϵs = map(pos -> calc_galerkin(pos, ψ, H, ψ, envs), 1:length(ψ))
3742
ϵ = maximum(ϵs)
3843
log = IterLog("DMRG")
@@ -43,17 +48,29 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG, envs = environme
4348
alg_eigsolve = updatetol(alg.alg_eigsolve, iter, ϵ)
4449

4550
zerovector!(ϵs)
51+
dir = 1
4652
for pos in [1:(length(ψ) - 1); length(ψ):-1:2]
53+
pos == length(ψ) && (dir = -1)
4754
h = AC_hamiltonian(pos, ψ, H, ψ, envs)
4855
_, vec = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve)
4956
ϵs[pos] = max(ϵs[pos], calc_galerkin(pos, ψ, H, ψ, envs))
50-
ψ.AC[pos] = vec
57+
if alg.expscheme isa NoExpand
58+
ψ.AC[pos] = vec
59+
elseif dir == 1
60+
AL, C = left_orth!(vec; positive = true)
61+
AL, C, ψ.AC[pos + 1] = changebonds_left(AL, C, ψ.AC[pos + 1], alg.expscheme)
62+
ψ.AC[pos] = (AL, C)
63+
elseif dir == -1
64+
C, temp = right_orth!(_transpose_tail.AC[pos]; copy = true); positive = true)
65+
C, ψ.AC[pos - 1], temp = changebonds_right(C, ψ.AC[pos - 1], temp, alg.expscheme)
66+
ψ.AC[pos] = (C, _transpose_front(temp))
67+
end
5168
end
5269
ϵ = maximum(ϵs)
5370

5471
ψ, envs = alg.finalize(iter, ψ, H, envs)::Tuple{typeof(ψ), typeof(envs)}
5572

56-
if ϵ <= alg.tol
73+
if ϵ <= alg.tol && iter > alg.miniter
5774
@infov 2 logfinish!(log, iter, ϵ, expectation_value(ψ, H, envs))
5875
break
5976
end
@@ -83,6 +100,8 @@ struct DMRG2{A, S, F} <: Algorithm
83100
"maximal amount of iterations"
84101
maxiter::Int
85102

103+
miniter::Int
104+
86105
"setting for how much information is displayed"
87106
verbosity::Int
88107

@@ -95,21 +114,23 @@ struct DMRG2{A, S, F} <: Algorithm
95114
"algorithm used for [truncation](@extref MatrixAlgebraKit.TruncationStrategy) of the two-site update"
96115
trscheme::TruncationStrategy
97116

117+
expscheme::Algorithm
118+
98119
"callback function applied after each iteration, of signature `finalize(iter, ψ, H, envs) -> ψ, envs`"
99120
finalize::F
100121
end
101122
# TODO: find better default truncation
102123
function DMRG2(;
103124
tol = Defaults.tol, maxiter = Defaults.maxiter, verbosity = Defaults.verbosity,
104-
alg_eigsolve = (;), alg_svd = Defaults.alg_svd(), trscheme,
105-
finalize = Defaults._finalize
125+
miniter = 0, alg_eigsolve = (;), alg_svd = Defaults.alg_svd(), trscheme,
126+
expscheme = NoExpand(), finalize = Defaults._finalize
106127
)
107128
alg_eigsolve′ = alg_eigsolve isa NamedTuple ? Defaults.alg_eigsolve(; alg_eigsolve...) :
108129
alg_eigsolve
109-
return DMRG2(tol, maxiter, verbosity, alg_eigsolve′, alg_svd, trscheme, finalize)
130+
return DMRG2(tol, maxiter, miniter, verbosity, alg_eigsolve′, alg_svd, trscheme, expscheme, finalize)
110131
end
111132

112-
function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environments(ψ, H))
133+
function find_groundstate!(::FiniteChainStyle, ψ, H, alg::DMRG2, envs = environments(ψ, H))
113134
ϵs = map(pos -> calc_galerkin(pos, ψ, H, ψ, envs), 1:length(ψ))
114135
ϵ = maximum(ϵs)
115136
log = IterLog("DMRG2")
@@ -126,6 +147,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm
126147
_, newA2center = fixedpoint(Hac2, ac2, :SR, alg_eigsolve)
127148

128149
al, c, ar = svd_trunc!(newA2center; trunc = alg.trscheme, alg = alg.alg_svd)
150+
al, c = changebonds_left(al, c, alg.expscheme)
129151
normalize!(c)
130152
v = @plansor ac2[1 2; 3 4] * conj(al[1 2; 5]) * conj(c[5; 6]) * conj(ar[6; 3 4])
131153
ϵs[pos] = max(ϵs[pos], abs(1 - abs(v)))
@@ -141,6 +163,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm
141163
_, newA2center = fixedpoint(Hac2, ac2, :SR, alg_eigsolve)
142164

143165
al, c, ar = svd_trunc!(newA2center; trunc = alg.trscheme, alg = alg.alg_svd)
166+
c, ar = changebonds_right(c, ar, alg.expscheme)
144167
normalize!(c)
145168
v = @plansor ac2[1 2; 3 4] * conj(al[1 2; 5]) * conj(c[5; 6]) * conj(ar[6; 3 4])
146169
ϵs[pos] = max(ϵs[pos], abs(1 - abs(v)))
@@ -152,7 +175,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm
152175
ϵ = maximum(ϵs)
153176
ψ, envs = alg.finalize(iter, ψ, H, envs)::Tuple{typeof(ψ), typeof(envs)}
154177

155-
if ϵ <= alg.tol
178+
if ϵ <= alg.tol && iter > alg.miniter
156179
@infov 2 logfinish!(log, iter, ϵ, expectation_value(ψ, H, envs))
157180
break
158181
end
@@ -165,7 +188,3 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm
165188
end
166189
return ψ, envs, ϵ
167190
end
168-
169-
function find_groundstate(ψ, H, alg::Union{DMRG, DMRG2}, envs...; kwargs...)
170-
return find_groundstate!(copy(ψ), H, alg, envs...; kwargs...)
171-
end

0 commit comments

Comments
 (0)