diff --git a/.github/workflows/CI.yml b/.github/workflows/Runtests.yml similarity index 86% rename from .github/workflows/CI.yml rename to .github/workflows/Runtests.yml index 476bde26..147ef774 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/Runtests.yml @@ -28,6 +28,7 @@ jobs: strategy: fail-fast: false matrix: + # for core tests version: - '1.8' - '1.9' @@ -40,6 +41,14 @@ jobs: - x64 group: - Core + + # for code quality tests + include: + - version: '1' + os: 'ubuntu-latest' + arch: 'x64' + group: 'Code-Quality' + steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 @@ -58,4 +67,4 @@ jobs: with: files: lcov.info token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true + fail_ci_if_error: true \ No newline at end of file diff --git a/Project.toml b/Project.toml index 3b218281..08cf4043 100644 --- a/Project.toml +++ b/Project.toml @@ -19,26 +19,26 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" [compat] -Aqua = "0.6, 0.7, 0.8" -DiffEqCallbacks = "2.24, 3" +DiffEqCallbacks = "2, 3" Distributed = "<0.0.1, 1" FFTW = "1.5" -Graphs = "1.7.4" +Graphs = "1.7" IncompleteLU = "0.2" LinearAlgebra = "<0.0.1, 1" LinearMaps = "3" LinearSolve = "2" -OrdinaryDiffEq = "6.30" +OrdinaryDiffEq = "6" +Pkg = "<0.0.1, 1" Random = "<0.0.1, 1" Reexport = "1" SparseArrays = "<0.0.1, 1" -SpecialFunctions = "2.2" +SpecialFunctions = "2" Test = "<0.0.1, 1" julia = "1.7" [extras] +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" [targets] -test = ["Test", "Aqua"] +test = ["Pkg", "Test"] diff --git a/src/general_functions.jl b/src/general_functions.jl index 6a02ed2c..5fdf12ac 100644 --- a/src/general_functions.jl +++ b/src/general_functions.jl @@ -115,7 +115,7 @@ end 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) +vec2mat(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = QuantumObject(vec2mat(A.data), OperatorQuantumObject(), A.dims) @doc raw""" gaussian(x::Number, μ::Number, σ::Number) @@ -166,18 +166,24 @@ Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true 0.0+0.0im 0.5+0.0im ``` """ -function ptrace(QO::QuantumObject{<:AbstractArray{T1},OpType}, sel::Vector{T2}) where - {T1,T2<:Int,OpType<:Union{KetQuantumObject,OperatorQuantumObject}} +function ptrace(QO::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, sel::Vector{T2}) where + {T1,T2<:Integer} length(QO.dims) == 1 && return QO - if isket(QO) || isbra(QO) - ρtr, dkeep = _ptrace_ket(QO.data, QO.dims, sel) - return QuantumObject(ρtr, dims=dkeep) - elseif isoper(QO) - ρtr, dkeep = _ptrace_oper(QO.data, QO.dims, sel) - return QuantumObject(ρtr, dims=dkeep) - end + ρtr, dkeep = _ptrace_ket(QO.data, QO.dims, sel) + return QuantumObject(ρtr, dims=dkeep) +end + +ptrace(QO::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, sel::Vector{T2}) where {T1,T2<:Integer} = ptrace(QO', sel) + +function ptrace(QO::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, sel::Vector{T2}) where + {T1,T2<:Integer} + + length(QO.dims) == 1 && return QO + + ρtr, dkeep = _ptrace_oper(QO.data, QO.dims, sel) + return QuantumObject(ρtr, dims=dkeep) end ptrace(QO::QuantumObject, sel::Int) = ptrace(QO, [sel]) @@ -400,4 +406,4 @@ end 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) \ No newline at end of file +mat2vec(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = QuantumObject(mat2vec(A.data), OperatorKetQuantumObject(), A.dims) \ No newline at end of file diff --git a/src/negativity.jl b/src/negativity.jl index 79386a32..c112b038 100644 --- a/src/negativity.jl +++ b/src/negativity.jl @@ -88,7 +88,7 @@ function _partial_transpose(ρ::QuantumObject{<:AbstractArray, OperatorQuantumOb ] return QuantumObject( reshape(PermutedDimsArray(reshape(ρ.data, (ρ.dims..., ρ.dims...)), pt_idx), size(ρ)), - OperatorQuantumObject, + OperatorQuantumObject(), ρ.dims ) end @@ -130,7 +130,7 @@ function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray, OperatorQua return QuantumObject( sparse(I_pt, J_pt, V_pt, M, N), - OperatorQuantumObject, + OperatorQuantumObject(), ρ.dims ) end \ No newline at end of file diff --git a/src/quantum_object.jl b/src/quantum_object.jl index 24484a39..daacb035 100644 --- a/src/quantum_object.jl +++ b/src/quantum_object.jl @@ -8,49 +8,49 @@ abstract type QuantumObjectType end @doc raw""" BraQuantumObject <: QuantumObjectType -Abstract type representing a bra state ``\bra{\psi}``. +Constructor representing a bra state ``\bra{\psi}``. """ -abstract type BraQuantumObject <: QuantumObjectType end +struct BraQuantumObject <: QuantumObjectType end @doc raw""" KetQuantumObject <: QuantumObjectType -Abstract type representing a ket state ``\ket{\psi}``. +Constructor representing a ket state ``\ket{\psi}``. """ -abstract type KetQuantumObject <: QuantumObjectType end +struct KetQuantumObject <: QuantumObjectType end @doc raw""" OperatorQuantumObject <: QuantumObjectType -Abstract type representing an operator ``\hat{O}``. +Constructor representing an operator ``\hat{O}``. """ -abstract type OperatorQuantumObject <: QuantumObjectType end +struct OperatorQuantumObject <: QuantumObjectType end @doc raw""" SuperOperatorQuantumObject <: QuantumObjectType -Abstract type representing a super-operator ``\hat{\mathcal{O}}``. +Constructor representing a super-operator ``\hat{\mathcal{O}}``. """ -abstract type SuperOperatorQuantumObject <: QuantumObjectType end +struct SuperOperatorQuantumObject <: QuantumObjectType end @doc raw""" OperatorBraQuantumObject <: QuantumObjectType -Abstract type representing a bra state in the super-operator formalism ``\langle\langle\rho|``. +Constructor representing a bra state in the super-operator formalism ``\langle\langle\rho|``. """ -abstract type OperatorBraQuantumObject <: QuantumObjectType end +struct OperatorBraQuantumObject <: QuantumObjectType end @doc raw""" OperatorKetQuantumObject <: QuantumObjectType -Abstract type representing a ket state in the super-operator formalism ``|\rho\rangle\rangle``. +Constructor representing a ket state in the super-operator formalism ``|\rho\rangle\rangle``. """ -abstract type OperatorKetQuantumObject <: QuantumObjectType end +struct OperatorKetQuantumObject <: QuantumObjectType end @doc raw""" mutable struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType} data::MT - type::Type{ObjType} + type::ObjType dims::Vector{Int} end @@ -74,11 +74,11 @@ true """ mutable struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType} <: AbstractQuantumObject data::MT - type::Type{ObjType} + type::ObjType dims::Vector{Int} end -function QuantumObject(A::AbstractArray{T, N}; type::Type{ObjType}=Nothing, dims=nothing) where {T,N,ObjType<:Union{Nothing,QuantumObjectType}} +function QuantumObject(A::AbstractArray{T, N}; type::ObjType=nothing, dims=nothing) where {T,N,ObjType<:Union{Nothing,QuantumObjectType}} # only accept 1D- and 2D-array if N == 1 @@ -89,13 +89,13 @@ function QuantumObject(A::AbstractArray{T, N}; type::Type{ObjType}=Nothing, dims end # decide QuantumObjectType from the size of A - if type == Nothing + if type === nothing if Size[1] == Size[2] - type = OperatorQuantumObject + type = OperatorQuantumObject() elseif Size[2] == 1 - type = KetQuantumObject + type = KetQuantumObject() elseif Size[1] == 1 - type = BraQuantumObject + type = BraQuantumObject() else throw(DomainError(Size, "The dimension of the array is not compatible with Quantum Object")) end @@ -103,13 +103,13 @@ function QuantumObject(A::AbstractArray{T, N}; type::Type{ObjType}=Nothing, dims # decide dims from the size of A and the given type if dims === nothing - if (type <: KetQuantumObject) || (type <: OperatorQuantumObject) + if (type isa KetQuantumObject) || (type isa OperatorQuantumObject) dims = [Size[1]] - elseif (type <: SuperOperatorQuantumObject) || (type <: OperatorKetQuantumObject) + elseif (type isa SuperOperatorQuantumObject) || (type isa OperatorKetQuantumObject) dims = [isqrt(Size[1])] - elseif type <: BraQuantumObject + elseif type isa BraQuantumObject dims = [Size[2]] - elseif type <: OperatorBraQuantumObject + elseif type isa OperatorBraQuantumObject dims = [isqrt(Size[2])] end end @@ -118,37 +118,37 @@ function QuantumObject(A::AbstractArray{T, N}; type::Type{ObjType}=Nothing, dims return QuantumObject(A, type, dims) end -function _check_QuantumObject(type::Type{KetQuantumObject}, prod_dims::Int, m::Int, n::Int) +function _check_QuantumObject(type::KetQuantumObject, prod_dims::Int, m::Int, n::Int) (n != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Ket type")) : nothing prod_dims != m ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing end -function _check_QuantumObject(type::Type{BraQuantumObject}, prod_dims::Int, m::Int, n::Int) +function _check_QuantumObject(type::BraQuantumObject, prod_dims::Int, m::Int, n::Int) (m != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Bra type")) : nothing prod_dims != n ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing end -function _check_QuantumObject(type::Type{OperatorQuantumObject}, prod_dims::Int, m::Int, n::Int) +function _check_QuantumObject(type::OperatorQuantumObject, prod_dims::Int, m::Int, n::Int) (m != n) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Operator type")) : nothing prod_dims != m ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing end -function _check_QuantumObject(type::Type{SuperOperatorQuantumObject}, prod_dims::Int, m::Int, n::Int) +function _check_QuantumObject(type::SuperOperatorQuantumObject, prod_dims::Int, m::Int, n::Int) (m != n) ? throw(DomainError((m, n), "The dimension of the array is not compatible with SuperOperator 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{OperatorKetQuantumObject}, prod_dims::Int, m::Int, n::Int) +function _check_QuantumObject(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) +function _check_QuantumObject(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 +function QuantumObject(A::QuantumObject{<:AbstractArray}; type::ObjType=A.type, dims=A.dims) where {ObjType<:QuantumObjectType} QuantumObject(A.data, type, dims) @@ -175,42 +175,42 @@ ket2dm(ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = Checks if the [`QuantumObject`](@ref) `A` is a [`BraQuantumObject`](@ref) state. """ -isbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: BraQuantumObject +isbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: BraQuantumObject """ isket(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`KetQuantumObject`](@ref) state. """ -isket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: KetQuantumObject +isket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: KetQuantumObject """ isoper(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorQuantumObject`](@ref) state. """ -isoper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: OperatorQuantumObject +isoper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: 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 +isoperbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: 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 +isoperket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: OperatorKetQuantumObject """ issuper(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`SuperOperatorQuantumObject`](@ref) state. """ -issuper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = A.type <: SuperOperatorQuantumObject +issuper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: SuperOperatorQuantumObject """ size(A::QuantumObject) @@ -263,12 +263,12 @@ Returns the length of the matrix or vector corresponding to the [`QuantumObject` """ Base.length(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = length(A.data) -SparseArrays.sparse(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject(sparse(A.data), OpType, A.dims) +SparseArrays.sparse(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject(sparse(A.data), OpType(), A.dims) SparseArrays.nnz(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = nnz(A.data) SparseArrays.nonzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = nonzeros(A.data) SparseArrays.rowvals(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = rowvals(A.data) SparseArrays.droptol!(A::QuantumObject{<:AbstractSparseArray,OpType}, tol::Real) where {OpType<:QuantumObjectType} = (droptol!(A.data, tol); return A) -SparseArrays.dropzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = QuantumObject(dropzeros(A.data), OpType, A.dims) +SparseArrays.dropzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = QuantumObject(dropzeros(A.data), A.type, A.dims) SparseArrays.dropzeros!(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = (dropzeros!(A.data); return A) Base.isequal(A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}) where @@ -289,13 +289,13 @@ function Base.show(io::IO, ::MIME"text/plain", QO::QuantumObject{<:AbstractArray op_data = QO.data op_dims = QO.dims op_type = QO.type - if op_type <: KetQuantumObject + if op_type isa KetQuantumObject op_type = "Ket" - elseif op_type <: BraQuantumObject + elseif op_type isa BraQuantumObject op_type = "Bra" - elseif op_type <: OperatorKetQuantumObject + elseif op_type isa OperatorKetQuantumObject op_type = "Operator-Ket" - elseif op_type <: OperatorBraQuantumObject + elseif op_type isa OperatorBraQuantumObject op_type = "Operator-Bra" else op_type = "SuperOperator" @@ -318,31 +318,31 @@ for op in (:(+), :(-), :(*)) {T1,T2,OpType<:QuantumObjectType} A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject($(op)(A.data, B.data), OpType, A.dims) + QuantumObject($(op)(A.data, B.data), OpType(), A.dims) end - LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject($(op)(A.data), OpType, A.dims) + LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject($(op)(A.data), OpType(), A.dims) LinearAlgebra.$op(n::T1, A::QuantumObject{<:AbstractArray{T2},OpType}) where {T1<:Number,T2,OpType<:QuantumObjectType} = - QuantumObject($(op)(n * I, A.data), OpType, A.dims) + QuantumObject($(op)(n * I, A.data), OpType(), A.dims) LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T1},OpType}, n::T2) where {T1,T2<:Number,OpType<:QuantumObjectType} = - QuantumObject($(op)(A.data, n * I), OpType, A.dims) + QuantumObject($(op)(A.data, n * I), OpType(), A.dims) end end function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}) where {T1,T2} A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, KetQuantumObject, A.dims) + QuantumObject(A.data * B.data, KetQuantumObject(), A.dims) end function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, 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(A.data * B.data, BraQuantumObject, A.dims) + QuantumObject(A.data * B.data, BraQuantumObject(), A.dims) end function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, B::QuantumObject{<:AbstractArray{T2},BraQuantumObject}) where {T1,T2} A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, OperatorQuantumObject, A.dims) + QuantumObject(A.data * B.data, OperatorQuantumObject(), A.dims) end function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}) where {T1,T2} @@ -352,7 +352,7 @@ 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) + 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} @@ -362,18 +362,18 @@ 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) + 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) + 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) + 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) + QuantumObject(/(A.data, n), OpType(), A.dims) function LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where {T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} @@ -382,22 +382,22 @@ function LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType}, B::Quan end Base.conj(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(conj(A.data), OpType, A.dims) + 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) + QuantumObject(adjoint(A.data), OpType(), A.dims) LinearAlgebra.transpose(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = - QuantumObject(transpose(A.data), OpType, A.dims) + QuantumObject(transpose(A.data), OpType(), A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},KetQuantumObject}) where {T} = - QuantumObject(adjoint(A.data), BraQuantumObject, A.dims) + QuantumObject(adjoint(A.data), BraQuantumObject(), A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},BraQuantumObject}) where {T} = - QuantumObject(adjoint(A.data), KetQuantumObject, A.dims) + QuantumObject(adjoint(A.data), KetQuantumObject(), A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = - QuantumObject(adjoint(A.data), OperatorBraQuantumObject, A.dims) + QuantumObject(adjoint(A.data), OperatorBraQuantumObject(), A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorBraQuantumObject}) where {T} = - QuantumObject(adjoint(A.data), OperatorKetQuantumObject, A.dims) + 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) + QuantumObject(sparse(inv(Matrix(A.data))), OpType(), A.dims) """ tr(A::QuantumObject}) @@ -450,7 +450,7 @@ julia> norm(ψ) """ LinearAlgebra.norm(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = norm(A.data) LinearAlgebra.normalize(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(normalize(A.data), OpType, A.dims) + QuantumObject(normalize(A.data), OpType(), A.dims) LinearAlgebra.normalize!(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = (normalize!(A.data); A) LinearAlgebra.ishermitian(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = ishermitian(A.data) @@ -503,7 +503,7 @@ Quantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian= function LinearAlgebra.kron(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where {T1,T2,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} - QuantumObject(kron(A.data, B.data), OpType, vcat(A.dims, B.dims)) + QuantumObject(kron(A.data, B.data), OpType(), vcat(A.dims, B.dims)) end @doc raw""" @@ -587,9 +587,9 @@ LinearAlgebra.triu!(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) w LinearAlgebra.tril!(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (tril!(A.data, k); A) LinearAlgebra.triu(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(triu(A.data, k), OpType, A.dims) +{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(triu(A.data, k), OpType(), A.dims) LinearAlgebra.tril(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(tril(A.data, k), OpType, A.dims) +{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(tril(A.data, k), OpType(), A.dims) LinearAlgebra.lmul!(a::Number, B::QuantumObject{<:AbstractArray}) = (lmul!(a, B.data); B) LinearAlgebra.rmul!(B::QuantumObject{<:AbstractArray}, a::Number) = (rmul!(B.data, a); B) @@ -598,13 +598,13 @@ LinearAlgebra.rmul!(B::QuantumObject{<:AbstractArray}, a::Number) = (rmul!(B.dat LinearAlgebra.sqrt(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(sqrt(A.data), OpType, A.dims) + QuantumObject(sqrt(A.data), OpType(), A.dims) LinearAlgebra.exp(A::QuantumObject{<:AbstractMatrix{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(dense_to_sparse(exp(A.data)), OpType, A.dims) + QuantumObject(dense_to_sparse(exp(A.data)), OpType(), A.dims) LinearAlgebra.exp(A::QuantumObject{<:AbstractSparseMatrix{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(_spexp(A.data), OpType, A.dims) + QuantumObject(_spexp(A.data), OpType(), A.dims) function _spexp(A::SparseMatrixCSC{T,M}; threshold=1e-14, nonzero_tol=1e-20) where {T,M} m = checksquare(A) # Throws exception if not square diff --git a/src/quantum_operators.jl b/src/quantum_operators.jl index 68f8d928..b5ea835a 100644 --- a/src/quantum_operators.jl +++ b/src/quantum_operators.jl @@ -11,7 +11,7 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr the same function is applied multiple times with a known Hilbert space dimension. """ spre(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O,1))) where {T} = - QuantumObject(kron(Id_cache, O.data), SuperOperatorQuantumObject, O.dims) + QuantumObject(kron(Id_cache, O.data), SuperOperatorQuantumObject(), O.dims) @doc raw""" spost(O::QuantumObject) @@ -26,7 +26,7 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr the same function is applied multiple times with a known Hilbert space dimension. """ spost(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O,1))) where {T} = - QuantumObject(kron(sparse(transpose(sparse(O.data))), Id_cache), SuperOperatorQuantumObject, O.dims) # TODO: fix the sparse conversion + QuantumObject(kron(sparse(transpose(sparse(O.data))), Id_cache), SuperOperatorQuantumObject(), O.dims) # TODO: fix the sparse conversion @doc raw""" sprepost(A::QuantumObject, B::QuantumObject) @@ -38,7 +38,7 @@ Since the density matrix is vectorized, this super-operator is always a matrix, obtained from ``\mathcal{O} \left(\hat{A}, \hat{B}\right) \boldsymbol{\cdot} = \text{spre}(A) * \text{spost}(B)``. """ sprepost(A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} = QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperatorQuantumObject, A.dims) # TODO: fix the sparse conversion + B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} = QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperatorQuantumObject(), A.dims) # TODO: fix the sparse conversion @doc raw""" lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1)) @@ -83,7 +83,7 @@ julia> fock(20, 3)' * a * fock(20, 4) 2.0 + 0.0im ``` """ -destroy(N::Int) = QuantumObject(spdiagm(1 => Array{ComplexF64}(sqrt.(1:N-1))), OperatorQuantumObject, [N]) +destroy(N::Int) = QuantumObject(spdiagm(1 => Array{ComplexF64}(sqrt.(1:N-1))), OperatorQuantumObject(), [N]) @doc raw""" create(N::Int) @@ -107,7 +107,7 @@ julia> fock(20, 4)' * a_d * fock(20, 3) 2.0 + 0.0im ``` """ -create(N::Int) = QuantumObject(spdiagm(-1 => Array{ComplexF64}(sqrt.(1:N-1))), OperatorQuantumObject, [N]) +create(N::Int) = QuantumObject(spdiagm(-1 => Array{ComplexF64}(sqrt.(1:N-1))), OperatorQuantumObject(), [N]) @doc raw""" sigmap() @@ -149,7 +149,7 @@ sigmaz() = sigmap() * sigmam() - sigmam() * sigmap() Identity operator ``\hat{\mathbb{1}}`` with Hilbert dimension `N`. """ -eye(N::Int; type::Type{ObjType}=OperatorQuantumObject, dims::Vector{Int}=[N]) where +eye(N::Int; type::ObjType=OperatorQuantumObject(), dims::Vector{Int}=[N]) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(Diagonal(ones(ComplexF64, N)), type, dims) @doc raw""" @@ -157,7 +157,7 @@ eye(N::Int; type::Type{ObjType}=OperatorQuantumObject, dims::Vector{Int}=[N]) wh Identity operator ``\hat{\mathbb{1}}`` with Hilbert dimension `N`. """ -qeye(N::Int; type::Type{ObjType}=OperatorQuantumObject, dims::Vector{Int}=[N]) where +qeye(N::Int; type::ObjType=OperatorQuantumObject(), dims::Vector{Int}=[N]) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eye(N, type=type, dims=dims) @doc raw""" @@ -168,11 +168,11 @@ to specify the list of dimensions `dims` if different subsystems are present. """ function fock(N::Int, pos::Int; dims::Vector{Int}=[N], sparse::Bool=false) if sparse - return QuantumObject(sparsevec([pos+1], [1.0+0im], N), KetQuantumObject, dims) + return QuantumObject(sparsevec([pos+1], [1.0+0im], N), KetQuantumObject(), dims) else array = zeros(ComplexF64, N) array[pos+1] = 1 - return QuantumObject(array, KetQuantumObject, dims) + return QuantumObject(array, KetQuantumObject(), dims) end end diff --git a/src/time_evolution/lr_mesolve.jl b/src/time_evolution/lr_mesolve.jl index 71801813..8068b770 100644 --- a/src/time_evolution/lr_mesolve.jl +++ b/src/time_evolution/lr_mesolve.jl @@ -368,7 +368,7 @@ end Additional keyword arguments for the ODEProblem. """ function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2, 2}, B::AbstractArray{T2, 2}, t_l::AbstractVector, c_ops::AbstractVector=[]; - e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions{AlgType}(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} + e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} # Formulation of problem H -= 0.5im*sum([Γ'*Γ for Γ in c_ops]) @@ -426,7 +426,7 @@ function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumO end function lr_mesolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2, 2}, B::AbstractArray{T2, 2}, t_l::AbstractVector, c_ops::AbstractVector=[]; - e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions{AlgType}(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} + e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} prob = lr_mesolveProblem(H, z, B, t_l, c_ops; e_ops=e_ops, f_ops=f_ops, opt=opt, kwargs...); return lr_mesolve(prob; kwargs...) diff --git a/src/time_evolution/mcsolve.jl b/src/time_evolution/mcsolve.jl index 5785cf74..8ea0307f 100644 --- a/src/time_evolution/mcsolve.jl +++ b/src/time_evolution/mcsolve.jl @@ -309,7 +309,7 @@ function mcsolve(H::QuantumObject{MT1,OperatorQuantumObject}, kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} if !isnothing(seeds) && length(seeds)!=n_traj - throw(ArgumentError("Length of seed must match n_traj ($n_traj), but got $(length(seed))")) + throw(ArgumentError("Length of seeds must match n_traj ($n_traj), but got $(length(seeds))")) end ens_prob_mc = mcsolveEnsembleProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, diff --git a/src/time_evolution/time_evolution.jl b/src/time_evolution/time_evolution.jl index 2de7e5d9..e76eaf53 100644 --- a/src/time_evolution/time_evolution.jl +++ b/src/time_evolution/time_evolution.jl @@ -194,7 +194,7 @@ function liouvillian_generalized(H::QuantumObject{MT, OperatorQuantumObject}, fi Ω1 = kron(Ω, M1) Ω2 = kron(M1, Ω) Ωdiff = Ω1 .- Ω2 - F2 = QuantumObject(gaussian.(Ωdiff, 0, σ), SuperOperatorQuantumObject, dims) + F2 = QuantumObject(gaussian.(Ωdiff, 0, σ), SuperOperatorQuantumObject(), dims) F2 = dense_to_sparse(F2, tol) L = liouvillian(H_d) @@ -239,8 +239,8 @@ function _liouvillian_floquet(L₀::QuantumObject{<:AbstractArray{T1},SuperOpera T = -(L_0 + 1im * n_i * ω * I + L_p * T) \ L_m_dense end - solver.tol == 0 && return QuantumObject(L_0 + L_m * S + L_p * T, SuperOperatorQuantumObject, L₀.dims) - return QuantumObject(dense_to_sparse(L_0 + L_m * S + L_p * T, solver.tol), SuperOperatorQuantumObject, L₀.dims) + solver.tol == 0 && return QuantumObject(L_0 + L_m * S + L_p * T, SuperOperatorQuantumObject(), L₀.dims) + return QuantumObject(dense_to_sparse(L_0 + L_m * S + L_p * T, solver.tol), SuperOperatorQuantumObject(), L₀.dims) end function steadystate(L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}; @@ -270,7 +270,7 @@ function _steadystate(L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumOb ρss_vec = L_tmp \ v0 ρss = reshape(ρss_vec, N, N) ρss = (ρss + ρss') / 2 # Hermitianize - QuantumObject(ρss, OperatorQuantumObject, L.dims) + QuantumObject(ρss, OperatorQuantumObject(), L.dims) end @doc raw""" diff --git a/test/aqua.jl b/test/aqua.jl index b158c897..99637669 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -1,3 +1,5 @@ +using Aqua + @testset "Code quality (Aqua.jl)" begin Aqua.test_all(QuantumToolbox; ambiguities = false,) end \ No newline at end of file diff --git a/test/jet.jl b/test/jet.jl new file mode 100644 index 00000000..b9c482c4 --- /dev/null +++ b/test/jet.jl @@ -0,0 +1,5 @@ +using JET + +@testset "Code quality (JET.jl)" begin + JET.test_package(QuantumToolbox; target_defined_modules=true, ignore_missing_comparison=true) +end \ No newline at end of file diff --git a/test/quantum_objects.jl b/test/quantum_objects.jl index 2c9ce581..8944f9d3 100644 --- a/test/quantum_objects.jl +++ b/test/quantum_objects.jl @@ -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, OperatorBraQuantumObject, OperatorKetQuantumObject] + for t in [nothing, KetQuantumObject(), BraQuantumObject(), OperatorQuantumObject(), SuperOperatorQuantumObject(), OperatorBraQuantumObject(), OperatorKetQuantumObject()] @test_throws DomainError Qobj(a, type=t) end end @@ -9,14 +9,14 @@ N = 10 a = rand(ComplexF64, 10) # @test_logs (:warn, "The norm of the input data is not one.") QuantumObject(a) - @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 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') @@ -39,7 +39,7 @@ a = sprand(ComplexF64, 100, 100, 0.1) a2 = Qobj(a) - a3 = Qobj(a, type=SuperOperatorQuantumObject) + a3 = Qobj(a, type=SuperOperatorQuantumObject()) @test isket(a2) == false @test isbra(a2) == false @@ -62,7 +62,7 @@ ρ = Qobj(rand(ComplexF64, 2, 2)) ρ_ket = mat2vec(ρ) ρ_bra = ρ_ket' - @test ρ_bra == Qobj(mat2vec(ρ.data)', type=OperatorBraQuantumObject) + @test ρ_bra == Qobj(mat2vec(ρ.data)', type=OperatorBraQuantumObject()) @test ρ == vec2mat(ρ_ket) @test isket(ρ_ket) == false @test isbra(ρ_ket) == false @@ -85,8 +85,8 @@ @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]) + @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) @@ -197,7 +197,7 @@ ψ_size = size(ψ) @test opstring == "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" - ψ2 = Qobj(rand(ComplexF64, 4), type=OperatorKetQuantumObject) + ψ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 diff --git a/test/runtests.jl b/test/runtests.jl index 500db40d..f1637392 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,6 @@ using Test +using Pkg using QuantumToolbox -using Aqua const GROUP = get(ENV, "GROUP", "All") @@ -8,7 +8,6 @@ const testdir = dirname(@__FILE__) # Put core tests in alphabetical order core_tests = [ - "aqua.jl", "correlations_and_spectrum.jl", "dynamical_fock_dimension_mesolve.jl", "dynamical-shifted-fock.jl", @@ -29,4 +28,10 @@ if (GROUP == "All") || (GROUP == "Core") for test in core_tests include(joinpath(testdir, test)) end +end + +if (GROUP == "All") || (GROUP == "Code-Quality") + Pkg.add(["Aqua", "JET"]) + include(joinpath(testdir, "aqua.jl")) + include(joinpath(testdir, "jet.jl")) end \ No newline at end of file diff --git a/test/time_evolution_and_partial_trace.jl b/test/time_evolution_and_partial_trace.jl index fbe37416..03cf86b5 100644 --- a/test/time_evolution_and_partial_trace.jl +++ b/test/time_evolution_and_partial_trace.jl @@ -12,6 +12,8 @@ e_ops = [a_d * a] sol = sesolve(H, psi0, t_l, e_ops=e_ops, alg=Vern7(), progress_bar=false) @test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1 + @test ptrace(sol.states[end], 1) ≈ ptrace(ket2dm(sol.states[end]), 1) + @test ptrace(sol.states[end]', 1) ≈ ptrace(sol.states[end], 1) a = destroy(N) a_d = a'