Skip to content

Commit

Permalink
Merge pull request qutip#44 from albertomercurio/dev/superoperator
Browse files Browse the repository at this point in the history
Support `OperatorBraQuantumObject` and `OperatorKetQuantumObject`
  • Loading branch information
albertomercurio authored Apr 7, 2024
2 parents 96528e5 + 0096192 commit 999823f
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 9 deletions.
4 changes: 4 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ CurrentModule = QuantumToolbox
BraQuantumObject
KetQuantumObject
OperatorQuantumObject
OperatorBraQuantumObject
OperatorKetQuantumObject
SuperOperatorQuantumObject
QuantumObject
Qobj
ket2dm
isbra
isket
isoper
isoperbra
isoperket
issuper
size
eltype
Expand Down
4 changes: 2 additions & 2 deletions src/QuantumToolbox.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ include("eigsolve.jl")
include("negativity.jl")
include("progress_bar.jl")

export QuantumObject, Qobj, BraQuantumObject, KetQuantumObject, OperatorQuantumObject, SuperOperatorQuantumObject, TimeEvolutionSol
export isket, isbra, isoper, issuper, ket2dm
export QuantumObject, Qobj, BraQuantumObject, KetQuantumObject, OperatorQuantumObject, OperatorBraQuantumObject, OperatorKetQuantumObject, SuperOperatorQuantumObject, TimeEvolutionSol
export isket, isbra, isoper, isoperbra, isoperket, issuper, ket2dm
export spre, spost, sprepost, lindblad_dissipator
export fock, basis, coherent
export sigmam, sigmap, sigmax, sigmay, sigmaz
Expand Down
15 changes: 14 additions & 1 deletion src/general_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ function vec2mat(A::AbstractVector)
reshape(A, newsize, newsize)
end

@doc raw"""
vec2mat(A::QuantumObject)
Convert a quantum object from vector (`OperatorKetQuantumObject`-type) to matrix (`OperatorQuantumObject`-type)
"""
vec2mat(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = QuantumObject(vec2mat(A.data), OperatorQuantumObject, A.dims)

@doc raw"""
gaussian(x::Number, μ::Number, σ::Number)
Expand Down Expand Up @@ -387,4 +393,11 @@ function mat2vec(::Type{M}) where M <: Union{Adjoint{<:BlasFloat,<:SparseMatrixC
npar = length(par)
(2 == npar) || error("Type $M is not supported.")
return SparseVector{par[1], par[2]}
end
end

@doc raw"""
mat2vec(A::QuantumObject)
Convert a quantum object from matrix (`OperatorQuantumObject`-type) to vector (`OperatorKetQuantumObject`-type)
"""
mat2vec(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = QuantumObject(mat2vec(A.data), OperatorKetQuantumObject, A.dims)
82 changes: 77 additions & 5 deletions src/quantum_object.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ Abstract type representing a super-operator ``\hat{\mathcal{O}}``.
"""
abstract type SuperOperatorQuantumObject <: QuantumObjectType end

@doc raw"""
OperatorBraQuantumObject <: QuantumObjectType
Abstract type representing a bra state in the super-operator formalism ``\langle\langle\rho|``.
"""
abstract type OperatorBraQuantumObject <: QuantumObjectType end

@doc raw"""
OperatorKetQuantumObject <: QuantumObjectType
Abstract type representing a ket state in the super-operator formalism ``|\rho\rangle\rangle``.
"""
abstract type OperatorKetQuantumObject <: QuantumObjectType end

@doc raw"""
mutable struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType}
data::MT
Expand Down Expand Up @@ -91,10 +105,12 @@ function QuantumObject(A::AbstractArray{T, N}; type::Type{ObjType}=Nothing, dims
if dims === nothing
if (type <: KetQuantumObject) || (type <: OperatorQuantumObject)
dims = [Size[1]]
elseif type <: SuperOperatorQuantumObject
elseif (type <: SuperOperatorQuantumObject) || (type <: OperatorKetQuantumObject)
dims = [isqrt(Size[1])]
elseif type <: BraQuantumObject
dims = [Size[2]]
elseif type <: OperatorBraQuantumObject
dims = [isqrt(Size[2])]
end
end

Expand Down Expand Up @@ -122,6 +138,16 @@ function _check_QuantumObject(type::Type{SuperOperatorQuantumObject}, prod_dims:
prod_dims != sqrt(m) ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing
end

function _check_QuantumObject(type::Type{OperatorKetQuantumObject}, prod_dims::Int, m::Int, n::Int)
(n != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Operator-Ket type")) : nothing
prod_dims != sqrt(m) ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing
end

function _check_QuantumObject(type::Type{OperatorBraQuantumObject}, prod_dims::Int, m::Int, n::Int)
(m != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Operator-Bra type")) : nothing
prod_dims != sqrt(n) ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing
end

function QuantumObject(A::QuantumObject{<:AbstractArray}; type::Type{ObjType}=A.type, dims=A.dims) where
{ObjType<:QuantumObjectType}

Expand Down Expand Up @@ -165,6 +191,20 @@ Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorQuantumObject`](@ref) s
"""
isoper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: OperatorQuantumObject

"""
isoperbra(A::QuantumObject)
Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorBraQuantumObject`](@ref) state.
"""
isoperbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: OperatorBraQuantumObject

"""
isoperket(A::QuantumObject)
Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorKetQuantumObject`](@ref) state.
"""
isoperket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: OperatorKetQuantumObject

"""
issuper(A::QuantumObject)
Expand Down Expand Up @@ -244,7 +284,7 @@ LinearAlgebra.Hermitian(A::QuantumObject{<:AbstractArray{T},OpType}, uplo::Symbo
QuantumObject(Hermitian(A.data, uplo), A.type, A.dims)

function Base.show(io::IO, ::MIME"text/plain", QO::QuantumObject{<:AbstractArray{T},OpType}) where
{T,OpType<:Union{BraQuantumObject,KetQuantumObject,SuperOperatorQuantumObject}}
{T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorBraQuantumObject,OperatorKetQuantumObject,SuperOperatorQuantumObject}}

op_data = QO.data
op_dims = QO.dims
Expand All @@ -253,6 +293,10 @@ function Base.show(io::IO, ::MIME"text/plain", QO::QuantumObject{<:AbstractArray
op_type = "Ket"
elseif op_type <: BraQuantumObject
op_type = "Bra"
elseif op_type <: OperatorKetQuantumObject
op_type = "Operator-Ket"
elseif op_type <: OperatorBraQuantumObject
op_type = "Operator-Bra"
else
op_type = "SuperOperator"
end
Expand Down Expand Up @@ -305,16 +349,40 @@ function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},BraQuantumObjec
A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension."))
A.data * B.data
end
function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject},
B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2}
A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension."))
QuantumObject(vec2mat(A.data * mat2vec(B.data)), OperatorQuantumObject, A.dims)
end
function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject},
B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}) where {T1,T2}
A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension."))
A.data * B.data
end
function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject},
B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}) where {T1,T2}
A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension."))
QuantumObject(A.data * B.data, OperatorKetQuantumObject, A.dims)
end
function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject},
B::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}) where {T1,T2}
A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension."))
QuantumObject(A.data * B.data, OperatorBraQuantumObject, A.dims)
end

LinearAlgebra.:(^)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} =
QuantumObject(^(A.data, n), OpType, A.dims)
LinearAlgebra.:(/)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} =
QuantumObject(/(A.data, n), OpType, A.dims)
LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType},
B::QuantumObject{<:AbstractArray{T2},OpType}) where {T1<:Number,T2<:Number,OpType<:KetQuantumObject} =
LinearAlgebra.dot(A.data, B.data)
function LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where
{T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}}

A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension."))
LinearAlgebra.dot(A.data, B.data)
end

Base.conj(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} =
QuantumObject(conj(A.data), OpType, A.dims)
LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
QuantumObject(adjoint(A.data), OpType, A.dims)
LinearAlgebra.transpose(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
Expand All @@ -323,6 +391,10 @@ LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},KetQuantumObject}) whe
QuantumObject(adjoint(A.data), BraQuantumObject, A.dims)
LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},BraQuantumObject}) where {T} =
QuantumObject(adjoint(A.data), KetQuantumObject, A.dims)
LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} =
QuantumObject(adjoint(A.data), OperatorBraQuantumObject, A.dims)
LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorBraQuantumObject}) where {T} =
QuantumObject(adjoint(A.data), OperatorKetQuantumObject, A.dims)

LinearAlgebra.inv(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
QuantumObject(sparse(inv(Matrix(A.data))), OpType, A.dims)
Expand Down
61 changes: 60 additions & 1 deletion test/quantum_objects.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@testset "Quantum Objects" begin
# unsupported size of array
for a in [rand(ComplexF64, 3, 2), rand(ComplexF64, 2, 2, 2)]
for t in [Nothing, KetQuantumObject, BraQuantumObject, OperatorQuantumObject, SuperOperatorQuantumObject]
for t in [Nothing, KetQuantumObject, BraQuantumObject, OperatorQuantumObject, SuperOperatorQuantumObject, OperatorBraQuantumObject, OperatorKetQuantumObject]
@test_throws DomainError Qobj(a, type=t)
end
end
Expand All @@ -12,9 +12,11 @@
@test_throws DomainError Qobj(a, type=BraQuantumObject)
@test_throws DomainError Qobj(a, type=OperatorQuantumObject)
@test_throws DomainError Qobj(a, type=SuperOperatorQuantumObject)
@test_throws DomainError Qobj(a, type=OperatorBraQuantumObject)
@test_throws DomainError Qobj(a', type=KetQuantumObject)
@test_throws DomainError Qobj(a', type=OperatorQuantumObject)
@test_throws DomainError Qobj(a', type=SuperOperatorQuantumObject)
@test_throws DomainError Qobj(a', type=OperatorKetQuantumObject)
@test_throws DimensionMismatch Qobj(a, dims=[2])
@test_throws DimensionMismatch Qobj(a', dims=[2])
a2 = Qobj(a')
Expand All @@ -23,10 +25,14 @@
@test isbra(a2) == true
@test isoper(a2) == false
@test issuper(a2) == false
@test isoperket(a2) == false
@test isoperbra(a2) == false
@test isket(a3) == true
@test isbra(a3) == false
@test isoper(a3) == false
@test issuper(a3) == false
@test isoperket(a3) == false
@test isoperbra(a3) == false
@test Qobj(a3) == a3
@test !(Qobj(a3) === a3)
@test isket(Qobj(Matrix([2 3])')) == true
Expand All @@ -39,10 +45,48 @@
@test isbra(a2) == false
@test isoper(a2) == true
@test issuper(a2) == false
@test isoperket(a2) == false
@test isoperbra(a2) == false
@test isket(a3) == false
@test isbra(a3) == false
@test isoper(a3) == false
@test issuper(a3) == true
@test isoperket(a3) == false
@test isoperbra(a3) == false
@test_throws DimensionMismatch Qobj(a, dims=[2])
@test_throws DimensionMismatch Qobj(a, dims=[2])

# Operator-Ket, Operator-Bra tests
H = 0.3 * sigmax() + 0.7 * sigmaz()
L = liouvillian(H)
ρ = Qobj(rand(ComplexF64, 2, 2))
ρ_ket = mat2vec(ρ)
ρ_bra = ρ_ket'
@test ρ_bra == Qobj(mat2vec.data)', type=OperatorBraQuantumObject)
@test ρ == vec2mat(ρ_ket)
@test isket(ρ_ket) == false
@test isbra(ρ_ket) == false
@test isoper(ρ_ket) == false
@test issuper(ρ_ket) == false
@test isoperket(ρ_ket) == true
@test isoperbra(ρ_ket) == false
@test isket(ρ_bra) == false
@test isbra(ρ_bra) == false
@test isoper(ρ_bra) == false
@test issuper(ρ_bra) == false
@test isoperket(ρ_bra) == false
@test isoperbra(ρ_bra) == true
@test ρ_bra.dims == [2]
@test ρ_ket.dims == [2]
@test H * ρ spre(H) * ρ
@test ρ * H spost(H) * ρ
@test H * ρ * H sprepost(H, H) * ρ
@test (L * ρ_ket).dims == [2]
@test L * ρ_ket -1im * (+(spre(H) * ρ_ket) - spost(H) * ρ_ket)
@test (ρ_bra * L')' == L * ρ_ket
@test sum((conj(ρ) .* ρ).data) dot(ρ_ket, ρ_ket) ρ_bra * ρ_ket
@test_throws DimensionMismatch Qobj(ρ_ket.data, type=OperatorKetQuantumObject, dims=[4])
@test_throws DimensionMismatch Qobj(ρ_bra.data, type=OperatorBraQuantumObject, dims=[4])

a = Array(a)
a4 = Qobj(a)
Expand All @@ -60,6 +104,7 @@

@test transpose(transpose(a2)) == a2
@test transpose(a2).data == transpose(a2.data)
@test adjoint(a2) transpose(conj(a2))
@test adjoint(adjoint(a2)) == a2
@test adjoint(a2).data == adjoint(a2.data)

Expand Down Expand Up @@ -152,6 +197,20 @@
ψ_size = size(ψ)
@test opstring == "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring"

ψ2 = Qobj(rand(ComplexF64, 4), type=OperatorKetQuantumObject)
opstring = sprint((t, s) -> show(t, "text/plain", s), ψ2)
datastring = sprint((t, s) -> show(t, "text/plain", s), ψ2.data)
ψ2_dims = ψ2.dims
ψ2_size = size(ψ2)
@test opstring == "Quantum Object: type=Operator-Ket dims=$ψ2_dims size=$ψ2_size\n$datastring"

ψ2 = ψ2'
opstring = sprint((t, s) -> show(t, "text/plain", s), ψ2)
datastring = sprint((t, s) -> show(t, "text/plain", s), ψ2.data)
ψ2_dims = ψ2.dims
ψ2_size = size(ψ2)
@test opstring == "Quantum Object: type=Operator-Bra dims=$ψ2_dims size=$ψ2_size\n$datastring"

ψ = coherent(30, 3)
α, δψ = get_coherence(ψ)
@test isapprox(abs(α), 3, atol=1e-5) && abs2(δψ[1]) > 0.999
Expand Down

0 comments on commit 999823f

Please sign in to comment.