@@ -55,9 +55,12 @@ DenseMPO(mpo::MPO) = mpo isa DenseMPO ? copy(mpo) : MPO(map(TensorMap, parent(mp
5555Base. parent (mpo:: MPO ) = mpo. O
5656Base. copy (mpo:: MPO ) = MPO (map (copy, mpo))
5757
58- function Base. similar (mpo:: MPO , :: Type{O} , L:: Int ) where {O}
58+ function Base. similar (mpo:: MPO{<:MPOTensor} , :: Type{O} , L:: Int ) where {O<: MPOTensor }
5959 return MPO (similar (parent (mpo), O, L))
6060end
61+ function Base. similar (mpo:: MPO , :: Type{T} ) where {T<: Number }
62+ return MPO (similar .(parent (mpo), T))
63+ end
6164
6265Base. repeat (mpo:: MPO , n:: Int ) = MPO (repeat (parent (mpo), n))
6366Base. repeat (mpo:: MPO , rows:: Int , cols:: Int ) = MultilineMPO (fill (repeat (mpo, cols), rows))
@@ -102,19 +105,20 @@ function Base.convert(::Type{TensorMap}, mpo::FiniteMPO{<:MPOTensor})
102105 return convert (TensorMap, _instantiate_finitempo (L, M, R))
103106end
104107
108+ Base. complex (mpo:: MPO ) = MPO (map (complex, parent (mpo)))
109+
105110# Linear Algebra
106111# --------------
107112# VectorInterface.scalartype(::Type{FiniteMPO{O}}) where {O} = scalartype(O)
108113
109114Base.:+ (mpo:: MPO ) = MPO (map (+ , parent (mpo)))
110- function Base.:+ (mpo1:: FiniteMPO{TO } , mpo2:: FiniteMPO{TO} ) where {TO <: MPOTensor }
111- ( N = length (mpo1)) == length ( mpo2) || throw ( ArgumentError ( " dimension mismatch " ) )
115+ function Base.:+ (mpo1:: FiniteMPO{<:MPOTensor } , mpo2:: FiniteMPO{<:MPOTensor} )
116+ N = check_length (mpo1, mpo2)
112117 @assert left_virtualspace (mpo1, 1 ) == left_virtualspace (mpo2, 1 ) &&
113118 right_virtualspace (mpo1, N) == right_virtualspace (mpo2, N)
114119
115- mpo = similar (parent (mpo1))
116120 halfN = N ÷ 2
117- A = storagetype (TO )
121+ A = storagetype (eltype (mpo1) )
118122
119123 # left half
120124 F₁ = isometry (A, (right_virtualspace (mpo1, 1 ) ⊕ right_virtualspace (mpo2, 1 )),
@@ -127,7 +131,9 @@ function Base.:+(mpo1::FiniteMPO{TO}, mpo2::FiniteMPO{TO}) where {TO<:MPOTensor}
127131
128132 # making sure that the new operator is "full rank"
129133 O, R = leftorth! (O)
130- mpo[1 ] = transpose (O, ((2 , 3 ), (1 , 4 )))
134+ O′ = transpose (O, ((2 , 3 ), (1 , 4 )))
135+ mpo = similar (mpo1, typeof (O′))
136+ mpo[1 ] = O′
131137
132138 for i in 2 : halfN
133139 # incorporate fusers from left side
@@ -193,11 +199,18 @@ function VectorInterface.scale!(mpo::MPO, α::Number)
193199 scale! (first (mpo), α)
194200 return mpo
195201end
202+ function VectorInterface. scale! (dst:: MPO , src:: MPO , α:: Number )
203+ N = check_length (dst, src)
204+ for i in 1 : N
205+ scale! (dst[i], src[i], i == 1 ? α : One ())
206+ end
207+ return dst
208+ end
209+
210+ function Base.:* (mpo1:: FiniteMPO{<:MPOTensor} , mpo2:: FiniteMPO{<:MPOTensor} )
211+ N = check_length (mpo1, mpo2)
212+ (S = spacetype (mpo1)) == spacetype (mpo2) || throw (SectorMismatch ())
196213
197- # TODO : merge implementation with that of InfiniteMPO
198- function Base.:* (mpo1:: FiniteMPO{TO} , mpo2:: FiniteMPO{TO} ) where {TO<: MPOTensor }
199- (N = length (mpo1)) == length (mpo2) || throw (ArgumentError (" dimension mismatch" ))
200- S = spacetype (TO)
201214 if (left_virtualspace (mpo1, 1 ) != oneunit (S) ||
202215 left_virtualspace (mpo2, 1 ) != oneunit (S)) ||
203216 (right_virtualspace (mpo1, N) != oneunit (S) ||
@@ -207,44 +220,34 @@ function Base.:*(mpo1::FiniteMPO{TO}, mpo2::FiniteMPO{TO}) where {TO<:MPOTensor}
207220 # would work and for now I dont feel like figuring out if this is important
208221 end
209222
210- O = similar (parent (mpo1))
211- A = storagetype (TO)
212-
213- # note order of mpos: mpo1 * mpo2 * state -> mpo2 on top of mpo1
214- local Fᵣ # trick to make Fᵣ defined in the loop
215- for i in 1 : N
216- Fₗ = i != 1 ? Fᵣ : fuser (A, left_virtualspace (mpo2, i), left_virtualspace (mpo1, i))
217- Fᵣ = fuser (A, right_virtualspace (mpo2, i), right_virtualspace (mpo1, i))
218- @plansor O[i][- 1 - 2 ; - 3 - 4 ] := Fₗ[- 1 ; 1 4 ] * mpo2[i][1 2 ; - 3 3 ] *
219- mpo1[i][4 - 2 ; 2 5 ] *
220- conj (Fᵣ[- 4 ; 3 5 ])
221- end
222-
223+ O = map (fuse_mul_mpo, parent (mpo1), parent (mpo2))
223224 return changebonds! (FiniteMPO (O), SvdCut (; trscheme= notrunc ()))
224225end
226+ function Base.:* (mpo1:: InfiniteMPO , mpo2:: InfiniteMPO )
227+ check_length (mpo1, mpo2)
228+ Os = map (fuse_mul_mpo, parent (mpo1), parent (mpo2))
229+ return InfiniteMPO (Os)
230+ end
225231
226232function Base.:* (mpo:: FiniteMPO , mps:: FiniteMPS )
227- length (mpo) == length (mps) || throw (ArgumentError (" dimension mismatch" ))
228-
229- A = [mps. AC[1 ]; mps. AR[2 : end ]]
230- TT = storagetype (eltype (A))
231-
232- local Fᵣ # trick to make Fᵣ defined in the loop
233- for i in 1 : length (mps)
234- Fₗ = i != 1 ? Fᵣ : fuser (TT, left_virtualspace (mps, i), left_virtualspace (mpo, i))
235- Fᵣ = fuser (TT, right_virtualspace (mps, i), right_virtualspace (mpo, i))
236- A[i] = _fuse_mpo_mps (mpo[i], A[i], Fₗ, Fᵣ)
233+ N = check_length (mpo, mps)
234+ T = TensorOperations. promote_contract (scalartype (mpo), scalartype (mps))
235+ A = TensorKit. similarstoragetype (eltype (mps), T)
236+ Fᵣ = fuser (A, left_virtualspace (mps, 1 ), left_virtualspace (mpo, 1 ))
237+ A2 = map (1 : N) do i
238+ A1 = i == 1 ? mps. AC[1 ] : mps. AR[i]
239+ Fₗ = Fᵣ
240+ Fᵣ = fuser (A, right_virtualspace (mps, i), right_virtualspace (mpo, i))
241+ return _fuse_mpo_mps (mpo[i], A1, Fₗ, Fᵣ)
237242 end
238-
239- return changebonds! (FiniteMPS (A),
240- SvdCut (; trscheme= truncbelow (eps (real (scalartype (TT)))));
241- normalize= false )
243+ trscheme = truncbelow (eps (real (T)))
244+ return changebonds! (FiniteMPS (A2), SvdCut (; trscheme); normalize= false )
242245end
243-
244246function Base.:* (mpo:: InfiniteMPO , mps:: InfiniteMPS )
245247 L = check_length (mpo, mps)
246248 T = promote_type (scalartype (mpo), scalartype (mps))
247- fusers = PeriodicArray (fuser .(T, left_virtualspace .(Ref (mps), 1 : L),
249+ A = TensorKit. similarstoragetype (eltype (mps), T)
250+ fusers = PeriodicArray (fuser .(A, left_virtualspace .(Ref (mps), 1 : L),
248251 left_virtualspace .(Ref (mpo), 1 : L)))
249252 As = map (1 : L) do i
250253 return _fuse_mpo_mps (mpo[i], mps. AL[i], fusers[i], fusers[i + 1 ])
@@ -260,12 +263,6 @@ function _fuse_mpo_mps(O::MPOTensor, A::MPSTensor, Fₗ, Fᵣ)
260263 return A′ isa AbstractBlockTensorMap ? TensorMap (A′) : A′
261264end
262265
263- function Base.:* (mpo1:: InfiniteMPO , mpo2:: InfiniteMPO )
264- check_length (mpo1, mpo2)
265- Os = map (fuse_mul_mpo, parent (mpo1), parent (mpo2))
266- return InfiniteMPO (Os)
267- end
268-
269266function Base.:* (mpo:: FiniteMPO{<:MPOTensor} , x:: AbstractTensorMap )
270267 @assert length (mpo) > 1
271268 @assert numout (x) == length (mpo)
281278# in the middle
282279function TensorKit. dot (bra:: FiniteMPS{T} , mpo:: FiniteMPO{<:MPOTensor} ,
283280 ket:: FiniteMPS{T} ) where {T}
284- (N = length (bra)) == length (mpo) == length (ket) ||
285- throw (ArgumentError (" dimension mismatch" ))
281+ N = check_length (bra, mpo, ket)
286282 Nhalf = N ÷ 2
287283 # left half
288284 ρ_left = isomorphism (storagetype (T),
0 commit comments