@@ -24,81 +24,6 @@ $(TYPEDFIELDS)
2424 alg_eigsolve:: A = Defaults. alg_eigsolve ()
2525end
2626
27- function find_groundstate (ost:: InfiniteMPS , H, alg:: IDMRG , envs = environments (ost, H))
28- ϵ:: Float64 = calc_galerkin (ost, H, ost, envs)
29- ψ = copy (ost)
30- log = IterLog (" IDMRG" )
31- local iter, E_current
32-
33- LoggingExtras. withlevel (; alg. verbosity) do
34- @infov 2 begin
35- E_current = expectation_value (ψ, H, envs)
36- loginit! (log, ϵ, E_current)
37- end
38- for outer iter in 1 : (alg. maxiter)
39- alg_eigsolve = updatetol (alg. alg_eigsolve, iter, ϵ)
40- C_current = ψ. C[0 ]
41-
42- # left to right sweep
43- for pos in 1 : length (ψ)
44- h = AC_hamiltonian (pos, ψ, H, ψ, envs)
45- _, ψ. AC[pos] = fixedpoint (h, ψ. AC[pos], :SR , alg_eigsolve)
46- if pos == length (ψ)
47- # AC needed in next sweep
48- ψ. AL[pos], ψ. C[pos] = left_orth (ψ. AC[pos])
49- else
50- ψ. AL[pos], ψ. C[pos] = left_orth! (ψ. AC[pos])
51- end
52- transfer_leftenv! (envs, ψ, H, ψ, pos + 1 )
53- end
54-
55- # right to left sweep
56- for pos in length (ψ): - 1 : 1
57- h = AC_hamiltonian (pos, ψ, H, ψ, envs)
58- _, ψ. AC[pos] = fixedpoint (h, ψ. AC[pos], :SR , alg_eigsolve)
59-
60- ψ. C[pos - 1 ], temp = right_orth! (_transpose_tail (ψ. AC[pos]; copy = (pos == 1 )))
61- ψ. AR[pos] = _transpose_front (temp)
62-
63- transfer_rightenv! (envs, ψ, H, ψ, pos - 1 )
64- end
65-
66- ϵ = norm (C_current - ψ. C[0 ])
67-
68- if ϵ < alg. tol
69- @infov 2 begin
70- E_next = expectation_value (ψ, H, envs)
71- ΔE = E_next - E_current
72- E_current = E_next
73- logfinish! (log, iter, ϵ, ΔE)
74- end
75- break
76- end
77- if iter == alg. maxiter
78- @warnv 1 begin
79- E_next = expectation_value (ψ, H, envs)
80- ΔE = E_next - E_current
81- E_current = E_next
82- logcancel! (log, iter, ϵ, ΔE)
83- end
84- else
85- @infov 3 begin
86- E_next = expectation_value (ψ, H, envs)
87- ΔE = E_next - E_current
88- E_current = E_next
89- logiter! (log, iter, ϵ, ΔE)
90- end
91- end
92- end
93- end
94-
95- alg_gauge = updatetol (alg. alg_gauge, iter, ϵ)
96- ψ′ = InfiniteMPS (ψ. AR[1 : end ]; alg_gauge. tol, alg_gauge. maxiter)
97- recalculate! (envs, ψ′, H, ψ′)
98-
99- return ψ′, envs, ϵ
100- end
101-
10227"""
10328$(TYPEDEF)
10429
@@ -131,121 +56,209 @@ $(TYPEDFIELDS)
13156 trscheme:: TruncationStrategy
13257end
13358
134- function find_groundstate (ost:: InfiniteMPS , H, alg:: IDMRG2 , envs = environments (ost, H))
135- length (ost) < 2 && throw (ArgumentError (" unit cell should be >= 2" ))
136- ϵ:: Float64 = calc_galerkin (ost, H, ost, envs)
13759
138- ψ = copy (ost)
139- log = IterLog (" IDMRG2" )
140- local iter
60+ # Internal state of the IDMRG algorithm
61+ struct IDMRGState{S, O, E, T}
62+ mps:: S
63+ operator:: O
64+ envs:: E
65+ iter:: Int
66+ ϵ:: Float64 # TODO : Could be any <:Real
67+ energy:: T
68+ end
69+ function IDMRGState {T} (mps:: S , operator:: O , envs:: E , iter:: Int , ϵ:: Float64 , energy) where {S, O, E, T}
70+ return IDMRGState {S, O, E, T} (mps, operator, envs, iter, ϵ, T (energy))
71+ end
72+
73+ function find_groundstate (mps, operator, alg:: alg_type , envs = environments (mps, operator)) where {alg_type <: Union{<:IDMRG, <:IDMRG2} }
74+ (length (mps) ≤ 1 && alg isa IDMRG2) && throw (ArgumentError (" unit cell should be >= 2" ))
75+ log = alg isa IDMRG ? IterLog (" IDMRG" ) : IterLog (" IDMRG2" )
76+ mps = copy (mps)
77+ iter = 0
78+ ϵ = calc_galerkin (mps, operator, mps, envs)
79+ E = zero (TensorOperations. promote_contract (scalartype (mps), scalartype (operator)))
14180
14281 LoggingExtras. withlevel (; alg. verbosity) do
143- @infov 2 loginit! (log, ϵ)
144- for outer iter in 1 : (alg. maxiter)
145- alg_eigsolve = updatetol (alg. alg_eigsolve, iter, ϵ)
146- C_current = ψ. C[0 ]
147-
148- # sweep from left to right
149- for pos in 1 : (length (ψ) - 1 )
150- ac2 = AC2 (ψ, pos; kind = :ACAR )
151- h_ac2 = AC2_hamiltonian (pos, ψ, H, ψ, envs)
152- _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
153-
154- al, c, ar = svd_trunc! (ac2′; trunc = alg. trscheme, alg = alg. alg_svd)
155- normalize! (c)
156-
157- ψ. AL[pos] = al
158- ψ. C[pos] = complex (c)
159- ψ. AR[pos + 1 ] = _transpose_front (ar)
160- ψ. AC[pos + 1 ] = _transpose_front (c * ar)
161-
162- transfer_leftenv! (envs, ψ, H, ψ, pos + 1 )
163- transfer_rightenv! (envs, ψ, H, ψ, pos)
82+ @infov 2 begin
83+ E = expectation_value (mps, operator, envs)
84+ loginit! (log, ϵ, E)
85+ end
86+ end
87+
88+ state = IDMRGState (mps, operator, envs, iter, ϵ, E)
89+ it = IterativeSolver (alg, state)
90+
91+ return LoggingExtras. withlevel (; alg. verbosity) do
92+ for (mps, envs, ϵ, ΔE) in it
93+ if ϵ ≤ alg. tol
94+ @infov 2 logfinish! (log, it. iter, ϵ, ΔE)
95+ break
96+ end
97+ if it. iter ≥ alg. maxiter
98+ @warnv 1 logcancel! (log, it. iter, ϵ, ΔE)
99+ break
164100 end
101+ @infov 3 logiter! (log, it. iter, ϵ, ΔE)
102+ end
165103
166- # update the edge
167- ψ . AL[ end ] = ψ . AC[ end ] / ψ . C[ end ]
168- ψ . AC[ 1 ] = _mul_tail (ψ . AL[ 1 ] , ψ. C[ 1 ] )
169- ac2 = AC2 (ψ, 0 ; kind = :ALAC )
170- h_ac2 = AC2_hamiltonian ( 0 , ψ, H, ψ, envs)
171- _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
104+ alg_gauge = updatetol (alg . alg_gauge, it . state . iter, it . state . ϵ)
105+ ψ′ = InfiniteMPS (it . state . mps . AR[ 1 : end ]; alg_gauge . tol, alg_gauge . maxiter)
106+ envs = recalculate! (it . state . envs , ψ′, it . state . operator, ψ′ )
107+ return ψ′, envs, it . state . ϵ
108+ end
109+ end
172110
173- al, c, ar = svd_trunc! (ac2′; trunc = alg. trscheme, alg = alg. alg_svd)
174- normalize! (c)
111+ function Base. iterate (
112+ it:: IterativeSolver{alg_type} , state:: IDMRGState{<:Any, <:Any, <:Any, T} = it. state
113+ ) where {alg_type <: Union{<:IDMRG, <:IDMRG2} , T}
114+ mps, envs, C_old, E_new = localupdate_step! (it, state)
115+
116+ # error criterion
117+ C = mps. C[0 ]
118+ space_C_old = _firstspace (C_old)
119+ space_C = _firstspace (C)
120+ if space_C != space_C_old
121+ smallest = infimum (space_C_old, space_C)
122+ e1 = isometry (space_C_old, smallest)
123+ e2 = isometry (space_C, smallest)
124+ ϵ = norm (e2' * C * e2 - e1' * C_old * e1)
125+ else
126+ ϵ = norm (C - C_old)
127+ end
175128
176- ψ . AL[ end ] = al
177- ψ . C[ end ] = complex (c)
178- ψ . AR[ 1 ] = _transpose_front (ar)
129+ # New energy
130+ ΔE = (E_new - state . energy) / 2
131+ (alg_type <: IDMRG2 && length (mps) == 2 ) && (ΔE /= 2 ) # This extra factor gives the correct energy per unit cell. I have no clue why right now.
179132
180- ψ. AC[end ] = _mul_tail (al, c)
181- ψ. AC[1 ] = _transpose_front (c * ar)
182- ψ. AL[1 ] = ψ. AC[1 ] / ψ. C[1 ]
133+ # update state
134+ it. state = IDMRGState {T} (mps, state. operator, envs, state. iter + 1 , ϵ, E_new)
183135
184- C_current = complex (c)
136+ return (mps, envs, ϵ, ΔE), it. state
137+ end
185138
186- # update environments
187- transfer_leftenv! (envs, ψ, H, ψ, 1 )
188- transfer_rightenv! (envs, ψ, H, ψ, 0 )
139+ function localupdate_step! (
140+ it:: IterativeSolver{<:IDMRG} , state
141+ )
142+ alg_eigsolve = updatetol (it. alg_eigsolve, state. iter, state. ϵ)
143+ return _localupdate_sweep_idmrg! (state. mps, state. operator, state. envs, alg_eigsolve)
144+ end
189145
190- # sweep from right to left
191- for pos in (length (ψ) - 1 ): - 1 : 1
192- ac2 = AC2 (ψ, pos; kind = :ALAC )
193- h_ac2 = AC2_hamiltonian (pos, ψ, H, ψ, envs)
194- _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
146+ function localupdate_step! (
147+ it:: IterativeSolver{<:IDMRG2} , state
148+ )
149+ alg_eigsolve = updatetol (it. alg_eigsolve, state. iter, state. ϵ)
150+ return _localupdate_sweep_idmrg2! (state. mps, state. operator, state. envs, alg_eigsolve, it. trscheme, it. alg_svd)
151+ end
195152
196- al, c, ar = svd_trunc! (ac2′; trunc = alg. trscheme, alg = alg. alg_svd)
197- normalize! (c)
153+ function _localupdate_sweep_idmrg! (ψ, H, envs, alg_eigsolve)
154+ local E
155+ C_old = ψ. C[0 ]
156+ # left to right sweep
157+ for pos in 1 : length (ψ)
158+ h = AC_hamiltonian (pos, ψ, H, ψ, envs)
159+ _, ψ. AC[pos] = fixedpoint (h, ψ. AC[pos], :SR , alg_eigsolve)
160+ if pos == length (ψ)
161+ # AC needed in next sweep
162+ ψ. AL[pos], ψ. C[pos] = left_orth (ψ. AC[pos])
163+ else
164+ ψ. AL[pos], ψ. C[pos] = left_orth! (ψ. AC[pos])
165+ end
166+ transfer_leftenv! (envs, ψ, H, ψ, pos + 1 )
167+ end
198168
199- ψ. AL[pos] = al
200- ψ. AC[pos] = _mul_tail (al, c)
201- ψ. C[pos] = complex (c)
202- ψ. AR[pos + 1 ] = _transpose_front (ar)
203- ψ. AC[pos + 1 ] = _transpose_front (c * ar)
169+ # right to left sweep
170+ for pos in length (ψ): - 1 : 1
171+ h = AC_hamiltonian (pos, ψ, H, ψ, envs)
172+ E, ψ. AC[pos] = fixedpoint (h, ψ. AC[pos], :SR , alg_eigsolve)
204173
205- transfer_leftenv! (envs, ψ, H, ψ, pos + 1 )
206- transfer_rightenv! (envs, ψ, H, ψ, pos)
207- end
174+ ψ. C[pos - 1 ], temp = right_orth! (_transpose_tail (ψ. AC[pos]; copy = (pos == 1 )))
175+ ψ. AR[pos] = _transpose_front (temp)
208176
209- # update the edge
210- ψ. AC[end ] = _mul_front (ψ. C[end - 1 ], ψ. AR[end ])
211- ψ. AR[1 ] = _transpose_front (ψ. C[end ] \ _transpose_tail (ψ. AC[1 ]))
212- ac2 = AC2 (ψ, 0 ; kind = :ACAR )
213- h_ac2 = AC2_hamiltonian (0 , ψ, H, ψ, envs)
214- _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
215- al, c, ar = svd_trunc! (ac2′; trunc = alg. trscheme, alg = alg. alg_svd)
216- normalize! (c)
217-
218- ψ. AL[end ] = al
219- ψ. C[end ] = complex (c)
220- ψ. AR[1 ] = _transpose_front (ar)
221-
222- ψ. AR[end ] = _transpose_front (ψ. C[end - 1 ] \ _transpose_tail (al * c))
223- ψ. AC[1 ] = _transpose_front (c * ar)
224-
225- transfer_leftenv! (envs, ψ, H, ψ, 1 )
226- transfer_rightenv! (envs, ψ, H, ψ, 0 )
227-
228- # update error
229- smallest = infimum (_firstspace (C_current), _firstspace (c))
230- e1 = isometry (_firstspace (C_current), smallest)
231- e2 = isometry (_firstspace (c), smallest)
232- ϵ = norm (e2' * c * e2 - e1' * C_current * e1)
233-
234- if ϵ < alg. tol
235- @infov 2 logfinish! (log, iter, ϵ)
236- break
237- end
238- if iter == alg. maxiter
239- @warnv 1 logcancel! (log, iter, ϵ)
240- else
241- @infov 3 logiter! (log, iter, ϵ)
242- end
243- end
177+ transfer_rightenv! (envs, ψ, H, ψ, pos - 1 )
244178 end
179+ return ψ, envs, C_old, E
180+ end
181+
245182
246- alg_gauge = updatetol (alg. alg_gauge, iter, ϵ)
247- ψ′ = InfiniteMPS (ψ. AR[1 : end ]; alg_gauge. tol, alg_gauge. maxiter)
248- recalculate! (envs, ψ′, H, ψ′)
183+ function _localupdate_sweep_idmrg2! (ψ, H, envs, alg_eigsolve, alg_trscheme, alg_svd)
184+ # sweep from left to right
185+ for pos in 1 : (length (ψ) - 1 )
186+ ac2 = AC2 (ψ, pos; kind = :ACAR )
187+ h_ac2 = AC2_hamiltonian (pos, ψ, H, ψ, envs)
188+ _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
189+
190+ al, c, ar = svd_trunc! (ac2′; trunc = alg_trscheme, alg = alg_svd)
191+ normalize! (c)
192+
193+ ψ. AL[pos] = al
194+ ψ. C[pos] = complex (c)
195+ ψ. AR[pos + 1 ] = _transpose_front (ar)
196+ ψ. AC[pos + 1 ] = _transpose_front (c * ar)
197+
198+ transfer_leftenv! (envs, ψ, H, ψ, pos + 1 )
199+ transfer_rightenv! (envs, ψ, H, ψ, pos)
200+ end
201+
202+ # update the edge
203+ ψ. AL[end ] = ψ. AC[end ] / ψ. C[end ]
204+ ψ. AC[1 ] = _mul_tail (ψ. AL[1 ], ψ. C[1 ])
205+ ac2 = AC2 (ψ, 0 ; kind = :ALAC )
206+ h_ac2 = AC2_hamiltonian (0 , ψ, H, ψ, envs)
207+ _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
208+
209+ al, c, ar = svd_trunc! (ac2′; trunc = alg_trscheme, alg = alg_svd)
210+ normalize! (c)
211+
212+ ψ. AL[end ] = al
213+ ψ. C[end ] = complex (c)
214+ ψ. AR[1 ] = _transpose_front (ar)
215+
216+ ψ. AC[end ] = _mul_tail (al, c)
217+ ψ. AC[1 ] = _transpose_front (c * ar)
218+ ψ. AL[1 ] = ψ. AC[1 ] / ψ. C[1 ]
219+
220+ C_old = complex (c)
221+
222+ # update environments
223+ transfer_leftenv! (envs, ψ, H, ψ, 1 )
224+ transfer_rightenv! (envs, ψ, H, ψ, 0 )
225+
226+ # sweep from right to left
227+ for pos in (length (ψ) - 1 ): - 1 : 1
228+ ac2 = AC2 (ψ, pos; kind = :ALAC )
229+ h_ac2 = AC2_hamiltonian (pos, ψ, H, ψ, envs)
230+ _, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
231+
232+ al, c, ar = svd_trunc! (ac2′; trunc = alg_trscheme, alg = alg_svd)
233+ normalize! (c)
234+
235+ ψ. AL[pos] = al
236+ ψ. AC[pos] = _mul_tail (al, c)
237+ ψ. C[pos] = complex (c)
238+ ψ. AR[pos + 1 ] = _transpose_front (ar)
239+ ψ. AC[pos + 1 ] = _transpose_front (c * ar)
240+
241+ transfer_leftenv! (envs, ψ, H, ψ, pos + 1 )
242+ transfer_rightenv! (envs, ψ, H, ψ, pos)
243+ end
249244
250- return ψ′, envs, ϵ
245+ # update the edge
246+ ψ. AC[end ] = _mul_front (ψ. C[end - 1 ], ψ. AR[end ])
247+ ψ. AR[1 ] = _transpose_front (ψ. C[end ] \ _transpose_tail (ψ. AC[1 ]))
248+ ac2 = AC2 (ψ, 0 ; kind = :ACAR )
249+ h_ac2 = AC2_hamiltonian (0 , ψ, H, ψ, envs)
250+ E, ac2′ = fixedpoint (h_ac2, ac2, :SR , alg_eigsolve)
251+ al, c, ar = svd_trunc! (ac2′; trunc = alg_trscheme, alg = alg_svd)
252+ normalize! (c)
253+
254+ ψ. AL[end ] = al
255+ ψ. C[end ] = complex (c)
256+ ψ. AR[1 ] = _transpose_front (ar)
257+
258+ ψ. AR[end ] = _transpose_front (ψ. C[end - 1 ] \ _transpose_tail (al * c))
259+ ψ. AC[1 ] = _transpose_front (c * ar)
260+
261+ transfer_leftenv! (envs, ψ, H, ψ, 1 )
262+ transfer_rightenv! (envs, ψ, H, ψ, 0 )
263+ return ψ, envs, C_old, E
251264end
0 commit comments