@@ -55,60 +55,73 @@ Construct an MPO that approximates ``\\exp(-iHdt)``.
5555""" make_time_mpo
5656
5757function make_time_mpo(H:: MPOHamiltonian , dt:: Number , alg:: TaylorCluster ;
58- tol= eps(real(scalartype(H)))^ ( 3 / 4 ) )
58+ tol= eps(real(scalartype(H))))
5959 N = alg. N
6060 τ = - 1im * dt
6161
6262 # Hack to store FiniteMPOhamiltonians in "square" MPO tensors
6363 if H isa FiniteMPOHamiltonian
6464 H′ = copy(H)
65- H′[1 ] = similar(H[2 ])
66- H′[end ] = similar(H[end - 1 ])
6765
68- for i in nonzero_keys(H[1 ])
69- H′[1 ][i] = H[1 ][i]
66+ V_left = left_virtualspace(H[1 ])
67+ V_left′ = BlockTensorKit. oplus(V_left, oneunit(V_left), oneunit(V_left))
68+ H′[1 ] = similar(H[1 ], V_left′ ⊗ space(H[1 ], 2 ) ← domain(H[1 ]))
69+ for (I, v) in nonzero_pairs(H[1 ])
70+ H′[1 ][I] = v
7071 end
71- for i in nonzero_keys(H[end ])
72- H′[end ][:, 1 , 1 , end ] = H[end ][:, 1 , 1 , 1 ]
72+
73+ V_right = right_virtualspace(H[end ])
74+ V_right′ = BlockTensorKit. oplus(oneunit(V_right), oneunit(V_right), V_right)
75+ H′[end ] = similar(H[end ], codomain(H[end ]) ← space(H[end ], 3 )' ⊗ V_right′)
76+ for (I, v) in nonzero_pairs(H[end ])
77+ H′[end ][I[1 ], 1 , 1 , end ] = v
7378 end
74- H′[1 ][end , 1 , 1 , end ] += add_util_leg(id(space(H[1 ][end , 1 , 1 , end ], 2 )))
75- H′[end ][1 , 1 , 1 , 1 ] += add_util_leg(id(space(H[end ][1 , 1 , 1 , 1 ], 2 )))
79+
80+ H′[1 ][end , 1 , 1 , end ] = H′[1 ][1 , 1 , 1 , 1 ]
81+ H′[end ][1 , 1 , 1 , 1 ] = H′[end ][end , 1 , 1 , end ]
7682 else
7783 H′ = H
7884 end
7985
8086 # Check if mpo has the same size everywhere. This is assumed in the following.
81- @assert allequal(size.(H′)) " make_time_mpo assumes all mpo tensors to have equal size. A fix for this is yet to be implemented"
87+ # @assert allequal(size.(H′)) "make_time_mpo assumes all mpo tensors to have equal size. A fix for this is yet to be implemented"
8288
8389 # start with H^N
8490 H_n = H′^ N
85- V = size(H′[ 1 ], 1 )
86- linds = LinearIndices(ntuple(i -> V, N) )
87- cinds = CartesianIndices(linds)
91+ virtual_sz = map( 0 : length(H′)) do i
92+ return i == 0 ? size(H′[ 1 ], 1 ) : size(H′[i], 4 )
93+ end
8894
8995 # extension step: Algorithm 3
9096 # incorporate higher order terms
9197 # TODO : don't need to fully construct H_next...
9298 if alg. extension
9399 H_next = H_n * H′
94- linds_next = LinearIndices(ntuple(i -> V, N + 1 ))
95100 for (i, slice) in enumerate(parent(H_n))
96- for a in cinds, b in cinds
101+ V_left = virtual_sz[i]
102+ V_right = virtual_sz[i + 1 ]
103+ linds_left = LinearIndices(ntuple(Returns(V_left), N))
104+ linds_right = LinearIndices(ntuple(Returns(V_right), N))
105+ linds_next_left = LinearIndices(ntuple(Returns(V_left), N + 1 ))
106+ linds_next_right = LinearIndices(ntuple(Returns(V_right), N + 1 ))
107+
108+ for a in CartesianIndices(linds_left), b in CartesianIndices(linds_right)
97109 all(> (1 ), b. I) || continue
98- all(in((1 , V )), a. I) && any(== (V ), a. I) && continue
110+ all(in((1 , V_left )), a. I) && any(== (V_left ), a. I) && continue
99111
100112 n1 = count(== (1 ), a. I) + 1
101- n3 = count(== (V ), b. I) + 1
113+ n3 = count(== (V_right ), b. I) + 1
102114 factor = τ * factorial(N) / (factorial(N + 1 ) * n1 * n3)
103115
104116 for c in 1 : (N + 1 ), d in 1 : (N + 1 )
105117 aₑ = insert!([a. I... ], c, 1 )
106- bₑ = insert!([b. I... ], d, V )
118+ bₑ = insert!([b. I... ], d, V_right )
107119
108120 # TODO : use VectorInterface for memory efficiency
109- slice[linds[a], 1 , 1 , linds[b]] += factor *
110- H_next[i][linds_next[aₑ... ], 1 , 1 ,
111- linds_next[bₑ... ]]
121+ slice[linds_left[a], 1 , 1 , linds_right[b]] += factor *
122+ H_next[i][linds_next_left[aₑ... ],
123+ 1 , 1 ,
124+ linds_next_right[bₑ... ]]
112125 end
113126 end
114127 end
@@ -117,12 +130,15 @@ function make_time_mpo(H::MPOHamiltonian, dt::Number, alg::TaylorCluster;
117130 # loopback step: Algorithm 1
118131 # constructing the Nth order time evolution MPO
119132 mpo = MPO(parent(H_n))
120- for slice in parent(mpo)
121- for b in cinds[2 : end ]
122- all(in((1 , V)), b. I) || continue
123-
124- b_lin = linds[b]
125- a = count(== (V), b. I)
133+ for (i, slice) in enumerate(parent(mpo))
134+ V_right = virtual_sz[i + 1 ]
135+ linds_right = LinearIndices(ntuple(Returns(V_right), N))
136+ cinds_right = CartesianIndices(linds_right)
137+ for b in cinds_right[2 : end ]
138+ all(in((1 , V_right)), b. I) || continue
139+
140+ b_lin = linds_right[b]
141+ a = count(== (V_right), b. I)
126142 factor = τ^ a * factorial(N - a) / factorial(N)
127143 slice[:, 1 , 1 , 1 ] = slice[:, 1 , 1 , 1 ] + factor * slice[:, 1 , 1 , b_lin]
128144 for I in nonzero_keys(slice)
@@ -132,54 +148,79 @@ function make_time_mpo(H::MPOHamiltonian, dt::Number, alg::TaylorCluster;
132148 end
133149
134150 # Remove equivalent rows and columns: Algorithm 2
135- for slice in parent(mpo)
136- for c in cinds
137- c_lin = linds[c]
151+ for (i, slice) in enumerate(parent(mpo))
152+ V_left = virtual_sz[i]
153+ linds_left = LinearIndices(ntuple(Returns(V_left), N))
154+ for c in CartesianIndices(linds_left)
155+ c_lin = linds_left[c]
138156 s_c = CartesianIndex(sort(collect(c. I); by= (!= (1 ))). .. )
139- s_r = CartesianIndex(sort(collect(c. I); by= (!= (V))). .. )
140157
141158 n1 = count(== (1 ), c. I)
142- n3 = count(== (V), c. I)
143-
144- if n3 <= n1 && s_c != c || n3 > n1 && s_r != c
145- if n3 <= n1 && s_c != c
146- for k in 1 : size(slice, 4 )
147- if CartesianIndex(c_lin, 1 , 1 , k) in nonzero_keys(slice)
148- slice[linds[s_c], 1 , 1 , k] += slice[c_lin, 1 , 1 , k]
149- end
150- end
151- elseif n3 > n1 && s_r != c
152- for k in 1 : size(slice, 1 )
153- if CartesianIndex(k, 1 , 1 , c_lin) in nonzero_keys(slice)
154- slice[k, 1 , 1 , linds[s_r]] += slice[k, 1 , 1 , c_lin]
155- end
159+ n3 = count(== (V_left), c. I)
160+
161+ if n3 <= n1 && s_c != c
162+ for k in 1 : size(slice, 4 )
163+ I = CartesianIndex(c_lin, 1 , 1 , k)
164+ if I in nonzero_keys(slice)
165+ slice[linds_left[s_c], 1 , 1 , k] += slice[I]
166+ delete!(slice, I)
156167 end
157168 end
158- for I in nonzero_keys(slice)
159- (I[1 ] == c_lin || I[4 ] == c_lin) && delete!(slice, I)
169+ end
170+ end
171+
172+ V_right = virtual_sz[i + 1 ]
173+ linds_right = LinearIndices(ntuple(Returns(V_right), N))
174+ for c in CartesianIndices(linds_right)
175+ c_lin = linds_right[c]
176+ s_r = CartesianIndex(sort(collect(c. I); by= (!= (V_right))). .. )
177+
178+ n1 = count(== (1 ), c. I)
179+ n3 = count(== (V_right), c. I)
180+
181+ if n3 > n1 && s_r != c
182+ for k in 1 : size(slice, 1 )
183+ I = CartesianIndex(k, 1 , 1 , c_lin)
184+ if I in nonzero_keys(slice)
185+ slice[k, 1 , 1 , linds_right[s_r]] += slice[I]
186+ delete!(slice, I)
187+ end
160188 end
161189 end
162190 end
163191 end
164192
165193 # Approximate compression step: Algorithm 4
166194 if alg. compression
167- for slice in parent(mpo)
168- for a in cinds
195+ for (i, slice) in enumerate(parent(mpo))
196+ V_right = virtual_sz[i + 1 ]
197+ linds_right = LinearIndices(ntuple(Returns(V_right), N))
198+ for a in CartesianIndices(linds_right)
169199 all(> (1 ), a. I) || continue
170- a_lin = linds[a]
171- n1 = count(== (V), a. I)
172- b = CartesianIndex(replace(a. I, V => 1 ))
173- b_lin = linds[b]
200+ a_lin = linds_right[a]
201+ n1 = count(== (V_right), a. I)
202+ n1 == 0 && continue
203+ b = CartesianIndex(replace(a. I, V_right => 1 ))
204+ b_lin = linds_right[b]
174205 factor = τ^ n1 * factorial(N - n1) / factorial(N)
175206 for k in 1 : size(slice, 1 )
176- if CartesianIndex(k, 1 , 1 , a_lin) in nonzero_keys(slice)
177- slice[k, 1 , 1 , b_lin] += factor * slice[k, 1 , 1 , a_lin]
207+ I = CartesianIndex(k, 1 , 1 , a_lin)
208+ if I in nonzero_keys(slice)
209+ slice[k, 1 , 1 , b_lin] += factor * slice[I]
210+ delete!(slice, I)
178211 end
179212 end
180-
181- for I in nonzero_keys(slice)
182- (I[1 ] == a_lin || I[4 ] == a_lin) && delete!(slice, I)
213+ end
214+ V_left = virtual_sz[i]
215+ linds_left = LinearIndices(ntuple(Returns(V_left), N))
216+ for a in CartesianIndices(linds_left)
217+ all(> (1 ), a. I) || continue
218+ a_lin = linds_left[a]
219+ n1 = count(== (V_left), a. I)
220+ n1 == 0 && continue
221+ for k in 1 : size(slice, 4 )
222+ I = CartesianIndex(a_lin, 1 , 1 , k)
223+ delete!(slice, I)
183224 end
184225 end
185226 end
@@ -191,7 +232,7 @@ function make_time_mpo(H::MPOHamiltonian, dt::Number, alg::TaylorCluster;
191232 mpo[end ] = mpo[end ][:, :, :, 1 ]
192233 end
193234
194- return remove_orphans!(mpo; tol= tol )
235+ return remove_orphans!(mpo; tol)
195236end
196237
197238has_prod_elem(slice, t1, t2) = all(map(x -> contains(slice, x... ), zip(t1, t2)))
0 commit comments