Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/qutip/QuantumToolbox.jl/tree/main)

- Rename `sparse_to_dense` as `to_dense` and `dense_to_sparse` as `to_sparse`. ([#392])

## [v0.26.0]
Release date: 2025-02-09

Expand Down Expand Up @@ -115,3 +117,4 @@ Release date: 2024-11-13
[#386]: https://github.com/qutip/QuantumToolbox.jl/issues/386
[#388]: https://github.com/qutip/QuantumToolbox.jl/issues/388
[#389]: https://github.com/qutip/QuantumToolbox.jl/issues/389
[#392]: https://github.com/qutip/QuantumToolbox.jl/issues/392
4 changes: 2 additions & 2 deletions docs/src/resources/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ ket2dm
expect
variance
LinearAlgebra.kron
sparse_to_dense
dense_to_sparse
to_dense
to_sparse
vec2mat
mat2vec
```
Expand Down
6 changes: 3 additions & 3 deletions docs/src/users_guide/QuantumObject/QuantumObject.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,14 @@ SparseMatrixCSC{Int64}(x_s)
Matrix{Float64}(x_s)
```

To convert between dense and sparse arrays, one can also use [`dense_to_sparse`](@ref) and [`sparse_to_dense`](@ref):
To convert between dense and sparse arrays, one can also use [`to_sparse`](@ref) and [`to_dense`](@ref):

```@example Qobj
x_d = sparse_to_dense(x_s)
x_d = to_dense(x_s)
```

```@example Qobj
dense_to_sparse(x_d)
to_sparse(x_d)
```

!!! note "Convert to GPU arrays"
Expand Down
6 changes: 3 additions & 3 deletions ext/QuantumToolboxCUDAExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ _change_eltype(::Type{T}, ::Val{32}) where {T<:AbstractFloat} = Float32
_change_eltype(::Type{Complex{T}}, ::Val{64}) where {T<:Union{Int,AbstractFloat}} = ComplexF64
_change_eltype(::Type{Complex{T}}, ::Val{32}) where {T<:Union{Int,AbstractFloat}} = ComplexF32

QuantumToolbox.sparse_to_dense(A::MT) where {MT<:AbstractCuSparseArray} = CuArray(A)
QuantumToolbox.to_dense(A::MT) where {MT<:AbstractCuSparseArray} = CuArray(A)

QuantumToolbox.sparse_to_dense(::Type{T1}, A::CuArray{T2}) where {T1<:Number,T2<:Number} = CuArray{T1}(A)
QuantumToolbox.sparse_to_dense(::Type{T}, A::AbstractCuSparseArray) where {T<:Number} = CuArray{T}(A)
QuantumToolbox.to_dense(::Type{T1}, A::CuArray{T2}) where {T1<:Number,T2<:Number} = CuArray{T1}(A)
QuantumToolbox.to_dense(::Type{T}, A::AbstractCuSparseArray) where {T<:Number} = CuArray{T}(A)

end
8 changes: 8 additions & 0 deletions src/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@ end
=#

export FFTCorrelation
export sparse_to_dense, dense_to_sparse

FFTCorrelation() = error(
"`FFTCorrelation` has been deprecated and will be removed in next major release, please use `spectrum_correlation_fft` to calculate the spectrum with FFT method instead.",
)

sparse_to_dense(args...) = error(
"`sparse_to_dense` has been deprecated and will be removed in next major release, please use `to_dense` instead.",
)
dense_to_sparse(args...) = error(
"`dense_to_sparse` has been deprecated and will be removed in next major release, please use `to_sparse` instead.",
)

correlation_3op_2t(
H::QuantumObject{HOpType},
ψ0::QuantumObject{StateOpType},
Expand Down
8 changes: 4 additions & 4 deletions src/qobj/arithmetic_and_attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ LinearAlgebra.tr(

Return the singular values of a [`QuantumObject`](@ref) in descending order
"""
LinearAlgebra.svdvals(A::QuantumObject) = svdvals(sparse_to_dense(A.data))
LinearAlgebra.svdvals(A::QuantumObject) = svdvals(to_dense(A.data))

@doc raw"""
norm(A::QuantumObject, p::Real)
Expand Down Expand Up @@ -415,7 +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) = QuantumObject(sqrt(sparse_to_dense(A.data)), A.type, A.dimensions)
LinearAlgebra.sqrt(A::QuantumObject) = QuantumObject(sqrt(to_dense(A.data)), A.type, A.dimensions)

@doc raw"""
log(A::QuantumObject)
Expand All @@ -425,7 +425,7 @@ Matrix logarithm of [`QuantumObject`](@ref)
Note that this function only supports for [`Operator`](@ref) and [`SuperOperator`](@ref)
"""
LinearAlgebra.log(A::QuantumObject{ObjType}) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
QuantumObject(log(sparse_to_dense(A.data)), A.type, A.dimensions)
QuantumObject(log(to_dense(A.data)), A.type, A.dimensions)

@doc raw"""
exp(A::QuantumObject)
Expand All @@ -437,7 +437,7 @@ Note that this function only supports for [`Operator`](@ref) and [`SuperOperator
LinearAlgebra.exp(
A::QuantumObject{ObjType,DimsType,<:AbstractMatrix},
) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject},DimsType} =
QuantumObject(dense_to_sparse(exp(A.data)), A.type, A.dimensions)
QuantumObject(to_sparse(exp(A.data)), A.type, A.dimensions)
LinearAlgebra.exp(
A::QuantumObject{ObjType,DimsType,<:AbstractSparseMatrix},
) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject},DimsType} =
Expand Down
8 changes: 4 additions & 4 deletions src/qobj/eigsolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,10 @@ function LinearAlgebra.eigen(
kwargs...,
) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}}
MT = typeof(A.data)
F = eigen(sparse_to_dense(A.data); kwargs...)
F = eigen(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
U::sparse_to_dense(MT) = F.vectors
E::mat2vec(to_dense(MT)) = F.values
U::to_dense(MT) = F.vectors

return EigsolveResult(E, U, A.type, A.dimensions, 0, 0, true)
end
Expand All @@ -478,7 +478,7 @@ Same as [`eigen(A::QuantumObject; kwargs...)`](@ref) but for only the eigenvalue
LinearAlgebra.eigvals(
A::QuantumObject{OpType};
kwargs...,
) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eigvals(sparse_to_dense(A.data); kwargs...)
) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eigvals(to_dense(A.data); kwargs...)

@doc raw"""
eigenenergies(A::QuantumObject; sparse::Bool=false, kwargs...)
Expand Down
28 changes: 14 additions & 14 deletions src/qobj/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Functions which manipulates QuantumObject

export ket2dm
export expect, variance
export sparse_to_dense, dense_to_sparse
export to_dense, to_sparse
export vec2mat, mat2vec

@doc raw"""
Expand Down Expand Up @@ -113,42 +113,42 @@ variance(O::QuantumObject{OperatorQuantumObject}, ψ::QuantumObject) = expect(O^
variance(O::QuantumObject{OperatorQuantumObject}, ψ::Vector{<:QuantumObject}) = expect(O^2, ψ) .- expect(O, ψ) .^ 2

@doc raw"""
sparse_to_dense(A::QuantumObject)
to_dense(A::QuantumObject)

Converts a sparse QuantumObject to a dense QuantumObject.
"""
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)
sparse_to_dense(A::MT) where {MT<:AbstractArray} = A
to_dense(A::QuantumObject) = QuantumObject(to_dense(A.data), A.type, A.dimensions)
to_dense(A::MT) where {MT<:AbstractSparseArray} = Array(A)
to_dense(A::MT) where {MT<:AbstractArray} = A

sparse_to_dense(::Type{T}, A::AbstractSparseArray) where {T<:Number} = Array{T}(A)
sparse_to_dense(::Type{T1}, A::AbstractArray{T2}) where {T1<:Number,T2<:Number} = Array{T1}(A)
sparse_to_dense(::Type{T}, A::AbstractArray{T}) where {T<:Number} = A
to_dense(::Type{T}, A::AbstractSparseArray) where {T<:Number} = Array{T}(A)
to_dense(::Type{T1}, A::AbstractArray{T2}) where {T1<:Number,T2<:Number} = Array{T1}(A)
to_dense(::Type{T}, A::AbstractArray{T}) where {T<:Number} = A

function sparse_to_dense(::Type{M}) where {M<:SparseMatrixCSC}
function to_dense(::Type{M}) where {M<:SparseMatrixCSC}
T = M
par = T.parameters
npar = length(par)
(2 == npar) || error("Type $M is not supported.")
return Matrix{par[1]}
end

sparse_to_dense(::Type{M}) where {M<:AbstractMatrix} = M
to_dense(::Type{M}) where {M<:AbstractMatrix} = M

@doc raw"""
dense_to_sparse(A::QuantumObject)
to_sparse(A::QuantumObject)

Converts a dense QuantumObject to a sparse QuantumObject.
"""
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}
to_sparse(A::QuantumObject, tol::Real = 1e-10) = QuantumObject(to_sparse(A.data, tol), A.type, A.dimensions)
function to_sparse(A::MT, tol::Real = 1e-10) where {MT<:AbstractMatrix}
idxs = findall(@. abs(A) > tol)
row_indices = getindex.(idxs, 1)
col_indices = getindex.(idxs, 2)
vals = getindex(A, idxs)
return sparse(row_indices, col_indices, vals, size(A)...)
end
function dense_to_sparse(A::VT, tol::Real = 1e-10) where {VT<:AbstractVector}
function to_sparse(A::VT, tol::Real = 1e-10) where {VT<:AbstractVector}
idxs = findall(@. abs(A) > tol)
vals = getindex(A, idxs)
return sparsevec(idxs, vals, length(A))
Expand Down
4 changes: 2 additions & 2 deletions src/qobj/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function rand_unitary(dimensions::Union{Dimensions,AbstractVector{Int},Tuple}, :
# Because inv(Λ) ⋅ R has real and strictly positive elements, Q · Λ is therefore Haar distributed.
Λ = diag(R) # take the diagonal elements of R
Λ ./= abs.(Λ) # rescaling the elements
return QuantumObject(sparse_to_dense(Q * Diagonal(Λ)); type = Operator, dims = dimensions)
return QuantumObject(to_dense(Q * Diagonal(Λ)); type = Operator, dims = dimensions)
end
function rand_unitary(dimensions::Union{Dimensions,AbstractVector{Int},Tuple}, ::Val{:exp})
N = prod(dimensions)
Expand All @@ -59,7 +59,7 @@ function rand_unitary(dimensions::Union{Dimensions,AbstractVector{Int},Tuple}, :
# generate Hermitian matrix
H = QuantumObject((Z + Z') / 2; type = Operator, dims = dimensions)

return sparse_to_dense(exp(-1.0im * H))
return to_dense(exp(-1.0im * H))
end
rand_unitary(dimensions::Union{Dimensions,AbstractVector{Int},Tuple}, ::Val{T}) where {T} =
throw(ArgumentError("Invalid distribution: $(T)"))
Expand Down
2 changes: 1 addition & 1 deletion src/qobj/quantum_object.jl
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ SciMLOperators.cache_operator(
L::AbstractQuantumObject{OpType},
u::AbstractVector,
) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
get_typename_wrapper(L)(cache_operator(L.data, sparse_to_dense(similar(u))), L.type, L.dimensions)
get_typename_wrapper(L)(cache_operator(L.data, to_dense(similar(u))), L.type, L.dimensions)

function SciMLOperators.cache_operator(
L::AbstractQuantumObject{OpType},
Expand Down
2 changes: 1 addition & 1 deletion src/qobj/quantum_object_evo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ function QuantumObjectEvolution(
end

# Preallocate the SciMLOperator cache using a dense vector as a reference
v0 = sparse_to_dense(similar(op.data, size(op, 1)))
v0 = to_dense(similar(op.data, size(op, 1)))
data = cache_operator(data, v0)

return QuantumObjectEvolution(data, type, dims)
Expand Down
2 changes: 1 addition & 1 deletion src/time_evolution/mesolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function mesolveProblem(
check_dimensions(L_evo, ψ0)

T = Base.promote_eltype(L_evo, ψ0)
ρ0 = sparse_to_dense(_CType(T), mat2vec(ket2dm(ψ0).data)) # Convert it to dense vector with complex element type
ρ0 = to_dense(_CType(T), mat2vec(ket2dm(ψ0).data)) # Convert it to dense vector with complex element type
L = L_evo.data

is_empty_e_ops = (e_ops isa Nothing) ? true : isempty(e_ops)
Expand Down
2 changes: 1 addition & 1 deletion src/time_evolution/sesolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function sesolveProblem(
check_dimensions(H_evo, ψ0)

T = Base.promote_eltype(H_evo, ψ0)
ψ0 = sparse_to_dense(_CType(T), get_data(ψ0)) # Convert it to dense vector with complex element type
ψ0 = to_dense(_CType(T), get_data(ψ0)) # Convert it to dense vector with complex element type
U = H_evo.data

is_empty_e_ops = (e_ops isa Nothing) ? true : isempty(e_ops)
Expand Down
2 changes: 1 addition & 1 deletion src/time_evolution/smesolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ function smesolveProblem(
dims = L_evo.dimensions

T = Base.promote_eltype(L_evo, ψ0)
ρ0 = sparse_to_dense(_CType(T), mat2vec(ket2dm(ψ0).data)) # Convert it to dense vector with complex element type
ρ0 = to_dense(_CType(T), mat2vec(ket2dm(ψ0).data)) # Convert it to dense vector with complex element type

progr = ProgressBar(length(tlist), enable = getVal(progress_bar))

Expand Down
2 changes: 1 addition & 1 deletion src/time_evolution/ssesolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ function ssesolveProblem(
check_dimensions(H_eff_evo, ψ0)
dims = H_eff_evo.dimensions

ψ0 = sparse_to_dense(_CType(ψ0), get_data(ψ0))
ψ0 = to_dense(_CType(ψ0), get_data(ψ0))

progr = ProgressBar(length(tlist), enable = getVal(progress_bar))

Expand Down
14 changes: 7 additions & 7 deletions src/time_evolution/time_evolution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -397,12 +397,12 @@ function liouvillian_generalized(
H_d = QuantumObject(Diagonal(complex(E)), type = Operator, dims = dims)

Ω = E' .- E
Ωp = triu(dense_to_sparse(Ω, tol), 1)
Ωp = triu(to_sparse(Ω, tol), 1)

# Filter in the Hilbert space
σ = isnothing(σ_filter) ? 500 * maximum([norm(field) / length(field) for field in fields]) : σ_filter
F1 = QuantumObject(gaussian.(Ω, 0, σ), type = Operator, dims = dims)
F1 = dense_to_sparse(F1, tol)
F1 = to_sparse(F1, tol)

# Filter in the Liouville space
# M1 = ones(final_size, final_size)
Expand All @@ -412,13 +412,13 @@ function liouvillian_generalized(
Ω2 = kron(M1, Ω)
Ωdiff = Ω1 .- Ω2
F2 = QuantumObject(gaussian.(Ωdiff, 0, σ), SuperOperator, dims)
F2 = dense_to_sparse(F2, tol)
F2 = to_sparse(F2, tol)

L = liouvillian(H_d)

for i in eachindex(fields)
# The operator that couples the system to the bath in the eigenbasis
X_op = dense_to_sparse((U'*fields[i]*U).data[1:final_size, 1:final_size], tol)
X_op = to_sparse((U'*fields[i]*U).data[1:final_size, 1:final_size], tol)
if ishermitian(fields[i])
X_op = (X_op + X_op') / 2 # Make sure it's hermitian
end
Expand Down Expand Up @@ -452,8 +452,8 @@ function _liouvillian_floquet(
L_0 = L₀.data
L_p = Lₚ.data
L_m = Lₘ.data
L_p_dense = sparse_to_dense(Lₚ.data)
L_m_dense = sparse_to_dense(Lₘ.data)
L_p_dense = to_dense(Lₚ.data)
L_m_dense = to_dense(Lₘ.data)

S = -(L_0 - 1im * n_max * ω * I) \ L_p_dense
T = -(L_0 + 1im * n_max * ω * I) \ L_m_dense
Expand All @@ -464,5 +464,5 @@ function _liouvillian_floquet(
end

tol == 0 && return QuantumObject(L_0 + L_m * S + L_p * T, SuperOperator, L₀.dimensions)
return QuantumObject(dense_to_sparse(L_0 + L_m * S + L_p * T, tol), SuperOperator, L₀.dimensions)
return QuantumObject(to_sparse(L_0 + L_m * S + L_p * T, tol), SuperOperator, L₀.dimensions)
end
2 changes: 1 addition & 1 deletion src/wigner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ julia> wig = wigner(ψ, xvec, xvec);
or taking advantage of the parallel computation of the `WignerLaguerre` method

```jldoctest wigner
julia> ρ = ket2dm(ψ) |> dense_to_sparse;
julia> ρ = ket2dm(ψ) |> to_sparse;

julia> wig = wigner(ρ, xvec, xvec, method=WignerLaguerre(parallel=true));

Expand Down
2 changes: 1 addition & 1 deletion test/core-test/eigenvalues_and_operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

# eigen solve for general matrices
vals, _, vecs = eigsolve(L.data, sigma = 0.01, k = 10, krylovdim = 50)
vals2, vecs2 = eigen(sparse_to_dense(L.data))
vals2, vecs2 = eigen(to_dense(L.data))
vals3, state3, vecs3 = eigsolve_al(L, 1 \ (40 * κ), k = 10, krylovdim = 50)
idxs = sortperm(vals2, by = abs)
vals2 = vals2[idxs][1:10]
Expand Down
20 changes: 10 additions & 10 deletions test/core-test/generalized_master_equation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
Tlist = [0, 0.0]

E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc = N_trunc, tol = tol)
Ω = dense_to_sparse((E'.-E)[1:N_trunc, 1:N_trunc], tol)
Ω = to_sparse((E'.-E)[1:N_trunc, 1:N_trunc], tol)

H_d = Qobj(dense_to_sparse((U'*H*U)[1:N_trunc, 1:N_trunc], tol))
Xp = Qobj(Ω .* dense_to_sparse(triu((U'*(a+a')*U).data[1:N_trunc, 1:N_trunc], 1), tol))
a2 = Qobj(dense_to_sparse((U'*a*U).data[1:N_trunc, 1:N_trunc], tol))
sm2 = Qobj(dense_to_sparse((U'*sm*U).data[1:N_trunc, 1:N_trunc], tol))
H_d = Qobj(to_sparse((U'*H*U)[1:N_trunc, 1:N_trunc], tol))
Xp = Qobj(Ω .* to_sparse(triu((U'*(a+a')*U).data[1:N_trunc, 1:N_trunc], 1), tol))
a2 = Qobj(to_sparse((U'*a*U).data[1:N_trunc, 1:N_trunc], tol))
sm2 = Qobj(to_sparse((U'*sm*U).data[1:N_trunc, 1:N_trunc], tol))

# Standard liouvillian case
c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2]
Expand All @@ -33,12 +33,12 @@
Tlist = [0.2, 0.0]

E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc = N_trunc, tol = tol)
Ω = dense_to_sparse((E'.-E)[1:N_trunc, 1:N_trunc], tol)
Ω = to_sparse((E'.-E)[1:N_trunc, 1:N_trunc], tol)

H_d = Qobj(dense_to_sparse((U'*H*U)[1:N_trunc, 1:N_trunc], tol))
Xp = Qobj(Ω .* dense_to_sparse(triu((U'*(a+a')*U).data[1:N_trunc, 1:N_trunc], 1), tol))
a2 = Qobj(dense_to_sparse((U'*a*U).data[1:N_trunc, 1:N_trunc], tol))
sm2 = Qobj(dense_to_sparse((U'*sm*U).data[1:N_trunc, 1:N_trunc], tol))
H_d = Qobj(to_sparse((U'*H*U)[1:N_trunc, 1:N_trunc], tol))
Xp = Qobj(Ω .* to_sparse(triu((U'*(a+a')*U).data[1:N_trunc, 1:N_trunc], 1), tol))
a2 = Qobj(to_sparse((U'*a*U).data[1:N_trunc, 1:N_trunc], tol))
sm2 = Qobj(to_sparse((U'*sm*U).data[1:N_trunc, 1:N_trunc], tol))

@test abs(expect(Xp' * Xp, steadystate(L1)) - n_thermal(1, Tlist[1])) / n_thermal(1, Tlist[1]) < 1e-4

Expand Down
2 changes: 1 addition & 1 deletion test/core-test/negativity_and_partial_transpose.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
@testset "partial_transpose" begin
# A (24 * 24)-matrix which contains number 1 ~ 576
A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims = (2, 3, 4))
A_sparse = dense_to_sparse(A_dense)
A_sparse = to_sparse(A_dense)
PT = (true, false)
for s1 in PT
for s2 in PT
Expand Down
Loading
Loading