diff --git a/src/MPSKit.jl b/src/MPSKit.jl index 8e96d607d..cd465643d 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -97,6 +97,7 @@ include("utility/logging.jl") using .IterativeLoggers include("utility/iterativesolvers.jl") +include("utility/styles.jl") include("utility/periodicarray.jl") include("utility/windowarray.jl") include("utility/multiline.jl") diff --git a/src/operators/mpo.jl b/src/operators/mpo.jl index ae16181fd..58b7e2ecf 100644 --- a/src/operators/mpo.jl +++ b/src/operators/mpo.jl @@ -17,6 +17,8 @@ Matrix Product Operator (MPO) acting on a finite tensor product space with a lin """ const FiniteMPO{O} = MPO{O, Vector{O}} Base.isfinite(::Type{<:FiniteMPO}) = true +GeometryStyle(::Type{<:FiniteMPO}) = FiniteChainStyle() +OperatorStyle(::Type{<:MPO}) = MPOStyle() function FiniteMPO(Os::AbstractVector{O}) where {O} for i in eachindex(Os)[1:(end - 1)] @@ -37,6 +39,7 @@ Matrix Product Operator (MPO) acting on an infinite tensor product space with a """ const InfiniteMPO{O} = MPO{O, PeriodicVector{O}} Base.isfinite(::Type{<:InfiniteMPO}) = false +GeometryStyle(::Type{<:InfiniteMPO}) = InfiniteChainStyle() function InfiniteMPO(Os::AbstractVector{O}) where {O} for i in eachindex(Os) diff --git a/src/operators/mpohamiltonian.jl b/src/operators/mpohamiltonian.jl index 97f938609..aa7c4004e 100644 --- a/src/operators/mpohamiltonian.jl +++ b/src/operators/mpohamiltonian.jl @@ -31,9 +31,11 @@ operators in a form that is compatible with this constructor. struct MPOHamiltonian{TO <: JordanMPOTensor, V <: AbstractVector{TO}} <: AbstractMPO{TO} W::V end +OperatorStyle(::Type{<:MPOHamiltonian}) = HamiltonianStyle() const FiniteMPOHamiltonian{O <: MPOTensor} = MPOHamiltonian{O, Vector{O}} Base.isfinite(::Type{<:FiniteMPOHamiltonian}) = true +GeometryStyle(::Type{<:FiniteMPOHamiltonian}) = FiniteChainStyle() function FiniteMPOHamiltonian(Ws::AbstractVector{O}) where {O <: MPOTensor} for i in eachindex(Ws)[1:(end - 1)] @@ -45,6 +47,7 @@ end const InfiniteMPOHamiltonian{O <: MPOTensor} = MPOHamiltonian{O, PeriodicVector{O}} Base.isfinite(::Type{<:InfiniteMPOHamiltonian}) = false +GeometryStyle(::Type{<:InfiniteMPOHamiltonian}) = InfiniteChainStyle() function InfiniteMPOHamiltonian(Ws::AbstractVector{O}) where {O <: MPOTensor} for i in eachindex(Ws) diff --git a/src/states/abstractmps.jl b/src/states/abstractmps.jl index 6dd8a1341..5c1e82c1d 100644 --- a/src/states/abstractmps.jl +++ b/src/states/abstractmps.jl @@ -173,6 +173,7 @@ abstract type AbstractFiniteMPS <: AbstractMPS end Base.eltype(ψ::AbstractMPS) = eltype(typeof(ψ)) VectorInterface.scalartype(T::Type{<:AbstractMPS}) = scalartype(site_type(T)) +Base.isfinite(ψ::AbstractMPS) = isfinite(typeof(ψ)) function Base.checkbounds(ψ::AbstractMPS, i) return Base.checkbounds(Bool, ψ, i) || throw(BoundsError(ψ, i)) diff --git a/src/states/finitemps.jl b/src/states/finitemps.jl index 44ac3fa64..b9e1e8734 100644 --- a/src/states/finitemps.jl +++ b/src/states/finitemps.jl @@ -311,7 +311,8 @@ function Base.similar(ψ::FiniteMPS{A, B}) where {A, B} return FiniteMPS{A, B}(similar(ψ.ALs), similar(ψ.ARs), similar(ψ.ACs), similar(ψ.Cs)) end -Base.isfinite(ψ::FiniteMPS) = true +Base.isfinite(::Type{<:FiniteMPS}) = true +GeometryStyle(::Type{<:FiniteMPS}) = FiniteChainStyle() Base.eachindex(ψ::FiniteMPS) = eachindex(ψ.AL) Base.eachindex(l::IndexStyle, ψ::FiniteMPS) = eachindex(l, ψ.AL) diff --git a/src/states/infinitemps.jl b/src/states/infinitemps.jl index 62c278afb..8e3780ad3 100644 --- a/src/states/infinitemps.jl +++ b/src/states/infinitemps.jl @@ -241,7 +241,8 @@ Base.size(ψ::InfiniteMPS, args...) = size(ψ.AL, args...) Base.length(ψ::InfiniteMPS) = length(ψ.AL) Base.eltype(ψ::InfiniteMPS) = eltype(typeof(ψ)) Base.eltype(::Type{<:InfiniteMPS{A}}) where {A} = A -Base.isfinite(ψ::InfiniteMPS) = false +Base.isfinite(::Type{<:InfiniteMPS}) = false +GeometryStyle(::Type{<:InfiniteMPS}) = InfiniteChainStyle() Base.copy(ψ::InfiniteMPS) = InfiniteMPS(copy(ψ.AL), copy(ψ.AR), copy(ψ.C), copy(ψ.AC)) function Base.copy!(ψ::InfiniteMPS, ϕ::InfiniteMPS) diff --git a/src/states/multilinemps.jl b/src/states/multilinemps.jl index 73f68fac6..6a66437b4 100644 --- a/src/states/multilinemps.jl +++ b/src/states/multilinemps.jl @@ -101,7 +101,7 @@ Base.convert(::Type{InfiniteMPS}, st::MultilineMPS) = only(st) Base.eltype(t::MultilineMPS) = eltype(t[1]) Base.copy!(ψ::MultilineMPS, ϕ::MultilineMPS) = (copy!.(parent(ψ), parent(ϕ)); ψ) -Base.isfinite(ψ::MultilineMPS) = false +Base.isfinite(::Type{<:MultilineMPS}) = false for f_space in (:physicalspace, :left_virtualspace, :right_virtualspace) @eval $f_space(t::MultilineMPS, i::Int, j::Int) = $f_space(t[i], j) diff --git a/src/states/quasiparticle_state.jl b/src/states/quasiparticle_state.jl index 87dbfc6e7..6fd61f30e 100644 --- a/src/states/quasiparticle_state.jl +++ b/src/states/quasiparticle_state.jl @@ -212,6 +212,8 @@ const FiniteQP{S <: FiniteMPS, T1, T2} = QP{S, T1, T2} const InfiniteQP{S <: InfiniteMPS, T1, T2} = QP{S, T1, T2} const MultilineQP{Q <: QP} = Multiline{Q} +GeometryStyle(::Type{<:QP{S, T1, T2}}) where {S, T1, T2} = GeometryStyle(S) + TensorKit.spacetype(::Union{QP{S}, Type{<:QP{S}}}) where {S} = spacetype(S) TensorKit.sectortype(::Union{QP{S}, Type{<:QP{S}}}) where {S} = sectortype(S) diff --git a/src/utility/multiline.jl b/src/utility/multiline.jl index 549766ee9..a1c861ff1 100644 --- a/src/utility/multiline.jl +++ b/src/utility/multiline.jl @@ -29,6 +29,7 @@ function Base.axes(m::Multiline, i::Int) i == 2 ? axes(parent(m)[1], 1) : throw(ArgumentError("Invalid index $i")) end Base.eachindex(m::Multiline) = CartesianIndices(size(m)) +Base.isfinite(m::Multiline) = isfinite(typeof(m)) eachsite(m::Multiline) = eachsite(first(parent(m))) @@ -54,6 +55,12 @@ function Base.repeat(A::Multiline, rows::Int, cols::Int) return Multiline(outer) end +# Style +# ---------------- + +OperatorStyle(::Type{Multiline{T}}) where {T} = OperatorStyle(T) +GeometryStyle(::Type{Multiline{T}}) where {T} = GeometryStyle(T) + # VectorInterface # --------------- VectorInterface.scalartype(::Type{Multiline{T}}) where {T} = scalartype(T) diff --git a/src/utility/styles.jl b/src/utility/styles.jl new file mode 100644 index 000000000..104b4e562 --- /dev/null +++ b/src/utility/styles.jl @@ -0,0 +1,37 @@ +""" + abstract type OperatorStyle + OperatorStyle(x) + OperatorStyle(::Type{T}) + +Trait to describe the operator behavior of the input `x` or type `T`, which can be either +* `MPOStyle()`: product of local factors; +* `HamiltonianStyle()`: sum of local terms. +""" +abstract type OperatorStyle end +OperatorStyle(x) = OperatorStyle(typeof(x)) +OperatorStyle(T::Type) = throw(MethodError(OperatorStyle, T)) # avoid stackoverflow if not defined + +struct MPOStyle <: OperatorStyle end +struct HamiltonianStyle <: OperatorStyle end + +@doc (@doc OperatorStyle) MPOStyle +@doc (@doc OperatorStyle) HamiltonianStyle + +""" + abstract type GeometryStyle + GeometryStyle(x) + GeometryStyle(::Type{T}) + +Trait to describe the geometry of the input `x` or type `T`, which can be either +* `FiniteChainStyle()`: object is defined on a finite chain; +* `InfiniteChainStyle()`: object is defined on an infinite chain. +""" +abstract type GeometryStyle end +GeometryStyle(x) = GeometryStyle(typeof(x)) +GeometryStyle(T::Type) = throw(MethodError(GeometryStyle, T)) # avoid stackoverflow if not defined + +struct FiniteChainStyle <: GeometryStyle end +struct InfiniteChainStyle <: GeometryStyle end + +@doc (@doc GeometryStyle) FiniteChainStyle +@doc (@doc GeometryStyle) InfiniteChainStyle diff --git a/test/operators.jl b/test/operators.jl index 03fadeea4..b2390437d 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -10,6 +10,8 @@ module TestOperators using MPSKit using MPSKit: _transpose_front, _transpose_tail, C_hamiltonian, AC_hamiltonian, AC2_hamiltonian + using MPSKit: GeometryStyle, FiniteChainStyle, InfiniteChainStyle, OperatorStyle, MPOStyle, + HamiltonianStyle using TensorKit using TensorKit: ℙ using VectorInterface: One @@ -32,6 +34,13 @@ module TestOperators mpo₂ = FiniteMPO(O₂) mpo₃ = FiniteMPO(O₃) + @test isfinite(mpo₁) + @test isfinite(typeof(mpo₁)) + @test GeometryStyle(typeof(mpo₁)) == FiniteChainStyle() + @test GeometryStyle(mpo₁) == FiniteChainStyle() + @test OperatorStyle(typeof(mpo₁)) == MPOStyle() + + @test @constinferred physicalspace(mpo₁) == fill(V, L) Vleft = @constinferred left_virtualspace(mpo₁) Vright = @constinferred right_virtualspace(mpo₂) @@ -81,6 +90,22 @@ module TestOperators end end + @testset "InfiniteMPO" begin + P = ℂ^2 + T = Float64 + + H1 = randn(T, P ← P) + H1 += H1' + H = InfiniteMPO([H1]) + + @test !isfinite(H) + @test !isfinite(typeof(H)) + @test GeometryStyle(typeof(H)) == InfiniteChainStyle() + @test GeometryStyle(H) == InfiniteChainStyle() + @test OperatorStyle(typeof(H)) == MPOStyle() + @test OperatorStyle(H) == MPOStyle() + end + @testset "MPOHamiltonian constructors" begin P = ℂ^2 T = Float64 @@ -109,6 +134,13 @@ module TestOperators H′ = FiniteMPOHamiltonian(map(Base.Fix1(collect, Any), Ws)) # without type info @test H ≈ H′ + @test isfinite(H) + @test isfinite(typeof(H)) + @test GeometryStyle(typeof(H)) == FiniteChainStyle() + @test GeometryStyle(H) == FiniteChainStyle() + @test OperatorStyle(typeof(H)) == HamiltonianStyle() + @test OperatorStyle(H) == HamiltonianStyle() + # Infinite Ws = [Wmid] H = InfiniteMPOHamiltonian( @@ -119,6 +151,13 @@ module TestOperators H′ = InfiniteMPOHamiltonian(map(Base.Fix1(collect, Any), Ws)) # without type info @test all(parent(H) .≈ parent(H′)) + + @test !isfinite(H) + @test !isfinite(typeof(H)) + @test GeometryStyle(typeof(H)) == InfiniteChainStyle() + @test GeometryStyle(H) == InfiniteChainStyle() + @test OperatorStyle(typeof(H)) == HamiltonianStyle() + @test OperatorStyle(H) == HamiltonianStyle() end @testset "Finite MPOHamiltonian" begin diff --git a/test/other.jl b/test/other.jl index af1ca0563..17b3138fe 100644 --- a/test/other.jl +++ b/test/other.jl @@ -8,6 +8,8 @@ module TestMiscellaneous using ..TestSetup using Test, TestExtras using MPSKit + using MPSKit: GeometryStyle, FiniteChainStyle, InfiniteChainStyle, OperatorStyle, MPOStyle, + HamiltonianStyle using TensorKit using TensorKit: ℙ using Plots @@ -101,4 +103,22 @@ module TestMiscellaneous check = " ⎡⠉⠉⠉⠉⎤🭻🭻⎡⡏⠉⠛⠟⎤🭻🭻⎡⡏⠉⠛⠟⎤🭻🭻⎡⡇⠀⎤ \n ⎣⠀⠀⠀⠀⎦ ⎣⡇⠀⠀⡂⎦ ⎣⡇⠀⠀⡂⎦ ⎣⡇⠀⎦ \n" @test output == check end + + @testset "Styles" begin + @test_throws MethodError OperatorStyle(42) + @test_throws MethodError OperatorStyle(Float64) + @test_throws MethodError GeometryStyle("abc") + @test_throws MethodError GeometryStyle(UInt8) + + @test OperatorStyle(MPO) == MPOStyle() + @test OperatorStyle(InfiniteMPO) == MPOStyle() + + @test GeometryStyle(FiniteMPOHamiltonian) == FiniteChainStyle() + @test GeometryStyle(InfiniteMPS) == InfiniteChainStyle() + @test GeometryStyle(FiniteMPS) == FiniteChainStyle() + @test GeometryStyle(FiniteMPO) == FiniteChainStyle() + @test GeometryStyle(FiniteMPOHamiltonian) == FiniteChainStyle() + @test GeometryStyle(InfiniteMPO) == InfiniteChainStyle() + @test GeometryStyle(InfiniteMPOHamiltonian) == InfiniteChainStyle() + end end diff --git a/test/states.jl b/test/states.jl index 7762b844c..3bed6207f 100644 --- a/test/states.jl +++ b/test/states.jl @@ -9,6 +9,7 @@ module TestStates using Test, TestExtras using MPSKit using MPSKit: _transpose_front, _transpose_tail + using MPSKit: GeometryStyle, FiniteChainStyle, InfiniteChainStyle using MPSKit: TransferMatrix using TensorKit using TensorKit: ℙ @@ -24,11 +25,18 @@ module TestStates L = rand(3:20) ψ = FiniteMPS(rand, elt, L, d, D) + @test eachindex(IndexLinear(), ψ) == eachindex(ψ) @test isfinite(ψ) + @test isfinite(typeof(ψ)) + @test isfinite(ψ) == isfinite(typeof(ψ)) + @test GeometryStyle(typeof(ψ)) == FiniteChainStyle() + @test GeometryStyle(ψ) == FiniteChainStyle() @test @constinferred physicalspace(ψ) == fill(d, L) @test all(x -> x ≾ D, @constinferred left_virtualspace(ψ)) @test all(x -> x ≾ D, @constinferred right_virtualspace(ψ)) + @test eltype(ψ) == eltype(typeof(ψ)) + ovl = dot(ψ, ψ) @test ovl ≈ norm(ψ.AC[1])^2 @@ -100,7 +108,14 @@ module TestStates ψ = InfiniteMPS([rand(elt, D * d, D), rand(elt, D * d, D)]; tol) + @test !isfinite(typeof(ψ)) @test !isfinite(ψ) + @test isfinite(ψ) == isfinite(typeof(ψ)) + @test GeometryStyle(typeof(ψ)) == InfiniteChainStyle() + @test GeometryStyle(ψ) == InfiniteChainStyle() + + @test eltype(ψ) == eltype(typeof(ψ)) + @test physicalspace(ψ) == fill(d, 2) @test all(x -> x ≾ D, left_virtualspace(ψ)) @test all(x -> x ≾ D, right_virtualspace(ψ)) @@ -132,6 +147,11 @@ module TestStates ]; tol ) + @test GeometryStyle(typeof(ψ)) == InfiniteChainStyle() + @test GeometryStyle(ψ) == InfiniteChainStyle() + + @test !isfinite(typeof(ψ)) + @test physicalspace(ψ) == fill(d, 2, 2) @test all(x -> x ≾ D, left_virtualspace(ψ)) @test all(x -> x ≾ D, right_virtualspace(ψ)) @@ -170,6 +190,8 @@ module TestStates # constructor 2 - used to take a "slice" from an infinite mps window_2 = WindowMPS(gs, 10) + @test eltype(window_1) == eltype(typeof(window_1)) + P = @constinferred physicalspace(window_2) Vleft = @constinferred left_virtualspace(window_2) Vright = @constinferred right_virtualspace(window_2) @@ -231,9 +253,13 @@ module TestStates ϕ₁ = LeftGaugedQP(rand, ψ) ϕ₂ = LeftGaugedQP(rand, ψ) + @test GeometryStyle(ϕ₁) == FiniteChainStyle() + @test GeometryStyle(typeof(ϕ₂)) == FiniteChainStyle() + @test @constinferred physicalspace(ϕ₁) == physicalspace(ψ) @test @constinferred left_virtualspace(ϕ₁) == left_virtualspace(ψ) @test @constinferred right_virtualspace(ϕ₁) == right_virtualspace(ψ) + @test TensorKit.sectortype(ϕ₁) == TensorKit.sectortype(ψ) @test norm(axpy!(1, ϕ₁, copy(ϕ₂))) ≤ norm(ϕ₁) + norm(ϕ₂) @test norm(ϕ₁) * 3 ≈ norm(ϕ₁ * 3) @@ -262,10 +288,15 @@ module TestStates period = rand(1:4) ψ = InfiniteMPS(fill(d, period), fill(D, period)) + @test eltype(ψ) == eltype(typeof(ψ)) + #rand_quasiparticle is a private non-exported function ϕ₁ = LeftGaugedQP(rand, ψ) ϕ₂ = LeftGaugedQP(rand, ψ) + @test GeometryStyle(ϕ₁) == InfiniteChainStyle() + @test GeometryStyle(typeof(ϕ₂)) == InfiniteChainStyle() + @test @constinferred physicalspace(ϕ₁) == physicalspace(ψ) @test @constinferred left_virtualspace(ϕ₁) == left_virtualspace(ψ) @test @constinferred right_virtualspace(ϕ₁) == right_virtualspace(ψ)