Skip to content

Commit 1e3c513

Browse files
leburgellkdvos
andauthored
Relax MPO element type restrictions (#244)
* Relax MPO element type restrictions * Apply suggestions from code review Co-authored-by: Lukas Devos <[email protected]> * Add TODO for merging finite and infinite MPO multiplication * Replace `similar` with appropriate `allocate_GL` --------- Co-authored-by: Lukas Devos <[email protected]>
1 parent 3c01bd8 commit 1e3c513

File tree

3 files changed

+35
-45
lines changed

3 files changed

+35
-45
lines changed

src/operators/abstractmpo.jl

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Matrix Product Operators
22
# ========================
33
"""
4-
abstract type AbstractMPO{O<:MPOTensor} <: AbstractVector{O} end
4+
abstract type AbstractMPO{O} <: AbstractVector{O} end
55
66
Abstract supertype for Matrix Product Operators (MPOs).
77
"""
8-
abstract type AbstractMPO{O<:MPOTensor} <: AbstractVector{O} end
8+
abstract type AbstractMPO{O} <: AbstractVector{O} end
99

1010
# useful union types
1111
const SparseMPO{O<:SparseBlockTensorMap} = AbstractMPO{O}
@@ -16,7 +16,7 @@ Base.size(mpo::AbstractMPO, args...) = size(parent(mpo), args...)
1616
Base.length(mpo::AbstractMPO) = length(parent(mpo))
1717

1818
@inline Base.getindex(mpo::AbstractMPO, i::Int) = getindex(parent(mpo), i)
19-
@inline function Base.setindex!(mpo::AbstractMPO, value::MPOTensor, i::Int)
19+
@inline function Base.setindex!(mpo::AbstractMPO, value, i::Int)
2020
setindex!(parent(mpo), value, i)
2121
return mpo
2222
end
@@ -194,20 +194,24 @@ end
194194
# Kernels
195195
# -------
196196
# TODO: diagram
197+
198+
function _fuse_mpo_mpo(O1::MPOTensor, O2::MPOTensor, Fₗ, Fᵣ)
199+
return @plansor O′[-1 -2; -3 -4] := Fₗ[-1; 1 2] *
200+
O2[1 3; -3 5] *
201+
O1[2 -2; 3 4] *
202+
conj(Fᵣ[-4; 5 4])
203+
end
204+
197205
"""
198206
fuse_mul_mpo(O1, O2)
199207
200208
Compute the mpo tensor that arises from multiplying MPOs.
201209
"""
202-
function fuse_mul_mpo(O1::MPOTensor, O2::MPOTensor)
210+
function fuse_mul_mpo(O1, O2)
203211
T = promote_type(scalartype(O1), scalartype(O2))
204212
F_left = fuser(T, left_virtualspace(O2), left_virtualspace(O1))
205213
F_right = fuser(T, right_virtualspace(O2), right_virtualspace(O1))
206-
@plansor O[-1 -2; -3 -4] := F_left[-1; 1 2] *
207-
O2[1 5; -3 3] *
208-
O1[2 -2; 5 4] *
209-
conj(F_right[-4; 3 4])
210-
return O
214+
return _fuse_mpo_mpo(O1, O2, F_left, F_right)
211215
end
212216
function fuse_mul_mpo(O1::BraidingTensor, O2::BraidingTensor)
213217
T = promote_type(scalartype(O1), scalartype(O2))

src/operators/mpo.jl

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
"""
2-
struct MPO{O<:MPOTensor,V<:AbstractVector{O}} <: AbstractMPO{O}
2+
struct MPO{O,V<:AbstractVector{O}} <: AbstractMPO{O}
33
44
Matrix Product Operator (MPO) acting on a tensor product space with a linear order.
55
66
See also: [`FiniteMPO`](@ref), [`InfiniteMPO`](@ref)
77
"""
8-
struct MPO{TO<:MPOTensor,V<:AbstractVector{TO}} <: AbstractMPO{TO}
8+
struct MPO{TO,V<:AbstractVector{TO}} <: AbstractMPO{TO}
99
O::V
1010
end
1111

1212
"""
13-
FiniteMPO(Os::Vector{<:MPOTensor}) -> FiniteMPO
14-
FiniteMPO(O::AbstractTensorMap{S,N,N}) where {S,N} -> FiniteMPO
13+
FiniteMPO(Os::Vector{O}) -> FiniteMPO{O}
14+
FiniteMPO(O::AbstractTensorMap{S,N,N}) where {S,N} -> FiniteMPO{O<:MPOTensor}
1515
1616
Matrix Product Operator (MPO) acting on a finite tensor product space with a linear order.
1717
"""
18-
const FiniteMPO{O<:MPOTensor} = MPO{O,Vector{O}}
18+
const FiniteMPO{O} = MPO{O,Vector{O}}
1919
Base.isfinite(::Type{<:FiniteMPO}) = true
2020

21-
function FiniteMPO(Os::AbstractVector{O}) where {O<:MPOTensor}
21+
function FiniteMPO(Os::AbstractVector{O}) where {O}
2222
for i in eachindex(Os)[1:(end - 1)]
2323
right_virtualspace(Os[i]) == left_virtualspace(Os[i + 1]) ||
2424
throw(SpaceMismatch("unmatching virtual spaces at site $i"))
@@ -31,14 +31,14 @@ function FiniteMPO(O::AbstractTensorMap{T,S,N,N}) where {T,S,N}
3131
end
3232

3333
"""
34-
InfiniteMPO(Os::PeriodicVector{<:MPOTensor}) -> InfiniteMPO
34+
InfiniteMPO(Os::PeriodicVector{O}) -> InfiniteMPO{O}
3535
3636
Matrix Product Operator (MPO) acting on an infinite tensor product space with a linear order.
3737
"""
38-
const InfiniteMPO{O<:MPOTensor} = MPO{O,PeriodicVector{O}}
38+
const InfiniteMPO{O} = MPO{O,PeriodicVector{O}}
3939
Base.isfinite(::Type{<:InfiniteMPO}) = false
4040

41-
function InfiniteMPO(Os::AbstractVector{O}) where {O<:MPOTensor}
41+
function InfiniteMPO(Os::AbstractVector{O}) where {O}
4242
for i in eachindex(Os)
4343
right_virtualspace(Os[i]) == left_virtualspace(Os[mod1(i + 1, end)]) ||
4444
throw(SpaceMismatch("umatching virtual spaces at site $i"))
@@ -55,7 +55,7 @@ DenseMPO(mpo::MPO) = mpo isa DenseMPO ? copy(mpo) : MPO(map(TensorMap, parent(mp
5555
Base.parent(mpo::MPO) = mpo.O
5656
Base.copy(mpo::MPO) = MPO(map(copy, mpo))
5757

58-
function Base.similar(mpo::MPO, ::Type{O}, L::Int) where {O<:MPOTensor}
58+
function Base.similar(mpo::MPO, ::Type{O}, L::Int) where {O}
5959
return MPO(similar(parent(mpo), O, L))
6060
end
6161

@@ -95,7 +95,7 @@ function _mps_to_mpo(A::GenericMPSTensor{S,3}) where {S}
9595
return O
9696
end
9797

98-
function Base.convert(::Type{TensorMap}, mpo::FiniteMPO)
98+
function Base.convert(::Type{TensorMap}, mpo::FiniteMPO{<:MPOTensor})
9999
N = length(mpo)
100100
# add trivial tensors to remove left and right trivial leg.
101101
V_left = left_virtualspace(mpo, 1)
@@ -120,7 +120,7 @@ end
120120
# VectorInterface.scalartype(::Type{FiniteMPO{O}}) where {O} = scalartype(O)
121121

122122
Base.:+(mpo::MPO) = MPO(map(+, parent(mpo)))
123-
function Base.:+(mpo1::FiniteMPO{TO}, mpo2::FiniteMPO{TO}) where {TO}
123+
function Base.:+(mpo1::FiniteMPO{TO}, mpo2::FiniteMPO{TO}) where {TO<:MPOTensor}
124124
(N = length(mpo1)) == length(mpo2) || throw(ArgumentError("dimension mismatch"))
125125
@assert left_virtualspace(mpo1, 1) == left_virtualspace(mpo2, 1) &&
126126
right_virtualspace(mpo1, N) == right_virtualspace(mpo2, N)
@@ -207,7 +207,8 @@ function VectorInterface.scale!(mpo::MPO, α::Number)
207207
return mpo
208208
end
209209

210-
function Base.:*(mpo1::FiniteMPO{TO}, mpo2::FiniteMPO{TO}) where {TO}
210+
# TODO: merge implementation with that of InfiniteMPO
211+
function Base.:*(mpo1::FiniteMPO{TO}, mpo2::FiniteMPO{TO}) where {TO<:MPOTensor}
211212
(N = length(mpo1)) == length(mpo2) || throw(ArgumentError("dimension mismatch"))
212213
S = spacetype(TO)
213214
if (left_virtualspace(mpo1, 1) != oneunit(S) ||
@@ -273,29 +274,16 @@ function _fuse_mpo_mps(O::MPOTensor, A::MPSTensor, Fₗ, Fᵣ)
273274
end
274275

275276
function Base.:*(mpo1::InfiniteMPO, mpo2::InfiniteMPO)
276-
L = check_length(mpo1, mpo2)
277-
278-
T = promote_type(scalartype(mpo1), scalartype(mpo2))
279-
make_fuser(i) = fuser(T, left_virtualspace(mpo2, i), left_virtualspace(mpo1, i))
280-
fusers = PeriodicArray(map(make_fuser, 1:L))
281-
282-
Os = map(1:L) do i
283-
return _fuse_mpo_mpo(mpo1[i], mpo2[i], fusers[i], fusers[i + 1])
284-
end
277+
check_length(mpo1, mpo2)
278+
Os = map(fuse_mul_mpo, parent(mpo1), parent(mpo2))
285279
return InfiniteMPO(Os)
286280
end
287281

288-
function _fuse_mpo_mpo(O1::MPOTensor, O2::MPOTensor, Fₗ, Fᵣ)
289-
return @plansor O′[-1 -2; -3 -4] := Fₗ[-1; 1 4] *
290-
O2[1 2; -3 3] *
291-
O1[4 -2; 2 5] *
292-
conj(Fᵣ[-4; 3 5])
293-
end
294-
295282
# TODO: I think the fastest order is to start from both ends, and take the overlap at the
296283
# largest virtual space cut, but it might be better to just multithread both sides and meet
297284
# in the middle
298-
function TensorKit.dot(bra::FiniteMPS{T}, mpo::FiniteMPO, ket::FiniteMPS{T}) where {T}
285+
function TensorKit.dot(bra::FiniteMPS{T}, mpo::FiniteMPO{<:MPOTensor},
286+
ket::FiniteMPS{T}) where {T}
299287
(N = length(bra)) == length(mpo) == length(ket) ||
300288
throw(ArgumentError("dimension mismatch"))
301289
Nhalf = N ÷ 2
@@ -320,17 +308,15 @@ function TensorKit.dot(bra::FiniteMPS{T}, mpo::FiniteMPO, ket::FiniteMPS{T}) whe
320308
end
321309
function TensorKit.dot(bra::InfiniteMPS, mpo::InfiniteMPO, ket::InfiniteMPS;
322310
ishermitian=false, krylovdim=30, kwargs...)
323-
ρ₀ = similar(bra.AL[1],
324-
left_virtualspace(ket, 1) * left_virtualspace(mpo, 1)
325-
left_virtualspace(bra, 1))
311+
ρ₀ = allocate_GL(bra, mpo, ket, 1)
326312
randomize!(ρ₀)
327313

328314
val, = fixedpoint(TransferMatrix(ket.AL, parent(mpo), bra.AL), ρ₀, :LM; ishermitian,
329315
krylovdim, kwargs...)
330316
return val
331317
end
332318

333-
function TensorKit.dot(mpo₁::FiniteMPO, mpo₂::FiniteMPO)
319+
function TensorKit.dot(mpo₁::FiniteMPO{TO}, mpo₂::FiniteMPO{TO}) where {TO<:MPOTensor}
334320
length(mpo₁) == length(mpo₂) || throw(ArgumentError("dimension mismatch"))
335321
N = length(mpo₁)
336322
Nhalf = N ÷ 2

src/operators/multilinempo.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ See also: [`Multiline`](@ref), [`AbstractMPO`](@ref)
1313
"""
1414
const MultilineMPO = Multiline{<:AbstractMPO}
1515

16-
function MultilineMPO(Os::AbstractMatrix{T}) where {T<:MPOTensor}
16+
function MultilineMPO(Os::AbstractMatrix)
1717
return MultilineMPO(map(FiniteMPO, eachrow(Os)))
1818
end
19-
function MultilineMPO(Os::PeriodicMatrix{T}) where {T<:MPOTensor}
19+
function MultilineMPO(Os::PeriodicMatrix)
2020
return MultilineMPO(map(InfiniteMPO, eachrow(Os)))
2121
end
2222
MultilineMPO(mpos::AbstractVector{<:AbstractMPO}) = Multiline(mpos)

0 commit comments

Comments
 (0)