diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f6929e57..21ec5bb78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add **GPUArrays** compatibility for `ptrace` function, by using **KernelAbstractions.jl**. ([#350]) - Introduce `Space`, `Dimensions`, `GeneralDimensions` structures to support wider definitions and operations of `Qobj/QobjEvo`, and potential functionalities in the future. ([#271], [#353], [#360]) - Improve lazy tensor warning for `SciMLOperators`. ([#370]) +- Change order of `AbstractQuantumObject` data type. For example, from `QuantumObject{DataType,ObjType,DimsType}` to `QuantumObject{ObjType,DimsType,DataType}`. ([#371]) ## [v0.24.0] Release date: 2024-12-13 @@ -77,3 +78,4 @@ Release date: 2024-11-13 [#353]: https://github.com/qutip/QuantumToolbox.jl/issues/353 [#360]: https://github.com/qutip/QuantumToolbox.jl/issues/360 [#370]: https://github.com/qutip/QuantumToolbox.jl/issues/370 +[#371]: https://github.com/qutip/QuantumToolbox.jl/issues/371 diff --git a/ext/QuantumToolboxCUDAExt.jl b/ext/QuantumToolboxCUDAExt.jl index 459356b05..c8258886b 100644 --- a/ext/QuantumToolboxCUDAExt.jl +++ b/ext/QuantumToolboxCUDAExt.jl @@ -1,6 +1,7 @@ module QuantumToolboxCUDAExt using QuantumToolbox +using QuantumToolbox: makeVal, getVal import CUDA: cu, CuArray import CUDA.CUSPARSE: CuSparseVector, CuSparseMatrixCSC, CuSparseMatrixCSR import SparseArrays: SparseVector, SparseMatrixCSC @@ -10,60 +11,56 @@ import SparseArrays: SparseVector, SparseMatrixCSC If `A.data` is a dense array, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CuArray` for gpu calculations. """ -CuArray(A::QuantumObject{Tq}) where {Tq<:Union{Vector,Matrix}} = QuantumObject(CuArray(A.data), A.type, A.dimensions) +CuArray(A::QuantumObject) = QuantumObject(CuArray(A.data), A.type, A.dimensions) @doc raw""" CuArray{T}(A::QuantumObject) If `A.data` is a dense array, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CuArray` with element type `T` for gpu calculations. """ -CuArray{T}(A::QuantumObject{Tq}) where {T,Tq<:Union{Vector,Matrix}} = - QuantumObject(CuArray{T}(A.data), A.type, A.dimensions) +CuArray{T}(A::QuantumObject) where {T} = QuantumObject(CuArray{T}(A.data), A.type, A.dimensions) @doc raw""" CuSparseVector(A::QuantumObject) If `A.data` is a sparse vector, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CUSPARSE.CuSparseVector` for gpu calculations. """ -CuSparseVector(A::QuantumObject{<:SparseVector}) = QuantumObject(CuSparseVector(A.data), A.type, A.dimensions) +CuSparseVector(A::QuantumObject) = QuantumObject(CuSparseVector(A.data), A.type, A.dimensions) @doc raw""" CuSparseVector{T}(A::QuantumObject) If `A.data` is a sparse vector, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CUSPARSE.CuSparseVector` with element type `T` for gpu calculations. """ -CuSparseVector{T}(A::QuantumObject{<:SparseVector}) where {T} = - QuantumObject(CuSparseVector{T}(A.data), A.type, A.dimensions) +CuSparseVector{T}(A::QuantumObject) where {T} = QuantumObject(CuSparseVector{T}(A.data), A.type, A.dimensions) @doc raw""" CuSparseMatrixCSC(A::QuantumObject) If `A.data` is in the type of `SparseMatrixCSC`, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CUSPARSE.CuSparseMatrixCSC` for gpu calculations. """ -CuSparseMatrixCSC(A::QuantumObject{<:SparseMatrixCSC}) = QuantumObject(CuSparseMatrixCSC(A.data), A.type, A.dimensions) +CuSparseMatrixCSC(A::QuantumObject) = QuantumObject(CuSparseMatrixCSC(A.data), A.type, A.dimensions) @doc raw""" CuSparseMatrixCSC{T}(A::QuantumObject) If `A.data` is in the type of `SparseMatrixCSC`, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CUSPARSE.CuSparseMatrixCSC` with element type `T` for gpu calculations. """ -CuSparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = - QuantumObject(CuSparseMatrixCSC{T}(A.data), A.type, A.dimensions) +CuSparseMatrixCSC{T}(A::QuantumObject) where {T} = QuantumObject(CuSparseMatrixCSC{T}(A.data), A.type, A.dimensions) @doc raw""" CuSparseMatrixCSR(A::QuantumObject) If `A.data` is in the type of `SparseMatrixCSC`, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CUSPARSE.CuSparseMatrixCSR` for gpu calculations. """ -CuSparseMatrixCSR(A::QuantumObject{<:SparseMatrixCSC}) = QuantumObject(CuSparseMatrixCSR(A.data), A.type, A.dimensions) +CuSparseMatrixCSR(A::QuantumObject) = QuantumObject(CuSparseMatrixCSR(A.data), A.type, A.dimensions) @doc raw""" CuSparseMatrixCSR(A::QuantumObject) If `A.data` is in the type of `SparseMatrixCSC`, return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA.CUSPARSE.CuSparseMatrixCSR` with element type `T` for gpu calculations. """ -CuSparseMatrixCSR{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = - QuantumObject(CuSparseMatrixCSR{T}(A.data), A.type, A.dimensions) +CuSparseMatrixCSR{T}(A::QuantumObject) where {T} = QuantumObject(CuSparseMatrixCSR{T}(A.data), A.type, A.dimensions) @doc raw""" cu(A::QuantumObject; word_size::Int=64) @@ -74,15 +71,26 @@ Return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA` arr - `A::QuantumObject`: The [`QuantumObject`](@ref) - `word_size::Int`: The word size of the element type of `A`, can be either `32` or `64`. Default to `64`. """ -cu(A::QuantumObject; word_size::Int = 64) = - ((word_size == 64) || (word_size == 32)) ? cu(A, Val(word_size)) : - throw(DomainError(word_size, "The word size should be 32 or 64.")) -cu(A::QuantumObject{T}, word_size::TW) where {T<:Union{Vector,Matrix},TW<:Union{Val{32},Val{64}}} = - CuArray{_change_eltype(eltype(A), word_size)}(A) -cu(A::QuantumObject{<:SparseVector}, word_size::TW) where {TW<:Union{Val{32},Val{64}}} = - CuSparseVector{_change_eltype(eltype(A), word_size)}(A) -cu(A::QuantumObject{<:SparseMatrixCSC}, word_size::TW) where {TW<:Union{Val{32},Val{64}}} = - CuSparseMatrixCSC{_change_eltype(eltype(A), word_size)}(A) +function cu(A::QuantumObject; word_size::Union{Val,Int} = Val(64)) + _word_size = getVal(makeVal(word_size)) + + ((_word_size == 64) || (_word_size == 32)) || throw(DomainError(_word_size, "The word size should be 32 or 64.")) + + return cu(A, makeVal(word_size)) +end +cu(A::QuantumObject, word_size::Union{Val{32},Val{64}}) = CuArray{_change_eltype(eltype(A), word_size)}(A) +function cu( + A::QuantumObject{ObjType,DimsType,<:SparseVector}, + word_size::Union{Val{32},Val{64}}, +) where {ObjType<:QuantumObjectType,DimsType<:AbstractDimensions} + return CuSparseVector{_change_eltype(eltype(A), word_size)}(A) +end +function cu( + A::QuantumObject{ObjType,DimsType,<:SparseMatrixCSC}, + word_size::Union{Val{32},Val{64}}, +) where {ObjType<:QuantumObjectType,DimsType<:AbstractDimensions} + return CuSparseMatrixCSC{_change_eltype(eltype(A), word_size)}(A) +end _change_eltype(::Type{T}, ::Val{64}) where {T<:Int} = Int64 _change_eltype(::Type{T}, ::Val{32}) where {T<:Int} = Int32 diff --git a/ext/QuantumToolboxCairoMakieExt.jl b/ext/QuantumToolboxCairoMakieExt.jl index f5a7a2272..23be6452d 100644 --- a/ext/QuantumToolboxCairoMakieExt.jl +++ b/ext/QuantumToolboxCairoMakieExt.jl @@ -6,7 +6,7 @@ using CairoMakie: Axis, Axis3, Colorbar, Figure, GridLayout, heatmap!, surface!, @doc raw""" plot_wigner( library::Val{:CairoMakie}, - state::QuantumObject{DT,OpType}; + state::QuantumObject{OpType}; xvec::Union{Nothing,AbstractVector} = nothing, yvec::Union{Nothing,AbstractVector} = nothing, g::Real = √2, @@ -15,7 +15,7 @@ using CairoMakie: Axis, Axis3, Colorbar, Figure, GridLayout, heatmap!, surface!, location::Union{GridPosition,Nothing} = nothing, colorbar::Bool = false, kwargs... - ) where {DT,OpType} + ) where {OpType} Plot the [Wigner quasipropability distribution](https://en.wikipedia.org/wiki/Wigner_quasiprobability_distribution) of `state` using the [`CairoMakie`](https://github.com/MakieOrg/Makie.jl/tree/master/CairoMakie) plotting library. @@ -44,7 +44,7 @@ Plot the [Wigner quasipropability distribution](https://en.wikipedia.org/wiki/Wi """ function QuantumToolbox.plot_wigner( library::Val{:CairoMakie}, - state::QuantumObject{DT,OpType}; + state::QuantumObject{OpType}; xvec::Union{Nothing,AbstractVector} = LinRange(-7.5, 7.5, 200), yvec::Union{Nothing,AbstractVector} = LinRange(-7.5, 7.5, 200), g::Real = √2, @@ -53,7 +53,7 @@ function QuantumToolbox.plot_wigner( location::Union{GridPosition,Nothing} = nothing, colorbar::Bool = false, kwargs..., -) where {DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} +) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} QuantumToolbox.getVal(projection) == :two_dim || QuantumToolbox.getVal(projection) == :three_dim || throw(ArgumentError("Unsupported projection: $projection")) @@ -74,7 +74,7 @@ end function _plot_wigner( ::Val{:CairoMakie}, - state::QuantumObject{DT,OpType}, + state::QuantumObject{OpType}, xvec::AbstractVector, yvec::AbstractVector, projection::Val{:two_dim}, @@ -83,7 +83,7 @@ function _plot_wigner( location::Union{GridPosition,Nothing}, colorbar::Bool; kwargs..., -) where {DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} +) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} fig, location = _getFigAndLocation(location) lyt = GridLayout(location) @@ -107,7 +107,7 @@ end function _plot_wigner( ::Val{:CairoMakie}, - state::QuantumObject{DT,OpType}, + state::QuantumObject{OpType}, xvec::AbstractVector, yvec::AbstractVector, projection::Val{:three_dim}, @@ -116,7 +116,7 @@ function _plot_wigner( location::Union{GridPosition,Nothing}, colorbar::Bool; kwargs..., -) where {DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} +) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} fig, location = _getFigAndLocation(location) lyt = GridLayout(location) diff --git a/src/correlations.jl b/src/correlations.jl index ada51d3da..ae9598f98 100644 --- a/src/correlations.jl +++ b/src/correlations.jl @@ -24,21 +24,16 @@ Returns the two-times correlation function of three operators ``\hat{A}``, ``\ha If the initial state `ψ0` is given as `nothing`, then the [`steadystate`](@ref) will be used as the initial state. Note that this is only implemented if `H` is constant ([`QuantumObject`](@ref)). """ function correlation_3op_2t( - H::AbstractQuantumObject{DataType,HOpType}, - ψ0::Union{Nothing,QuantumObject{<:AbstractArray{T1},StateOpType}}, + H::AbstractQuantumObject{HOpType}, + ψ0::Union{Nothing,QuantumObject{StateOpType}}, tlist::AbstractVector, τlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple}, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - C::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}; + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, + C::QuantumObject{OperatorQuantumObject}; kwargs..., ) where { - DataType, - T1, - T2, - T3, - T4, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } @@ -79,20 +74,15 @@ Returns the one-time correlation function of three operators ``\hat{A}``, ``\hat If the initial state `ψ0` is given as `nothing`, then the [`steadystate`](@ref) will be used as the initial state. Note that this is only implemented if `H` is constant ([`QuantumObject`](@ref)). """ function correlation_3op_1t( - H::AbstractQuantumObject{DataType,HOpType}, - ψ0::Union{Nothing,QuantumObject{<:AbstractArray{T1},StateOpType}}, + H::AbstractQuantumObject{HOpType}, + ψ0::Union{Nothing,QuantumObject{StateOpType}}, τlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple}, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - C::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}; + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, + C::QuantumObject{OperatorQuantumObject}; kwargs..., ) where { - DataType, - T1, - T2, - T3, - T4, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } @@ -119,20 +109,16 @@ If the initial state `ψ0` is given as `nothing`, then the [`steadystate`](@ref) When `reverse=true`, the correlation function is calculated as ``\left\langle \hat{A}(t) \hat{B}(t + \tau) \right\rangle``. """ function correlation_2op_2t( - H::AbstractQuantumObject{DataType,HOpType}, - ψ0::Union{Nothing,QuantumObject{<:AbstractArray{T1},StateOpType}}, + H::AbstractQuantumObject{HOpType}, + ψ0::Union{Nothing,QuantumObject{StateOpType}}, tlist::AbstractVector, τlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple}, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}; + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}; reverse::Bool = false, kwargs..., ) where { - DataType, - T1, - T2, - T3, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } @@ -163,19 +149,15 @@ If the initial state `ψ0` is given as `nothing`, then the [`steadystate`](@ref) When `reverse=true`, the correlation function is calculated as ``\left\langle \hat{A}(0) \hat{B}(\tau) \right\rangle``. """ function correlation_2op_1t( - H::AbstractQuantumObject{DataType,HOpType}, - ψ0::Union{Nothing,QuantumObject{<:AbstractArray{T1},StateOpType}}, + H::AbstractQuantumObject{HOpType}, + ψ0::Union{Nothing,QuantumObject{StateOpType}}, τlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple}, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}; + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}; reverse::Bool = false, kwargs..., ) where { - DataType, - T1, - T2, - T3, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } diff --git a/src/deprecated.jl b/src/deprecated.jl index 98d92193d..b39a392bf 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -21,21 +21,16 @@ FFTCorrelation() = error( ) correlation_3op_2t( - H::QuantumObject{<:AbstractArray{T1},HOpType}, - ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, + H::QuantumObject{HOpType}, + ψ0::QuantumObject{StateOpType}, t_l::AbstractVector, τ_l::AbstractVector, - A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, - C::QuantumObject{<:AbstractArray{T5},OperatorQuantumObject}, + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, + C::QuantumObject{OperatorQuantumObject}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; kwargs..., ) where { - T1, - T2, - T3, - T4, - T5, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } = error( @@ -43,20 +38,15 @@ correlation_3op_2t( ) correlation_3op_1t( - H::QuantumObject{<:AbstractArray{T1},HOpType}, - ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, + H::QuantumObject{HOpType}, + ψ0::QuantumObject{StateOpType}, τ_l::AbstractVector, - A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, - C::QuantumObject{<:AbstractArray{T5},OperatorQuantumObject}, + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, + C::QuantumObject{OperatorQuantumObject}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; kwargs..., ) where { - T1, - T2, - T3, - T4, - T5, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } = error( @@ -64,20 +54,16 @@ correlation_3op_1t( ) correlation_2op_2t( - H::QuantumObject{<:AbstractArray{T1},HOpType}, - ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, + H::QuantumObject{HOpType}, + ψ0::QuantumObject{StateOpType}, t_l::AbstractVector, τ_l::AbstractVector, - A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; reverse::Bool = false, kwargs..., ) where { - T1, - T2, - T3, - T4, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } = error( @@ -85,19 +71,15 @@ correlation_2op_2t( ) correlation_2op_1t( - H::QuantumObject{<:AbstractArray{T1},HOpType}, - ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, + H::QuantumObject{HOpType}, + ψ0::QuantumObject{StateOpType}, τ_l::AbstractVector, - A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; reverse::Bool = false, kwargs..., ) where { - T1, - T2, - T3, - T4, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } = error( diff --git a/src/metrics.jl b/src/metrics.jl index 6bbcc7cc6..e178e579b 100644 --- a/src/metrics.jl +++ b/src/metrics.jl @@ -51,11 +51,8 @@ julia> entropy_vn(ρ, base=2) 1.0 ``` """ -function entropy_vn( - ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}; - base::Int = 0, - tol::Real = 1e-15, -) where {T} +function entropy_vn(ρ::QuantumObject{OperatorQuantumObject}; base::Int = 0, tol::Real = 1e-15) + T = eltype(ρ) vals = eigenenergies(ρ) indexes = findall(x -> abs(x) > tol, vals) length(indexes) == 0 && return zero(real(T)) @@ -71,9 +68,9 @@ Calculates the entanglement by doing the partial trace of `QO`, selecting only t with the indices contained in the `sel` vector, and then using the Von Neumann entropy [`entropy_vn`](@ref). """ function entanglement( - QO::QuantumObject{<:AbstractArray{T},OpType}, + QO::QuantumObject{OpType}, sel::Union{AbstractVector{Int},Tuple}, -) where {T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} +) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} ψ = normalize(QO) ρ_tr = ptrace(ψ, sel) entropy = entropy_vn(ρ_tr) @@ -90,11 +87,9 @@ Calculates the [trace distance](https://en.wikipedia.org/wiki/Trace_distance) be Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref). """ tracedist( - ρ::QuantumObject{<:AbstractArray{T1},ObjType1}, - σ::QuantumObject{<:AbstractArray{T2},ObjType2}, + ρ::QuantumObject{ObjType1}, + σ::QuantumObject{ObjType2}, ) where { - T1, - T2, ObjType1<:Union{KetQuantumObject,OperatorQuantumObject}, ObjType2<:Union{KetQuantumObject,OperatorQuantumObject}, } = norm(ket2dm(ρ) - ket2dm(σ), 1) / 2 @@ -109,23 +104,11 @@ Here, the definition is from Nielsen & Chuang, "Quantum Computation and Quantum Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref). """ -function fidelity( - ρ::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - σ::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, -) where {T1,T2} +function fidelity(ρ::QuantumObject{OperatorQuantumObject}, σ::QuantumObject{OperatorQuantumObject}) sqrt_ρ = sqrt(ρ) eigval = abs.(eigvals(sqrt_ρ * σ * sqrt_ρ)) return sum(sqrt, eigval) end -fidelity( - ρ::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - ψ::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, -) where {T1,T2} = sqrt(abs(expect(ρ, ψ))) -fidelity( - ψ::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, - σ::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, -) where {T1,T2} = fidelity(σ, ψ) -fidelity( - ψ::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, - ϕ::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, -) where {T1,T2} = abs(dot(ψ, ϕ)) +fidelity(ρ::QuantumObject{OperatorQuantumObject}, ψ::QuantumObject{KetQuantumObject}) = sqrt(abs(expect(ρ, ψ))) +fidelity(ψ::QuantumObject{KetQuantumObject}, σ::QuantumObject{OperatorQuantumObject}) = fidelity(σ, ψ) +fidelity(ψ::QuantumObject{KetQuantumObject}, ϕ::QuantumObject{KetQuantumObject}) = abs(dot(ψ, ϕ)) diff --git a/src/negativity.jl b/src/negativity.jl index f9fa2a215..eefaab3d3 100644 --- a/src/negativity.jl +++ b/src/negativity.jl @@ -70,7 +70,7 @@ Return the partial transpose of a density matrix ``\rho``, where `mask` is an ar # Returns - `ρ_pt::QuantumObject`: The density matrix with the selected subsystems transposed. """ -function partial_transpose(ρ::QuantumObject{DT,OperatorQuantumObject}, mask::Vector{Bool}) where {DT} +function partial_transpose(ρ::QuantumObject{OperatorQuantumObject}, mask::Vector{Bool}) if length(mask) != length(ρ.dimensions) throw(ArgumentError("The length of \`mask\` should be equal to the length of \`ρ.dims\`.")) end @@ -78,7 +78,7 @@ function partial_transpose(ρ::QuantumObject{DT,OperatorQuantumObject}, mask::Ve end # for dense matrices -function _partial_transpose(ρ::QuantumObject{DT,OperatorQuantumObject}, mask::Vector{Bool}) where {DT<:AbstractArray} +function _partial_transpose(ρ::QuantumObject{OperatorQuantumObject}, mask::Vector{Bool}) isa(ρ.dimensions, GeneralDimensions) && (get_dimensions_to(ρ) != get_dimensions_from(ρ)) && throw(ArgumentError("Invalid partial transpose for dims = $(_get_dims_string(ρ.dimensions))")) @@ -103,7 +103,10 @@ function _partial_transpose(ρ::QuantumObject{DT,OperatorQuantumObject}, mask::V end # for sparse matrices -function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray,OperatorQuantumObject}, mask::Vector{Bool}) +function _partial_transpose( + ρ::QuantumObject{OperatorQuantumObject,DimsType,<:AbstractSparseArray}, + mask::Vector{Bool}, +) where {DimsType<:AbstractDimensions} isa(ρ.dimensions, GeneralDimensions) && (get_dimensions_to(ρ) != get_dimensions_from(ρ)) && throw(ArgumentError("Invalid partial transpose for dims = $(_get_dims_string(ρ.dimensions))")) diff --git a/src/qobj/arithmetic_and_attributes.jl b/src/qobj/arithmetic_and_attributes.jl index 0ae908b6f..15a0f430d 100644 --- a/src/qobj/arithmetic_and_attributes.jl +++ b/src/qobj/arithmetic_and_attributes.jl @@ -64,9 +64,9 @@ for ADimType in (:Dimensions, :GeneralDimensions) if ADimType == BDimType == :Dimensions @eval begin function LinearAlgebra.:(*)( - A::AbstractQuantumObject{DT1,OperatorQuantumObject,<:$ADimType}, - B::AbstractQuantumObject{DT2,OperatorQuantumObject,<:$BDimType}, - ) where {DT1,DT2} + A::AbstractQuantumObject{OperatorQuantumObject,<:$ADimType}, + B::AbstractQuantumObject{OperatorQuantumObject,<:$BDimType}, + ) check_dimensions(A, B) QType = promote_op_type(A, B) return QType(A.data * B.data, Operator, A.dimensions) @@ -75,9 +75,9 @@ for ADimType in (:Dimensions, :GeneralDimensions) else @eval begin function LinearAlgebra.:(*)( - A::AbstractQuantumObject{DT1,OperatorQuantumObject,<:$ADimType}, - B::AbstractQuantumObject{DT2,OperatorQuantumObject,<:$BDimType}, - ) where {DT1,DT2} + A::AbstractQuantumObject{OperatorQuantumObject,<:$ADimType}, + B::AbstractQuantumObject{OperatorQuantumObject,<:$BDimType}, + ) check_mul_dimensions(get_dimensions_from(A), get_dimensions_to(B)) QType = promote_op_type(A, B) return QType( @@ -92,64 +92,55 @@ for ADimType in (:Dimensions, :GeneralDimensions) end function LinearAlgebra.:(*)( - A::AbstractQuantumObject{DT1,OperatorQuantumObject}, - B::QuantumObject{DT2,KetQuantumObject,<:Dimensions}, -) where {DT1,DT2} + A::AbstractQuantumObject{OperatorQuantumObject}, + B::QuantumObject{KetQuantumObject,<:Dimensions}, +) check_mul_dimensions(get_dimensions_from(A), get_dimensions_to(B)) return QuantumObject(A.data * B.data, Ket, Dimensions(get_dimensions_to(A))) end function LinearAlgebra.:(*)( - A::QuantumObject{DT1,BraQuantumObject,<:Dimensions}, - B::AbstractQuantumObject{DT2,OperatorQuantumObject}, -) where {DT1,DT2} + A::QuantumObject{BraQuantumObject,<:Dimensions}, + B::AbstractQuantumObject{OperatorQuantumObject}, +) check_mul_dimensions(get_dimensions_from(A), get_dimensions_to(B)) return QuantumObject(A.data * B.data, Bra, Dimensions(get_dimensions_from(B))) end -function LinearAlgebra.:(*)( - A::QuantumObject{DT1,KetQuantumObject}, - B::QuantumObject{DT2,BraQuantumObject}, -) where {DT1,DT2} +function LinearAlgebra.:(*)(A::QuantumObject{KetQuantumObject}, B::QuantumObject{BraQuantumObject}) check_dimensions(A, B) return QuantumObject(A.data * B.data, Operator, A.dimensions) # to align with QuTiP, don't use kron(A, B) to do it. end -function LinearAlgebra.:(*)( - A::QuantumObject{DT1,BraQuantumObject}, - B::QuantumObject{DT2,KetQuantumObject}, -) where {DT1,DT2} +function LinearAlgebra.:(*)(A::QuantumObject{BraQuantumObject}, B::QuantumObject{KetQuantumObject}) check_dimensions(A, B) return A.data * B.data end function LinearAlgebra.:(*)( - A::AbstractQuantumObject{DT1,SuperOperatorQuantumObject}, - B::QuantumObject{DT2,OperatorQuantumObject}, -) where {DT1,DT2} + A::AbstractQuantumObject{SuperOperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, +) check_dimensions(A, B) return QuantumObject(vec2mat(A.data * mat2vec(B.data)), Operator, A.dimensions) end -function LinearAlgebra.:(*)( - A::QuantumObject{DT1,OperatorBraQuantumObject}, - B::QuantumObject{DT2,OperatorKetQuantumObject}, -) where {DT1,DT2} +function LinearAlgebra.:(*)(A::QuantumObject{OperatorBraQuantumObject}, B::QuantumObject{OperatorKetQuantumObject}) check_dimensions(A, B) return A.data * B.data end function LinearAlgebra.:(*)( - A::AbstractQuantumObject{DT1,SuperOperatorQuantumObject}, - B::QuantumObject{DT2,OperatorKetQuantumObject}, -) where {DT1,DT2} + A::AbstractQuantumObject{SuperOperatorQuantumObject}, + B::QuantumObject{OperatorKetQuantumObject}, +) check_dimensions(A, B) return QuantumObject(A.data * B.data, OperatorKet, A.dimensions) end function LinearAlgebra.:(*)( - A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, - B::AbstractQuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, -) where {T1,T2} + A::QuantumObject{OperatorBraQuantumObject}, + B::AbstractQuantumObject{SuperOperatorQuantumObject}, +) check_dimensions(A, B) return QuantumObject(A.data * B.data, OperatorBra, A.dimensions) end -LinearAlgebra.:(^)(A::QuantumObject{DT}, n::T) where {DT,T<:Number} = QuantumObject(^(A.data, n), A.type, A.dimensions) -LinearAlgebra.:(/)(A::AbstractQuantumObject{DT}, n::T) where {DT,T<:Number} = +LinearAlgebra.:(^)(A::QuantumObject, n::T) where {T<:Number} = QuantumObject(^(A.data, n), A.type, A.dimensions) +LinearAlgebra.:(/)(A::AbstractQuantumObject, n::T) where {T<:Number} = get_typename_wrapper(A)(A.data / n, A.type, A.dimensions) @doc raw""" @@ -164,9 +155,9 @@ Note that `A` and `B` should be [`Ket`](@ref) or [`OperatorKet`](@ref) `A ⋅ B` (where `⋅` can be typed by tab-completing `\cdot` in the REPL) is a synonym of `dot(A, B)`. """ function LinearAlgebra.dot( - A::QuantumObject{DT1,OpType}, - B::QuantumObject{DT2,OpType}, -) where {DT1,DT2,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} + A::QuantumObject{OpType}, + B::QuantumObject{OpType}, +) where {OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} check_dimensions(A, B) return LinearAlgebra.dot(A.data, B.data) end @@ -185,18 +176,18 @@ Supports the following inputs: `matrix_element(i, A, j)` is a synonym of `dot(i, A, j)`. """ function LinearAlgebra.dot( - i::QuantumObject{DT1,KetQuantumObject}, - A::AbstractQuantumObject{DT2,OperatorQuantumObject}, - j::QuantumObject{DT3,KetQuantumObject}, -) where {DT1,DT2,DT3} + i::QuantumObject{KetQuantumObject}, + A::AbstractQuantumObject{OperatorQuantumObject}, + j::QuantumObject{KetQuantumObject}, +) check_dimensions(i, A, j) return LinearAlgebra.dot(i.data, A.data, j.data) end function LinearAlgebra.dot( - i::QuantumObject{DT1,OperatorKetQuantumObject}, - A::AbstractQuantumObject{DT2,SuperOperatorQuantumObject}, - j::QuantumObject{DT3,OperatorKetQuantumObject}, -) where {DT1,DT2,DT3} + i::QuantumObject{OperatorKetQuantumObject}, + A::AbstractQuantumObject{SuperOperatorQuantumObject}, + j::QuantumObject{OperatorKetQuantumObject}, +) check_dimensions(i, A, j) return LinearAlgebra.dot(i.data, A.data, j.data) end @@ -215,9 +206,7 @@ Return a similar [`AbstractQuantumObject`](@ref) with `dims` and `type` are same Note that `A` must be [`Operator`](@ref) or [`SuperOperator`](@ref). """ -Base.one( - A::AbstractQuantumObject{DT,OpType}, -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +Base.one(A::AbstractQuantumObject{OpType}) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = get_typename_wrapper(A)(one(A.data), A.type, A.dimensions) @doc raw""" @@ -233,8 +222,8 @@ Base.conj(A::AbstractQuantumObject) = get_typename_wrapper(A)(conj(A.data), A.ty Lazy matrix transpose of the [`AbstractQuantumObject`](@ref). """ LinearAlgebra.transpose( - A::AbstractQuantumObject{DT,OpType}, -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + A::AbstractQuantumObject{OpType}, +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = get_typename_wrapper(A)(transpose(A.data), A.type, transpose(A.dimensions)) @doc raw""" @@ -248,16 +237,14 @@ Lazy adjoint (conjugate transposition) of the [`AbstractQuantumObject`](@ref) `A'` and `dag(A)` are synonyms of `adjoint(A)`. """ LinearAlgebra.adjoint( - A::AbstractQuantumObject{DT,OpType}, -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + A::AbstractQuantumObject{OpType}, +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = get_typename_wrapper(A)(adjoint(A.data), A.type, adjoint(A.dimensions)) -LinearAlgebra.adjoint(A::QuantumObject{DT,KetQuantumObject}) where {DT} = - QuantumObject(adjoint(A.data), Bra, adjoint(A.dimensions)) -LinearAlgebra.adjoint(A::QuantumObject{DT,BraQuantumObject}) where {DT} = - QuantumObject(adjoint(A.data), Ket, adjoint(A.dimensions)) -LinearAlgebra.adjoint(A::QuantumObject{DT,OperatorKetQuantumObject}) where {DT} = +LinearAlgebra.adjoint(A::QuantumObject{KetQuantumObject}) = QuantumObject(adjoint(A.data), Bra, adjoint(A.dimensions)) +LinearAlgebra.adjoint(A::QuantumObject{BraQuantumObject}) = QuantumObject(adjoint(A.data), Ket, adjoint(A.dimensions)) +LinearAlgebra.adjoint(A::QuantumObject{OperatorKetQuantumObject}) = QuantumObject(adjoint(A.data), OperatorBra, adjoint(A.dimensions)) -LinearAlgebra.adjoint(A::QuantumObject{DT,OperatorBraQuantumObject}) where {DT} = +LinearAlgebra.adjoint(A::QuantumObject{OperatorBraQuantumObject}) = QuantumObject(adjoint(A.data), OperatorKet, adjoint(A.dimensions)) @doc raw""" @@ -266,14 +253,14 @@ LinearAlgebra.adjoint(A::QuantumObject{DT,OperatorBraQuantumObject}) where {DT} Matrix inverse of the [`AbstractQuantumObject`](@ref). If `A` is a [`QuantumObjectEvolution`](@ref), the inverse is computed at the last computed time. """ LinearAlgebra.inv( - A::AbstractQuantumObject{DT,OpType}, -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + A::AbstractQuantumObject{OpType}, +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(sparse(inv(Matrix(A.data))), A.type, A.dimensions) LinearAlgebra.Hermitian( - A::QuantumObject{DT,OpType}, + A::QuantumObject{OpType}, uplo::Symbol = :U, -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(Hermitian(A.data, uplo), A.type, A.dimensions) @doc raw""" @@ -300,21 +287,18 @@ julia> tr(a' * a) 190.0 + 0.0im ``` """ +LinearAlgebra.tr(A::QuantumObject{OpType}) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + tr(A.data) LinearAlgebra.tr( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = tr(A.data) -LinearAlgebra.tr( - A::QuantumObject{<:Union{<:Hermitian{TF},Symmetric{TR}},OpType}, -) where {TF<:BlasFloat,TR<:Real,OpType<:OperatorQuantumObject} = real(tr(A.data)) + A::QuantumObject{OpType,DimsType,<:Union{<:Hermitian{TF},Symmetric{TR}}}, +) where {OpType<:OperatorQuantumObject,DimsType,TF<:BlasFloat,TR<:Real} = real(tr(A.data)) @doc raw""" svdvals(A::QuantumObject) Return the singular values of a [`QuantumObject`](@ref) in descending order """ -LinearAlgebra.svdvals(A::QuantumObject{<:AbstractVector}) = svdvals(A.data) -LinearAlgebra.svdvals(A::QuantumObject{<:AbstractMatrix}) = svdvals(A.data) -LinearAlgebra.svdvals(A::QuantumObject{<:AbstractSparseMatrix}) = svdvals(sparse_to_dense(A.data)) +LinearAlgebra.svdvals(A::QuantumObject) = svdvals(sparse_to_dense(A.data)) @doc raw""" norm(A::QuantumObject, p::Real) @@ -347,14 +331,14 @@ julia> norm(ψ) ``` """ LinearAlgebra.norm( - A::QuantumObject{<:AbstractArray{T},OpType}, + A::QuantumObject{OpType}, p::Real = 2, -) where {T,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorKetQuantumObject,OperatorBraQuantumObject}} = +) where {OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorKetQuantumObject,OperatorBraQuantumObject}} = norm(A.data, p) function LinearAlgebra.norm( - A::QuantumObject{<:AbstractArray{T},OpType}, + A::QuantumObject{OpType}, p::Real = 1, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} p == 2.0 && return norm(A.data, 2) return norm(svdvals(A), p) end @@ -375,10 +359,10 @@ Support for the following types of [`QuantumObject`](@ref): Also, see [`norm`](@ref) about its definition for different types of [`QuantumObject`](@ref). """ LinearAlgebra.normalize( - A::QuantumObject{<:AbstractArray{T},ObjType}, + A::QuantumObject{ObjType}, p::Real = 2, -) where {T,ObjType<:Union{KetQuantumObject,BraQuantumObject}} = QuantumObject(A.data / norm(A, p), A.type, A.dimensions) -LinearAlgebra.normalize(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, p::Real = 1) where {T} = +) where {ObjType<:Union{KetQuantumObject,BraQuantumObject}} = QuantumObject(A.data / norm(A, p), A.type, A.dimensions) +LinearAlgebra.normalize(A::QuantumObject{OperatorQuantumObject}, p::Real = 1) = QuantumObject(A.data / norm(A, p), A.type, A.dimensions) @doc raw""" @@ -393,36 +377,34 @@ Support for the following types of [`QuantumObject`](@ref): Also, see [`norm`](@ref) about its definition for different types of [`QuantumObject`](@ref). """ LinearAlgebra.normalize!( - A::QuantumObject{<:AbstractArray{T},ObjType}, + A::QuantumObject{ObjType}, p::Real = 2, -) where {T,ObjType<:Union{KetQuantumObject,BraQuantumObject}} = (rmul!(A.data, 1 / norm(A, p)); A) -LinearAlgebra.normalize!(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, p::Real = 1) where {T} = - (rmul!(A.data, 1 / norm(A, p)); A) +) where {ObjType<:Union{KetQuantumObject,BraQuantumObject}} = (rmul!(A.data, 1 / norm(A, p)); A) +LinearAlgebra.normalize!(A::QuantumObject{OperatorQuantumObject}, p::Real = 1) = (rmul!(A.data, 1 / norm(A, p)); A) LinearAlgebra.triu!( - A::QuantumObject{<:AbstractArray{T},OpType}, + A::QuantumObject{OpType}, k::Integer = 0, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (triu!(A.data, k); A) +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (triu!(A.data, k); A) LinearAlgebra.tril!( - A::QuantumObject{<:AbstractArray{T},OpType}, + A::QuantumObject{OpType}, k::Integer = 0, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (tril!(A.data, k); A) +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (tril!(A.data, k); A) LinearAlgebra.triu( - A::QuantumObject{<:AbstractArray{T},OpType}, + A::QuantumObject{OpType}, k::Integer = 0, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(triu(A.data, k), A.type, A.dimensions) LinearAlgebra.tril( - A::QuantumObject{<:AbstractArray{T},OpType}, + A::QuantumObject{OpType}, k::Integer = 0, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(tril(A.data, k), A.type, A.dimensions) -LinearAlgebra.lmul!(a::Number, B::QuantumObject{<:AbstractArray}) = (lmul!(a, B.data); B) -LinearAlgebra.rmul!(B::QuantumObject{<:AbstractArray}, a::Number) = (rmul!(B.data, a); B) +LinearAlgebra.lmul!(a::Number, B::QuantumObject) = (lmul!(a, B.data); B) +LinearAlgebra.rmul!(B::QuantumObject, a::Number) = (rmul!(B.data, a); B) -@inline LinearAlgebra.mul!(y::AbstractVector{Ty}, A::QuantumObject{<:AbstractMatrix{Ta}}, x, α, β) where {Ty,Ta} = - mul!(y, A.data, x, α, β) +@inline LinearAlgebra.mul!(y::AbstractVector{T}, A::QuantumObject, x, α, β) where {T} = mul!(y, A.data, x, α, β) @doc raw""" √(A) @@ -433,8 +415,7 @@ Matrix square root of [`QuantumObject`](@ref) !!! note `√(A)` (where `√` can be typed by tab-completing `\sqrt` in the REPL) is a synonym of `sqrt(A)`. """ -LinearAlgebra.sqrt(A::QuantumObject{<:AbstractArray{T}}) where {T} = - QuantumObject(sqrt(sparse_to_dense(A.data)), A.type, A.dimensions) +LinearAlgebra.sqrt(A::QuantumObject) = QuantumObject(sqrt(sparse_to_dense(A.data)), A.type, A.dimensions) @doc raw""" log(A::QuantumObject) @@ -443,9 +424,7 @@ Matrix logarithm of [`QuantumObject`](@ref) Note that this function only supports for [`Operator`](@ref) and [`SuperOperator`](@ref) """ -LinearAlgebra.log( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +LinearAlgebra.log(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(log(sparse_to_dense(A.data)), A.type, A.dimensions) @doc raw""" @@ -456,12 +435,12 @@ Matrix exponential of [`QuantumObject`](@ref) Note that this function only supports for [`Operator`](@ref) and [`SuperOperator`](@ref) """ LinearAlgebra.exp( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + A::QuantumObject{ObjType,DimsType,<:AbstractMatrix}, +) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject},DimsType} = QuantumObject(dense_to_sparse(exp(A.data)), A.type, A.dimensions) LinearAlgebra.exp( - A::QuantumObject{<:AbstractSparseMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + A::QuantumObject{ObjType,DimsType,<:AbstractSparseMatrix}, +) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject},DimsType} = QuantumObject(_spexp(A.data), A.type, A.dimensions) function _spexp(A::SparseMatrixCSC{T,M}; threshold = 1e-14, nonzero_tol = 1e-20) where {T,M} @@ -504,9 +483,8 @@ Matrix sine of [`QuantumObject`](@ref), defined as Note that this function only supports for [`Operator`](@ref) and [`SuperOperator`](@ref) """ -LinearAlgebra.sin( - A::QuantumObject{DT,ObjType}, -) where {DT,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (exp(1im * A) - exp(-1im * A)) / 2im +LinearAlgebra.sin(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + (exp(1im * A) - exp(-1im * A)) / 2im @doc raw""" cos(A::QuantumObject) @@ -517,9 +495,8 @@ Matrix cosine of [`QuantumObject`](@ref), defined as Note that this function only supports for [`Operator`](@ref) and [`SuperOperator`](@ref) """ -LinearAlgebra.cos( - A::QuantumObject{DT,ObjType}, -) where {DT,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (exp(1im * A) + exp(-1im * A)) / 2 +LinearAlgebra.cos(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + (exp(1im * A) + exp(-1im * A)) / 2 @doc raw""" diag(A::QuantumObject, k::Int=0) @@ -529,17 +506,17 @@ Return the `k`-th diagonal elements of a matrix-type [`QuantumObject`](@ref) Note that this function only supports for [`Operator`](@ref) and [`SuperOperator`](@ref) """ LinearAlgebra.diag( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, + A::QuantumObject{ObjType}, k::Int = 0, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = diag(A.data, k) +) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = diag(A.data, k) @doc raw""" proj(ψ::QuantumObject) Return the projector for a [`Ket`](@ref) or [`Bra`](@ref) type of [`QuantumObject`](@ref) """ -proj(ψ::QuantumObject{<:AbstractArray{T},KetQuantumObject}) where {T} = ψ * ψ' -proj(ψ::QuantumObject{<:AbstractArray{T},BraQuantumObject}) where {T} = ψ' * ψ +proj(ψ::QuantumObject{KetQuantumObject}) = ψ * ψ' +proj(ψ::QuantumObject{BraQuantumObject}) = ψ' * ψ @doc raw""" ptrace(QO::QuantumObject, sel) @@ -588,7 +565,7 @@ Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true 0.0+0.0im 0.5+0.0im ``` """ -function ptrace(QO::QuantumObject{<:AbstractArray,KetQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) +function ptrace(QO::QuantumObject{KetQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) _non_static_array_warning("sel", sel) n_s = length(sel) @@ -609,9 +586,9 @@ function ptrace(QO::QuantumObject{<:AbstractArray,KetQuantumObject}, sel::Union{ return QuantumObject(ρtr, type = Operator, dims = Dimensions(dkeep)) end -ptrace(QO::QuantumObject{<:AbstractArray,BraQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) = ptrace(QO', sel) +ptrace(QO::QuantumObject{BraQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) = ptrace(QO', sel) -function ptrace(QO::QuantumObject{<:AbstractArray,OperatorQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) +function ptrace(QO::QuantumObject{OperatorQuantumObject}, sel::Union{AbstractVector{Int},Tuple}) # TODO: support for special cases when some of the subsystems have same `to` and `from` space isa(QO.dimensions, GeneralDimensions) && (get_dimensions_to(QO) != get_dimensions_from(QO)) && @@ -711,18 +688,16 @@ Calculate the purity of a [`QuantumObject`](@ref): ``\textrm{Tr}(\rho^2)`` Note that this function only supports for [`Ket`](@ref), [`Bra`](@ref), and [`Operator`](@ref) """ -purity(ρ::QuantumObject{<:AbstractArray{T},ObjType}) where {T,ObjType<:Union{KetQuantumObject,BraQuantumObject}} = - sum(abs2, ρ.data) -purity(ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = real(tr(ρ.data^2)) +purity(ρ::QuantumObject{ObjType}) where {ObjType<:Union{KetQuantumObject,BraQuantumObject}} = sum(abs2, ρ.data) +purity(ρ::QuantumObject{OperatorQuantumObject}) = real(tr(ρ.data^2)) @doc raw""" tidyup(A::QuantumObject, tol::Real=1e-14) Given a [`QuantumObject`](@ref) `A`, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than `tol`. """ -tidyup(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = - QuantumObject(tidyup(A.data, tol), A.type, A.dimensions) -tidyup(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = tidyup!(copy(A), tol) +tidyup(A::QuantumObject, tol::T = 1e-14) where {T<:Real} = QuantumObject(tidyup(A.data, tol), A.type, A.dimensions) +tidyup(A::AbstractArray, tol::T2 = 1e-14) where {T2<:Real} = tidyup!(copy(A), tol) @doc raw""" tidyup!(A::QuantumObject, tol::Real=1e-14) @@ -731,8 +706,8 @@ Given a [`QuantumObject`](@ref) `A`, check the real and imaginary parts of each Note that this function is an in-place version of [`tidyup`](@ref). """ -tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = (tidyup!(A.data, tol); A) -function tidyup!(A::AbstractSparseArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} +tidyup!(A::QuantumObject, tol::T = 1e-14) where {T<:Real} = (tidyup!(A.data, tol); A) +function tidyup!(A::AbstractSparseArray, tol::T2 = 1e-14) where {T2<:Real} tidyup!(nonzeros(A), tol) # tidyup A.nzval in-place (also support for CUDA sparse arrays) return dropzeros!(A) end @@ -754,7 +729,7 @@ Get the coherence value ``\alpha`` by measuring the expectation value of the des It returns both ``\alpha`` and the corresponding state with the coherence removed: ``\ket{\delta_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \ket{\psi}`` for a pure state, and ``\hat{\rho_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \hat{\rho} \exp ( -\bar{\alpha} \hat{a} + \alpha \hat{a}^\dagger )`` for a density matrix. These states correspond to the quantum fluctuations around the coherent state ``\ket{\alpha}`` or ``|\alpha\rangle\langle\alpha|``. """ -function get_coherence(ψ::QuantumObject{<:AbstractArray,KetQuantumObject}) +function get_coherence(ψ::QuantumObject{KetQuantumObject}) a = destroy(prod(ψ.dimensions)) α = expect(a, ψ) D = exp(α * a' - conj(α) * a) @@ -762,7 +737,7 @@ function get_coherence(ψ::QuantumObject{<:AbstractArray,KetQuantumObject}) return α, D' * ψ end -function get_coherence(ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject}) +function get_coherence(ρ::QuantumObject{OperatorQuantumObject}) a = destroy(prod(ρ.dimensions)) α = expect(a, ρ) D = exp(α * a' - conj(α) * a) @@ -798,9 +773,9 @@ true It is highly recommended to use `permute(A, order)` with `order` as `Tuple` or `SVector` to keep type stability. See the [related Section](@ref doc:Type-Stability) about type stability for more details. """ function SparseArrays.permute( - A::QuantumObject{<:AbstractArray{T},ObjType}, + A::QuantumObject{ObjType}, order::Union{AbstractVector{Int},Tuple}, -) where {T,ObjType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} +) where {ObjType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} (length(order) != length(A.dimensions)) && throw(ArgumentError("The order list must have the same length as the number of subsystems (A.dims)")) diff --git a/src/qobj/block_diagonal_form.jl b/src/qobj/block_diagonal_form.jl index ca3e89a68..118189492 100644 --- a/src/qobj/block_diagonal_form.jl +++ b/src/qobj/block_diagonal_form.jl @@ -51,8 +51,8 @@ Return the block-diagonal form of a [`QuantumObject`](@ref). This is very useful The [`BlockDiagonalForm`](@ref) of `A`. """ function block_diagonal_form( - A::QuantumObject{DT,OpType}, -) where {DT<:AbstractSparseMatrix,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} + A::QuantumObject{OpType}, +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} bdf = block_diagonal_form(A.data) B = QuantumObject(bdf.B, type = A.type, dims = A.dimensions) P = QuantumObject(bdf.P, type = A.type, dims = A.dimensions) diff --git a/src/qobj/boolean_functions.jl b/src/qobj/boolean_functions.jl index c67f8fe43..935d1b3d9 100644 --- a/src/qobj/boolean_functions.jl +++ b/src/qobj/boolean_functions.jl @@ -11,7 +11,7 @@ export isunitary Checks if the [`QuantumObject`](@ref) `A` is a [`BraQuantumObject`](@ref). Default case returns `false` for any other inputs. """ isbra(A::QuantumObject) = isbra(typeof(A)) -isbra(::Type{QuantumObject{DT,BraQuantumObject,N}}) where {DT,N} = true +isbra(::Type{<:QuantumObject{BraQuantumObject,N}}) where {N} = true isbra(A) = false # default case @doc raw""" @@ -20,7 +20,7 @@ isbra(A) = false # default case Checks if the [`QuantumObject`](@ref) `A` is a [`KetQuantumObject`](@ref). Default case returns `false` for any other inputs. """ isket(A::QuantumObject) = isket(typeof(A)) -isket(::Type{QuantumObject{DT,KetQuantumObject,N}}) where {DT,N} = true +isket(::Type{<:QuantumObject{KetQuantumObject,N}}) where {N} = true isket(A) = false # default case @doc raw""" @@ -29,7 +29,7 @@ isket(A) = false # default case Checks if the [`AbstractQuantumObject`](@ref) `A` is a [`OperatorQuantumObject`](@ref). Default case returns `false` for any other inputs. """ isoper(A::AbstractQuantumObject) = isoper(typeof(A)) -isoper(::Type{<:AbstractQuantumObject{DT,OperatorQuantumObject,N}}) where {DT,N} = true +isoper(::Type{<:AbstractQuantumObject{OperatorQuantumObject,N}}) where {N} = true isoper(A) = false # default case @doc raw""" @@ -38,7 +38,7 @@ isoper(A) = false # default case Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorBraQuantumObject`](@ref). Default case returns `false` for any other inputs. """ isoperbra(A::QuantumObject) = isoperbra(typeof(A)) -isoperbra(::Type{QuantumObject{DT,OperatorBraQuantumObject,N}}) where {DT,N} = true +isoperbra(::Type{<:QuantumObject{OperatorBraQuantumObject,N}}) where {N} = true isoperbra(A) = false # default case @doc raw""" @@ -47,7 +47,7 @@ isoperbra(A) = false # default case Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorKetQuantumObject`](@ref). Default case returns `false` for any other inputs. """ isoperket(A::QuantumObject) = isoperket(typeof(A)) -isoperket(::Type{QuantumObject{DT,OperatorKetQuantumObject,N}}) where {DT,N} = true +isoperket(::Type{<:QuantumObject{OperatorKetQuantumObject,N}}) where {N} = true isoperket(A) = false # default case @doc raw""" @@ -56,7 +56,7 @@ isoperket(A) = false # default case Checks if the [`AbstractQuantumObject`](@ref) `A` is a [`SuperOperatorQuantumObject`](@ref). Default case returns `false` for any other inputs. """ issuper(A::AbstractQuantumObject) = issuper(typeof(A)) -issuper(::Type{<:AbstractQuantumObject{DT,SuperOperatorQuantumObject,N}}) where {DT,N} = true +issuper(::Type{<:AbstractQuantumObject{SuperOperatorQuantumObject,N}}) where {N} = true issuper(A) = false # default case @doc raw""" @@ -91,8 +91,7 @@ Test whether the [`QuantumObject`](@ref) ``U`` is unitary operator. This functio Note that all the keyword arguments will be passed to `Base.isapprox`. """ -isunitary(U::QuantumObject{<:AbstractArray{T}}; kwargs...) where {T} = - isoper(U) ? isapprox(U.data * U.data', I(size(U, 1)); kwargs...) : false +isunitary(U::QuantumObject; kwargs...) = isoper(U) ? isapprox(U.data * U.data', I(size(U, 1)); kwargs...) : false @doc raw""" SciMLOperators.iscached(A::AbstractQuantumObject) diff --git a/src/qobj/eigsolve.jl b/src/qobj/eigsolve.jl index cbccbed2d..f53cec4ee 100644 --- a/src/qobj/eigsolve.jl +++ b/src/qobj/eigsolve.jl @@ -45,7 +45,7 @@ julia> λ 1.0 + 0.0im julia> ψ -2-element Vector{QuantumObject{Vector{ComplexF64}, KetQuantumObject, Dimensions{1, Tuple{Space}}}}: +2-element Vector{QuantumObject{KetQuantumObject, Dimensions{1, Tuple{Space}}, Vector{ComplexF64}}}: Quantum Object: type=Ket dims=[2] size=(2,) 2-element Vector{ComplexF64}: @@ -273,7 +273,7 @@ Solve for the eigenvalues and eigenvectors of a matrix `A` using the Arnoldi met - `EigsolveResult`: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver """ function eigsolve( - A::QuantumObject{<:AbstractMatrix}; + A::QuantumObject; v0::Union{Nothing,AbstractVector} = nothing, sigma::Union{Nothing,Real} = nothing, k::Int = 1, @@ -343,7 +343,7 @@ end @doc raw""" eigsolve_al( - H::Union{AbstractQuantumObject{DT1,HOpType},Tuple}, + H::Union{AbstractQuantumObject{HOpType},Tuple}, T::Real, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::OrdinaryDiffEqAlgorithm = Tsit5(), @@ -382,7 +382,7 @@ Solve the eigenvalue problem for a Liouvillian superoperator `L` using the Arnol - [1] Minganti, F., & Huybrechts, D. (2022). Arnoldi-Lindblad time evolution: Faster-than-the-clock algorithm for the spectrum of time-independent and Floquet open quantum systems. Quantum, 6, 649. """ function eigsolve_al( - H::Union{AbstractQuantumObject{DT1,HOpType},Tuple}, + H::Union{AbstractQuantumObject{HOpType},Tuple}, T::Real, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::OrdinaryDiffEqAlgorithm = Tsit5(), @@ -393,7 +393,7 @@ function eigsolve_al( maxiter::Int = 200, eigstol::Real = 1e-6, kwargs..., -) where {DT1,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} L_evo = _mesolve_make_L_QobjEvo(H, c_ops) prob = mesolveProblem( @@ -408,7 +408,7 @@ function eigsolve_al( # prog = ProgressUnknown(desc="Applications:", showspeed = true, enabled=progress) - Lmap = ArnoldiLindbladIntegratorMap(eltype(DT1), size(L_evo), integrator) + Lmap = ArnoldiLindbladIntegratorMap(eltype(H), size(L_evo), integrator) res = _eigsolve(Lmap, mat2vec(ρ0), L_evo.type, L_evo.dimensions, k, krylovdim, maxiter = maxiter, tol = eigstol) # finish!(prog) @@ -458,9 +458,10 @@ true ``` """ function LinearAlgebra.eigen( - A::QuantumObject{MT,OpType}; + A::QuantumObject{OpType}; kwargs..., -) where {MT<:AbstractMatrix,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} + MT = typeof(A.data) F = eigen(sparse_to_dense(A.data); kwargs...) # This fixes a type inference issue. But doesn't work for GPU arrays E::mat2vec(sparse_to_dense(MT)) = F.values @@ -475,10 +476,9 @@ end Same as [`eigen(A::QuantumObject; kwargs...)`](@ref) but for only the eigenvalues. """ LinearAlgebra.eigvals( - A::QuantumObject{<:AbstractArray{T},OpType}; + A::QuantumObject{OpType}; kwargs..., -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = - eigvals(sparse_to_dense(A.data); kwargs...) +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eigvals(sparse_to_dense(A.data); kwargs...) @doc raw""" eigenenergies(A::QuantumObject; sparse::Bool=false, kwargs...) @@ -494,10 +494,10 @@ Calculate the eigenenergies - `::Vector{<:Number}`: a list of eigenvalues """ function eigenenergies( - A::QuantumObject{<:AbstractArray{T},OpType}; + A::QuantumObject{OpType}; sparse::Bool = false, kwargs..., -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} if !sparse return eigvals(A; kwargs...) else @@ -519,10 +519,10 @@ Calculate the eigenvalues and corresponding eigenvectors - `::EigsolveResult`: containing the eigenvalues, the eigenvectors, and some information from the solver. see also [`EigsolveResult`](@ref) """ function eigenstates( - A::QuantumObject{<:AbstractArray{T},OpType}; + A::QuantumObject{OpType}; sparse::Bool = false, kwargs..., -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} if !sparse return eigen(A; kwargs...) else diff --git a/src/qobj/functions.jl b/src/qobj/functions.jl index fbc7f3031..00791f344 100644 --- a/src/qobj/functions.jl +++ b/src/qobj/functions.jl @@ -12,9 +12,9 @@ export vec2mat, mat2vec Transform the ket state ``\ket{\psi}`` into a pure density matrix ``\hat{\rho} = |\psi\rangle\langle\psi|``. """ -ket2dm(ψ::QuantumObject{<:AbstractArray{T},KetQuantumObject}) where {T} = ψ * ψ' +ket2dm(ψ::QuantumObject{KetQuantumObject}) = ψ * ψ' -ket2dm(ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = ρ +ket2dm(ρ::QuantumObject{OperatorQuantumObject}) = ρ @doc raw""" expect(O::AbstractQuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}}) @@ -43,43 +43,30 @@ julia> expect(Hermitian(a' * a), ψ) |> round 3.0 ``` """ -function expect( - O::AbstractQuantumObject{DT1,OperatorQuantumObject}, - ψ::QuantumObject{DT2,KetQuantumObject}, -) where {DT1,DT2} +function expect(O::AbstractQuantumObject{OperatorQuantumObject}, ψ::QuantumObject{KetQuantumObject}) return dot(ψ.data, O.data, ψ.data) end +expect(O::AbstractQuantumObject{OperatorQuantumObject}, ψ::QuantumObject{BraQuantumObject}) = expect(O, ψ') +expect(O::QuantumObject{OperatorQuantumObject}, ρ::QuantumObject{OperatorQuantumObject}) = tr(O * ρ) function expect( - O::AbstractQuantumObject{DT1,OperatorQuantumObject}, - ψ::QuantumObject{DT2,BraQuantumObject}, -) where {DT1,DT2} - return expect(O, ψ') -end -function expect( - O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - ρ::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, -) where {T1,T2} - return tr(O * ρ) -end -function expect( - O::QuantumObject{<:Union{<:Hermitian{TF},<:Symmetric{TR}},OperatorQuantumObject}, - ψ::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, -) where {TF<:Number,TR<:Real,T2} + O::QuantumObject{OperatorQuantumObject,DimsType,<:Union{<:Hermitian{TF},<:Symmetric{TR}}}, + ψ::QuantumObject{KetQuantumObject}, +) where {DimsType<:AbstractDimensions,TF<:Number,TR<:Real} return real(dot(ψ.data, O.data, ψ.data)) end function expect( - O::QuantumObject{<:Union{<:Hermitian{TF},<:Symmetric{TR}},OperatorQuantumObject}, - ψ::QuantumObject{<:AbstractArray{T2},BraQuantumObject}, -) where {TF<:Number,TR<:Real,T2} + O::QuantumObject{OperatorQuantumObject,DimsType,<:Union{<:Hermitian{TF},<:Symmetric{TR}}}, + ψ::QuantumObject{BraQuantumObject}, +) where {DimsType<:AbstractDimensions,TF<:Number,TR<:Real} return real(expect(O, ψ')) end function expect( - O::QuantumObject{<:Union{<:Hermitian{TF},<:Symmetric{TR}},OperatorQuantumObject}, - ρ::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, -) where {TF<:Number,TR<:Real,T2} + O::QuantumObject{OperatorQuantumObject,DimsType,<:Union{<:Hermitian{TF},<:Symmetric{TR}}}, + ρ::QuantumObject{OperatorQuantumObject}, +) where {DimsType<:AbstractDimensions,TF<:Number,TR<:Real} return real(tr(O * ρ)) end -function expect(O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ρ::Vector{<:QuantumObject}) where {T1} +function expect(O::QuantumObject{OperatorQuantumObject}, ρ::Vector{<:QuantumObject}) _expect = _ρ -> expect(O, _ρ) return _expect.(ρ) end @@ -95,17 +82,15 @@ The function returns a real number if `O` is hermitian, and returns a complex nu Note that `ψ` can also be given as a list of [`QuantumObject`](@ref), it returns a list of expectation values. """ -variance(O::QuantumObject{DT1,OperatorQuantumObject}, ψ::QuantumObject{DT2}) where {DT1,DT2} = - expect(O^2, ψ) - expect(O, ψ)^2 -variance(O::QuantumObject{DT1,OperatorQuantumObject}, ψ::Vector{<:QuantumObject}) where {DT1} = - expect(O^2, ψ) .- expect(O, ψ) .^ 2 +variance(O::QuantumObject{OperatorQuantumObject}, ψ::QuantumObject) = expect(O^2, ψ) - expect(O, ψ)^2 +variance(O::QuantumObject{OperatorQuantumObject}, ψ::Vector{<:QuantumObject}) = expect(O^2, ψ) .- expect(O, ψ) .^ 2 @doc raw""" sparse_to_dense(A::QuantumObject) Converts a sparse QuantumObject to a dense QuantumObject. """ -sparse_to_dense(A::QuantumObject{<:AbstractVecOrMat}) = QuantumObject(sparse_to_dense(A.data), A.type, A.dimensions) +sparse_to_dense(A::QuantumObject) = QuantumObject(sparse_to_dense(A.data), A.type, A.dimensions) sparse_to_dense(A::MT) where {MT<:AbstractSparseArray} = Array(A) for op in (:Transpose, :Adjoint) @eval sparse_to_dense(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = Array(A) @@ -131,8 +116,7 @@ sparse_to_dense(::Type{M}) where {M<:AbstractMatrix} = M Converts a dense QuantumObject to a sparse QuantumObject. """ -dense_to_sparse(A::QuantumObject{<:AbstractVecOrMat}, tol::Real = 1e-10) = - QuantumObject(dense_to_sparse(A.data, tol), A.type, A.dimensions) +dense_to_sparse(A::QuantumObject, tol::Real = 1e-10) = QuantumObject(dense_to_sparse(A.data, tol), A.type, A.dimensions) function dense_to_sparse(A::MT, tol::Real = 1e-10) where {MT<:AbstractMatrix} idxs = findall(@. abs(A) > tol) row_indices = getindex.(idxs, 1) @@ -180,9 +164,9 @@ julia> a.dims, O.dims ``` """ function LinearAlgebra.kron( - A::AbstractQuantumObject{DT1,OpType,<:Dimensions}, - B::AbstractQuantumObject{DT2,OpType,<:Dimensions}, -) where {DT1,DT2,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} + A::AbstractQuantumObject{OpType,<:Dimensions}, + B::AbstractQuantumObject{OpType,<:Dimensions}, +) where {OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} QType = promote_op_type(A, B) _lazy_tensor_warning(A.data, B.data) return QType(kron(A.data, B.data), A.type, Dimensions((A.dimensions.to..., B.dimensions.to...))) @@ -194,9 +178,9 @@ for ADimType in (:Dimensions, :GeneralDimensions) if !(ADimType == BDimType == :Dimensions) # not for this case because it's already implemented @eval begin function LinearAlgebra.kron( - A::AbstractQuantumObject{DT1,OperatorQuantumObject,<:$ADimType}, - B::AbstractQuantumObject{DT2,OperatorQuantumObject,<:$BDimType}, - ) where {DT1,DT2} + A::AbstractQuantumObject{OperatorQuantumObject,<:$ADimType}, + B::AbstractQuantumObject{OperatorQuantumObject,<:$BDimType}, + ) QType = promote_op_type(A, B) _lazy_tensor_warning(A.data, B.data) return QType( @@ -218,10 +202,7 @@ for AOpType in (:KetQuantumObject, :BraQuantumObject, :OperatorQuantumObject) for BOpType in (:KetQuantumObject, :BraQuantumObject, :OperatorQuantumObject) if (AOpType != BOpType) @eval begin - function LinearAlgebra.kron( - A::AbstractQuantumObject{DT1,$AOpType}, - B::AbstractQuantumObject{DT2,$BOpType}, - ) where {DT1,DT2} + function LinearAlgebra.kron(A::AbstractQuantumObject{$AOpType}, B::AbstractQuantumObject{$BOpType}) QType = promote_op_type(A, B) _lazy_tensor_warning(A.data, B.data) return QType( @@ -259,16 +240,14 @@ end Convert a quantum object from vector ([`OperatorKetQuantumObject`](@ref)-type) to matrix ([`OperatorQuantumObject`](@ref)-type) """ -vec2mat(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = - QuantumObject(vec2mat(A.data), Operator, A.dimensions) +vec2mat(A::QuantumObject{OperatorKetQuantumObject}) = QuantumObject(vec2mat(A.data), Operator, A.dimensions) @doc raw""" mat2vec(A::QuantumObject) Convert a quantum object from matrix ([`OperatorQuantumObject`](@ref)-type) to vector ([`OperatorKetQuantumObject`](@ref)-type) """ -mat2vec(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = - QuantumObject(mat2vec(A.data), OperatorKet, A.dimensions) +mat2vec(A::QuantumObject{OperatorQuantumObject}) = QuantumObject(mat2vec(A.data), OperatorKet, A.dimensions) @doc raw""" mat2vec(A::AbstractMatrix) diff --git a/src/qobj/operators.jl b/src/qobj/operators.jl index 9b0e1de5f..2c3e05d9f 100644 --- a/src/qobj/operators.jl +++ b/src/qobj/operators.jl @@ -73,11 +73,8 @@ Return the commutator (or `anti`-commutator) of the two [`QuantumObject`](@ref): Note that `A` and `B` must be [`Operator`](@ref) """ -commutator( - A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}; - anti::Bool = false, -) where {T1,T2} = A * B - (-1)^anti * B * A +commutator(A::QuantumObject{OperatorQuantumObject}, B::QuantumObject{OperatorQuantumObject}; anti::Bool = false) = + A * B - (-1)^anti * B * A @doc raw""" destroy(N::Int) @@ -481,10 +478,9 @@ Note that we put ``\hat{\sigma}_{-} = \begin{pmatrix} 0 & 0 \\ 1 & 0 \end{pmatri """ fcreate(N::Union{Int,Val}, j::Int) = _Jordan_Wigner(N, j, sigmam()) -_Jordan_Wigner(N::Int, j::Int, op::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = - _Jordan_Wigner(Val(N), j, op) +_Jordan_Wigner(N::Int, j::Int, op::QuantumObject{OperatorQuantumObject}) = _Jordan_Wigner(Val(N), j, op) -function _Jordan_Wigner(::Val{N}, j::Int, op::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {N,T} +function _Jordan_Wigner(::Val{N}, j::Int, op::QuantumObject{OperatorQuantumObject}) where {N} (N < 1) && throw(ArgumentError("The total number of sites (N) cannot be less than 1")) ((j > N) || (j < 1)) && throw(ArgumentError("The site index (j) should satisfy: 1 ≤ j ≤ N")) diff --git a/src/qobj/quantum_object.jl b/src/qobj/quantum_object.jl index a2ba3ffdf..f2c6f5569 100644 --- a/src/qobj/quantum_object.jl +++ b/src/qobj/quantum_object.jl @@ -9,7 +9,7 @@ It also implements the fundamental functions in Julia standard library: export QuantumObject @doc raw""" - struct QuantumObject{DataType<:AbstractArray,ObjType<:QuantumObjectType,DimType<:AbstractDimensions} <: AbstractQuantumObject{DataType,ObjType,DimType} + struct QuantumObject{ObjType<:QuantumObjectType,DimType<:AbstractDimensions,DataType<:AbstractArray} <: AbstractQuantumObject{ObjType,DimType,DataType} data::DataType type::ObjType dimensions::DimType @@ -44,19 +44,19 @@ julia> a.dimensions Dimensions{1, Tuple{Space}}((Space(20),)) ``` """ -struct QuantumObject{DataType<:AbstractArray,ObjType<:QuantumObjectType,DimType<:AbstractDimensions} <: - AbstractQuantumObject{DataType,ObjType,DimType} +struct QuantumObject{ObjType<:QuantumObjectType,DimType<:AbstractDimensions,DataType<:AbstractArray} <: + AbstractQuantumObject{ObjType,DimType,DataType} data::DataType type::ObjType dimensions::DimType - function QuantumObject(data::MT, type::ObjType, dims) where {MT<:AbstractArray,ObjType<:QuantumObjectType} + function QuantumObject(data::DT, type::ObjType, dims) where {DT<:AbstractArray,ObjType<:QuantumObjectType} dimensions = _gen_dimensions(dims) _size = _get_size(data) _check_QuantumObject(type, dimensions, _size[1], _size[2]) - return new{MT,ObjType,typeof(dimensions)}(data, type, dimensions) + return new{ObjType,typeof(dimensions),DT}(data, type, dimensions) end end @@ -132,12 +132,8 @@ function QuantumObject( throw(DomainError(size(A), "The size of the array is not compatible with vector or matrix.")) end -function QuantumObject( - A::QuantumObject{<:AbstractArray{T,N}}; - type::ObjType = A.type, - dims = A.dimensions, -) where {T,N,ObjType<:QuantumObjectType} - _size = N == 1 ? (length(A), 1) : size(A) +function QuantumObject(A::QuantumObject; type::ObjType = A.type, dims = A.dimensions) where {ObjType<:QuantumObjectType} + _size = _get_size(A.data) dimensions = _gen_dimensions(dims) _check_QuantumObject(type, dimensions, _size[1], _size[2]) return QuantumObject(copy(A.data), type, dimensions) @@ -145,9 +141,8 @@ end function Base.show( io::IO, - QO::QuantumObject{<:AbstractArray{T},OpType}, + QO::QuantumObject{OpType}, ) where { - T, OpType<:Union{ BraQuantumObject, KetQuantumObject, @@ -188,14 +183,13 @@ end Base.real(x::QuantumObject) = QuantumObject(real(x.data), x.type, x.dimensions) Base.imag(x::QuantumObject) = QuantumObject(imag(x.data), x.type, x.dimensions) -SparseArrays.sparse(A::QuantumObject{<:AbstractArray{T}}) where {T} = - QuantumObject(sparse(A.data), A.type, A.dimensions) -SparseArrays.nnz(A::QuantumObject{<:AbstractSparseArray}) = nnz(A.data) -SparseArrays.nonzeros(A::QuantumObject{<:AbstractSparseArray}) = nonzeros(A.data) -SparseArrays.rowvals(A::QuantumObject{<:AbstractSparseArray}) = rowvals(A.data) -SparseArrays.droptol!(A::QuantumObject{<:AbstractSparseArray}, tol::Real) = (droptol!(A.data, tol); return A) -SparseArrays.dropzeros(A::QuantumObject{<:AbstractSparseArray}) = QuantumObject(dropzeros(A.data), A.type, A.dimensions) -SparseArrays.dropzeros!(A::QuantumObject{<:AbstractSparseArray}) = (dropzeros!(A.data); return A) +SparseArrays.sparse(A::QuantumObject) = QuantumObject(sparse(A.data), A.type, A.dimensions) +SparseArrays.nnz(A::QuantumObject) = nnz(A.data) +SparseArrays.nonzeros(A::QuantumObject) = nonzeros(A.data) +SparseArrays.rowvals(A::QuantumObject) = rowvals(A.data) +SparseArrays.droptol!(A::QuantumObject, tol::Real) = (droptol!(A.data, tol); return A) +SparseArrays.dropzeros(A::QuantumObject) = QuantumObject(dropzeros(A.data), A.type, A.dimensions) +SparseArrays.dropzeros!(A::QuantumObject) = (dropzeros!(A.data); return A) @doc raw""" SciMLOperators.cached_operator(L::AbstractQuantumObject, u) @@ -208,17 +202,15 @@ Here, `u` can be in either the following types: - [`OperatorKet`](@ref)-type [`QuantumObject`](@ref) (if `L` is a [`SuperOperator`](@ref)) """ SciMLOperators.cache_operator( - L::AbstractQuantumObject{DT,OpType}, + L::AbstractQuantumObject{OpType}, u::AbstractVector, -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = get_typename_wrapper(L)(cache_operator(L.data, sparse_to_dense(similar(u))), L.type, L.dimensions) function SciMLOperators.cache_operator( - L::AbstractQuantumObject{DT1,OpType}, - u::QuantumObject{DT2,SType}, + L::AbstractQuantumObject{OpType}, + u::QuantumObject{SType}, ) where { - DT1, - DT2, OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, SType<:Union{KetQuantumObject,OperatorKetQuantumObject}, } @@ -233,17 +225,13 @@ function SciMLOperators.cache_operator( end # data type conversions -Base.Vector(A::QuantumObject{<:AbstractVector}) = QuantumObject(Vector(A.data), A.type, A.dimensions) -Base.Vector{T}(A::QuantumObject{<:AbstractVector}) where {T<:Number} = - QuantumObject(Vector{T}(A.data), A.type, A.dimensions) -Base.Matrix(A::QuantumObject{<:AbstractMatrix}) = QuantumObject(Matrix(A.data), A.type, A.dimensions) -Base.Matrix{T}(A::QuantumObject{<:AbstractMatrix}) where {T<:Number} = - QuantumObject(Matrix{T}(A.data), A.type, A.dimensions) -SparseArrays.SparseVector(A::QuantumObject{<:AbstractVector}) = - QuantumObject(SparseVector(A.data), A.type, A.dimensions) -SparseArrays.SparseVector{T}(A::QuantumObject{<:SparseVector}) where {T<:Number} = +Base.Vector(A::QuantumObject) = QuantumObject(Vector(A.data), A.type, A.dimensions) +Base.Vector{T}(A::QuantumObject) where {T<:Number} = QuantumObject(Vector{T}(A.data), A.type, A.dimensions) +Base.Matrix(A::QuantumObject) = QuantumObject(Matrix(A.data), A.type, A.dimensions) +Base.Matrix{T}(A::QuantumObject) where {T<:Number} = QuantumObject(Matrix{T}(A.data), A.type, A.dimensions) +SparseArrays.SparseVector(A::QuantumObject) = QuantumObject(SparseVector(A.data), A.type, A.dimensions) +SparseArrays.SparseVector{T}(A::QuantumObject) where {T<:Number} = QuantumObject(SparseVector{T}(A.data), A.type, A.dimensions) -SparseArrays.SparseMatrixCSC(A::QuantumObject{<:AbstractMatrix}) = - QuantumObject(SparseMatrixCSC(A.data), A.type, A.dimensions) -SparseArrays.SparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T<:Number} = +SparseArrays.SparseMatrixCSC(A::QuantumObject) = QuantumObject(SparseMatrixCSC(A.data), A.type, A.dimensions) +SparseArrays.SparseMatrixCSC{T}(A::QuantumObject) where {T<:Number} = QuantumObject(SparseMatrixCSC{T}(A.data), A.type, A.dimensions) diff --git a/src/qobj/quantum_object_base.jl b/src/qobj/quantum_object_base.jl index cec0992b3..da9deeb86 100644 --- a/src/qobj/quantum_object_base.jl +++ b/src/qobj/quantum_object_base.jl @@ -14,7 +14,7 @@ export QuantumObjectType, export Bra, Ket, Operator, OperatorBra, OperatorKet, SuperOperator @doc raw""" - abstract type AbstractQuantumObject{DataType,ObjType,DimType} + abstract type AbstractQuantumObject{ObjType,DimType,DataType} Abstract type for all quantum objects like [`QuantumObject`](@ref) and [`QuantumObjectEvolution`](@ref). @@ -24,7 +24,7 @@ julia> sigmax() isa AbstractQuantumObject true ``` """ -abstract type AbstractQuantumObject{DataType,ObjType,DimType} end +abstract type AbstractQuantumObject{ObjType,DimType,DataType} end abstract type QuantumObjectType end @@ -263,25 +263,24 @@ function Base.getproperty(A::AbstractQuantumObject, key::Symbol) end # this returns `to` in GeneralDimensions representation -get_dimensions_to(A::AbstractQuantumObject{DT,KetQuantumObject,<:Dimensions{N}}) where {DT,N} = A.dimensions.to -get_dimensions_to(A::AbstractQuantumObject{DT,BraQuantumObject,<:Dimensions{N}}) where {DT,N} = space_one_list(N) -get_dimensions_to(A::AbstractQuantumObject{DT,OperatorQuantumObject,<:Dimensions{N}}) where {DT,N} = A.dimensions.to -get_dimensions_to(A::AbstractQuantumObject{DT,OperatorQuantumObject,<:GeneralDimensions{N}}) where {DT,N} = - A.dimensions.to +get_dimensions_to(A::AbstractQuantumObject{KetQuantumObject,<:Dimensions{N}}) where {N} = A.dimensions.to +get_dimensions_to(A::AbstractQuantumObject{BraQuantumObject,<:Dimensions{N}}) where {N} = space_one_list(N) +get_dimensions_to(A::AbstractQuantumObject{OperatorQuantumObject,<:Dimensions{N}}) where {N} = A.dimensions.to +get_dimensions_to(A::AbstractQuantumObject{OperatorQuantumObject,<:GeneralDimensions{N}}) where {N} = A.dimensions.to get_dimensions_to( - A::AbstractQuantumObject{DT,ObjType,<:Dimensions{N}}, -) where {DT,ObjType<:Union{SuperOperatorQuantumObject,OperatorBraQuantumObject,OperatorKetQuantumObject},N} = + A::AbstractQuantumObject{ObjType,<:Dimensions{N}}, +) where {ObjType<:Union{SuperOperatorQuantumObject,OperatorBraQuantumObject,OperatorKetQuantumObject},N} = A.dimensions.to # this returns `from` in GeneralDimensions representation -get_dimensions_from(A::AbstractQuantumObject{DT,KetQuantumObject,<:Dimensions{N}}) where {DT,N} = space_one_list(N) -get_dimensions_from(A::AbstractQuantumObject{DT,BraQuantumObject,<:Dimensions{N}}) where {DT,N} = A.dimensions.to -get_dimensions_from(A::AbstractQuantumObject{DT,OperatorQuantumObject,<:Dimensions{N}}) where {DT,N} = A.dimensions.to -get_dimensions_from(A::AbstractQuantumObject{DT,OperatorQuantumObject,<:GeneralDimensions{N}}) where {DT,N} = +get_dimensions_from(A::AbstractQuantumObject{KetQuantumObject,<:Dimensions{N}}) where {N} = space_one_list(N) +get_dimensions_from(A::AbstractQuantumObject{BraQuantumObject,<:Dimensions{N}}) where {N} = A.dimensions.to +get_dimensions_from(A::AbstractQuantumObject{OperatorQuantumObject,<:Dimensions{N}}) where {N} = A.dimensions.to +get_dimensions_from(A::AbstractQuantumObject{OperatorQuantumObject,<:GeneralDimensions{N}}) where {N} = A.dimensions.from get_dimensions_from( - A::AbstractQuantumObject{DT,ObjType,<:Dimensions{N}}, -) where {DT,ObjType<:Union{SuperOperatorQuantumObject,OperatorBraQuantumObject,OperatorKetQuantumObject},N} = + A::AbstractQuantumObject{ObjType,<:Dimensions{N}}, +) where {ObjType<:Union{SuperOperatorQuantumObject,OperatorBraQuantumObject,OperatorKetQuantumObject},N} = A.dimensions.to # functions for getting Float or Complex element type diff --git a/src/qobj/quantum_object_evo.jl b/src/qobj/quantum_object_evo.jl index f055c61ae..5cd4d828b 100644 --- a/src/qobj/quantum_object_evo.jl +++ b/src/qobj/quantum_object_evo.jl @@ -5,7 +5,7 @@ This file defines the QuantumObjectEvolution (QobjEvo) structure. export QuantumObjectEvolution @doc raw""" - struct QuantumObjectEvolution{DataType<:AbstractSciMLOperator,ObjType<:QuantumObjectType,DimType<:AbstractDimensions} <: AbstractQuantumObject{DataType,ObjType,DimType} + struct QuantumObjectEvolution{ObjType<:QuantumObjectType,DimType<:AbstractDimensions,DataType<:AbstractSciMLOperator} <: AbstractQuantumObject{ObjType,DimType,DataType} data::DataType type::ObjType dimensions::DimType @@ -109,10 +109,10 @@ Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=fal ``` """ struct QuantumObjectEvolution{ - DataType<:AbstractSciMLOperator, ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, DimType<:AbstractDimensions, -} <: AbstractQuantumObject{DataType,ObjType,DimType} + DataType<:AbstractSciMLOperator, +} <: AbstractQuantumObject{ObjType,DimType,DataType} data::DataType type::ObjType dimensions::DimType @@ -130,7 +130,7 @@ struct QuantumObjectEvolution{ _size = _get_size(data) _check_QuantumObject(type, dimensions, _size[1], _size[2]) - return new{DT,ObjType,typeof(dimensions)}(data, type, dimensions) + return new{ObjType,typeof(dimensions),DT}(data, type, dimensions) end end @@ -503,11 +503,11 @@ true ``` """ function (A::QuantumObjectEvolution)( - ψout::QuantumObject{DT1,QobjType}, - ψin::QuantumObject{DT2,QobjType}, + ψout::QuantumObject{QobjType}, + ψin::QuantumObject{QobjType}, p, t, -) where {DT1,DT2,QobjType<:Union{KetQuantumObject,OperatorKetQuantumObject}} +) where {QobjType<:Union{KetQuantumObject,OperatorKetQuantumObject}} check_dimensions(A, ψout, ψin) if isoper(A) && isoperket(ψin) @@ -531,10 +531,10 @@ end Apply the time-dependent [`QuantumObjectEvolution`](@ref) object `A` to the input state `ψ` at time `t` with parameters `p`. Out-of-place version of [`(A::QuantumObjectEvolution)(ψout, ψin, p, t)`](@ref). The output state is stored in a new [`QuantumObject`](@ref) object. This function mimics the behavior of a `AbstractSciMLOperator` object. """ function (A::QuantumObjectEvolution)( - ψ::QuantumObject{DT,QobjType}, + ψ::QuantumObject{QobjType}, p, t, -) where {DT,QobjType<:Union{KetQuantumObject,OperatorKetQuantumObject}} +) where {QobjType<:Union{KetQuantumObject,OperatorKetQuantumObject}} ψout = QuantumObject(similar(ψ.data), ψ.type, ψ.dimensions) return A(ψout, ψ, p, t) end diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index 85c942bd9..7fe381478 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -77,7 +77,7 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr See also [`spost`](@ref) and [`sprepost`](@ref). """ -spre(A::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(A, 1))) where {DT} = +spre(A::AbstractQuantumObject{OperatorQuantumObject}, Id_cache = I(size(A, 1))) = get_typename_wrapper(A)(_spre(A.data, Id_cache), SuperOperator, A.dimensions) @doc raw""" @@ -96,7 +96,7 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr See also [`spre`](@ref) and [`sprepost`](@ref). """ -spost(B::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(B, 1))) where {DT} = +spost(B::AbstractQuantumObject{OperatorQuantumObject}, Id_cache = I(size(B, 1))) = get_typename_wrapper(B)(_spost(B.data, Id_cache), SuperOperator, B.dimensions) @doc raw""" @@ -113,10 +113,7 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r See also [`spre`](@ref) and [`spost`](@ref). """ -function sprepost( - A::AbstractQuantumObject{DT1,OperatorQuantumObject}, - B::AbstractQuantumObject{DT2,OperatorQuantumObject}, -) where {DT1,DT2} +function sprepost(A::AbstractQuantumObject{OperatorQuantumObject}, B::AbstractQuantumObject{OperatorQuantumObject}) check_dimensions(A, B) return promote_op_type(A, B)(_sprepost(A.data, B.data), SuperOperator, A.dimensions) end @@ -135,11 +132,11 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr See also [`spre`](@ref), [`spost`](@ref), and [`sprepost`](@ref). """ -lindblad_dissipator(O::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache = I(size(O, 1))) where {DT} = +lindblad_dissipator(O::AbstractQuantumObject{OperatorQuantumObject}, Id_cache = I(size(O, 1))) = get_typename_wrapper(O)(_lindblad_dissipator(O.data, Id_cache), SuperOperator, O.dimensions) # It is already a SuperOperator -lindblad_dissipator(O::AbstractQuantumObject{DT,SuperOperatorQuantumObject}, Id_cache = nothing) where {DT} = O +lindblad_dissipator(O::AbstractQuantumObject{SuperOperatorQuantumObject}, Id_cache = nothing) = O @doc raw""" liouvillian(H::AbstractQuantumObject, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing, Id_cache=I(prod(H.dimensions))) @@ -161,10 +158,10 @@ The optional argument `Id_cache` can be used to pass a precomputed identity matr See also [`spre`](@ref), [`spost`](@ref), and [`lindblad_dissipator`](@ref). """ function liouvillian( - H::AbstractQuantumObject{DT,OpType}, + H::AbstractQuantumObject{OpType}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing, Id_cache = I(prod(H.dimensions)), -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} L = liouvillian(H, Id_cache) if !(c_ops isa Nothing) # sum all the (time-independent) c_ops first @@ -182,7 +179,7 @@ function liouvillian( return L end -liouvillian(H::AbstractQuantumObject{DT,OperatorQuantumObject}, Id_cache::Diagonal = I(prod(H.dimensions))) where {DT} = +liouvillian(H::AbstractQuantumObject{OperatorQuantumObject}, Id_cache::Diagonal = I(prod(H.dimensions))) = get_typename_wrapper(H)(_liouvillian(H.data, Id_cache), SuperOperator, H.dimensions) -liouvillian(H::AbstractQuantumObject{DT,SuperOperatorQuantumObject}, Id_cache::Diagonal) where {DT} = H +liouvillian(H::AbstractQuantumObject{SuperOperatorQuantumObject}, Id_cache::Diagonal) = H diff --git a/src/qobj/synonyms.jl b/src/qobj/synonyms.jl index 7f00dbc13..aa5f72f26 100644 --- a/src/qobj/synonyms.jl +++ b/src/qobj/synonyms.jl @@ -59,7 +59,7 @@ Matrix square root of [`Operator`](@ref) type of [`QuantumObject`](@ref) Note that for other types of [`QuantumObject`](@ref) use `sprt(A)` instead. """ -sqrtm(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = sqrt(A) +sqrtm(A::QuantumObject{OperatorQuantumObject}) = sqrt(A) @doc raw""" logm(A::QuantumObject) @@ -68,9 +68,7 @@ Matrix logarithm of [`QuantumObject`](@ref) Note that this function is same as `log(A)` and only supports for [`Operator`](@ref) and [`SuperOperator`](@ref). """ -logm( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = log(A) +logm(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = log(A) @doc raw""" expm(A::QuantumObject) @@ -79,9 +77,7 @@ Matrix exponential of [`QuantumObject`](@ref) Note that this function is same as `exp(A)` and only supports for [`Operator`](@ref) and [`SuperOperator`](@ref). """ -expm( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = exp(A) +expm(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = exp(A) @doc raw""" sinm(A::QuantumObject) @@ -92,9 +88,7 @@ Matrix sine of [`QuantumObject`](@ref), defined as Note that this function is same as `sin(A)` and only supports for [`Operator`](@ref) and [`SuperOperator`](@ref). """ -sinm( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = sin(A) +sinm(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = sin(A) @doc raw""" cosm(A::QuantumObject) @@ -105,6 +99,4 @@ Matrix cosine of [`QuantumObject`](@ref), defined as Note that this function is same as `cos(A)` and only supports for [`Operator`](@ref) and [`SuperOperator`](@ref). """ -cosm( - A::QuantumObject{<:AbstractMatrix{T},ObjType}, -) where {T,ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = cos(A) +cosm(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = cos(A) diff --git a/src/spectrum.jl b/src/spectrum.jl index af4d08b1a..77b690976 100644 --- a/src/spectrum.jl +++ b/src/spectrum.jl @@ -30,8 +30,8 @@ PseudoInverse(; alg::SciMLLinearSolveAlgorithm = KrylovJL_GMRES()) = PseudoInver spectrum(H::QuantumObject, ωlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple}, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}; + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}; solver::SpectrumSolver=ExponentialSeries(), kwargs...) @@ -46,14 +46,14 @@ See also the following list for `SpectrumSolver` docstrings: - [`PseudoInverse`](@ref) """ function spectrum( - H::QuantumObject{MT1,HOpType}, + H::QuantumObject{HOpType}, ωlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple}, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}; + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}; solver::SpectrumSolver = ExponentialSeries(), kwargs..., -) where {MT1<:AbstractMatrix,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} return _spectrum(liouvillian(H, c_ops), ωlist, A, B, solver; kwargs...) end @@ -77,13 +77,13 @@ function _spectrum_get_rates_vecs_ss(L, solver::ExponentialSeries{T,false}) wher end function _spectrum( - L::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, + L::QuantumObject{SuperOperatorQuantumObject}, ωlist::AbstractVector, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, solver::ExponentialSeries; kwargs..., -) where {T1,T2,T3} +) check_dimensions(L, A, B) rates, vecs, ρss = _spectrum_get_rates_vecs_ss(L, solver) @@ -103,13 +103,13 @@ function _spectrum( end function _spectrum( - L::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, + L::QuantumObject{SuperOperatorQuantumObject}, ωlist::AbstractVector, - A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, + A::QuantumObject{OperatorQuantumObject}, + B::QuantumObject{OperatorQuantumObject}, solver::PseudoInverse; kwargs..., -) where {T1,T2,T3} +) check_dimensions(L, A, B) ωList = convert(Vector{_FType(L)}, ωlist) # Convert it to support GPUs and avoid type instabilities diff --git a/src/steadystate.jl b/src/steadystate.jl index 43b23a2c3..a88ef8bf5 100644 --- a/src/steadystate.jl +++ b/src/steadystate.jl @@ -65,7 +65,7 @@ end @doc raw""" steadystate( - H::QuantumObject{DT,OpType}, + H::QuantumObject{OpType}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; solver::SteadyStateSolver = SteadyStateDirectSolver(), kwargs..., @@ -80,21 +80,17 @@ Solve the stationary state based on different solvers. - `kwargs`: The keyword arguments for the solver. """ function steadystate( - H::QuantumObject{DT,OpType}, + H::QuantumObject{OpType}, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; solver::SteadyStateSolver = SteadyStateDirectSolver(), kwargs..., -) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} L = liouvillian(H, c_ops) return _steadystate(L, solver; kwargs...) end -function _steadystate( - L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, - solver::SteadyStateLinearSolver; - kwargs..., -) where {T} +function _steadystate(L::QuantumObject{SuperOperatorQuantumObject}, solver::SteadyStateLinearSolver; kwargs...) L_tmp = L.data N = prod(L.dimensions) weight = norm(L_tmp, 1) / length(L_tmp) @@ -129,11 +125,7 @@ function _steadystate( return QuantumObject(ρss, Operator, L.dimensions) end -function _steadystate( - L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, - solver::SteadyStateEigenSolver; - kwargs..., -) where {T} +function _steadystate(L::QuantumObject{SuperOperatorQuantumObject}, solver::SteadyStateEigenSolver; kwargs...) N = prod(L.dimensions) kwargs = merge((sigma = 1e-8, k = 1), (; kwargs...)) @@ -145,10 +137,7 @@ function _steadystate( return QuantumObject(ρss, Operator, L.dimensions) end -function _steadystate( - L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, - solver::SteadyStateDirectSolver, -) where {T} +function _steadystate(L::QuantumObject{SuperOperatorQuantumObject}, solver::SteadyStateDirectSolver) L_tmp = L.data N = prod(L.dimensions) weight = norm(L_tmp, 1) / length(L_tmp) @@ -173,11 +162,7 @@ function _steadystate( return QuantumObject(ρss, Operator, L.dimensions) end -_steadystate( - L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, - solver::SteadyStateODESolver; - kwargs..., -) where {T} = throw( +_steadystate(L::QuantumObject{SuperOperatorQuantumObject}, solver::SteadyStateODESolver; kwargs...) = throw( ArgumentError( "The initial state ψ0 is required for SteadyStateODESolver, use the following call instead: `steadystate(H, ψ0, tmax, c_ops)`.", ), @@ -185,8 +170,8 @@ _steadystate( @doc raw""" steadystate( - H::QuantumObject{DT1,HOpType}, - ψ0::QuantumObject{DT2,StateOpType}, + H::QuantumObject{HOpType}, + ψ0::QuantumObject{StateOpType}, tmax::Real = Inf, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; solver::SteadyStateODESolver = SteadyStateODESolver(), @@ -220,8 +205,8 @@ or - `kwargs`: The keyword arguments for the ODEProblem. """ function steadystate( - H::QuantumObject{DT1,HOpType}, - ψ0::QuantumObject{DT2,StateOpType}, + H::QuantumObject{HOpType}, + ψ0::QuantumObject{StateOpType}, tmax::Real = Inf, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; solver::SteadyStateODESolver = SteadyStateODESolver(), @@ -229,8 +214,6 @@ function steadystate( abstol::Real = 1.0e-10, kwargs..., ) where { - DT1, - DT2, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } @@ -265,9 +248,9 @@ end @doc raw""" steadystate_floquet( - H_0::QuantumObject{MT,OpType1}, - H_p::QuantumObject{<:AbstractArray,OpType2}, - H_m::QuantumObject{<:AbstractArray,OpType3}, + H_0::QuantumObject{OpType1}, + H_p::QuantumObject{OpType2}, + H_m::QuantumObject{OpType3}, ωd::Number, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; n_max::Integer = 2, @@ -343,9 +326,9 @@ In the case of `SSFloquetEffectiveLiouvillian`, instead, the effective Liouvilli - `kwargs...`: Additional keyword arguments to be passed to the solver. """ function steadystate_floquet( - H_0::QuantumObject{MT,OpType1}, - H_p::QuantumObject{<:AbstractArray,OpType2}, - H_m::QuantumObject{<:AbstractArray,OpType3}, + H_0::QuantumObject{OpType1}, + H_p::QuantumObject{OpType2}, + H_m::QuantumObject{OpType3}, ωd::Number, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; n_max::Integer = 2, @@ -353,7 +336,6 @@ function steadystate_floquet( solver::FSolver = SSFloquetLinearSystem(), kwargs..., ) where { - MT<:AbstractArray, OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, @@ -367,15 +349,18 @@ function steadystate_floquet( end function _steadystate_floquet( - L_0::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, - L_p::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, - L_m::QuantumObject{<:AbstractArray{T3},SuperOperatorQuantumObject}, + L_0::QuantumObject{SuperOperatorQuantumObject}, + L_p::QuantumObject{SuperOperatorQuantumObject}, + L_m::QuantumObject{SuperOperatorQuantumObject}, ωd::Number, solver::SSFloquetLinearSystem; n_max::Integer = 1, tol::R = 1e-8, kwargs..., -) where {T1,T2,T3,R<:Real} +) where {R<:Real} + T1 = eltype(L_0) + T2 = eltype(L_p) + T3 = eltype(L_m) T = promote_type(T1, T2, T3) L_0_mat = get_data(L_0) @@ -425,9 +410,9 @@ function _steadystate_floquet( end function _steadystate_floquet( - L_0::QuantumObject{<:AbstractArray,SuperOperatorQuantumObject}, - L_p::QuantumObject{<:AbstractArray,SuperOperatorQuantumObject}, - L_m::QuantumObject{<:AbstractArray,SuperOperatorQuantumObject}, + L_0::QuantumObject{SuperOperatorQuantumObject}, + L_p::QuantumObject{SuperOperatorQuantumObject}, + L_m::QuantumObject{SuperOperatorQuantumObject}, ωd::Number, solver::SSFloquetEffectiveLiouvillian; n_max::Integer = 1, diff --git a/src/time_evolution/lr_mesolve.jl b/src/time_evolution/lr_mesolve.jl index f8a62cb8f..bddcc40bf 100644 --- a/src/time_evolution/lr_mesolve.jl +++ b/src/time_evolution/lr_mesolve.jl @@ -366,9 +366,9 @@ get_B(u::AbstractArray{T}, N::Integer, M::Integer) where {T} = reshape(view(u, ( @doc raw""" lr_mesolveProblem( - H::QuantumObject{DT1,OperatorQuantumObject}, - z::AbstractArray{T2,2}, - B::AbstractArray{T2,2}, + H::QuantumObject{OperatorQuantumObject}, + z::AbstractArray{T,2}, + B::AbstractArray{T,2}, tlist::AbstractVector, c_ops::Union{AbstractVector,Tuple}=(); e_ops::Union{AbstractVector,Tuple}=(), @@ -391,16 +391,16 @@ Formulates the ODEproblem for the low-rank time evolution of the system. The fun - `kwargs`: Additional keyword arguments. """ function lr_mesolveProblem( - H::QuantumObject{DT1,OperatorQuantumObject}, - z::AbstractArray{T2,2}, - B::AbstractArray{T2,2}, + H::QuantumObject{OperatorQuantumObject}, + z::AbstractArray{T,2}, + B::AbstractArray{T,2}, tlist::AbstractVector, c_ops::Union{AbstractVector,Tuple} = (); e_ops::Union{AbstractVector,Tuple} = (), f_ops::Union{AbstractVector,Tuple} = (), opt::NamedTuple = lr_mesolve_options_default, kwargs..., -) where {DT1,T2} +) where {T} Hdims = H.dimensions # Formulation of problem @@ -497,9 +497,9 @@ end @doc raw""" lr_mesolve( - H::QuantumObject{DT1,OperatorQuantumObject}, - z::AbstractArray{T2,2}, - B::AbstractArray{T2,2}, + H::QuantumObject{OperatorQuantumObject}, + z::AbstractArray{T,2}, + B::AbstractArray{T,2}, tlist::AbstractVector, c_ops::Union{AbstractVector,Tuple}=(); e_ops::Union{AbstractVector,Tuple}=(), @@ -522,7 +522,7 @@ Time evolution of an open quantum system using the low-rank master equation. For - `kwargs`: Additional keyword arguments. """ function lr_mesolve( - H::QuantumObject{DT1,OperatorQuantumObject}, + H::QuantumObject{OperatorQuantumObject}, z::AbstractArray{T2,2}, B::AbstractArray{T2,2}, tlist::AbstractVector, @@ -531,7 +531,7 @@ function lr_mesolve( f_ops::Union{AbstractVector,Tuple} = (), opt::NamedTuple = lr_mesolve_options_default, kwargs..., -) where {DT1,T2} +) where {T2} prob = lr_mesolveProblem(H, z, B, tlist, c_ops; e_ops = e_ops, f_ops = f_ops, opt = opt, kwargs...) return lr_mesolve(prob; kwargs...) end diff --git a/src/time_evolution/mcsolve.jl b/src/time_evolution/mcsolve.jl index 99b5d3fad..de37de3d1 100644 --- a/src/time_evolution/mcsolve.jl +++ b/src/time_evolution/mcsolve.jl @@ -82,8 +82,8 @@ end @doc raw""" mcsolveProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -151,8 +151,8 @@ If the environmental measurements register a quantum jump, the wave function und - `prob`: The [`TimeEvolutionProblem`](@ref) containing the `ODEProblem` for the Monte Carlo wave function time evolution. """ function mcsolveProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -160,7 +160,7 @@ function mcsolveProblem( rng::AbstractRNG = default_rng(), jump_callback::TJC = ContinuousLindbladJumpCallback(), kwargs..., -) where {DT1,DT2,TJC<:LindbladJumpCallbackType} +) where {TJC<:LindbladJumpCallbackType} haskey(kwargs, :save_idxs) && throw(ArgumentError("The keyword argument \"save_idxs\" is not supported in QuantumToolbox.")) @@ -186,8 +186,8 @@ end @doc raw""" mcsolveEnsembleProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -265,8 +265,8 @@ If the environmental measurements register a quantum jump, the wave function und - `prob`: The [`TimeEvolutionProblem`](@ref) containing the Ensemble `ODEProblem` for the Monte Carlo wave function time evolution. """ function mcsolveEnsembleProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -279,7 +279,7 @@ function mcsolveEnsembleProblem( prob_func::Union{Function,Nothing} = nothing, output_func::Union{Tuple,Nothing} = nothing, kwargs..., -) where {DT1,DT2,TJC<:LindbladJumpCallbackType} +) where {TJC<:LindbladJumpCallbackType} _prob_func = prob_func isa Nothing ? _mcsolve_dispatch_prob_func(rng, ntraj, tlist) : prob_func _output_func = output_func isa Nothing ? _mcsolve_dispatch_output_func(ensemble_method, progress_bar, ntraj) : output_func @@ -308,8 +308,8 @@ end @doc raw""" mcsolve( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::OrdinaryDiffEqAlgorithm = Tsit5(), @@ -393,8 +393,8 @@ If the environmental measurements register a quantum jump, the wave function und - `sol::TimeEvolutionMCSol`: The solution of the time evolution. See also [`TimeEvolutionMCSol`](@ref). """ function mcsolve( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::OrdinaryDiffEqAlgorithm = Tsit5(), @@ -409,7 +409,7 @@ function mcsolve( output_func::Union{Tuple,Nothing} = nothing, normalize_states::Union{Val,Bool} = Val(true), kwargs..., -) where {DT1,DT2,TJC<:LindbladJumpCallbackType} +) where {TJC<:LindbladJumpCallbackType} ens_prob_mc = mcsolveEnsembleProblem( H, ψ0, diff --git a/src/time_evolution/mesolve.jl b/src/time_evolution/mesolve.jl index d119785b3..b7eb62886 100644 --- a/src/time_evolution/mesolve.jl +++ b/src/time_evolution/mesolve.jl @@ -5,8 +5,8 @@ _mesolve_make_L_QobjEvo(H::Union{QuantumObjectEvolution,Tuple}, c_ops) = liouvil @doc raw""" mesolveProblem( - H::Union{AbstractQuantumObject{DT1,HOpType},Tuple}, - ψ0::QuantumObject{DT2,StateOpType}, + H::Union{AbstractQuantumObject{HOpType},Tuple}, + ψ0::QuantumObject{StateOpType}, tlist, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -52,8 +52,8 @@ where - `prob::ODEProblem`: The ODEProblem for the master equation time evolution. """ function mesolveProblem( - H::Union{AbstractQuantumObject{DT1,HOpType},Tuple}, - ψ0::QuantumObject{DT2,StateOpType}, + H::Union{AbstractQuantumObject{HOpType},Tuple}, + ψ0::QuantumObject{StateOpType}, tlist, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -62,8 +62,6 @@ function mesolveProblem( inplace::Union{Val,Bool} = Val(true), kwargs..., ) where { - DT1, - DT2, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } @@ -94,8 +92,8 @@ end @doc raw""" mesolve( - H::Union{AbstractQuantumObject{DT1,HOpType},Tuple}, - ψ0::QuantumObject{DT2,StateOpType}, + H::Union{AbstractQuantumObject{HOpType},Tuple}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::OrdinaryDiffEqAlgorithm = Tsit5(), @@ -144,8 +142,8 @@ where - `sol::TimeEvolutionSol`: The solution of the time evolution. See also [`TimeEvolutionSol`](@ref) """ function mesolve( - H::Union{AbstractQuantumObject{DT1,HOpType},Tuple}, - ψ0::QuantumObject{DT2,StateOpType}, + H::Union{AbstractQuantumObject{HOpType},Tuple}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::OrdinaryDiffEqAlgorithm = Tsit5(), @@ -155,8 +153,6 @@ function mesolve( inplace::Union{Val,Bool} = Val(true), kwargs..., ) where { - DT1, - DT2, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, } diff --git a/src/time_evolution/sesolve.jl b/src/time_evolution/sesolve.jl index 341a2cc55..b76613f88 100644 --- a/src/time_evolution/sesolve.jl +++ b/src/time_evolution/sesolve.jl @@ -1,14 +1,15 @@ export sesolveProblem, sesolve -_sesolve_make_U_QobjEvo(H::QuantumObjectEvolution{<:MatrixOperator}) = - QobjEvo(MatrixOperator(-1im * H.data.A), dims = H.dimensions, type = Operator) +_sesolve_make_U_QobjEvo( + H::QuantumObjectEvolution{OperatorQuantumObject,DimsType,<:MatrixOperator}, +) where {DimsType<:AbstractDimensions} = QobjEvo(MatrixOperator(-1im * H.data.A), dims = H.dimensions, type = Operator) _sesolve_make_U_QobjEvo(H::QuantumObject) = QobjEvo(MatrixOperator(-1im * H.data), dims = H.dimensions, type = Operator) _sesolve_make_U_QobjEvo(H::Union{QuantumObjectEvolution,Tuple}) = QobjEvo(H, -1im) @doc raw""" sesolveProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, params = NullParameters(), @@ -46,15 +47,15 @@ Generate the ODEProblem for the Schrödinger time evolution of a quantum system: - `prob`: The [`TimeEvolutionProblem`](@ref) containing the `ODEProblem` for the Schrödinger time evolution of the system. """ function sesolveProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, params = NullParameters(), progress_bar::Union{Val,Bool} = Val(true), inplace::Union{Val,Bool} = Val(true), kwargs..., -) where {DT1,DT2} +) haskey(kwargs, :save_idxs) && throw(ArgumentError("The keyword argument \"save_idxs\" is not supported in QuantumToolbox.")) @@ -83,8 +84,8 @@ end @doc raw""" sesolve( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector; alg::OrdinaryDiffEqAlgorithm = Tsit5(), e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -125,8 +126,8 @@ Time evolution of a closed quantum system using the Schrödinger equation: - `sol::TimeEvolutionSol`: The solution of the time evolution. See also [`TimeEvolutionSol`](@ref) """ function sesolve( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector; alg::OrdinaryDiffEqAlgorithm = Tsit5(), e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -134,7 +135,7 @@ function sesolve( progress_bar::Union{Val,Bool} = Val(true), inplace::Union{Val,Bool} = Val(true), kwargs..., -) where {DT1,DT2} +) prob = sesolveProblem( H, ψ0, diff --git a/src/time_evolution/ssesolve.jl b/src/time_evolution/ssesolve.jl index cdd2de9bb..d0cee3721 100644 --- a/src/time_evolution/ssesolve.jl +++ b/src/time_evolution/ssesolve.jl @@ -90,8 +90,8 @@ _ScalarOperator_e2_2(op, f = +) = @doc raw""" ssesolveProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -146,8 +146,8 @@ Above, `C_n` is the `n`-th collapse operator and `dW_j(t)` is the real Wiener in - `prob`: The `SDEProblem` for the Stochastic Schrödinger time evolution of the system. """ function ssesolveProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -155,7 +155,7 @@ function ssesolveProblem( rng::AbstractRNG = default_rng(), progress_bar::Union{Val,Bool} = Val(true), kwargs..., -) where {DT1,DT2} +) haskey(kwargs, :save_idxs) && throw(ArgumentError("The keyword argument \"save_idxs\" is not supported in QuantumToolbox.")) @@ -204,8 +204,8 @@ end @doc raw""" ssesolveEnsembleProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -269,8 +269,8 @@ Above, `C_n` is the `n`-th collapse operator and `dW_j(t)` is the real Wiener i - `prob::EnsembleProblem with SDEProblem`: The Ensemble SDEProblem for the Stochastic Shrödinger time evolution. """ function ssesolveEnsembleProblem( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing; e_ops::Union{Nothing,AbstractVector,Tuple} = nothing, @@ -282,7 +282,7 @@ function ssesolveEnsembleProblem( output_func::Function = _ssesolve_dispatch_output_func(ensemble_method), progress_bar::Union{Val,Bool} = Val(true), kwargs..., -) where {DT1,DT2} +) progr = ProgressBar(ntraj, enable = getVal(progress_bar)) if ensemble_method isa EnsembleDistributed progr_channel::RemoteChannel{Channel{Bool}} = RemoteChannel(() -> Channel{Bool}(1)) @@ -324,8 +324,8 @@ end @doc raw""" ssesolve( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::StochasticDiffEqAlgorithm = SRA1(), @@ -394,8 +394,8 @@ Above, `C_n` is the `n`-th collapse operator and `dW_j(t)` is the real Wiener in - `sol::TimeEvolutionSSESol`: The solution of the time evolution. See also [`TimeEvolutionSSESol`](@ref). """ function ssesolve( - H::Union{AbstractQuantumObject{DT1,OperatorQuantumObject},Tuple}, - ψ0::QuantumObject{DT2,KetQuantumObject}, + H::Union{AbstractQuantumObject{OperatorQuantumObject},Tuple}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing; alg::StochasticDiffEqAlgorithm = SRA1(), @@ -408,7 +408,7 @@ function ssesolve( output_func::Function = _ssesolve_dispatch_output_func(ensemble_method), progress_bar::Union{Val,Bool} = Val(true), kwargs..., -) where {DT1,DT2} +) ens_prob = ssesolveEnsembleProblem( H, ψ0, diff --git a/src/time_evolution/time_evolution.jl b/src/time_evolution/time_evolution.jl index ec429b1d1..75f385e34 100644 --- a/src/time_evolution/time_evolution.jl +++ b/src/time_evolution/time_evolution.jl @@ -215,29 +215,26 @@ ContinuousLindbladJumpCallback(; interp_points::Int = 10) = ContinuousLindbladJu ####################################### function liouvillian_floquet( - L₀::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, - Lₚ::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, - Lₘ::QuantumObject{<:AbstractArray{T3},SuperOperatorQuantumObject}, + L₀::QuantumObject{SuperOperatorQuantumObject}, + Lₚ::QuantumObject{SuperOperatorQuantumObject}, + Lₘ::QuantumObject{SuperOperatorQuantumObject}, ω::Real; n_max::Int = 3, tol::Real = 1e-15, -) where {T1,T2,T3} +) check_dimensions(L₀, Lₚ, Lₘ) return _liouvillian_floquet(L₀, Lₚ, Lₘ, ω, n_max, tol) end function liouvillian_floquet( - H::QuantumObject{<:AbstractArray{T1},OpType1}, - Hₚ::QuantumObject{<:AbstractArray{T2},OpType2}, - Hₘ::QuantumObject{<:AbstractArray{T3},OpType3}, + H::QuantumObject{OpType1}, + Hₚ::QuantumObject{OpType2}, + Hₘ::QuantumObject{OpType3}, ω::Real, c_ops::Union{Nothing,AbstractVector,Tuple} = nothing; n_max::Int = 3, tol::Real = 1e-15, ) where { - T1, - T2, - T3, OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, @@ -254,13 +251,13 @@ Constructs the generalized Liouvillian for a system coupled to a bath of harmoni See, e.g., Settineri, Alessio, et al. "Dissipation and thermal noise in hybrid quantum systems in the ultrastrong-coupling regime." Physical Review A 98.5 (2018): 053834. """ function liouvillian_generalized( - H::QuantumObject{MT,OperatorQuantumObject}, + H::QuantumObject{OperatorQuantumObject}, fields::Vector, T_list::Vector{<:Real}; N_trunc::Union{Int,Nothing} = nothing, tol::Real = 1e-12, σ_filter::Union{Nothing,Real} = nothing, -) where {MT<:AbstractMatrix} +) (length(fields) == length(T_list)) || throw(DimensionMismatch("The number of fields, ωs and Ts must be the same.")) dims = (N_trunc isa Nothing) ? H.dimensions : SVector(N_trunc) @@ -317,13 +314,13 @@ function liouvillian_generalized( end function _liouvillian_floquet( - L₀::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, - Lₚ::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, - Lₘ::QuantumObject{<:AbstractArray{T3},SuperOperatorQuantumObject}, + L₀::QuantumObject{SuperOperatorQuantumObject}, + Lₚ::QuantumObject{SuperOperatorQuantumObject}, + Lₘ::QuantumObject{SuperOperatorQuantumObject}, ω::Real, n_max::Int, tol::Real, -) where {T1,T2,T3} +) L_0 = L₀.data L_p = Lₚ.data L_m = Lₘ.data diff --git a/src/time_evolution/time_evolution_dynamical.jl b/src/time_evolution/time_evolution_dynamical.jl index 81cf3260d..a548a1f4d 100644 --- a/src/time_evolution/time_evolution_dynamical.jl +++ b/src/time_evolution/time_evolution_dynamical.jl @@ -139,16 +139,16 @@ end function dfd_mesolveProblem( H::Function, - ψ0::QuantumObject{DT1,StateOpType}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, c_ops::Function, maxdims::Vector{T2}, dfd_params::NamedTuple = NamedTuple(); - e_ops::Function = (dim_list) -> Vector{Vector{DT1}}([]), + e_ops::Function = (dim_list) -> Vector{Vector{eltype(ψ0)}}([]), params::NamedTuple = NamedTuple(), tol_list::Vector{<:Number} = fill(1e-8, length(maxdims)), kwargs..., -) where {DT1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} +) where {T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} length(ψ0.dimensions) != length(maxdims) && throw(DimensionMismatch("'dim_list' and 'maxdims' do not have the same dimension.")) @@ -209,17 +209,17 @@ Time evolution of an open quantum system using master equation, dynamically chan """ function dfd_mesolve( H::Function, - ψ0::QuantumObject{<:AbstractArray{T1},StateOpType}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, c_ops::Function, maxdims::Vector{T2}, dfd_params::NamedTuple = NamedTuple(); alg::OrdinaryDiffEqAlgorithm = Tsit5(), - e_ops::Function = (dim_list) -> Vector{Vector{T1}}([]), + e_ops::Function = (dim_list) -> Vector{Vector{eltype(ψ0)}}([]), params::NamedTuple = NamedTuple(), tol_list::Vector{<:Number} = fill(1e-8, length(maxdims)), kwargs..., -) where {T1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} +) where {T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} dfd_prob = dfd_mesolveProblem( H, ψ0, @@ -341,7 +341,7 @@ end function dsf_mesolveProblem( H::Function, - ψ0::QuantumObject{<:AbstractVector{T},StateOpType}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, c_ops::Function, op_list::Union{AbstractVector,Tuple}, @@ -352,12 +352,14 @@ function dsf_mesolveProblem( δα_list::Vector{<:Real} = fill(0.2, length(op_list)), krylov_dim::Int = max(6, min(10, cld(length(ket2dm(ψ0).data), 4))), kwargs..., -) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} +) where {StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} op_list = deepcopy(op_list) H₀ = H(op_list .+ α0_l, dsf_params) c_ops₀ = c_ops(op_list .+ α0_l, dsf_params) e_ops₀ = e_ops(op_list .+ α0_l, dsf_params) + T = eltype(ψ0) + αt_list = convert(Vector{T}, α0_l) op_l_vec = map(op -> mat2vec(get_data(op)'), op_list) # Create the Krylov subspace with kron(H₀.data, H₀.data) just for initialize @@ -421,7 +423,7 @@ Time evolution of an open quantum system using master equation and the Dynamical """ function dsf_mesolve( H::Function, - ψ0::QuantumObject{<:AbstractVector{T},StateOpType}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, c_ops::Function, op_list::Union{AbstractVector,Tuple}, @@ -433,7 +435,7 @@ function dsf_mesolve( δα_list::Vector{<:Real} = fill(0.2, length(op_list)), krylov_dim::Int = max(6, min(10, cld(length(ket2dm(ψ0).data), 4))), kwargs..., -) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} +) where {StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} dsf_prob = dsf_mesolveProblem( H, ψ0, @@ -454,7 +456,7 @@ end function dsf_mesolve( H::Function, - ψ0::QuantumObject{<:AbstractVector{T},StateOpType}, + ψ0::QuantumObject{StateOpType}, tlist::AbstractVector, op_list::Union{AbstractVector,Tuple}, α0_l::Vector{<:Number} = zeros(length(op_list)), @@ -465,7 +467,7 @@ function dsf_mesolve( δα_list::Vector{<:Real} = fill(0.2, length(op_list)), krylov_dim::Int = max(6, min(10, cld(length(ket2dm(ψ0).data), 4))), kwargs..., -) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} +) where {StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} c_ops = op_list -> () return dsf_mesolve( H, @@ -599,7 +601,7 @@ end function dsf_mcsolveEnsembleProblem( H::Function, - ψ0::QuantumObject{<:AbstractVector{T},KetQuantumObject}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Function, op_list::Union{AbstractVector,Tuple}, @@ -614,12 +616,14 @@ function dsf_mcsolveEnsembleProblem( krylov_dim::Int = min(5, cld(length(ψ0.data), 3)), progress_bar::Union{Bool,Val} = Val(true), kwargs..., -) where {T,TJC<:LindbladJumpCallbackType} +) where {TJC<:LindbladJumpCallbackType} op_list = deepcopy(op_list) H₀ = H(op_list .+ α0_l, dsf_params) c_ops₀ = c_ops(op_list .+ α0_l, dsf_params) e_ops₀ = e_ops(op_list .+ α0_l, dsf_params) + T = eltype(ψ0) + αt_list = convert(Vector{T}, α0_l) expv_cache = arnoldi(H₀.data, ψ0.data, krylov_dim) @@ -692,7 +696,7 @@ Time evolution of a quantum system using the Monte Carlo wave function method an """ function dsf_mcsolve( H::Function, - ψ0::QuantumObject{<:AbstractVector{T},KetQuantumObject}, + ψ0::QuantumObject{KetQuantumObject}, tlist::AbstractVector, c_ops::Function, op_list::Union{AbstractVector,Tuple}, @@ -708,7 +712,7 @@ function dsf_mcsolve( krylov_dim::Int = min(5, cld(length(ψ0.data), 3)), progress_bar::Union{Bool,Val} = Val(true), kwargs..., -) where {T,TJC<:LindbladJumpCallbackType} +) where {TJC<:LindbladJumpCallbackType} ens_prob_mc = dsf_mcsolveEnsembleProblem( H, ψ0, diff --git a/src/visualization.jl b/src/visualization.jl index 92ca2f67e..bd21582a0 100644 --- a/src/visualization.jl +++ b/src/visualization.jl @@ -2,17 +2,17 @@ export plot_wigner @doc raw""" plot_wigner( - state::QuantumObject{DT,OpType}; + state::QuantumObject{OpType}; library::Union{Val,Symbol}=Val(:CairoMakie), kwargs... - ) where {DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject} + ) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject} Plot the [Wigner quasipropability distribution](https://en.wikipedia.org/wiki/Wigner_quasiprobability_distribution) of `state` using the [`wigner`](@ref) function. The `library` keyword argument specifies the plotting library to use, defaulting to [`CairoMakie`](https://github.com/MakieOrg/Makie.jl/tree/master/CairoMakie). # Arguments -- `state::QuantumObject{DT,OpType}`: The quantum state for which to plot the Wigner distribution. +- `state::QuantumObject`: The quantum state for which to plot the Wigner distribution. - `library::Union{Val,Symbol}`: The plotting library to use. Default is `Val(:CairoMakie)`. - `kwargs...`: Additional keyword arguments to pass to the plotting function. See the documentation for the specific plotting library for more information. @@ -23,15 +23,15 @@ The `library` keyword argument specifies the plotting library to use, defaulting If you want to keep type stability, it is recommended to use `Val(:CairoMakie)` instead of `:CairoMakie` as the plotting library. See [this link](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and the [related Section](@ref doc:Type-Stability) about type stability for more details. """ plot_wigner( - state::QuantumObject{DT,OpType}; + state::QuantumObject{OpType}; library::Union{Val,Symbol} = Val(:CairoMakie), kwargs..., -) where {DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} = +) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} = plot_wigner(makeVal(library), state; kwargs...) plot_wigner( ::Val{T}, - state::QuantumObject{DT,OpType}; + state::QuantumObject{OpType}; kwargs..., -) where {T,DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} = +) where {T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} = throw(ArgumentError("The specified plotting library $T is not available. Try running `using $T` first.")) diff --git a/src/wigner.jl b/src/wigner.jl index 9e3bdbe03..d85385c63 100644 --- a/src/wigner.jl +++ b/src/wigner.jl @@ -13,7 +13,7 @@ WignerLaguerre(; parallel = false, tol = 1e-14) = WignerLaguerre(parallel, tol) @doc raw""" wigner( - state::QuantumObject{DT,OpType}, + state::QuantumObject{OpType}, xvec::AbstractVector, yvec::AbstractVector; g::Real = √2, @@ -67,12 +67,12 @@ julia> wig = wigner(ρ, xvec, xvec, method=WignerLaguerre(parallel=true)); ``` """ function wigner( - state::QuantumObject{DT,OpType}, + state::QuantumObject{OpType}, xvec::AbstractVector, yvec::AbstractVector; g::Real = √2, method::WignerSolver = WignerClenshaw(), -) where {DT,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} +) where {OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} ρ = ket2dm(state).data return _wigner(ρ, xvec, yvec, g, method) diff --git a/test/core-test/low_rank_dynamics.jl b/test/core-test/low_rank_dynamics.jl index fc1d0769c..c7ce03c06 100644 --- a/test/core-test/low_rank_dynamics.jl +++ b/test/core-test/low_rank_dynamics.jl @@ -9,7 +9,7 @@ M = latt.N + 1 # Number of states in the LR basis # Define initial state - ϕ = Vector{QuantumObject{Vector{ComplexF64},KetQuantumObject,Dimensions{M - 1,NTuple{M - 1,Space}}}}(undef, M) + ϕ = Vector{QuantumObject{KetQuantumObject,Dimensions{M - 1,NTuple{M - 1,Space}},Vector{ComplexF64}}}(undef, M) ϕ[1] = kron(fill(basis(2, 1), N_modes)...) i = 1 diff --git a/test/core-test/quantum_objects.jl b/test/core-test/quantum_objects.jl index 91738bdc9..8761a57af 100644 --- a/test/core-test/quantum_objects.jl +++ b/test/core-test/quantum_objects.jl @@ -346,14 +346,14 @@ for T in [ComplexF32, ComplexF64] N = 4 a = rand(T, N) - @inferred QuantumObject{typeof(a),KetQuantumObject,Dimensions{1}} Qobj(a) + @inferred QuantumObject{KetQuantumObject,Dimensions{1},typeof(a)} Qobj(a) for type in [Ket, OperatorKet] @inferred Qobj(a, type = type) end UnionType = Union{ - QuantumObject{Matrix{T},BraQuantumObject,Dimensions{1,Tuple{Space}}}, - QuantumObject{Matrix{T},OperatorQuantumObject,Dimensions{1,Tuple{Space}}}, + QuantumObject{BraQuantumObject,Dimensions{1,Tuple{Space}},Matrix{T}}, + QuantumObject{OperatorQuantumObject,Dimensions{1,Tuple{Space}},Matrix{T}}, } a = rand(T, 1, N) @inferred UnionType Qobj(a) @@ -362,8 +362,8 @@ end UnionType2 = Union{ - QuantumObject{Matrix{T},OperatorQuantumObject,GeneralDimensions{1,Tuple{Space},Tuple{Space}}}, - QuantumObject{Matrix{T},OperatorQuantumObject,Dimensions{1,Tuple{Space}}}, + QuantumObject{OperatorQuantumObject,GeneralDimensions{1,Tuple{Space},Tuple{Space}},Matrix{T}}, + QuantumObject{OperatorQuantumObject,Dimensions{1,Tuple{Space}},Matrix{T}}, } a = rand(T, N, N) @inferred UnionType Qobj(a) diff --git a/test/core-test/quantum_objects_evo.jl b/test/core-test/quantum_objects_evo.jl index 130bfb32a..fec8235c0 100644 --- a/test/core-test/quantum_objects_evo.jl +++ b/test/core-test/quantum_objects_evo.jl @@ -133,8 +133,8 @@ for T in [ComplexF32, ComplexF64] a = MatrixOperator(rand(T, N, N)) UnionType = Union{ - QuantumObjectEvolution{typeof(a),OperatorQuantumObject,GeneralDimensions{1,Tuple{Space},Tuple{Space}}}, - QuantumObjectEvolution{typeof(a),OperatorQuantumObject,Dimensions{1,Tuple{Space}}}, + QuantumObjectEvolution{OperatorQuantumObject,GeneralDimensions{1,Tuple{Space},Tuple{Space}},typeof(a)}, + QuantumObjectEvolution{OperatorQuantumObject,Dimensions{1,Tuple{Space}},typeof(a)}, } @inferred UnionType QobjEvo(a) @inferred UnionType QobjEvo(a, type = Operator)