From e748b30c6ab982f19e12c08963564cac98357149 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 21 May 2024 00:14:38 +0200 Subject: [PATCH 1/4] Format Documents --- docs/make.jl | 8 +- ext/QuantumToolboxCUDAExt.jl | 12 +- src/arnoldi.jl | 50 ++-- src/correlations.jl | 50 ++-- src/eigsolve.jl | 236 +++++++++--------- src/general_functions.jl | 68 ++--- src/negativity.jl | 22 +- src/permutation.jl | 10 +- src/progress_bar.jl | 4 +- src/quantum_object.jl | 8 +- src/quantum_operators.jl | 20 +- src/spin_lattice.jl | 50 ++-- src/time_evolution/lr_mesolve.jl | 208 +++++++-------- src/time_evolution/mcsolve.jl | 80 +++--- src/time_evolution/mesolve.jl | 24 +- src/time_evolution/sesolve.jl | 16 +- src/time_evolution/time_evolution.jl | 56 ++--- .../time_evolution_dynamical.jl | 148 +++++------ src/versioninfo.jl | 10 +- src/wigner.jl | 48 ++-- test/aqua.jl | 2 +- test/correlations_and_spectrum.jl | 4 +- test/cuda_ext.jl | 70 +++--- test/dynamical-shifted-fock.jl | 106 ++++---- test/dynamical_fock_dimension_mesolve.jl | 4 +- test/eigenvalues_and_operators.jl | 30 +-- test/generalized_master_equation.jl | 28 +-- test/low_rank_dynamics.jl | 80 +++--- test/negativity_and_partial_transpose.jl | 12 +- test/permutation.jl | 20 +- test/quantum_objects.jl | 42 ++-- test/steady_state.jl | 2 +- 32 files changed, 764 insertions(+), 764 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 3453b413..274e63de 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -8,21 +8,21 @@ DocMeta.setdocmeta!(QuantumToolbox, :DocTestSetup, :(using QuantumToolbox); recu makedocs(; modules=[QuantumToolbox], authors="Alberto Mercurio", - repo = Remotes.GitHub("albertomercurio", "QuantumToolbox.jl"), + repo=Remotes.GitHub("albertomercurio", "QuantumToolbox.jl"), sitename="QuantumToolbox.jl", format=Documenter.HTML(; prettyurls=get(ENV, "CI", "false") == "true", canonical="https://albertomercurio.github.io/QuantumToolbox.jl", edit_link="main", assets=String[], - mathengine = MathJax3(Dict( + mathengine=MathJax3(Dict( :loader => Dict("load" => ["[tex]/physics"]), :tex => Dict( - "inlineMath" => [["\$","\$"], ["\\(","\\)"]], + "inlineMath" => [["\$", "\$"], ["\\(", "\\)"]], "tags" => "ams", "packages" => ["base", "ams", "autoload", "physics"], ), - )), + )), ), pages=[ "index.md", diff --git a/ext/QuantumToolboxCUDAExt.jl b/ext/QuantumToolboxCUDAExt.jl index 4ade069e..a7410385 100644 --- a/ext/QuantumToolboxCUDAExt.jl +++ b/ext/QuantumToolboxCUDAExt.jl @@ -10,7 +10,7 @@ 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.dims) +CuArray(A::QuantumObject{Tq}) where {Tq<:Union{Vector,Matrix}} = QuantumObject(CuArray(A.data), A.type, A.dims) @doc raw""" CuArray{T}(A::QuantumObject) @@ -31,7 +31,7 @@ CuSparseVector(A::QuantumObject{<:SparseVector}) = QuantumObject(CuSparseVector( 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.dims) +CuSparseVector{T}(A::QuantumObject{<:SparseVector}) where {T} = QuantumObject(CuSparseVector{T}(A.data), A.type, A.dims) @doc raw""" CuSparseMatrixCSC(A::QuantumObject) @@ -45,7 +45,7 @@ CuSparseMatrixCSC(A::QuantumObject{<:SparseMatrixCSC}) = QuantumObject(CuSparseM 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.dims) +CuSparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = QuantumObject(CuSparseMatrixCSC{T}(A.data), A.type, A.dims) @doc raw""" CuSparseMatrixCSR(A::QuantumObject) @@ -59,7 +59,7 @@ CuSparseMatrixCSR(A::QuantumObject{<:SparseMatrixCSC}) = QuantumObject(CuSparseM 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.dims) +CuSparseMatrixCSR{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = QuantumObject(CuSparseMatrixCSR{T}(A.data), A.type, A.dims) @doc raw""" cu(A::QuantumObject; word_size::Int=32) @@ -72,8 +72,8 @@ Return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA` arr """ cu(A::QuantumObject; word_size::Int=32) = ((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) +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) _change_eltype(::Type{T}, ::Val{64}) where {T<:Int} = Int64 _change_eltype(::Type{T}, ::Val{32}) where {T<:Int} = Int32 diff --git a/src/arnoldi.jl b/src/arnoldi.jl index e70f3715..eaa7f9bf 100644 --- a/src/arnoldi.jl +++ b/src/arnoldi.jl @@ -1,49 +1,49 @@ export ArnoldiSpace, arnoldi, arnoldi!, arnoldi_init!, arnoldi_step! export expv!, expv -struct ArnoldiSpace{VT<:AbstractMatrix{<: BlasFloat}, HT<:AbstractMatrix{<: BlasFloat}, mT<:Integer} +struct ArnoldiSpace{VT<:AbstractMatrix{<:BlasFloat},HT<:AbstractMatrix{<:BlasFloat},mT<:Integer} V::VT H::HT Hcopy::HT m::mT end -function Base.copy(AS::ArnoldiSpace{<:AbstractMatrix{T1}, <:AbstractMatrix{T1}}) where T1 <: BlasFloat +function Base.copy(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}) where {T1<:BlasFloat} ArnoldiSpace(copy(AS.V), copy(AS.H), copy(AS.Hcopy), AS.m) end -function Base.deepcopy(AS::ArnoldiSpace{<:AbstractMatrix{T1}, <:AbstractMatrix{T1}}) where T1 <: BlasFloat +function Base.deepcopy(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}) where {T1<:BlasFloat} ArnoldiSpace(deepcopy(AS.V), deepcopy(AS.H), deepcopy(AS.Hcopy), AS.m) end -function arnoldi_init!(A, b::AbstractVector{T}, V::AbstractMatrix{T}, H::AbstractMatrix{T}) where T <: BlasFloat +function arnoldi_init!(A, b::AbstractVector{T}, V::AbstractMatrix{T}, H::AbstractMatrix{T}) where {T<:BlasFloat} v₁ = view(V, :, 1) v₂ = view(V, :, 2) v₁ .= b normalize!(v₁) mul!(v₂, A, v₁) - H[1,1] = dot(v₁, v₂) - axpy!(-H[1,1], v₁, v₂) - H[2,1] = norm(v₂) - v₂ ./= H[2,1] + H[1, 1] = dot(v₁, v₂) + axpy!(-H[1, 1], v₁, v₂) + H[2, 1] = norm(v₂) + v₂ ./= H[2, 1] end - -function arnoldi_step!(A, V::AbstractMatrix{T}, H::AbstractMatrix{T}, i::TI) where {T <: BlasFloat, TI <: Integer} - vᵢ = view(V,:,i) - vᵢ₊₁ = view(V,:,i+1) + +function arnoldi_step!(A, V::AbstractMatrix{T}, H::AbstractMatrix{T}, i::TI) where {T<:BlasFloat,TI<:Integer} + vᵢ = view(V, :, i) + vᵢ₊₁ = view(V, :, i + 1) mul!(vᵢ₊₁, A, vᵢ) for j = 1:i - vⱼ = view(V,:,j) - H[j,i] = dot(vⱼ, vᵢ₊₁) - axpy!(-H[j,i], vⱼ, vᵢ₊₁) + vⱼ = view(V, :, j) + H[j, i] = dot(vⱼ, vᵢ₊₁) + axpy!(-H[j, i], vⱼ, vᵢ₊₁) end - β = H[i+1,i] = norm(vᵢ₊₁) - vᵢ₊₁ ./= H[i+1,i] + β = H[i+1, i] = norm(vᵢ₊₁) + vᵢ₊₁ ./= H[i+1, i] return β end -function arnoldi!(AS::ArnoldiSpace{<:AbstractMatrix{T1}, <:AbstractMatrix{T1}}, A, b::AbstractVector{T2}) where {T1 <: BlasFloat, T2 <: BlasFloat} +function arnoldi!(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, A, b::AbstractVector{T2}) where {T1<:BlasFloat,T2<:BlasFloat} n = size(A, 2) V = AS.V H = AS.H @@ -59,18 +59,18 @@ function arnoldi!(AS::ArnoldiSpace{<:AbstractMatrix{T1}, <:AbstractMatrix{T1}}, return AS end -function arnoldi(A, b::AbstractVector{T}, m::Integer) where T <: BlasFloat +function arnoldi(A, b::AbstractVector{T}, m::Integer) where {T<:BlasFloat} n = size(A, 2) - V = similar(b, n, m+1) - H = zeros(T, m+1, m) + V = similar(b, n, m + 1) + H = zeros(T, m + 1, m) AS = ArnoldiSpace(V, H, copy(H), m) arnoldi!(AS, A, b) end ### EXPV TOOLS ### -function expv!(x::AbstractVector{T1}, AS::ArnoldiSpace{<:AbstractMatrix{T1}, <:AbstractMatrix{T1}}, - t::T2, b::AbstractVector{T1}) where {T1 <: BlasFloat, T2 <: Union{BlasFloat, BlasInt}} +function expv!(x::AbstractVector{T1}, AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, + t::T2, b::AbstractVector{T1}) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} H = AS.H Hcopy = AS.Hcopy @@ -96,12 +96,12 @@ function expv!(x::AbstractVector{T1}, AS::ArnoldiSpace{<:AbstractMatrix{T1}, <:A return x end -function expv!(x::AbstractVector{T1}, A, t::T2, b::AbstractVector{T1}; m::Int=min(30, cld(2*length(b), 3))) where {T1 <: BlasFloat, T2 <: Union{BlasFloat, BlasInt}} +function expv!(x::AbstractVector{T1}, A, t::T2, b::AbstractVector{T1}; m::Int=min(30, cld(2 * length(b), 3))) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} AS = arnoldi(A, b, m) expv!(x, AS, t, b) end -function expv(A, t::T1, b::AbstractVector{T2}; m::Int=min(30, cld(2*length(b), 3))) where {T1 <: BlasFloat, T2 <: BlasFloat} +function expv(A, t::T1, b::AbstractVector{T2}; m::Int=min(30, cld(2 * length(b), 3))) where {T1<:BlasFloat,T2<:BlasFloat} x = similar(b) expv!(x, A, t, b, m=m) end \ No newline at end of file diff --git a/src/correlations.jl b/src/correlations.jl index d518fb68..75448bb2 100644 --- a/src/correlations.jl +++ b/src/correlations.jl @@ -10,7 +10,7 @@ struct ExponentialSeries <: SpectrumSolver calc_steadystate::Bool end -ExponentialSeries(;tol=1e-14,calc_steadystate=false) = ExponentialSeries(tol,calc_steadystate) +ExponentialSeries(; tol=1e-14, calc_steadystate=false) = ExponentialSeries(tol, calc_steadystate) @doc raw""" correlation_3op_2t(H::QuantumObject, @@ -35,15 +35,15 @@ function correlation_3op_2t(H::QuantumObject{<:AbstractArray{T1},HOpType}, c_ops::AbstractVector=[]; kwargs...) where {T1,T2,T3,T4,T5,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - + (H.dims == ψ0.dims && H.dims == A.dims && - H.dims == B.dims && H.dims == C.dims) || throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + H.dims == B.dims && H.dims == C.dims) || throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - kwargs2 = (;kwargs...) - kwargs2 = merge(kwargs2, (saveat = collect(t_l),)) + kwargs2 = (; kwargs...) + kwargs2 = merge(kwargs2, (saveat=collect(t_l),)) ρt = mesolve(H, ψ0, t_l, c_ops; kwargs2...).states - corr = map((t,ρ)->mesolve(H, C*ρ*A, τ_l .+ t, c_ops, e_ops=[B]; kwargs...).expect[1,:], t_l, ρt) + corr = map((t, ρ) -> mesolve(H, C * ρ * A, τ_l .+ t, c_ops, e_ops=[B]; kwargs...).expect[1, :], t_l, ρt) corr end @@ -73,14 +73,14 @@ function correlation_2op_2t(H::QuantumObject{<:AbstractArray{T1},HOpType}, reverse::Bool=false, kwargs...) where {T1,T2,T3,T4,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - + C = eye(prod(H.dims), dims=H.dims) if reverse corr = correlation_3op_2t(H, ψ0, t_l, τ_l, A, B, C, c_ops; kwargs...) else corr = correlation_3op_2t(H, ψ0, t_l, τ_l, C, A, B, c_ops; kwargs...) end - + reduce(hcat, corr) end @@ -107,10 +107,10 @@ function correlation_2op_1t(H::QuantumObject{<:AbstractArray{T1},HOpType}, reverse::Bool=false, kwargs...) where {T1,T2,T3,T4,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - + corr = correlation_2op_2t(H, ψ0, [0], τ_l, A, B, c_ops; reverse=reverse, kwargs...) - - corr[:,1] + + corr[:, 1] end @doc raw""" @@ -131,10 +131,10 @@ function spectrum(H::QuantumObject{MT1,HOpType}, c_ops::Vector{QuantumObject{MT2,COpType}}=Vector{QuantumObject{MT1,HOpType}}([]); solver::MySolver=ExponentialSeries(), kwargs...) where {MT1<:AbstractMatrix,MT2<:AbstractMatrix,T2,T3, - HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - MySolver<:SpectrumSolver} - + HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + MySolver<:SpectrumSolver} + return _spectrum(H, ω_list, A, B, c_ops, solver; kwargs...) end @@ -145,13 +145,13 @@ function _spectrum(H::QuantumObject{<:AbstractArray{T1},HOpType}, c_ops, solver::FFTCorrelation; kwargs...) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + Nsamples = length(ω_list) ω_max = abs(maximum(ω_list)) - dω = 2*ω_max/(Nsamples-1) + dω = 2 * ω_max / (Nsamples - 1) ω_l = -ω_max:dω:ω_max - T = 2π/(ω_l[2]-ω_l[1]) + T = 2π / (ω_l[2] - ω_l[1]) τ_l = range(0, T, length=length(ω_l)) ρss = steadystate(H, c_ops) @@ -169,7 +169,7 @@ function _spectrum(H::QuantumObject{<:AbstractArray{T1},HOpType}, c_ops, solver::ExponentialSeries; kwargs...) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + (H.dims == A.dims == B.dims) || throw(DimensionMismatch("The dimensions of H, A and B must be the same")) L = liouvillian(H, c_ops) @@ -190,23 +190,23 @@ function _spectrum(H::QuantumObject{<:AbstractArray{T1},HOpType}, ρss = steadystate(L).data else ss_idx = argmin(abs2.(rates)) - ρss = vec2mat(@view(vecs[:,ss_idx])) + ρss = vec2mat(@view(vecs[:, ss_idx])) ρss2 = (ρss + ρss') / 2 ρss2 ./= tr(ρss2) ρss .= ρss2 end - + ρ0 = B.data * ρss v = vecs \ mat2vec(ρ0) - - amps = map(i->v[i] * tr(A.data * vec2mat(@view(vecs[:,i]))), eachindex(rates)) + + amps = map(i -> v[i] * tr(A.data * vec2mat(@view(vecs[:, i]))), eachindex(rates)) idxs = findall(x -> abs(x) > solver.tol, amps) amps, rates = amps[idxs], rates[idxs] # @. amps = abs(amps) # idxs = findall(x -> real(x) < 0, amps) # @. amps[idxs] -= 2*real(amps[idxs]) - - spec = map(ω->2*real(sum(@. amps * (1 / (1im * ω - rates)))), ω_l) + + spec = map(ω -> 2 * real(sum(@. amps * (1 / (1im * ω - rates)))), ω_l) return ω_l, spec end diff --git a/src/eigsolve.jl b/src/eigsolve.jl index 5abb132b..ddf71dbe 100644 --- a/src/eigsolve.jl +++ b/src/eigsolve.jl @@ -46,7 +46,7 @@ julia> T 0.707107+0.0im 0.707107+0.0im ``` """ -struct EigsolveResult{T1<:Vector{<:Number}, T2<:AbstractMatrix{<:Number}, ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} +struct EigsolveResult{T1<:Vector{<:Number},T2<:AbstractMatrix{<:Number},ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} values::T1 vectors::T2 type::ObjType @@ -57,7 +57,7 @@ struct EigsolveResult{T1<:Vector{<:Number}, T2<:AbstractMatrix{<:Number}, ObjTyp end Base.iterate(res::EigsolveResult) = (res.values, Val(:vector_list)) -Base.iterate(res::EigsolveResult{T1,T2,Nothing}, ::Val{:vector_list}) where {T1, T2} = ([res.vectors[:, k] for k in 1:length(res.values)], Val(:vectors)) +Base.iterate(res::EigsolveResult{T1,T2,Nothing}, ::Val{:vector_list}) where {T1,T2} = ([res.vectors[:, k] for k in 1:length(res.values)], Val(:vectors)) Base.iterate(res::EigsolveResult{T1,T2,OperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} = ([QuantumObject(res.vectors[:, k], Ket, res.dims) for k in 1:length(res.values)], Val(:vectors)) Base.iterate(res::EigsolveResult{T1,T2,SuperOperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} = ([QuantumObject(res.vectors[:, k], OperatorKet, res.dims) for k in 1:length(res.values)], Val(:vectors)) Base.iterate(res::EigsolveResult, ::Val{:vectors}) = (res.vectors, Val(:done)) @@ -73,92 +73,92 @@ function Base.show(io::IO, res::EigsolveResult) end if VERSION < v"1.10" -for (hseqr, elty) in - ((:zhseqr_,:ComplexF64), - (:chseqr_,:ComplexF32)) - @eval begin - # * .. Scalar Arguments .. - # CHARACTER JOB, COMPZ - # INTEGER N, ILO, IHI, LWORK, LDH, LDZ, INFO - # * .. - # * .. Array Arguments .. - # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) - function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Int, ihi::Int, - H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) - require_one_based_indexing(H, Z) - chkstride1(H) - n = checksquare(H) - checksquare(Z) == n || throw(DimensionMismatch()) - ldh = max(1, stride(H, 2)) - ldz = max(1, stride(Z, 2)) - w = similar(H, $elty, n) - work = Vector{$elty}(undef, 1) - lwork = BlasInt(-1) - info = Ref{BlasInt}() - for i = 1:2 # first call returns lwork as work[1] - ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, - (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, - Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, - Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, - Ptr{BlasInt}), - job, compz, n, ilo, ihi, - H, ldh, w, Z, ldz, work, - lwork, info) - chklapackerror(info[]) - if i == 1 - lwork = BlasInt(real(work[1])) - resize!(work, lwork) + for (hseqr, elty) in + ((:zhseqr_, :ComplexF64), + (:chseqr_, :ComplexF32)) + @eval begin + # * .. Scalar Arguments .. + # CHARACTER JOB, COMPZ + # INTEGER N, ILO, IHI, LWORK, LDH, LDZ, INFO + # * .. + # * .. Array Arguments .. + # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) + function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Int, ihi::Int, + H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + require_one_based_indexing(H, Z) + chkstride1(H) + n = checksquare(H) + checksquare(Z) == n || throw(DimensionMismatch()) + ldh = max(1, stride(H, 2)) + ldz = max(1, stride(Z, 2)) + w = similar(H, $elty, n) + work = Vector{$elty}(undef, 1) + lwork = BlasInt(-1) + info = Ref{BlasInt}() + for i = 1:2 # first call returns lwork as work[1] + ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, + (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, + Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, + Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, + Ptr{BlasInt}), + job, compz, n, ilo, ihi, + H, ldh, w, Z, ldz, work, + lwork, info) + chklapackerror(info[]) + if i == 1 + lwork = BlasInt(real(work[1])) + resize!(work, lwork) + end end + H, Z, w end - H, Z, w end end -end -for (hseqr, elty) in - ((:dhseqr_,:Float64), - (:shseqr_,:Float32)) - @eval begin - # * .. Scalar Arguments .. - # CHARACTER JOB, COMPZ - # INTEGER N, ILO, IHI, LWORK, LDH, LDZ, INFO - # * .. - # * .. Array Arguments .. - # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) - function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Int, ihi::Int, - H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) - require_one_based_indexing(H, Z) - chkstride1(H) - n = checksquare(H) - checksquare(Z) == n || throw(DimensionMismatch()) - ldh = max(1, stride(H, 2)) - ldz = max(1, stride(Z, 2)) - wr = similar(H, $elty, n) - wi = similar(H, $elty, n) - work = Vector{$elty}(undef, 1) - lwork = BlasInt(-1) - info = Ref{BlasInt}() - for i = 1:2 # first call returns lwork as work[1] - ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, - (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, - Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ptr{$elty}, - Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, - Ptr{BlasInt}), - job, compz, n, ilo, ihi, - H, ldh, wr, wi, Z, ldz, work, - lwork, info) - chklapackerror(info[]) - if i == 1 - lwork = BlasInt(real(work[1])) - resize!(work, lwork) + for (hseqr, elty) in + ((:dhseqr_, :Float64), + (:shseqr_, :Float32)) + @eval begin + # * .. Scalar Arguments .. + # CHARACTER JOB, COMPZ + # INTEGER N, ILO, IHI, LWORK, LDH, LDZ, INFO + # * .. + # * .. Array Arguments .. + # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) + function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Int, ihi::Int, + H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + require_one_based_indexing(H, Z) + chkstride1(H) + n = checksquare(H) + checksquare(Z) == n || throw(DimensionMismatch()) + ldh = max(1, stride(H, 2)) + ldz = max(1, stride(Z, 2)) + wr = similar(H, $elty, n) + wi = similar(H, $elty, n) + work = Vector{$elty}(undef, 1) + lwork = BlasInt(-1) + info = Ref{BlasInt}() + for i = 1:2 # first call returns lwork as work[1] + ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, + (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, + Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ptr{$elty}, + Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, + Ptr{BlasInt}), + job, compz, n, ilo, ihi, + H, ldh, wr, wi, Z, ldz, work, + lwork, info) + chklapackerror(info[]) + if i == 1 + lwork = BlasInt(real(work[1])) + resize!(work, lwork) + end end + H, Z, complex.(wr, wi) end - H, Z, complex.(wr, wi) end end -end -hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) -hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) + hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) + hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) end function _map_ldiv(linsolve, y, x) @@ -187,19 +187,19 @@ function _update_schur_eigs!(Hₘ, Uₘ, Uₘᵥ, f, m, β, sorted_vals) copyto!(Uₘ, Hₘ) LAPACK.orghr!(1, m, Uₘ, F.τ) Tₘ, Uₘ, values = hseqr!(Hₘ, Uₘ) - sortperm!(sorted_vals, values, by = abs, rev = true) + sortperm!(sorted_vals, values, by=abs, rev=true) _permuteschur!(Tₘ, Uₘ, sorted_vals) mul!(f, Uₘᵥ, β) return Tₘ, Uₘ end -function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k::Int = 1, - m::Int = max(20, 2*k+1); tol::Real = 1e-8, maxiter::Int = 200) where {T<:BlasFloat,ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} +function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k::Int=1, + m::Int=max(20, 2 * k + 1); tol::Real=1e-8, maxiter::Int=200) where {T<:BlasFloat,ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} n = size(A, 2) - V = similar(b, n, m+1) - H = zeros(T, m+1, m) + V = similar(b, n, m + 1) + H = zeros(T, m + 1, m) arnoldi_init!(A, b, V, H) @@ -215,11 +215,11 @@ function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k: Vₘ = view(V, :, 1:m) Hₘ = view(H, 1:m, 1:m) - qₘ = view(V, :, m+1) - βeₘ = view(H, m+1, 1:m) + qₘ = view(V, :, m + 1) + βeₘ = view(H, m + 1, 1:m) β = real(H[m+1, m]) Uₘ = one(Hₘ) - + Uₘᵥ = view(Uₘ, m, 1:m) cache0 = similar(b, m, m) @@ -228,8 +228,8 @@ function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k: sorted_vals = Array{Int16}(undef, m) V₁ₖ = view(V, :, 1:k) - Vₖ₊₁ = view(V, :, k+1) - Hₖ₊₁₁ₖ = view(H, k+1, 1:k) + Vₖ₊₁ = view(V, :, k + 1) + Hₖ₊₁₁ₖ = view(H, k + 1, 1:k) cache1₁ₖ = view(cache1, :, 1:k) cache2₁ₖ = view(cache2, 1:k) @@ -254,7 +254,7 @@ function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k: for j in k+1:m β = arnoldi_step!(A, V, H, j) if β < tol - numops += j-k-1 + numops += j - k - 1 break end end @@ -263,8 +263,8 @@ function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k: Tₘ, Uₘ = _update_schur_eigs!(Hₘ, Uₘ, Uₘᵥ, f, m, β, sorted_vals) - numops += m-k-1 - iter+=1 + numops += m - k - 1 + iter += 1 end vals = diag(view(Tₘ, 1:k, 1:k)) @@ -289,46 +289,46 @@ end Solve for the eigenvalues and eigenvectors of a matrix `A` using the Arnoldi method. The keyword arguments are passed to the linear solver. """ -function eigsolve(A::QuantumObject{<:AbstractMatrix}; v0::Union{Nothing,AbstractVector}=nothing, - sigma::Union{Nothing, Real}=nothing, k::Int = 1, - krylovdim::Int = max(20, 2*k+1), tol::Real = 1e-8, maxiter::Int = 200, - solver::Union{Nothing, LinearSolve.SciMLLinearSolveAlgorithm} = nothing, kwargs...) +function eigsolve(A::QuantumObject{<:AbstractMatrix}; v0::Union{Nothing,AbstractVector}=nothing, + sigma::Union{Nothing,Real}=nothing, k::Int=1, + krylovdim::Int=max(20, 2 * k + 1), tol::Real=1e-8, maxiter::Int=200, + solver::Union{Nothing,LinearSolve.SciMLLinearSolveAlgorithm}=nothing, kwargs...) - return eigsolve(A.data; v0=v0, type=A.type, dims=A.dims, sigma=sigma, k=k, krylovdim=krylovdim, tol=tol, - maxiter=maxiter, solver=solver, kwargs...) + return eigsolve(A.data; v0=v0, type=A.type, dims=A.dims, sigma=sigma, k=k, krylovdim=krylovdim, tol=tol, + maxiter=maxiter, solver=solver, kwargs...) end -function eigsolve(A; v0::Union{Nothing,AbstractVector}=nothing, - type::Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}=nothing, +function eigsolve(A; v0::Union{Nothing,AbstractVector}=nothing, + type::Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}=nothing, dims::Vector{Int}=Int[], - sigma::Union{Nothing, Real}=nothing, k::Int = 1, - krylovdim::Int = max(20, 2*k+1), tol::Real = 1e-8, maxiter::Int = 200, - solver::Union{Nothing, LinearSolve.SciMLLinearSolveAlgorithm} = nothing, kwargs...) + sigma::Union{Nothing,Real}=nothing, k::Int=1, + krylovdim::Int=max(20, 2 * k + 1), tol::Real=1e-8, maxiter::Int=200, + solver::Union{Nothing,LinearSolve.SciMLLinearSolveAlgorithm}=nothing, kwargs...) T = eltype(A) isH = ishermitian(A) v0 === nothing && (v0 = normalize!(rand(T, size(A, 1)))) if sigma === nothing - res = _eigsolve(A, v0, type, dims, k, krylovdim, tol = tol, maxiter = maxiter) + res = _eigsolve(A, v0, type, dims, k, krylovdim, tol=tol, maxiter=maxiter) vals = res.values else Aₛ = A - sigma * I solver === nothing && (solver = isH ? KrylovJL_MINRES() : KrylovJL_GMRES()) - kwargs2 = (;kwargs...) + kwargs2 = (; kwargs...) condition = !haskey(kwargs2, :Pl) && typeof(A) <: SparseMatrixCSC - condition && (kwargs2 = merge(kwargs2, (Pl = ilu(Aₛ, τ=0.01),))) + condition && (kwargs2 = merge(kwargs2, (Pl=ilu(Aₛ, τ=0.01),))) - !haskey(kwargs2, :abstol) && (kwargs2 = merge(kwargs2, (abstol = tol*1e-6,))) - !haskey(kwargs2, :reltol) && (kwargs2 = merge(kwargs2, (reltol = tol*1e-6,))) + !haskey(kwargs2, :abstol) && (kwargs2 = merge(kwargs2, (abstol=tol * 1e-6,))) + !haskey(kwargs2, :reltol) && (kwargs2 = merge(kwargs2, (reltol=tol * 1e-6,))) prob = LinearProblem(Aₛ, v0) linsolve = init(prob, solver; kwargs2...) - Amap = LinearMap{T}((y,x) -> _map_ldiv(linsolve, y, x), length(v0)) + Amap = LinearMap{T}((y, x) -> _map_ldiv(linsolve, y, x), length(v0)) - res = _eigsolve(Amap, v0, type, dims, k, krylovdim, tol = tol, maxiter = maxiter) + res = _eigsolve(Amap, v0, type, dims, k, krylovdim, tol=tol, maxiter=maxiter) vals = @. (1 + sigma * res.values) / res.values end @@ -380,18 +380,18 @@ function eigsolve_al(H::QuantumObject{MT1,HOpType}, alg::OrdinaryDiffEqAlgorithm=Tsit5(), H_t::Union{Nothing,Function}=nothing, params::NamedTuple=NamedTuple(), - ρ0::AbstractMatrix = rand_dm(prod(H.dims)).data, + ρ0::AbstractMatrix=rand_dm(prod(H.dims)).data, k::Int=1, krylovdim::Int=min(10, size(H, 1)), maxiter::Int=200, eigstol::Real=1e-6, kwargs...) where {MT1<:AbstractMatrix,MT2<:AbstractMatrix, - HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} + HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} L = liouvillian(H, c_ops) - prob = mesolveProblem(L, QuantumObject(ρ0, dims=H.dims), [0,T]; alg=alg, - H_t=H_t, params=params, progress_bar=false, kwargs...) + prob = mesolveProblem(L, QuantumObject(ρ0, dims=H.dims), [0, T]; alg=alg, + H_t=H_t, params=params, progress_bar=false, kwargs...) integrator = init(prob, alg) # prog = ProgressUnknown(desc="Applications:", showspeed = true, enabled=progress) @@ -401,7 +401,7 @@ function eigsolve_al(H::QuantumObject{MT1,HOpType}, solve!(integrator) integrator.u end - + Lmap = LinearMap{eltype(MT1)}(arnoldi_lindblad_solve, size(L, 1), ismutating=false) res = _eigsolve(Lmap, mat2vec(ρ0), L.type, L.dims, k, krylovdim, maxiter=maxiter, tol=eigstol) @@ -413,7 +413,7 @@ function eigsolve_al(H::QuantumObject{MT1,HOpType}, for i in eachindex(res.values) vec = view(res.vectors, :, i) vals[i] = dot(vec, L.data, vec) - @. vecs[:,i] = vec * exp(-1im*angle(vec[1])) + @. vecs[:, i] = vec * exp(-1im * angle(vec[1])) end return EigsolveResult(vals, vecs, res.type, res.dims, res.iter, res.numops, res.converged) @@ -459,7 +459,7 @@ true ``` """ function LinearAlgebra.eigen(A::QuantumObject{MT,OpType}; kwargs...) where - {MT<:AbstractMatrix,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +{MT<:AbstractMatrix,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} F = eigen(sparse_to_dense(A.data); kwargs...) # This fixes a type inference issue. But doesn't work for GPU arrays diff --git a/src/general_functions.jl b/src/general_functions.jl index bc680198..6d90c627 100644 --- a/src/general_functions.jl +++ b/src/general_functions.jl @@ -31,11 +31,11 @@ Converts a sparse QuantumObject to a dense QuantumObject. sparse_to_dense(A::QuantumObject{<:AbstractVecOrMat}) = QuantumObject(sparse_to_dense(A.data), A.type, A.dims) sparse_to_dense(A::MT) where {MT<:AbstractSparseMatrix} = Array(A) for op in (:Transpose, :Adjoint) - @eval sparse_to_dense(A::$op{T, <:AbstractSparseMatrix}) where {T<:BlasFloat} = Array(A) + @eval sparse_to_dense(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = Array(A) end sparse_to_dense(A::MT) where {MT<:AbstractArray} = A -function sparse_to_dense(::Type{M}) where M <: SparseMatrixCSC +function sparse_to_dense(::Type{M}) where {M<:SparseMatrixCSC} T = M par = T.parameters npar = length(par) @@ -43,7 +43,7 @@ function sparse_to_dense(::Type{M}) where M <: SparseMatrixCSC return Matrix{par[1]} end -sparse_to_dense(::Type{M}) where M <: AbstractMatrix = M +sparse_to_dense(::Type{M}) where {M<:AbstractMatrix} = M """ dense_to_sparse(A::QuantumObject) @@ -69,9 +69,9 @@ end Removes those elements of a QuantumObject `A` whose 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.dims) -tidyup(A::AbstractArray{T}, tol::T2=1e-14) where {T, T2<:Real} = @. T(abs(A) > tol) * A -tidyup(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T, T2<:Real} = droptol!(copy(A), tol) +tidyup(A::QuantumObject{<:AbstractArray{T}}, tol::T2=1e-14) where {T,T2<:Real} = QuantumObject(tidyup(A.data, tol), A.type, A.dims) +tidyup(A::AbstractArray{T}, tol::T2=1e-14) where {T,T2<:Real} = @. T(abs(A) > tol) * A +tidyup(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T,T2<:Real} = droptol!(copy(A), tol) """ tidyup!(A::QuantumObject, tol::Real=1e-14) @@ -79,9 +79,9 @@ tidyup(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T, T2<:Real} = droptol! Removes those elements of a QuantumObject `A` whose absolute value is less than `tol`. In-place version of [`tidyup`](#tidyup). """ -tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2=1e-14) where {T, T2<:Real} = (tidyup!(A.data, tol); A) -tidyup!(A::AbstractArray{T}, tol::T2=1e-14) where {T, T2<:Real} = @. A = T(abs(A) > tol) * A -tidyup!(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T, T2<:Real} = droptol!(A, tol) +tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2=1e-14) where {T,T2<:Real} = (tidyup!(A.data, tol); A) +tidyup!(A::AbstractArray{T}, tol::T2=1e-14) where {T,T2<:Real} = @. A = T(abs(A) > tol) * A +tidyup!(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T,T2<:Real} = droptol!(A, tol) """ get_data(A::QuantumObject) @@ -102,8 +102,8 @@ function mat2vec(A::MT) where {MT<:AbstractSparseMatrix} return sparsevec(i .+ (j .- 1) .* size(A, 1), v, prod(size(A))) end for op in (:Transpose, :Adjoint) - @eval mat2vec(A::$op{T, <:AbstractSparseMatrix}) where {T<:BlasFloat} = mat2vec(sparse(A)) - @eval mat2vec(A::$op{T, <:AbstractMatrix}) where {T<:BlasFloat} = mat2vec(Matrix(A)) + @eval mat2vec(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = mat2vec(sparse(A)) + @eval mat2vec(A::$op{T,<:AbstractMatrix}) where {T<:BlasFloat} = mat2vec(Matrix(A)) end @@ -174,8 +174,8 @@ Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true ``` """ function ptrace(QO::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, sel::Vector{T2}) where - {T1,T2<:Integer} - +{T1,T2<:Integer} + length(QO.dims) == 1 && return QO ρtr, dkeep = _ptrace_ket(QO.data, QO.dims, sel) @@ -185,8 +185,8 @@ end ptrace(QO::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, sel::Vector{T2}) where {T1,T2<:Integer} = ptrace(QO', sel) function ptrace(QO::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, sel::Vector{T2}) where - {T1,T2<:Integer} - +{T1,T2<:Integer} + length(QO.dims) == 1 && return QO ρtr, dkeep = _ptrace_oper(QO.data, QO.dims, sel) @@ -241,7 +241,7 @@ julia> entropy_vn(ρ, base=2) function entropy_vn(ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}; base::Int=0, tol::Real=1e-15) where {T} vals = eigvals(ρ) indexes = abs.(vals) .> tol - 1 ∉ indexes && return 0 + 1 ∉ indexes && return 0 nzvals = vals[indexes] logvals = base != 0 ? log.(base, Complex.(nzvals)) : log.(Complex.(nzvals)) return -real(sum(nzvals .* logvals)) @@ -308,10 +308,10 @@ It returns both ``\alpha`` and the state ``\ket{\delta_\psi} = \exp ( \bar{\alpha} \hat{a} - \alpha \hat{a}^\dagger )``. The latter corresponds to the quantum fulctuations around the coherent state ``\ket{\alpha}``. """ -function get_coherence(ψ::QuantumObject{<:AbstractArray{T}, StateOpType}) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - a = destroy(size(ψ,1)) +function get_coherence(ψ::QuantumObject{<:AbstractArray{T},StateOpType}) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} + a = destroy(size(ψ, 1)) α = expect(a, ψ) - D = exp(α*a' - conj(α)*a) + D = exp(α * a' - conj(α) * a) α, D' * ψ end @@ -339,8 +339,8 @@ Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref). tracedist(ρ::QuantumObject{<:AbstractArray{T1},ObjType1}, σ::QuantumObject{<:AbstractArray{T2},ObjType2}) where {T1,T2,ObjType1<:Union{KetQuantumObject,OperatorQuantumObject},ObjType2<:Union{KetQuantumObject,OperatorQuantumObject}} = norm(ket2dm(ρ) - ket2dm(σ), 1) / 2 function _ptrace_ket(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector{T2}) where - {T1,T2<:Integer} - +{T1,T2<:Integer} + rd = dims nd = length(rd) @@ -351,7 +351,7 @@ function _ptrace_ket(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector dtrace = @view(rd[qtrace]) vmat = reshape(QO, reverse(rd)...) - topermute = nd+1 .- vcat(sel, qtrace) + topermute = nd + 1 .- vcat(sel, qtrace) vmat = PermutedDimsArray(vmat, topermute) vmat = reshape(vmat, prod(dkeep), prod(dtrace)) @@ -359,8 +359,8 @@ function _ptrace_ket(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector end function _ptrace_oper(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector{T2}) where - {T1,T2<:Integer} - +{T1,T2<:Integer} + rd = dims nd = length(rd) @@ -371,47 +371,47 @@ function _ptrace_oper(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vecto dtrace = @view(rd[qtrace]) ρmat = reshape(QO, reverse!(repeat(rd, 2))...) - topermute = 2*nd+1 .- vcat(qtrace, qtrace .+ nd, sel, sel .+ nd) + topermute = 2 * nd + 1 .- vcat(qtrace, qtrace .+ nd, sel, sel .+ nd) reverse!(topermute) ρmat = PermutedDimsArray(ρmat, topermute) ## TODO: Check if it works always - + # ρmat = row_major_reshape(ρmat, prod(dtrace), prod(dtrace), prod(dkeep), prod(dkeep)) # res = dropdims(mapslices(tr, ρmat, dims=(1,2)), dims=(1,2)) ρmat = reshape(ρmat, prod(dkeep), prod(dkeep), prod(dtrace), prod(dtrace)) - res = dropdims(mapslices(tr, ρmat, dims=(3,4)), dims=(3,4)) + res = dropdims(mapslices(tr, ρmat, dims=(3, 4)), dims=(3, 4)) return res, dkeep end -function mat2vec(::Type{M}) where M <: DenseMatrix +function mat2vec(::Type{M}) where {M<:DenseMatrix} T = hasproperty(M, :body) ? M.body : M par = T.parameters npar = length(par) (2 ≤ npar ≤ 3) || error("Type $M is not supported.") if npar == 2 - S = T.name.wrapper{par[1], 1} + S = T.name.wrapper{par[1],1} else - S = T.name.wrapper{par[1], 1, par[3]} + S = T.name.wrapper{par[1],1,par[3]} end return S end -function mat2vec(::Type{M}) where M <: SparseMatrixCSC +function mat2vec(::Type{M}) where {M<:SparseMatrixCSC} T = M par = T.parameters npar = length(par) (2 == npar) || error("Type $M is not supported.") - return SparseVector{par[1], par[2]} + return SparseVector{par[1],par[2]} end -function mat2vec(::Type{M}) where M <: Union{Adjoint{<:BlasFloat,<:SparseMatrixCSC}, Transpose{<:BlasFloat,<:SparseMatrixCSC}} +function mat2vec(::Type{M}) where {M<:Union{Adjoint{<:BlasFloat,<:SparseMatrixCSC},Transpose{<:BlasFloat,<:SparseMatrixCSC}}} T = M.parameters[2] par = T.parameters npar = length(par) (2 == npar) || error("Type $M is not supported.") - return SparseVector{par[1], par[2]} + return SparseVector{par[1],par[2]} end @doc raw""" diff --git a/src/negativity.jl b/src/negativity.jl index f58223b4..fa384c4a 100644 --- a/src/negativity.jl +++ b/src/negativity.jl @@ -68,25 +68,25 @@ 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{T, OperatorQuantumObject}, mask::Vector{Bool}) where T - if length(mask) != length(ρ.dims) +function partial_transpose(ρ::QuantumObject{T,OperatorQuantumObject}, mask::Vector{Bool}) where {T} + if length(mask) != length(ρ.dims) error("The length of \`mask\` should be equal to the length of \`ρ.dims\`.") end return _partial_transpose(ρ, mask) end # for dense matrices -function _partial_transpose(ρ::QuantumObject{<:AbstractArray, OperatorQuantumObject}, mask::Vector{Bool}) +function _partial_transpose(ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject}, mask::Vector{Bool}) mask2 = [1 + Int(i) for i in mask] # mask2 has elements with values equal to 1 or 2 # 1 - the subsystem don't need to be transposed # 2 - the subsystem need be transposed nsys = length(mask2) - pt_dims = reshape(Vector(1:(2 * nsys)), (nsys, 2)) - pt_idx = [ - [pt_dims[n, mask2[n]] for n in 1:nsys]; # origin value in mask2 - [pt_dims[n, 3 - mask2[n]] for n in 1:nsys] # opposite value in mask2 (1 -> 2, and 2 -> 1) + pt_dims = reshape(Vector(1:(2*nsys)), (nsys, 2)) + pt_idx = [ + [pt_dims[n, mask2[n]] for n in 1:nsys]; # origin value in mask2 + [pt_dims[n, 3-mask2[n]] for n in 1:nsys] # opposite value in mask2 (1 -> 2, and 2 -> 1) ] return QuantumObject( reshape(permutedims(reshape(ρ.data, (ρ.dims..., ρ.dims...)), pt_idx), size(ρ)), @@ -96,12 +96,12 @@ function _partial_transpose(ρ::QuantumObject{<:AbstractArray, OperatorQuantumOb end # for sparse matrices -function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray, OperatorQuantumObject}, mask::Vector{Bool}) +function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray,OperatorQuantumObject}, mask::Vector{Bool}) M, N = size(ρ) dimsTuple = Tuple(ρ.dims) colptr = ρ.data.colptr rowval = ρ.data.rowval - nzval = ρ.data.nzval + nzval = ρ.data.nzval len = length(nzval) # for partial transposed data @@ -110,8 +110,8 @@ function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray, OperatorQua V_pt = Vector{eltype(ρ)}(undef, len) n = 0 - for j in 1:(length(colptr) - 1) - for p in colptr[j]:(colptr[j + 1] - 1) + for j in 1:(length(colptr)-1) + for p in colptr[j]:(colptr[j+1]-1) n += 1 i = rowval[p] if i == j diff --git a/src/permutation.jl b/src/permutation.jl index 2cf88ffb..91c0e8ee 100644 --- a/src/permutation.jl +++ b/src/permutation.jl @@ -7,11 +7,11 @@ function bdf(A::SparseMatrixCSC{T,M}) where {T,M} idxs = connected_components(G) P = sparse(1:n, reduce(vcat, idxs), ones(n), n, n) block_sizes = map(length, idxs) - + P, P * A * P', block_sizes end -function bdf(A::QuantumObject{SparseMatrixCSC{T,M},OpType}) where {T,M,OpType<:Union{OperatorQuantumObject, SuperOperatorQuantumObject}} +function bdf(A::QuantumObject{SparseMatrixCSC{T,M},OpType}) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} P, A_bd, block_sizes = bdf(A.data) P, QuantumObject(A_bd, A.type, A.dims), block_sizes end @@ -19,15 +19,15 @@ end function get_bdf_blocks(A::SparseMatrixCSC{T,M}, block_sizes::Vector{Int}) where {T,M} num_blocks = length(block_sizes) block_indices = M[1] - block_list = [A[1:block_sizes[1],1:block_sizes[1]]] + block_list = [A[1:block_sizes[1], 1:block_sizes[1]]] for i in 2:num_blocks idx = sum(view(block_sizes, 1:i-1)) + 1 push!(block_indices, idx) - push!(block_list, A[idx:idx-1+block_sizes[i],idx:idx-1+block_sizes[i]]) + push!(block_list, A[idx:idx-1+block_sizes[i], idx:idx-1+block_sizes[i]]) end block_list, block_indices end -function get_bdf_blocks(A::QuantumObject{SparseMatrixCSC{T,M},OpType}, block_sizes::Vector{Int}) where {T,M,OpType<:Union{OperatorQuantumObject, SuperOperatorQuantumObject}} +function get_bdf_blocks(A::QuantumObject{SparseMatrixCSC{T,M},OpType}, block_sizes::Vector{Int}) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} get_bdf_blocks(A.data, block_sizes) end \ No newline at end of file diff --git a/src/progress_bar.jl b/src/progress_bar.jl index 4de7bd17..dce1a625 100644 --- a/src/progress_bar.jl +++ b/src/progress_bar.jl @@ -1,6 +1,6 @@ export ProgressBar, next! -mutable struct ProgressBar{CT,T1<:Integer, T2<:Real} +mutable struct ProgressBar{CT,T1<:Integer,T2<:Real} counter::CT max_counts::T1 enable::Bool @@ -23,7 +23,7 @@ function next!(p::ProgressBar, io::IO=stdout) max_counts = p.max_counts bar_width = p.bar_width start_time = p.start_time - + percentage = counter / max_counts percentage_100 = lpad(round(100 * percentage, digits=1), 5, " ") progress = floor(Int, bar_width * percentage) diff --git a/src/quantum_object.jl b/src/quantum_object.jl index 55b0b949..94734736 100644 --- a/src/quantum_object.jl +++ b/src/quantum_object.jl @@ -129,7 +129,7 @@ struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType} <: AbstractQu dims::Vector{Int} end -function QuantumObject(A::AbstractArray{T, N}; type::ObjType=nothing, dims=nothing) where {T,N,ObjType<:Union{Nothing,QuantumObjectType}} +function QuantumObject(A::AbstractArray{T,N}; type::ObjType=nothing, dims=nothing) where {T,N,ObjType<:Union{Nothing,QuantumObjectType}} # only accept 1D- and 2D-array if N == 1 @@ -153,7 +153,7 @@ function QuantumObject(A::AbstractArray{T, N}; type::ObjType=nothing, dims=nothi end # decide dims from the size of A and the given type - if dims === nothing + if dims === nothing if (type isa KetQuantumObject) || (type isa OperatorQuantumObject) dims = [Size[1]] elseif (type isa SuperOperatorQuantumObject) || (type isa OperatorKetQuantumObject) @@ -409,8 +409,8 @@ LinearAlgebra.:(^)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T, QuantumObject(^(A.data, n), OpType(), A.dims) LinearAlgebra.:(/)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} = QuantumObject(/(A.data, n), OpType(), A.dims) -function LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where -{T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} +function LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where +{T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) LinearAlgebra.dot(A.data, B.data) diff --git a/src/quantum_operators.jl b/src/quantum_operators.jl index b0649e7e..c336bd8d 100644 --- a/src/quantum_operators.jl +++ b/src/quantum_operators.jl @@ -16,7 +16,7 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{O}\right) \boldsymbol{\cdot} = The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -spre(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O,1))) where {T} = +spre(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O, 1))) where {T} = QuantumObject(kron(Id_cache, O.data), SuperOperator, O.dims) @doc raw""" @@ -31,7 +31,7 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{O}\right) \boldsymbol{\cdot} = The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -spost(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O,1))) where {T} = +spost(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O, 1))) where {T} = QuantumObject(kron(sparse(transpose(sparse(O.data))), Id_cache), SuperOperator, O.dims) # TODO: fix the sparse conversion @doc raw""" @@ -44,7 +44,7 @@ Since the density matrix is vectorized, this super-operator is always a matrix, obtained from ``\mathcal{O} \left(\hat{A}, \hat{B}\right) \boldsymbol{\cdot} = \text{spre}(A) * \text{spost}(B)``. """ sprepost(A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} = QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperator, A.dims) # TODO: fix the sparse conversion + B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} = QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperator, A.dims) # TODO: fix the sparse conversion @doc raw""" lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1)) @@ -59,7 +59,7 @@ considering the density matrix ``\hat{\rho}`` in the vectorized form. The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -function lindblad_dissipator(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O,1))) where {T} +function lindblad_dissipator(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O, 1))) where {T} Od_O = O' * O return sprepost(O, O') - spre(Od_O, Id_cache) / 2 - spost(Od_O, Id_cache) / 2 end @@ -155,16 +155,16 @@ sigmaz() = sigmap() * sigmam() - sigmam() * sigmap() Identity operator ``\hat{\mathbb{1}}`` with Hilbert dimension `N`. """ -eye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where - {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(Diagonal(ones(ComplexF64, N)), type, dims) +eye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where +{ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(Diagonal(ones(ComplexF64, N)), type, dims) @doc raw""" qeye(N::Int; type=OperatorQuantumObject, dims=[N]) Identity operator ``\hat{\mathbb{1}}`` with Hilbert dimension `N`. """ -qeye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where - {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eye(N, type=type, dims=dims) +qeye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where +{ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eye(N, type=type, dims=dims) @doc raw""" fock(N::Int, pos::Int; dims::Vector{Int}=[N], sparse::Bool=false) @@ -174,7 +174,7 @@ to specify the list of dimensions `dims` if different subsystems are present. """ function fock(N::Int, pos::Int; dims::Vector{Int}=[N], sparse::Bool=false) if sparse - return QuantumObject(sparsevec([pos+1], [1.0+0im], N), Ket, dims) + return QuantumObject(sparsevec([pos + 1], [1.0 + 0im], N), Ket, dims) else array = zeros(ComplexF64, N) array[pos+1] = 1 @@ -218,7 +218,7 @@ end Generates the projection operator ``\hat{O} = \dyad{i}{j}`` with Hilbert space dimension `N`. """ -projection(N::Int, i::Int, j::Int) = QuantumObject(sparse([i+1],[j+1],[1.0+0.0im], N, N)) +projection(N::Int, i::Int, j::Int) = QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N)) @doc raw""" sinm(O::QuantumObject) diff --git a/src/spin_lattice.jl b/src/spin_lattice.jl index 6a5f9f9d..7eb06c39 100644 --- a/src/spin_lattice.jl +++ b/src/spin_lattice.jl @@ -3,59 +3,59 @@ export Lattice, mb, TFIM, nn, sx, sy, sz, sm, sp, pbc, obc sx = sigmax() sy = -sigmay() sz = -sigmaz() -sm = (sx - 1im*sy)/2 -sp = (sx + 1im*sy)/2 +sm = (sx - 1im * sy) / 2 +sp = (sx + 1im * sy) / 2 #Lattice structure -Base.@kwdef struct Lattice{TN<:Integer, TLI<:LinearIndices, TCI<:CartesianIndices} +Base.@kwdef struct Lattice{TN<:Integer,TLI<:LinearIndices,TCI<:CartesianIndices} Nx::TN Ny::TN - N::TN = Nx*Ny - lin_idx::TLI = LinearIndices((Nx,Ny)) - car_idx::TCI = CartesianIndices((Nx,Ny)) + N::TN = Nx * Ny + lin_idx::TLI = LinearIndices((Nx, Ny)) + car_idx::TCI = CartesianIndices((Nx, Ny)) end #Definition of many-body operators function mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, i::Integer, N::Integer) where {T1} T = s.dims[1] - QuantumObject(kron(eye(T^(i-1)), s, eye(T^(N-i))); dims=fill(2, N)) + QuantumObject(kron(eye(T^(i - 1)), s, eye(T^(N - i))); dims=fill(2, N)) end mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, i::Integer, latt::Lattice) where {T1} = mb(s, i, latt.N) -mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, row::Integer, col::Integer, latt::Lattice) where {T1} = mb(s, latt.idx[row,col], latt.N) +mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, row::Integer, col::Integer, latt::Lattice) where {T1} = mb(s, latt.idx[row, col], latt.N) mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, x::CartesianIndex, latt::Lattice) where {T1} = mb(s, latt.idx[x], latt.N) #Definition of nearest-neighbour sites on lattice -pbc(i::Integer, N::Integer) = 1 + (i - 1 +N) % N -obc(i::Integer, N::Integer) = (i>=1 && i<=N) +pbc(i::Integer, N::Integer) = 1 + (i - 1 + N) % N +obc(i::Integer, N::Integer) = (i >= 1 && i <= N) pbc(i::Vector{Int}, N::Integer) = pbc.(i, N) -obc(i::Vector{Int}, N::Integer) = filter(x->obc(x,N), i) +obc(i::Vector{Int}, N::Integer) = filter(x -> obc(x, N), i) function nn(i::CartesianIndex, latt::Lattice, bc::Function; order::Integer=1) - row = bc([i[1]+order, i[1]-order], latt.Nx) - col = bc([i[2]+order, i[2]-order], latt.Ny) - vcat([CartesianIndex(r,i[2]) for r in row],[CartesianIndex(i[1],c) for c in col]) + row = bc([i[1] + order, i[1] - order], latt.Nx) + col = bc([i[2] + order, i[2] - order], latt.Ny) + vcat([CartesianIndex(r, i[2]) for r in row], [CartesianIndex(i[1], c) for c in col]) end function TFIM(Jx::Real, Jy::Real, Jz::Real, hx::Real, γ::Real, latt::Lattice; bc::Function=pbc, order::Integer=1) S = [mb(sm, i, latt) for i in 1:latt.N] - c_ops = sqrt(γ).*S - - op_sum(S::Vector{QuantumObject{SparseMatrixCSC{ComplexF64, Int64}, OperatorQuantumObject}}, i::CartesianIndex) = S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nn(i,latt,bc;order=order)]]) - + c_ops = sqrt(γ) .* S + + op_sum(S::Vector{QuantumObject{SparseMatrixCSC{ComplexF64,Int64},OperatorQuantumObject}}, i::CartesianIndex) = S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nn(i, latt, bc; order=order)]]) + H = 0 - if (Jx!=0 || hx!=0) + if (Jx != 0 || hx != 0) S .= [mb(sx, i, latt) for i in 1:latt.N] - H+= Jx/2 * mapreduce(i->op_sum(S, i), +, latt.car_idx) #/2 because we are double counting - H+= hx * sum(S) + H += Jx / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx) #/2 because we are double counting + H += hx * sum(S) end - if Jy!=0 + if Jy != 0 S .= [mb(sy, i, latt) for i in 1:latt.N] - H+= Jy/2 * mapreduce(i->op_sum(S, i), +, latt.car_idx) + H += Jy / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx) end - if Jz!=0 + if Jz != 0 S .= [mb(sz, i, latt) for i in 1:latt.N] - H+= Jz/2 * mapreduce(i->op_sum(S, i), +, latt.car_idx) + H += Jz / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx) end H, c_ops end; diff --git a/src/time_evolution/lr_mesolve.jl b/src/time_evolution/lr_mesolve.jl index 8068b770..1615b7f0 100644 --- a/src/time_evolution/lr_mesolve.jl +++ b/src/time_evolution/lr_mesolve.jl @@ -4,7 +4,7 @@ export lr_mesolve, lr_mesolveProblem, LRTimeEvolutionSol, LRMesolveOptions # STRUCT DEFINITIONS #=======================================================# -struct LRTimeEvolutionSol{TT<:Vector{<:Real}, TS<:AbstractVector, TE<:Matrix{ComplexF64}, TM<:Vector{<:Integer}} +struct LRTimeEvolutionSol{TT<:Vector{<:Real},TS<:AbstractVector,TE<:Matrix{ComplexF64},TM<:Vector{<:Integer}} times::TT z::TS B::TS @@ -27,17 +27,17 @@ struct LRMesolveOptions{AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} end function LRMesolveOptions(; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - progress::Bool=true, - err_max::Real=0., - p0::Real=0., - atol_inv::Real=1e-4, - M_max::Integer=typemax(Int), - compute_Si::Bool=true, - _is_dynamical::Bool=err_max>0, - adj_condition::String="variational", - Δt::Real=0. - ) + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), + progress::Bool=true, + err_max::Real=0.0, + p0::Real=0.0, + atol_inv::Real=1e-4, + M_max::Integer=typemax(Int), + compute_Si::Bool=true, + _is_dynamical::Bool=err_max > 0, + adj_condition::String="variational", + Δt::Real=0.0 +) return LRMesolveOptions{typeof(alg)}(alg, progress, err_max, p0, atol_inv, M_max, compute_Si, _is_dynamical, adj_condition, Δt) end @@ -46,7 +46,7 @@ end # ADDITIONAL FUNCTIONS #=======================================================# -select(x::Real, xarr::AbstractArray, retval=false) = retval ? xarr[argmin(abs.(x .-xarr))] : argmin(abs.(x .-xarr)) +select(x::Real, xarr::AbstractArray, retval=false) = retval ? xarr[argmin(abs.(x .- xarr))] : argmin(abs.(x .- xarr)) """ _pinv!(A, T1, T2; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T @@ -65,19 +65,19 @@ select(x::Real, xarr::AbstractArray, retval=false) = retval ? xarr[argmin(abs.(x Absolute tolerance for the calculation of the pseudo-inverse. rtol : Real Relative tolerance for the calculation of the pseudo-inverse. -""" -function _pinv!(A::AbstractMatrix{T}, T1::AbstractMatrix{T}, T2::AbstractMatrix{T}; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T +""" +function _pinv!(A::AbstractMatrix{T}, T1::AbstractMatrix{T}, T2::AbstractMatrix{T}; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T)))) * min(size(A)...)) * iszero(atol)) where {T} if isdiag(A) - idxA = diagind(A) - diagA = view(A, idxA) + idxA = diagind(A) + diagA = view(A, idxA) maxabsA = maximum(abs, diagA) - λ = max(rtol * maxabsA, atol) - return Matrix(Diagonal( pinv.(diagA) .* 1 ./(1 .+(λ./real(diagA)).^6) )) + λ = max(rtol * maxabsA, atol) + return Matrix(Diagonal(pinv.(diagA) .* 1 ./ (1 .+ (λ ./ real(diagA)) .^ 6))) end SVD = svd(A) λ = max(rtol * maximum(SVD.S), atol) - SVD.S .= pinv.(SVD.S) .* 1 ./(1 .+(λ./SVD.S).^6) + SVD.S .= pinv.(SVD.S) .* 1 ./ (1 .+ (λ ./ SVD.S) .^ 6) mul!(T2, Diagonal(SVD.S), SVD.U') mul!(T1, SVD.Vt', T2) end @@ -99,25 +99,25 @@ end idx : Integer The index of the current time step. """ -function _calculate_expectation!(p,z,B,idx) - e_ops = p.e_ops - f_ops = p.f_ops - expvals = p.expvals - funvals = p.funvals +function _calculate_expectation!(p, z, B, idx) + e_ops = p.e_ops + f_ops = p.f_ops + expvals = p.expvals + funvals = p.funvals p.Ml[idx] = p.M #Expectation values - Oz = p.A0 + Oz = p.A0 zOz = p.temp_MM - @inbounds for (i,e) in enumerate(e_ops) + @inbounds for (i, e) in enumerate(e_ops) mul!(Oz, e, z) mul!(zOz, z', Oz) - expvals[i,idx] = dot(B,zOz) + expvals[i, idx] = dot(B, zOz) end - + #Function values - @inbounds for (i,f) in enumerate(f_ops) - funvals[i,idx] = f(p,z,B) + @inbounds for (i, f) in enumerate(f_ops) + funvals[i, idx] = f(p, z, B) end end @@ -138,15 +138,15 @@ function _save_control_lr_mesolve(u, t, integrator) end function _save_affect_lr_mesolve!(integrator) - ip = integrator.p - N,M = ip.N, ip.M + ip = integrator.p + N, M = ip.N, ip.M idx = select(integrator.t, ip.t_l) @views z = reshape(integrator.u[1:N*M], N, M) @views B = reshape(integrator.u[N*M+1:end], M, M) - _calculate_expectation!(ip,z,B,idx) + _calculate_expectation!(ip, z, B, idx) - if integrator.p.opt.progress + if integrator.p.opt.progress print("\rProgress: $(round(Int, 100*idx/length(ip.t_l)))%") flush(stdout) end @@ -173,9 +173,9 @@ end The integrator of the problem. """ function _adjM_condition_ratio(u, t, integrator) - ip = integrator.p + ip = integrator.p opt = ip.opt - N,M = ip.N, ip.M + N, M = ip.N, ip.M C = ip.A0 σ = ip.temp_MM @@ -184,9 +184,9 @@ function _adjM_condition_ratio(u, t, integrator) mul!(C, z, sqrt(B)) mul!(σ, C', C) p = abs.(eigvals(σ)) - err = p[1]/p[end] + err = p[1] / p[end] - (err>=opt.err_max && M= opt.err_max && M < N && M < opt.M_max) end """ @@ -203,12 +203,12 @@ end The integrator of the problem. """ function _adjM_condition_variational(u, t, integrator) - ip = integrator.p + ip = integrator.p opt = ip.opt - N,M = ip.N, ip.M - err = abs(ip.scalars[1]*sqrt(ip.M)) + N, M = ip.N, ip.M + err = abs(ip.scalars[1] * sqrt(ip.M)) - (err>=opt.err_max && M= opt.err_max && M < N && M < opt.M_max) end """ @@ -222,34 +222,34 @@ end The integrator of the problem. """ function _adjM_affect!(integrator) - ip = integrator.p + ip = integrator.p opt = ip.opt - Δt = opt.Δt - N,M = ip.N, ip.M + Δt = opt.Δt + N, M = ip.N, ip.M @views begin - z = Δt>0 ? reshape(ip.u_save[1:N*M], N, M) : reshape(integrator.u[1:N*M], N, M) - B = Δt>0 ? reshape(ip.u_save[N*M+1:end], M, M) : reshape(integrator.u[N*M+1:end], M, M) - ψ = ip.L_tilde[:,1] + z = Δt > 0 ? reshape(ip.u_save[1:N*M], N, M) : reshape(integrator.u[1:N*M], N, M) + B = Δt > 0 ? reshape(ip.u_save[N*M+1:end], M, M) : reshape(integrator.u[N*M+1:end], M, M) + ψ = ip.L_tilde[:, 1] normalize!(ψ) z = hcat(z, ψ) - B = cat(B, opt.p0, dims=(1,2)) - resize!(integrator, length(z)+length(B)) - integrator.u[1:length(z)] .= z[:] + B = cat(B, opt.p0, dims=(1, 2)) + resize!(integrator, length(z) + length(B)) + integrator.u[1:length(z)] .= z[:] integrator.u[length(z)+1:end] .= B[:] end - integrator.p = merge(integrator.p, ( M=ip.M+1, L_tilde=similar(z), A0=similar(z), Bi=similar(B), L=similar(B), temp_MM=similar(B), S=similar(B), Si=similar(B), )) + integrator.p = merge(integrator.p, (M=ip.M + 1, L_tilde=similar(z), A0=similar(z), Bi=similar(B), L=similar(B), temp_MM=similar(B), S=similar(B), Si=similar(B),)) mul!(integrator.p.S, z', z) !(opt.compute_Si) && (integrator.p.Si .= _pinv!(Hermitian(integrator.p.S), integrator.temp_MM, integrator.L, atol=opt.atol_inv)) - if Δt>0 + if Δt > 0 integrator.p = merge(integrator.p, (u_save=copy(integrator.u),)) - t0 = ip.scalars[2] + t0 = ip.scalars[2] reinit!(integrator, integrator.u; t0=t0, erase_sol=false) - - if length(integrator.sol.t)>1 + + if length(integrator.sol.t) > 1 idx = findlast(integrator.sol.t .<= t0) resize!(integrator.sol.t, idx) resize!(integrator.sol.u, idx) @@ -287,24 +287,24 @@ function dBdz!(du, u, p, t) Bi, L, temp_MM, S, Si = p.Bi, p.L, p.temp_MM, p.S, p.Si #Get z, B, dz, and dB by reshaping u - N,M = p.N, p.M + N, M = p.N, p.M opt = p.opt - @views z = reshape(u[1:N*M], N, M) + @views z = reshape(u[1:N*M], N, M) @views dz = reshape(du[1:N*M], N, M) - @views B = reshape(u[N*M+1:end], M, M) + @views B = reshape(u[N*M+1:end], M, M) @views dB = reshape(du[N*M+1:end], M, M) #Assign A0 and S - mul!(S,z',z) - B .= (B+B')/2 + mul!(S, z', z) + B .= (B + B') / 2 mul!(temp_MM, S, B) B .= B ./ tr(temp_MM) - mul!(A0,z,B) + mul!(A0, z, B) # Calculate inverse opt.compute_Si && (Si .= _pinv!(Hermitian(S), temp_MM, L, atol=opt.atol_inv)) - Bi .= _pinv!(Hermitian(B), temp_MM, L, atol=opt.atol_inv) + Bi .= _pinv!(Hermitian(B), temp_MM, L, atol=opt.atol_inv) # Calculate the effective Hamiltonian part of L_tilde mul!(dz, H, A0) @@ -319,20 +319,20 @@ function dBdz!(du, u, p, t) mul!(temp_MM, B, L) mul!(L_tilde, dz, temp_MM, 1, 1) end - + # Calculate L mul!(L, z', L_tilde) mul!(temp_MM, Si, L) - p.scalars[1] = real(tr(temp_MM)/M) + p.scalars[1] = real(tr(temp_MM) / M) # Calculate dz mul!(L_tilde, z, temp_MM, -1, 1) #Ltilde is now (Ltilde - z*Si*L) - mul!(dB, Si, Bi) + mul!(dB, Si, Bi) mul!(dz, L_tilde, dB) # Calculate dB mul!(dB, temp_MM, Si) - temp_MM.=Si + temp_MM .= Si lmul!(p.scalars[1], temp_MM) dB .-= temp_MM end @@ -367,68 +367,68 @@ end kwargs : NamedTuple Additional keyword arguments for the ODEProblem. """ -function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2, 2}, B::AbstractArray{T2, 2}, t_l::AbstractVector, c_ops::AbstractVector=[]; +function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2,2}, B::AbstractArray{T2,2}, t_l::AbstractVector, c_ops::AbstractVector=[]; e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} - + # Formulation of problem - H -= 0.5im*sum([Γ'*Γ for Γ in c_ops]) - H = get_data(H) + H -= 0.5im * sum([Γ' * Γ for Γ in c_ops]) + H = get_data(H) c_ops = get_data.(c_ops) e_ops = get_data.(e_ops) - + # Initialization of Arrays expvals = Array{ComplexF64}(undef, length(e_ops), length(t_l)) funvals = Array{ComplexF64}(undef, length(f_ops), length(t_l)) - Ml = Array{Int64}(undef, length(t_l)) + Ml = Array{Int64}(undef, length(t_l)) # Initialization of parameters. Scalars represents in order: Tr(S^{-1}L), t0 - p = (N=size(z,1), M=size(z,2), H=H, Γ=c_ops, e_ops=e_ops, f_ops=f_ops, opt=opt, t_l=t_l, - expvals=expvals, funvals=funvals, Ml=Ml, - L_tilde=similar(z), A0=similar(z), Bi=similar(B), L=similar(B), temp_MM=similar(B), S=similar(B), Si=similar(B), - u_save=vcat(vec(z), vec(B)), scalars=[0.,t_l[1]],) - - mul!(p.S,z',z) + p = (N=size(z, 1), M=size(z, 2), H=H, Γ=c_ops, e_ops=e_ops, f_ops=f_ops, opt=opt, t_l=t_l, + expvals=expvals, funvals=funvals, Ml=Ml, + L_tilde=similar(z), A0=similar(z), Bi=similar(B), L=similar(B), temp_MM=similar(B), S=similar(B), Si=similar(B), + u_save=vcat(vec(z), vec(B)), scalars=[0.0, t_l[1]],) + + mul!(p.S, z', z) p.Si .= pinv(Hermitian(p.S), atol=opt.atol_inv) - + # Initialization of Callbacks kwargs2 = kwargs if !isempty(e_ops) || !isempty(f_ops) - _calculate_expectation!(p,z,B,1) - cb_save = DiscreteCallback(_save_control_lr_mesolve, _save_affect_lr_mesolve!, save_positions=(false,false)) + _calculate_expectation!(p, z, B, 1) + cb_save = DiscreteCallback(_save_control_lr_mesolve, _save_affect_lr_mesolve!, save_positions=(false, false)) kwargs2 = merge(kwargs2, haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_save, kwargs2[:callback])) : Dict(:callback => cb_save)) end if opt.is_dynamical - if opt.Δt>0 + if opt.Δt > 0 cb_periodicsave = PeriodicCallback(_periodicsave_func, opt.Δt, final_affect=true, save_positions=(false, false)) kwargs2 = merge(kwargs2, haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_periodicsave, kwargs2[:callback])) : Dict(:callback => cb_periodicsave)) end - if opt.adj_condition=="variational" + if opt.adj_condition == "variational" adj_condition_function = _adjM_condition_variational - elseif opt.adj_condition=="ratio" + elseif opt.adj_condition == "ratio" adj_condition_function = _adjM_condition_ratio else error("adj_condition must be either 'variational' or 'ratio'") end - cb_adjM = DiscreteCallback(adj_condition_function, _adjM_affect!, save_positions=(false,false)) + cb_adjM = DiscreteCallback(adj_condition_function, _adjM_affect!, save_positions=(false, false)) kwargs2 = merge(kwargs2, haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_adjM, kwargs2[:callback])) : Dict(:callback => cb_adjM)) end - + # Initialization of ODEProblem's kwargs !haskey(kwargs2, :abstol) && (kwargs2 = merge(kwargs2, Dict(:abstol => 1e-7))) !haskey(kwargs2, :reltol) && (kwargs2 = merge(kwargs2, Dict(:reltol => 1e-5))) !haskey(kwargs2, :saveat) && (kwargs2 = merge(kwargs2, Dict(:saveat => [t_l[end]]))) - + # Initialization of ODEProblem tspan = (t_l[1], t_l[end]) return ODEProblem(dBdz!, p.u_save, tspan, p; kwargs2...) - end +end -function lr_mesolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2, 2}, B::AbstractArray{T2, 2}, t_l::AbstractVector, c_ops::AbstractVector=[]; +function lr_mesolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2,2}, B::AbstractArray{T2,2}, t_l::AbstractVector, c_ops::AbstractVector=[]; e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} - - prob = lr_mesolveProblem(H, z, B, t_l, c_ops; e_ops=e_ops, f_ops=f_ops, opt=opt, kwargs...); + + prob = lr_mesolveProblem(H, z, B, t_l, c_ops; e_ops=e_ops, f_ops=f_ops, opt=opt, kwargs...) return lr_mesolve(prob; kwargs...) end @@ -438,11 +438,11 @@ end #=======================================================# function get_z(u::AbstractArray{T}, N::Integer, M::Integer) where {T} - reshape(view(u,1:M*N), N,M) + reshape(view(u, 1:M*N), N, M) end function get_B(u::AbstractArray{T}, N::Integer, M::Integer) where {T} - reshape(view(u,(M*N+1):length(u)), M,M) + reshape(view(u, (M*N+1):length(u)), M, M) end """ @@ -460,16 +460,16 @@ function lr_mesolve(prob::ODEProblem; kwargs...) sol = solve(prob, prob.p.opt.alg, tstops=prob.p.t_l) prob.p.opt.progress && print("\n") - N = prob.p.N - Ll = length.(sol.u) - Ml = @. Int((sqrt(N^2+4*Ll)-N)/2) + N = prob.p.N + Ll = length.(sol.u) + Ml = @. Int((sqrt(N^2 + 4 * Ll) - N) / 2) - if !haskey(kwargs, :save_idxs) - Bt = map(x -> get_B(x[1],N,x[2]), zip(sol.u,Ml)) - zt = map(x -> get_z(x[1],N,x[2]), zip(sol.u,Ml)) - else - Bt = get_B(sol.u,N,Ml) - zt = get_z(sol.u,N,Ml) + if !haskey(kwargs, :save_idxs) + Bt = map(x -> get_B(x[1], N, x[2]), zip(sol.u, Ml)) + zt = map(x -> get_z(x[1], N, x[2]), zip(sol.u, Ml)) + else + Bt = get_B(sol.u, N, Ml) + zt = get_z(sol.u, N, Ml) end return LRTimeEvolutionSol(sol.t, zt, Bt, prob.p.expvals, prob.p.funvals, prob.p.Ml) diff --git a/src/time_evolution/mcsolve.jl b/src/time_evolution/mcsolve.jl index 901286b6..4db42ceb 100644 --- a/src/time_evolution/mcsolve.jl +++ b/src/time_evolution/mcsolve.jl @@ -36,7 +36,7 @@ function LindbladJumpAffect!(integrator) weights_mc[i] = real(dot(cache_mc, cache_mc)) end cumsum!(cumsum_weights_mc, weights_mc) - collaps_idx = getindex(1:length(weights_mc), findfirst(>(rand()*sum(weights_mc)), cumsum_weights_mc)) + collaps_idx = getindex(1:length(weights_mc), findfirst(>(rand() * sum(weights_mc)), cumsum_weights_mc)) mul!(cache_mc, c_ops[collaps_idx], ψ) normalize!(cache_mc) copyto!(integrator.u, cache_mc) @@ -62,22 +62,22 @@ function _mcsolve_prob_func(prob, i, repeat) seeds = internal_params.seeds !isnothing(seeds) && Random.seed!(seeds[i]) - prm = merge(internal_params, (expvals = similar(internal_params.expvals), - cache_mc = similar(internal_params.cache_mc), weights_mc = similar(internal_params.weights_mc), - cumsum_weights_mc = similar(internal_params.weights_mc), random_n = Ref(rand()), progr_mc = ProgressBar(size(internal_params.expvals, 2), enable=false), jump_times_which_idx = Ref(1), - jump_times = similar(internal_params.jump_times), jump_which = similar(internal_params.jump_which))) + prm = merge(internal_params, (expvals=similar(internal_params.expvals), + cache_mc=similar(internal_params.cache_mc), weights_mc=similar(internal_params.weights_mc), + cumsum_weights_mc=similar(internal_params.weights_mc), random_n=Ref(rand()), progr_mc=ProgressBar(size(internal_params.expvals, 2), enable=false), jump_times_which_idx=Ref(1), + jump_times=similar(internal_params.jump_times), jump_which=similar(internal_params.jump_which))) remake(prob, p=prm) end function _mcsolve_output_func(sol, i) - resize!(sol.prob.p.jump_times, sol.prob.p.jump_times_which_idx[]-1) - resize!(sol.prob.p.jump_which, sol.prob.p.jump_times_which_idx[]-1) + resize!(sol.prob.p.jump_times, sol.prob.p.jump_times_which_idx[] - 1) + resize!(sol.prob.p.jump_which, sol.prob.p.jump_times_which_idx[] - 1) (sol, false) end function _mcsolve_generate_statistics(sol, i, times, states, expvals_all, jump_times, jump_which) - sol_i = sol[:,i] + sol_i = sol[:, i] sol_u = haskey(sol_i.prob.kwargs, :save_idxs) ? sol_i.u : [QuantumObject(sol_i.u[i], dims=sol_i.prob.p.Hdims) for i in 1:length(sol_i.u)] copyto!(view(expvals_all, i, :, :), sol_i.prob.p.expvals) @@ -123,12 +123,12 @@ time evolution of an open quantum system. function mcsolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[]; + c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[]; alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), - seeds::Union{Nothing, Vector{Int}}=nothing, + seeds::Union{Nothing,Vector{Int}}=nothing, jump_callback::TJC=ContinuousLindbladJumpCallback(), kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} @@ -148,14 +148,14 @@ function mcsolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, jump_times = Vector{Float64}(undef, jump_times_which_init_size) jump_which = Vector{Int16}(undef, jump_times_which_init_size) - params2 = (expvals = expvals, e_ops_mc = e_ops2, - is_empty_e_ops_mc = isempty(e_ops), - progr_mc = ProgressBar(length(t_l), enable=false), seeds = seeds, - random_n = Ref(rand()), c_ops = get_data.(c_ops), cache_mc = cache_mc, - weights_mc = weights_mc, cumsum_weights_mc = cumsum_weights_mc, - jump_times = jump_times, jump_which = jump_which, - jump_times_which_init_size=jump_times_which_init_size, - jump_times_which_idx = Ref(1), params...) + params2 = (expvals=expvals, e_ops_mc=e_ops2, + is_empty_e_ops_mc=isempty(e_ops), + progr_mc=ProgressBar(length(t_l), enable=false), seeds=seeds, + random_n=Ref(rand()), c_ops=get_data.(c_ops), cache_mc=cache_mc, + weights_mc=weights_mc, cumsum_weights_mc=cumsum_weights_mc, + jump_times=jump_times, jump_which=jump_which, + jump_times_which_init_size=jump_times_which_init_size, + jump_times_which_idx=Ref(1), params...) mcsolveProblem(H_eff, ψ0, t_l, alg, H_t, params2, jump_callback; kwargs...) end @@ -171,8 +171,8 @@ function mcsolveProblem(H_eff::QuantumObject{<:AbstractArray{T1},OperatorQuantum cb1 = DiscreteCallback(LindbladJumpDiscreteCondition, LindbladJumpAffect!, save_positions=(false, false)) cb2 = PresetTimeCallback(t_l, _save_func_mcsolve, save_positions=(false, false)) - kwargs2 = (;kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb1, cb2, kwargs2.callback),)) : merge(kwargs2, (callback = CallbackSet(cb1, cb2),)) + kwargs2 = (; kwargs...) + kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb1, cb2, kwargs2.callback),)) : merge(kwargs2, (callback=CallbackSet(cb1, cb2),)) sesolveProblem(H_eff, ψ0, t_l; alg=alg, H_t=H_t, params=params, kwargs2...) end @@ -187,10 +187,10 @@ function mcsolveProblem(H_eff::QuantumObject{<:AbstractArray{T1},OperatorQuantum kwargs...) where {T1,T2} cb1 = ContinuousCallback(LindbladJumpContinuousCondition, LindbladJumpAffect!, nothing, - interp_points=jump_callback.interp_points, save_positions=(false, false)) + interp_points=jump_callback.interp_points, save_positions=(false, false)) cb2 = PresetTimeCallback(t_l, _save_func_mcsolve, save_positions=(false, false)) - kwargs2 = (;kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb1, cb2, kwargs2.callback),)) : merge(kwargs2, (callback = CallbackSet(cb1, cb2),)) + kwargs2 = (; kwargs...) + kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb1, cb2, kwargs2.callback),)) : merge(kwargs2, (callback=CallbackSet(cb1, cb2),)) sesolveProblem(H_eff, ψ0, t_l; alg=alg, H_t=H_t, params=params, kwargs2...) end @@ -234,22 +234,22 @@ wave function time evolution. function mcsolveEnsembleProblem(H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[]; + c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[]; alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), jump_callback::TJC=ContinuousLindbladJumpCallback(), - seeds::Union{Nothing, Vector{Int}}=nothing, + seeds::Union{Nothing,Vector{Int}}=nothing, prob_func::Function=_mcsolve_prob_func, output_func::Function=_mcsolve_output_func, kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} - prob_mc = mcsolveProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, seeds=seeds, jump_callback=jump_callback, kwargs...) + prob_mc = mcsolveProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, + H_t=H_t, params=params, seeds=seeds, jump_callback=jump_callback, kwargs...) ensemble_prob = EnsembleProblem(prob_mc, prob_func=prob_func, - output_func=output_func, safetycopy=false) + output_func=output_func, safetycopy=false) return ensemble_prob end @@ -296,12 +296,12 @@ Time evolution of an open quantum system using quantum trajectories. function mcsolve(H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[]; + c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[]; alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), - seeds::Union{Nothing, Vector{Int}}=nothing, + seeds::Union{Nothing,Vector{Int}}=nothing, n_traj::Int=1, ensemble_method=EnsembleThreads(), jump_callback::TJC=ContinuousLindbladJumpCallback(), @@ -309,13 +309,13 @@ function mcsolve(H::QuantumObject{MT1,OperatorQuantumObject}, output_func::Function=_mcsolve_output_func, kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} - if !isnothing(seeds) && length(seeds)!=n_traj + if !isnothing(seeds) && length(seeds) != n_traj throw(ArgumentError("Length of seeds must match n_traj ($n_traj), but got $(length(seeds))")) - end + end - ens_prob_mc = mcsolveEnsembleProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, seeds=seeds, jump_callback=jump_callback, prob_func=prob_func, - output_func=output_func, kwargs...) + ens_prob_mc = mcsolveEnsembleProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, + H_t=H_t, params=params, seeds=seeds, jump_callback=jump_callback, prob_func=prob_func, + output_func=output_func, kwargs...) return mcsolve(ens_prob_mc; alg=alg, n_traj=n_traj, ensemble_method=ensemble_method, kwargs...) end @@ -328,9 +328,9 @@ function mcsolve(ens_prob_mc::EnsembleProblem; sol = solve(ens_prob_mc, alg, ensemble_method, trajectories=n_traj) - expvals_all = Array{ComplexF64}(undef, length(sol), size(sol[:,1].prob.p.expvals)...) + expvals_all = Array{ComplexF64}(undef, length(sol), size(sol[:, 1].prob.p.expvals)...) times = Vector{Vector{Float64}}(undef, length(sol)) - states = haskey(sol[:,1].prob.kwargs, :save_idxs) ? Vector{Vector{eltype(sol[:,1].u[1])}}(undef, length(sol)) : Vector{Vector{QuantumObject}}(undef, length(sol)) + states = haskey(sol[:, 1].prob.kwargs, :save_idxs) ? Vector{Vector{eltype(sol[:, 1].u[1])}}(undef, length(sol)) : Vector{Vector{QuantumObject}}(undef, length(sol)) jump_times = Vector{Vector{Float64}}(undef, length(sol)) jump_which = Vector{Vector{Int16}}(undef, length(sol)) diff --git a/src/time_evolution/mesolve.jl b/src/time_evolution/mesolve.jl index ede45034..b3058c27 100644 --- a/src/time_evolution/mesolve.jl +++ b/src/time_evolution/mesolve.jl @@ -10,7 +10,7 @@ function _save_func_mesolve(integrator) # This is equivalent to tr(op * ρ), when both are matrices. # The advantage of using this convention is that I don't need # to reshape u to make it a matrix, but I reshape the e_ops once. - + ρ = integrator.u _expect = op -> dot(op, ρ) @. expvals[:, progr.counter[]+1] = _expect(e_ops) @@ -22,10 +22,10 @@ end mesolve_ti_dudt!(du, u, p, t) = mul!(du, p.L, u) function mesolve_td_dudt!(du, u, p, t) mul!(du, p.L, u) - L_t = p.H_t(t,p) + L_t = p.H_t(t, p) mul!(du, L_t, u, 1, 1) end - + """ mesolveProblem(H::QuantumObject, ψ0::QuantumObject, @@ -57,9 +57,9 @@ Generates the ODEProblem for the master equation time evolution of an open quant function mesolveProblem(H::QuantumObject{MT1,HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, t_l, - c_ops::Vector{QuantumObject{Tc, COpType}}=QuantumObject{MT1, HOpType}[]; + c_ops::Vector{QuantumObject{Tc,COpType}}=QuantumObject{MT1,HOpType}[]; alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), progress_bar::Bool=true, @@ -78,10 +78,10 @@ function mesolveProblem(H::QuantumObject{MT1,HOpType}, progr = ProgressBar(length(t_l), enable=progress_bar) expvals = Array{ComplexF64}(undef, length(e_ops), length(t_l)) e_ops2 = @. mat2vec(adjoint(get_data(e_ops))) - - p = (L = L, progr = progr, Hdims = H.dims, e_ops = e_ops2, expvals = expvals, H_t = H_t, is_empty_e_ops = isempty(e_ops), params...) - default_values = (abstol = 1e-7, reltol = 1e-5, saveat = [t_l[end]]) + p = (L=L, progr=progr, Hdims=H.dims, e_ops=e_ops2, expvals=expvals, H_t=H_t, is_empty_e_ops=isempty(e_ops), params...) + + default_values = (abstol=1e-7, reltol=1e-5, saveat=[t_l[end]]) kwargs2 = merge(default_values, kwargs) if !isempty(e_ops) || progress_bar cb1 = PresetTimeCallback(t_l, _save_func_mesolve, save_positions=(false, false)) @@ -131,9 +131,9 @@ Time evolution of an open quantum system using master equation. function mesolve(H::QuantumObject{MT1,HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc, COpType}}=QuantumObject{MT1, HOpType}[]; + c_ops::Vector{QuantumObject{Tc,COpType}}=QuantumObject{MT1,HOpType}[]; alg::OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), progress_bar::Bool=true, @@ -143,8 +143,8 @@ function mesolve(H::QuantumObject{MT1,HOpType}, COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} prob = mesolveProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, progress_bar=progress_bar, kwargs...) - + H_t=H_t, params=params, progress_bar=progress_bar, kwargs...) + return mesolve(prob, alg; kwargs...) end diff --git a/src/time_evolution/sesolve.jl b/src/time_evolution/sesolve.jl index 737a0ff8..d50b8de5 100644 --- a/src/time_evolution/sesolve.jl +++ b/src/time_evolution/sesolve.jl @@ -20,7 +20,7 @@ end sesolve_ti_dudt!(du, u, p, t) = mul!(du, p.U, u) function sesolve_td_dudt!(du, u, p, t) mul!(du, p.U, u) - H_t = p.H_t(t,p) + H_t = p.H_t(t, p) mul!(du, H_t, u, -1im, 1) end @@ -55,7 +55,7 @@ function sesolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector; alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{MT2, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{MT2,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), progress_bar::Bool=true, @@ -72,9 +72,9 @@ function sesolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, expvals = Array{ComplexF64}(undef, length(e_ops), length(t_l)) e_ops2 = get_data.(e_ops) - p = (U = U, e_ops = e_ops2, expvals = expvals, progr = progr, Hdims = H.dims, H_t = H_t, is_empty_e_ops = isempty(e_ops), params...) + p = (U=U, e_ops=e_ops2, expvals=expvals, progr=progr, Hdims=H.dims, H_t=H_t, is_empty_e_ops=isempty(e_ops), params...) - default_values = (abstol = 1e-7, reltol = 1e-5, saveat = [t_l[end]]) + default_values = (abstol=1e-7, reltol=1e-5, saveat=[t_l[end]]) kwargs2 = merge(default_values, kwargs) if !isempty(e_ops) || progress_bar cb1 = PresetTimeCallback(t_l, _save_func_sesolve, save_positions=(false, false)) @@ -124,15 +124,15 @@ function sesolve(H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector; alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{MT2, OperatorQuantumObject}}=QuantumObject{MT1, OperatorQuantumObject}[], + e_ops::Vector{QuantumObject{MT2,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), progress_bar::Bool=true, kwargs...) where {MT1<:AbstractMatrix,T2,MT2<:AbstractMatrix} prob = sesolveProblem(H, ψ0, t_l; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, progress_bar=progress_bar, kwargs...) - + H_t=H_t, params=params, progress_bar=progress_bar, kwargs...) + return sesolve(prob, alg; kwargs...) end @@ -145,7 +145,7 @@ end function _sesolve_sol(sol; kwargs...) Hdims = sol.prob.p.Hdims - ψt = !haskey(kwargs, :save_idxs) ? map(ϕ -> QuantumObject(ϕ, dims = Hdims), sol.u) : sol.u + ψt = !haskey(kwargs, :save_idxs) ? map(ϕ -> QuantumObject(ϕ, dims=Hdims), sol.u) : sol.u return TimeEvolutionSol(sol.t, ψt, sol.prob.p.expvals) end \ No newline at end of file diff --git a/src/time_evolution/time_evolution.jl b/src/time_evolution/time_evolution.jl index d1313fe7..d2549fc7 100644 --- a/src/time_evolution/time_evolution.jl +++ b/src/time_evolution/time_evolution.jl @@ -9,7 +9,7 @@ export SteadyStateSolver, SteadyStateDirectSolver abstract type LiouvillianSolver end -struct LiouvillianDirectSolver{T<:Real} <: LiouvillianSolver +struct LiouvillianDirectSolver{T<:Real} <: LiouvillianSolver tol::T end @@ -17,14 +17,14 @@ abstract type SteadyStateSolver end struct SteadyStateDirectSolver <: SteadyStateSolver end -struct TimeEvolutionSol{TT<:Vector{<:Real}, TS<:AbstractVector, TE<:Matrix{ComplexF64}} +struct TimeEvolutionSol{TT<:Vector{<:Real},TS<:AbstractVector,TE<:Matrix{ComplexF64}} times::TT states::TS expect::TE end -struct TimeEvolutionMCSol{TT<:Vector{<:Vector{<:Real}}, TS<:AbstractVector, TE<:Matrix{ComplexF64}, - TEA<:Array{ComplexF64, 3}, TJT<:Vector{<:Vector{<:Real}}, TJW<:Vector{<:Vector{<:Integer}}} +struct TimeEvolutionMCSol{TT<:Vector{<:Vector{<:Real}},TS<:AbstractVector,TE<:Matrix{ComplexF64}, + TEA<:Array{ComplexF64,3},TJT<:Vector{<:Vector{<:Real}},TJW<:Vector{<:Vector{<:Integer}}} times::TT states::TS expect::TE @@ -33,7 +33,7 @@ struct TimeEvolutionMCSol{TT<:Vector{<:Vector{<:Real}}, TS<:AbstractVector, TE<: jump_which::TJW end -LiouvillianDirectSolver(;tol=1e-16) = LiouvillianDirectSolver(tol) +LiouvillianDirectSolver(; tol=1e-16) = LiouvillianDirectSolver(tol) abstract type LindbladJumpCallbackType end @@ -44,7 +44,7 @@ end struct DiscreteLindbladJumpCallback <: LindbladJumpCallbackType end -ContinuousLindbladJumpCallback(;interp_points::Int=10) = ContinuousLindbladJumpCallback(interp_points) +ContinuousLindbladJumpCallback(; interp_points::Int=10) = ContinuousLindbladJumpCallback(interp_points) ## Sum of operators @@ -56,9 +56,9 @@ struct OperatorSum{CT<:Vector{<:Number},OT<:Vector{<:QuantumObject}} <: Abstract # Check if all the operators have the same dimensions dims = operators[1].dims optype = operators[1].type - mapreduce(x->x.dims == dims && x.type == optype, &, operators) || throw(DimensionMismatch("All the operators must have the same dimensions.")) - T = promote_type(mapreduce(x->eltype(x.data), promote_type, operators), - mapreduce(eltype, promote_type, coefficients)) + mapreduce(x -> x.dims == dims && x.type == optype, &, operators) || throw(DimensionMismatch("All the operators must have the same dimensions.")) + T = promote_type(mapreduce(x -> eltype(x.data), promote_type, operators), + mapreduce(eltype, promote_type, coefficients)) coefficients2 = T.(coefficients) new{Vector{T},OT}(coefficients2, operators) end @@ -75,12 +75,12 @@ function update_coefficients!(A::OperatorSum, coefficients) A.coefficients .= coefficients end -@inline function LinearAlgebra.mul!(y::AbstractVector{T}, A::OperatorSum, x::AbstractVector, α, β) where T +@inline function LinearAlgebra.mul!(y::AbstractVector{T}, A::OperatorSum, x::AbstractVector, α, β) where {T} # Note that β is applied only to the first term - mul!(y, A.operators[1], x, α*A.coefficients[1], β) + mul!(y, A.operators[1], x, α * A.coefficients[1], β) @inbounds for i in 2:length(A.operators) A.coefficients[i] == 0 && continue - mul!(y, A.operators[i], x, α*A.coefficients[i], 1) + mul!(y, A.operators[i], x, α * A.coefficients[i], 1) end y end @@ -114,7 +114,7 @@ end end ####################################### - + ### LIOUVILLIAN AND STEADYSTATE ### @doc raw""" @@ -130,8 +130,8 @@ the same function is applied multiple times with a known Hilbert space dimension function liouvillian(H::QuantumObject{MT1,OpType1}, c_ops::Vector{QuantumObject{MT2,OpType2}}=Vector{QuantumObject{MT1,OpType1}}([]), Id_cache=I(prod(H.dims))) where {MT1<:AbstractMatrix,MT2<:AbstractMatrix, - OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} + OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} L = liouvillian(H, Id_cache) for c_op in c_ops @@ -160,9 +160,9 @@ function liouvillian_floquet(H::QuantumObject{<:AbstractArray{T1},OpType1}, Hₚ::QuantumObject{<:AbstractArray{T2},OpType2}, Hₘ::QuantumObject{<:AbstractArray{T3},OpType3}, ω::Real; n_max::Int=4, solver::LiouvillianSolver=LiouvillianDirectSolver()) where {T1,T2,T3, - OpType1<:Union{OperatorQuantumObject, SuperOperatorQuantumObject}, - OpType2<:Union{OperatorQuantumObject, SuperOperatorQuantumObject}, - OpType3<:Union{OperatorQuantumObject, SuperOperatorQuantumObject}} + OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} liouvillian_floquet(liouvillian(H, c_ops), liouvillian(Hₚ), liouvillian(Hₘ), ω, solver=solver, n_max=n_max) end @@ -175,12 +175,12 @@ 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}, fields::Vector, - T_list::Vector{<:Real}; N_trunc::Int=size(H,1), tol::Real=1e-12, σ_filter::Union{Nothing, Real}=nothing) where {MT<:AbstractMatrix} +function liouvillian_generalized(H::QuantumObject{MT,OperatorQuantumObject}, fields::Vector, + T_list::Vector{<:Real}; N_trunc::Int=size(H, 1), 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 == size(H,1) ? H.dims : [N_trunc] + dims = N_trunc == size(H, 1) ? H.dims : [N_trunc] result = eigen(H) E = real.(result.values[1:N_trunc]) U = QuantumObject(result.vectors, result.type, result.dims) @@ -194,7 +194,7 @@ function liouvillian_generalized(H::QuantumObject{MT, OperatorQuantumObject}, fi σ = isnothing(σ_filter) ? 500 * maximum([norm(field) / length(field) for field in fields]) : σ_filter F1 = QuantumObject(gaussian.(Ω, 0, σ), dims=dims) F1 = dense_to_sparse(F1, tol) - + # Filter in the Liouville space # M1 = ones(N_trunc, N_trunc) M1 = similar(E, N_trunc, N_trunc) @@ -209,20 +209,20 @@ function liouvillian_generalized(H::QuantumObject{MT, OperatorQuantumObject}, fi 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:N_trunc, 1:N_trunc], tol) + X_op = dense_to_sparse((U'*fields[i]*U).data[1:N_trunc, 1:N_trunc], tol) if ishermitian(fields[i]) X_op = (X_op + X_op') / 2 # Make sure it's hermitian end # Ohmic reservoir N_th = n_th.(Ωp, T_list[i]) - Sp₀ = QuantumObject( triu(X_op, 1), dims=dims ) - Sp₁ = QuantumObject( droptol!( (@. Ωp * N_th * Sp₀.data), tol), dims=dims ) - Sp₂ = QuantumObject( droptol!( (@. Ωp * (1 + N_th) * Sp₀.data), tol), dims=dims ) + Sp₀ = QuantumObject(triu(X_op, 1), dims=dims) + Sp₁ = QuantumObject(droptol!((@. Ωp * N_th * Sp₀.data), tol), dims=dims) + Sp₂ = QuantumObject(droptol!((@. Ωp * (1 + N_th) * Sp₀.data), tol), dims=dims) # S0 = QuantumObject( spdiagm(diag(X_op)), dims=dims ) - L += 1 / 2 * ( F2 .* (sprepost(Sp₁', Sp₀) + sprepost(Sp₀', Sp₁)) - spre(F1 .* (Sp₀ * Sp₁')) - spost(F1 .* (Sp₁ * Sp₀')) ) - L += 1 / 2 * ( F2 .* (sprepost(Sp₂, Sp₀') + sprepost(Sp₀, Sp₂')) - spre(F1 .* (Sp₀' * Sp₂)) - spost(F1 .* (Sp₂' * Sp₀)) ) + L += 1 / 2 * (F2 .* (sprepost(Sp₁', Sp₀) + sprepost(Sp₀', Sp₁)) - spre(F1 .* (Sp₀ * Sp₁')) - spost(F1 .* (Sp₁ * Sp₀'))) + L += 1 / 2 * (F2 .* (sprepost(Sp₂, Sp₀') + sprepost(Sp₀, Sp₂')) - spre(F1 .* (Sp₀' * Sp₂)) - spost(F1 .* (Sp₂' * Sp₀))) end return E, U, L diff --git a/src/time_evolution/time_evolution_dynamical.jl b/src/time_evolution/time_evolution_dynamical.jl index 96bbdc01..14b855b6 100644 --- a/src/time_evolution/time_evolution_dynamical.jl +++ b/src/time_evolution/time_evolution_dynamical.jl @@ -38,8 +38,8 @@ function _increase_dims(QO::AbstractArray{T}, dims::Vector{<:Integer}, sel::Abst ρmat2 = similar(QO, reverse!(repeat(rd_new, 2))...) ρmat = reshape(QO, reverse!(repeat(rd, 2))...) for i in eachindex(sel) - fill!(selectdim(ρmat2, nd-sel[i]+1, rd[sel[i]]+1:rd_new[sel[i]]), 0) - fill!(selectdim(ρmat2, 2*nd-sel[i]+1, rd[sel[i]]+1:rd_new[sel[i]]), 0) + fill!(selectdim(ρmat2, nd - sel[i] + 1, rd[sel[i]]+1:rd_new[sel[i]]), 0) + fill!(selectdim(ρmat2, 2 * nd - sel[i] + 1, rd[sel[i]]+1:rd_new[sel[i]]), 0) end copyto!(view(ρmat2, reverse!(repeat([1:n for n in rd], 2))...), ρmat) ρmat = reshape(ρmat2, prod(rd_new), prod(rd_new)) @@ -59,10 +59,10 @@ function _DFDIncreaseReduceCondition(u, t, integrator) reduce_list = internal_params.reduce_list pillow_list = internal_params.pillow_list dfd_ρt_cache = internal_params.dfd_ρt_cache - + # I need this cache because I can't reshape directly the integrator.u copyto!(dfd_ρt_cache, u) - + @inbounds for i in eachindex(dim_list) maxdim_i = maxdims[i] dim_i = dim_list[i] @@ -93,9 +93,9 @@ function _DFDIncreaseReduceAffect!(integrator) dim_list_evo = internal_params.dim_list_evo dfd_ρt_cache = internal_params.dfd_ρt_cache dfd_params = internal_params.dfd_params - + ρt = vec2mat(dfd_ρt_cache) - + @views pillow_increase = pillow_list[increase_list] @views pillow_reduce = pillow_list[reduce_list] dim_increase = findall(increase_list) @@ -121,8 +121,8 @@ function _DFDIncreaseReduceAffect!(integrator) resize!(integrator, size(L, 1)) copyto!(integrator.u, mat2vec(ρt)) - integrator.p = merge(internal_params, (L = L, e_ops = e_ops2, - dfd_ρt_cache = similar(integrator.u))) + integrator.p = merge(internal_params, (L=L, e_ops=e_ops2, + dfd_ρt_cache=similar(integrator.u))) end function dfd_mesolveProblem(H::Function, ψ0::QuantumObject{<:AbstractArray{T1},StateOpType}, @@ -148,18 +148,18 @@ function dfd_mesolveProblem(H::Function, ψ0::QuantumObject{<:AbstractArray{T1}, increase_list = zeros(Bool, length(dim_list)) pillow_list = _dfd_set_pillow.(dim_list) - params2 = merge(params, (H_fun = H, c_ops_fun = c_ops, e_ops_fun = e_ops, - dim_list = dim_list, maxdims = maxdims, tol_list = tol_list, - reduce_list = reduce_list, increase_list = increase_list, pillow_list = pillow_list, - dim_list_evo_times = dim_list_evo_times, dim_list_evo = dim_list_evo, - dfd_ρt_cache = similar(ψ0.data, length(ψ0.data)^2), dfd_params = dfd_params)) + params2 = merge(params, (H_fun=H, c_ops_fun=c_ops, e_ops_fun=e_ops, + dim_list=dim_list, maxdims=maxdims, tol_list=tol_list, + reduce_list=reduce_list, increase_list=increase_list, pillow_list=pillow_list, + dim_list_evo_times=dim_list_evo_times, dim_list_evo=dim_list_evo, + dfd_ρt_cache=similar(ψ0.data, length(ψ0.data)^2), dfd_params=dfd_params)) cb_dfd = DiscreteCallback(_DFDIncreaseReduceCondition, _DFDIncreaseReduceAffect!, save_positions=(false, false)) - kwargs2 = (;kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb_dfd, kwargs2.callback),)) : merge(kwargs2, (callback = cb_dfd,)) + kwargs2 = (; kwargs...) + kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb_dfd, kwargs2.callback),)) : merge(kwargs2, (callback=cb_dfd,)) mesolveProblem(H₀, ψ0, t_l, c_ops₀; e_ops=e_ops₀, alg=alg, H_t=H_t, - params=params2, kwargs2...) + params=params2, kwargs2...) end """ @@ -184,9 +184,9 @@ function dfd_mesolve(H::Function, ψ0::QuantumObject{<:AbstractArray{T1},StateOp params::NamedTuple=NamedTuple(), tol_list::Vector{<:Number}=fill(1e-8, length(maxdims)), kwargs...) where {T1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - + dfd_prob = dfd_mesolveProblem(H, ψ0, t_l, c_ops, maxdims, dfd_params; alg=alg, e_ops=e_ops, H_t=H_t, - params=params, tol_list=tol_list, kwargs...) + params=params, tol_list=tol_list, kwargs...) sol = solve(dfd_prob, alg) @@ -262,9 +262,9 @@ function _DSF_mesolve_Affect!(integrator) # expv!(integrator.u, expv_cache, one(αt), dsf_cache) dsf_displace_cache_full.coefficients[i] = Δα - dsf_displace_cache_full.coefficients[i + op_l_length] = -conj(Δα) - dsf_displace_cache_full.coefficients[i + 2*op_l_length] = conj(Δα) - dsf_displace_cache_full.coefficients[i + 3*op_l_length] = -Δα + dsf_displace_cache_full.coefficients[i+op_l_length] = -conj(Δα) + dsf_displace_cache_full.coefficients[i+2*op_l_length] = conj(Δα) + dsf_displace_cache_full.coefficients[i+3*op_l_length] = -Δα αt_list[i] += Δα end @@ -282,17 +282,17 @@ function _DSF_mesolve_Affect!(integrator) end function dsf_mesolveProblem(H::Function, - ψ0::QuantumObject{<:AbstractArray{T}, StateOpType}, + ψ0::QuantumObject{<:AbstractArray{T},StateOpType}, t_l::AbstractVector, c_ops::Function, op_list::Vector{TOl}, α0_l::Vector{<:Number}=zeros(length(op_list)), dsf_params::NamedTuple=NamedTuple(); alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list,p) -> Vector{TOl}([]), + e_ops::Function=(op_list, p) -> Vector{TOl}([]), H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - krylov_dim::Int=min(5,cld(length(ket2dm(ψ0).data), 3)), + krylov_dim::Int=min(5, cld(length(ket2dm(ψ0).data), 3)), kwargs...) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} op_l = op_list @@ -300,27 +300,27 @@ function dsf_mesolveProblem(H::Function, c_ops₀ = c_ops(op_l .+ α0_l, dsf_params) e_ops₀ = e_ops(op_l .+ α0_l, dsf_params) - αt_list = convert(Vector{T}, α0_l) + αt_list = convert(Vector{T}, α0_l) op_l_vec = map(op -> mat2vec(get_data(op)'), op_l) # Create the Krylov subspace with kron(H₀.data, H₀.data) just for initialize expv_cache = arnoldi(kron(H₀.data, H₀.data), mat2vec(ket2dm(ψ0).data), krylov_dim) dsf_identity = I(prod(H₀.dims)) - dsf_displace_cache_left = map(op->Qobj(kron(op.data, dsf_identity)), op_l) - dsf_displace_cache_left_dag = map(op->Qobj(kron(sparse(op.data'), dsf_identity)), op_l) - dsf_displace_cache_right = map(op->Qobj(kron(dsf_identity, op.data)), op_l) - dsf_displace_cache_right_dag = map(op->Qobj(kron(dsf_identity, sparse(op.data'))), op_l) + dsf_displace_cache_left = map(op -> Qobj(kron(op.data, dsf_identity)), op_l) + dsf_displace_cache_left_dag = map(op -> Qobj(kron(sparse(op.data'), dsf_identity)), op_l) + dsf_displace_cache_right = map(op -> Qobj(kron(dsf_identity, op.data)), op_l) + dsf_displace_cache_right_dag = map(op -> Qobj(kron(dsf_identity, sparse(op.data'))), op_l) dsf_displace_cache_full = OperatorSum(zeros(length(op_l) * 4), vcat(dsf_displace_cache_left, dsf_displace_cache_left_dag, dsf_displace_cache_right, dsf_displace_cache_right_dag)) params2 = params - params2 = merge(params, (H_fun = H, c_ops_fun = c_ops, e_ops_fun = e_ops, - op_l = op_l, op_l_vec = op_l_vec, αt_list = αt_list, δα_list = δα_list, - dsf_cache = similar(ψ0.data, length(ψ0.data)^2), expv_cache=expv_cache, - dsf_identity=dsf_identity, dsf_params = dsf_params, - dsf_displace_cache_full=dsf_displace_cache_full)) + params2 = merge(params, (H_fun=H, c_ops_fun=c_ops, e_ops_fun=e_ops, + op_l=op_l, op_l_vec=op_l_vec, αt_list=αt_list, δα_list=δα_list, + dsf_cache=similar(ψ0.data, length(ψ0.data)^2), expv_cache=expv_cache, + dsf_identity=dsf_identity, dsf_params=dsf_params, + dsf_displace_cache_full=dsf_displace_cache_full)) cb_dsf = DiscreteCallback(_DSF_mesolve_Condition, _DSF_mesolve_Affect!, save_positions=(false, false)) - kwargs2 = (;kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb_dsf, kwargs2.callback),)) : merge(kwargs2, (callback = cb_dsf,)) + kwargs2 = (; kwargs...) + kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb_dsf, kwargs2.callback),)) : merge(kwargs2, (callback=cb_dsf,)) mesolveProblem(H₀, ψ0, t_l, c_ops₀; e_ops=e_ops₀, alg=alg, H_t=H_t, params=params2, kwargs2...) end @@ -343,42 +343,42 @@ end Time evolution of an open quantum system using master equation and the Dynamical Shifted Fock algorithm. """ function dsf_mesolve(H::Function, - ψ0::QuantumObject{<:AbstractArray{T}, StateOpType}, + ψ0::QuantumObject{<:AbstractArray{T},StateOpType}, t_l::AbstractVector, c_ops::Function, op_list::Vector{TOl}, α0_l::Vector{<:Number}=zeros(length(op_list)), dsf_params::NamedTuple=NamedTuple(); alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list,p) -> Vector{TOl}([]), + e_ops::Function=(op_list, p) -> Vector{TOl}([]), H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - krylov_dim::Int=min(5,cld(length(ket2dm(ψ0).data), 3)), + krylov_dim::Int=min(5, cld(length(ket2dm(ψ0).data), 3)), kwargs...) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} dsf_prob = dsf_mesolveProblem(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, H_t=H_t, - params=params, δα_list=δα_list, krylov_dim=krylov_dim, kwargs...) - + params=params, δα_list=δα_list, krylov_dim=krylov_dim, kwargs...) + return mesolve(dsf_prob; alg=alg, kwargs...) end function dsf_mesolve(H::Function, - ψ0::QuantumObject{<:AbstractArray{T}, StateOpType}, + ψ0::QuantumObject{<:AbstractArray{T},StateOpType}, t_l::AbstractVector, op_list::Vector{TOl}, α0_l::Vector{<:Number}=zeros(length(op_list)), dsf_params::NamedTuple=NamedTuple(); alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list,p) -> Vector{TOl}([]), + e_ops::Function=(op_list, p) -> Vector{TOl}([]), H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - krylov_dim::Int=min(5,cld(length(ket2dm(ψ0).data), 3)), + krylov_dim::Int=min(5, cld(length(ket2dm(ψ0).data), 3)), kwargs...) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} c_ops = op_list -> Vector{TOl}([]) return dsf_mesolve(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, H_t=H_t, - params=params, δα_list=δα_list, krylov_dim=krylov_dim, kwargs...) + params=params, δα_list=δα_list, krylov_dim=krylov_dim, kwargs...) end @@ -444,7 +444,7 @@ function _DSF_mcsolve_Affect!(integrator) # expv!(integrator.u, expv_cache, one(αt), dsf_cache) dsf_displace_cache_full.coefficients[i] = conj(Δα) - dsf_displace_cache_full.coefficients[i + op_l_length] = -Δα + dsf_displace_cache_full.coefficients[i+op_l_length] = -Δα αt_list[i] += Δα end @@ -466,31 +466,31 @@ end function _dsf_mcsolve_prob_func(prob, i, repeat) internal_params = prob.p - prm = merge(internal_params, (U = copy(internal_params.U), e_ops_mc = copy(internal_params.e_ops_mc), - c_ops = copy(internal_params.c_ops), expvals = similar(internal_params.expvals), - cache_mc = similar(internal_params.cache_mc), weights_mc = similar(internal_params.weights_mc), - cumsum_weights_mc = similar(internal_params.weights_mc), random_n = Ref(rand()), progr_mc = ProgressBar(size(internal_params.expvals, 2), enable=false), jump_times_which_idx = Ref(1), - jump_times = similar(internal_params.jump_times), jump_which = similar(internal_params.jump_which), - αt_list = copy(internal_params.αt_list), dsf_cache1 = similar(internal_params.dsf_cache1), - dsf_cache2 = similar(internal_params.dsf_cache2), expv_cache = copy(internal_params.expv_cache), - dsf_displace_cache_full = OperatorSum(copy(internal_params.dsf_displace_cache_full.coefficients), internal_params.dsf_displace_cache_full.operators))) + prm = merge(internal_params, (U=copy(internal_params.U), e_ops_mc=copy(internal_params.e_ops_mc), + c_ops=copy(internal_params.c_ops), expvals=similar(internal_params.expvals), + cache_mc=similar(internal_params.cache_mc), weights_mc=similar(internal_params.weights_mc), + cumsum_weights_mc=similar(internal_params.weights_mc), random_n=Ref(rand()), progr_mc=ProgressBar(size(internal_params.expvals, 2), enable=false), jump_times_which_idx=Ref(1), + jump_times=similar(internal_params.jump_times), jump_which=similar(internal_params.jump_which), + αt_list=copy(internal_params.αt_list), dsf_cache1=similar(internal_params.dsf_cache1), + dsf_cache2=similar(internal_params.dsf_cache2), expv_cache=copy(internal_params.expv_cache), + dsf_displace_cache_full=OperatorSum(copy(internal_params.dsf_displace_cache_full.coefficients), internal_params.dsf_displace_cache_full.operators))) remake(prob, p=prm) end function dsf_mcsolveEnsembleProblem(H::Function, - ψ0::QuantumObject{<:AbstractArray{T}, KetQuantumObject}, + ψ0::QuantumObject{<:AbstractArray{T},KetQuantumObject}, t_l::AbstractVector, c_ops::Function, op_list::Vector{TOl}, α0_l::Vector{<:Number}=zeros(length(op_list)), dsf_params::NamedTuple=NamedTuple(); alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list,p) -> Vector{TOl}([]), + e_ops::Function=(op_list, p) -> Vector{TOl}([]), H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), δα_list::Vector{<:Real}=fill(0.2, length(op_list)), jump_callback::TJC=ContinuousLindbladJumpCallback(), - krylov_dim::Int=min(5,cld(length(ψ0.data), 3)), + krylov_dim::Int=min(5, cld(length(ψ0.data), 3)), kwargs...) where {T,TOl,TJC<:LindbladJumpCallbackType} op_l = op_list @@ -498,26 +498,26 @@ function dsf_mcsolveEnsembleProblem(H::Function, c_ops₀ = c_ops(op_l .+ α0_l, dsf_params) e_ops₀ = e_ops(op_l .+ α0_l, dsf_params) - αt_list = convert(Vector{T}, α0_l) + αt_list = convert(Vector{T}, α0_l) expv_cache = arnoldi(H₀.data, ψ0.data, krylov_dim) - dsf_displace_cache = map(op->Qobj(op.data), op_l) - dsf_displace_cache_dag = map(op->Qobj(sparse(op.data')), op_l) + dsf_displace_cache = map(op -> Qobj(op.data), op_l) + dsf_displace_cache_dag = map(op -> Qobj(sparse(op.data')), op_l) dsf_displace_cache_full = OperatorSum(zeros(length(op_l) * 2), vcat(dsf_displace_cache, dsf_displace_cache_dag)) - params2 = merge(params, (H_fun = H, c_ops_fun = c_ops, e_ops_fun = e_ops, - op_l = op_l, αt_list = αt_list, δα_list = δα_list, - dsf_cache1 = similar(ψ0.data), dsf_cache2 = similar(ψ0.data), - expv_cache = expv_cache, dsf_params=dsf_params, dsf_displace_cache_full=dsf_displace_cache_full)) + params2 = merge(params, (H_fun=H, c_ops_fun=c_ops, e_ops_fun=e_ops, + op_l=op_l, αt_list=αt_list, δα_list=δα_list, + dsf_cache1=similar(ψ0.data), dsf_cache2=similar(ψ0.data), + expv_cache=expv_cache, dsf_params=dsf_params, dsf_displace_cache_full=dsf_displace_cache_full)) cb_dsf = DiscreteCallback(_DSF_mcsolve_Condition, _DSF_mcsolve_Affect!, save_positions=(false, false)) - kwargs2 = (;kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb_dsf, kwargs2.callback),)) : merge(kwargs2, (callback = cb_dsf,)) + kwargs2 = (; kwargs...) + kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb_dsf, kwargs2.callback),)) : merge(kwargs2, (callback=cb_dsf,)) mcsolveEnsembleProblem(H₀, ψ0, t_l, c_ops₀; e_ops=e_ops₀, alg=alg, H_t=H_t, - params=params2, jump_callback=jump_callback, - prob_func=_dsf_mcsolve_prob_func, kwargs2...) + params=params2, jump_callback=jump_callback, + prob_func=_dsf_mcsolve_prob_func, kwargs2...) end """ @@ -542,26 +542,26 @@ Time evolution of a quantum system using the Monte Carlo wave function method and the Dynamical Shifted Fock algorithm. """ function dsf_mcsolve(H::Function, - ψ0::QuantumObject{<:AbstractArray{T}, KetQuantumObject}, + ψ0::QuantumObject{<:AbstractArray{T},KetQuantumObject}, t_l::AbstractVector, c_ops::Function, op_list::Vector{TOl}, α0_l::Vector{<:Number}=zeros(length(op_list)), dsf_params::NamedTuple=NamedTuple(); alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list,p) -> Vector{TOl}([]), + e_ops::Function=(op_list, p) -> Vector{TOl}([]), H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, params::NamedTuple=NamedTuple(), δα_list::Vector{<:Real}=fill(0.2, length(op_list)), n_traj::Int=1, ensemble_method=EnsembleThreads(), jump_callback::TJC=ContinuousLindbladJumpCallback(), - krylov_dim::Int=min(5,cld(length(ψ0.data), 3)), + krylov_dim::Int=min(5, cld(length(ψ0.data), 3)), kwargs...) where {T,TOl,TJC<:LindbladJumpCallbackType} - ens_prob_mc = dsf_mcsolveEnsembleProblem(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, δα_list=δα_list, - jump_callback=jump_callback, krylov_dim=krylov_dim, kwargs...) + ens_prob_mc = dsf_mcsolveEnsembleProblem(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, + H_t=H_t, params=params, δα_list=δα_list, + jump_callback=jump_callback, krylov_dim=krylov_dim, kwargs...) return mcsolve(ens_prob_mc; alg=alg, n_traj=n_traj, ensemble_method=ensemble_method, kwargs...) end \ No newline at end of file diff --git a/src/versioninfo.jl b/src/versioninfo.jl index abd20a4d..f76cecfa 100644 --- a/src/versioninfo.jl +++ b/src/versioninfo.jl @@ -33,22 +33,22 @@ function versioninfo(io::IO=stdout) "====================================\n", "Julia Version: $(VERSION)" ) - println(io, + println(io, """OS : $(OS_name) ($(Sys.MACHINE))""" ) - println(io, + println(io, """CPU : $(length(cpu)) × $(cpu[1].model)""" ) println(io, """Memory : $(round(Sys.total_memory() / 2 ^ 30, digits=3)) GB""" ) - println(io, + println(io, """WORD_SIZE: $(Sys.WORD_SIZE)""" ) - println(io, + println(io, """LIBM : $(Base.libm_name)""" ) - println(io, + println(io, """LLVM : libLLVM-$(Base.libllvm_version) ($(Sys.JIT), $(Sys.CPU_NAME))""" ) println(io, diff --git a/src/wigner.jl b/src/wigner.jl index 5754f372..c1319d79 100644 --- a/src/wigner.jl +++ b/src/wigner.jl @@ -9,7 +9,7 @@ struct WignerLaguerre <: WignerSolver tol::Float64 end -WignerLaguerre(;parallel=false, tol=1e-14) = WignerLaguerre(parallel, tol) +WignerLaguerre(; parallel=false, tol=1e-14) = WignerLaguerre(parallel, tol) @doc raw""" wigner(state::QuantumObject, xvec::AbstractVector, yvec::AbstractVector; g::Real=√2, @@ -25,8 +25,8 @@ sparse matrices, while the Clenshaw algorithm is faster for dense matrices. The `parallel` parameter which defaults to `true` and uses multithreading to speed up the calculation. """ function wigner(state::QuantumObject{<:AbstractArray{T},OpType}, xvec::AbstractVector, - yvec::AbstractVector; g::Real=√2, solver::MySolver=WignerLaguerre()) where - {T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}, + yvec::AbstractVector; g::Real=√2, solver::MySolver=WignerLaguerre()) where +{T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}, MySolver<:WignerSolver} if isket(state) @@ -41,8 +41,8 @@ function wigner(state::QuantumObject{<:AbstractArray{T},OpType}, xvec::AbstractV end function _wigner(ρ::AbstractArray, xvec::AbstractVector{T}, yvec::AbstractVector{T}, - g::Real, solver::WignerLaguerre) where {T <: BlasFloat} - + g::Real, solver::WignerLaguerre) where {T<:BlasFloat} + g = convert(T, g) X, Y = meshgrid(xvec, yvec) A = g / 2 * (X + 1im * Y) @@ -53,8 +53,8 @@ function _wigner(ρ::AbstractArray, xvec::AbstractVector{T}, yvec::AbstractVecto end function _wigner(ρ::AbstractArray{T1}, xvec::AbstractVector{T}, yvec::AbstractVector{T}, - g::Real, solver::WignerClenshaw) where {T1 <: BlasFloat, T <: BlasFloat} - + g::Real, solver::WignerClenshaw) where {T1<:BlasFloat,T<:BlasFloat} + g = convert(T, g) M = size(ρ, 1) X, Y = meshgrid(xvec, yvec) @@ -73,7 +73,7 @@ function _wigner(ρ::AbstractArray{T1}, xvec::AbstractVector{T}, yvec::AbstractV while L > 0 L -= 1 - ρdiag = _wig_laguerre_clenshaw!(res, L, B, lmul!(1 + Int(L!=0), diag(ρ, L)), y0, y1, y0_old) + ρdiag = _wig_laguerre_clenshaw!(res, L, B, lmul!(1 + Int(L != 0), diag(ρ, L)), y0, y1, y0_old) @. W = ρdiag + W * A / √(L + 1) end @@ -85,29 +85,29 @@ function _wigner_laguerre(ρ::AbstractSparseArray, A::AbstractArray, W::Abstract B = @. 4 * abs2(A) if solver.parallel - iter = filter(x->x[2]>=x[1], collect(zip(rows, cols, vals))) + iter = filter(x -> x[2] >= x[1], collect(zip(rows, cols, vals))) Wtot = similar(B, size(B)..., length(iter)) Threads.@threads for i in eachindex(iter) m, n, ρmn = iter[i] - m, n = m-1, n-1 + m, n = m - 1, n - 1 # Γ_mn = (1 + Int(m!=n)) * sqrt(gamma(m+1) / gamma(n+1)) - Γ_mn = (1 + Int(m!=n)) * sqrt( exp(loggamma(m+1) - loggamma(n+1)) ) # Is this a good trick? + Γ_mn = (1 + Int(m != n)) * sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) - @. Wtot[:,:,i] = real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * - _genlaguerre(m, n - m, B)) + @. Wtot[:, :, i] = real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * + _genlaguerre(m, n - m, B)) end W .= dropdims(sum(Wtot, dims=3), dims=3) else - for i in Iterators.filter(x->x[2]>=x[1], zip(rows, cols, vals)) + for i in Iterators.filter(x -> x[2] >= x[1], zip(rows, cols, vals)) m, n, ρmn = i - m, n = m-1, n-1 + m, n = m - 1, n - 1 # Γ_mn = (1 + Int(m!=n)) * sqrt(gamma(m+1) / gamma(n+1)) - Γ_mn = (1 + Int(m!=n)) * sqrt( exp(loggamma(m+1) - loggamma(n+1)) ) # Is this a good trick? + Γ_mn = (1 + Int(m != n)) * sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) @. W += real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * - _genlaguerre(m, n - m, B)) + _genlaguerre(m, n - m, B)) end end @@ -118,7 +118,7 @@ function _wigner_laguerre(ρ::AbstractArray, A::AbstractArray, W::AbstractArray, tol = solver.tol M = size(ρ, 1) B = @. 4 * abs2(A) - + if solver.parallel throw(ArgumentError("Parallel version is not implemented for dense matrices")) else @@ -128,11 +128,11 @@ function _wigner_laguerre(ρ::AbstractArray, A::AbstractArray, W::AbstractArray, for n in m+1:M-1 ρmn = ρ[m+1, n+1] # Γ_mn = sqrt(gamma(m+1) / gamma(n+1)) - Γ_mn = sqrt( exp(loggamma(m+1) - loggamma(n+1)) ) # Is this a good trick? + Γ_mn = sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) abs(ρmn) > tol && (@. W += 2 * real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * - _genlaguerre(m, n - m, B))) + _genlaguerre(m, n - m, B))) end end end @@ -150,17 +150,17 @@ end # return L # end # This is a little bit slower, but it supports GPU -function _genlaguerre(n::Int, α::Number, x::T) where {T <: BlasFloat} +function _genlaguerre(n::Int, α::Number, x::T) where {T<:BlasFloat} α = convert(T, α) - p0, p1 = one(T), -x+(α+1) + p0, p1 = one(T), -x + (α + 1) n == 0 && return p0 for k = 1:n-1 - p1, p0 = ((2k+α+1)/(k+1) - x/(k+1))*p1 - (k+α)/(k+1)*p0, p1 + p1, p0 = ((2k + α + 1) / (k + 1) - x / (k + 1)) * p1 - (k + α) / (k + 1) * p0, p1 end p1 end -function check_inf(x::T) where T +function check_inf(x::T) where {T} if isinf(x) return x > zero(T) ? floatmax(T) : -floatmax(T) else diff --git a/test/aqua.jl b/test/aqua.jl index 99637669..1ffd4984 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -1,5 +1,5 @@ using Aqua @testset "Code quality (Aqua.jl)" begin - Aqua.test_all(QuantumToolbox; ambiguities = false,) + Aqua.test_all(QuantumToolbox; ambiguities=false,) end \ No newline at end of file diff --git a/test/correlations_and_spectrum.jl b/test/correlations_and_spectrum.jl index 0167fbde..e1183d8e 100644 --- a/test/correlations_and_spectrum.jl +++ b/test/correlations_and_spectrum.jl @@ -9,8 +9,8 @@ spec1 = spec1 ./ maximum(spec1) spec2 = spec2 ./ maximum(spec2) - test_func1 = maximum(real.(spec1)) * (0.1/2)^2 ./ ((ω_l1 .- 1).^2 .+ (0.1/2)^2) - test_func2 = maximum(real.(spec2)) * (0.1/2)^2 ./ ((ω_l2 .- 1).^2 .+ (0.1/2)^2) + test_func1 = maximum(real.(spec1)) * (0.1 / 2)^2 ./ ((ω_l1 .- 1) .^ 2 .+ (0.1 / 2)^2) + test_func2 = maximum(real.(spec2)) * (0.1 / 2)^2 ./ ((ω_l2 .- 1) .^ 2 .+ (0.1 / 2)^2) idxs1 = test_func1 .> 0.05 idxs2 = test_func2 .> 0.05 @test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < 0.01 diff --git a/test/cuda_ext.jl b/test/cuda_ext.jl index 44652d01..93f9c54b 100644 --- a/test/cuda_ext.jl +++ b/test/cuda_ext.jl @@ -6,15 +6,15 @@ CUDA.versioninfo() @testset "CUDA Extension" begin - ψdi = Qobj( Int64[1, 0]) - ψdf = Qobj( Float64[1, 0]) + ψdi = Qobj(Int64[1, 0]) + ψdf = Qobj(Float64[1, 0]) ψdc = Qobj(ComplexF64[1, 0]) ψsi = dense_to_sparse(ψdi) ψsf = dense_to_sparse(ψdf) ψsc = dense_to_sparse(ψdc) - Xdi = Qobj( Int64[0 1; 1 0]) - Xdf = Qobj( Float64[0 1; 1 0]) + Xdi = Qobj(Int64[0 1; 1 0]) + Xdf = Qobj(Float64[0 1; 1 0]) Xdc = Qobj(ComplexF64[0 1; 1 0]) Xsi = dense_to_sparse(Xdi) Xsf = dense_to_sparse(Xdf) @@ -23,36 +23,36 @@ CUDA.versioninfo() @test_throws DomainError cu(ψdi; word_size=16) # type conversion of CUDA dense arrays - @test typeof(cu(ψdi; word_size=64).data) == typeof(CuArray(ψdi).data) == CuArray{Int64, 1, CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdi; word_size=32).data) == typeof(CuArray{Int32}(ψdi).data) == CuArray{Int32, 1, CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdf; word_size=64).data) == typeof(CuArray(ψdf).data) == CuArray{Float64, 1, CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdf; word_size=32).data) == typeof(CuArray{Float32}(ψdf).data) == CuArray{Float32, 1, CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdc; word_size=64).data) == typeof(CuArray(ψdc).data) == CuArray{ComplexF64, 1, CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdc; word_size=32).data) == typeof(CuArray{ComplexF32}(ψdc).data) == CuArray{ComplexF32, 1, CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdi; word_size=64).data) == typeof(CuArray(Xdi).data) == CuArray{Int64, 2, CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdi; word_size=32).data) == typeof(CuArray{Int32}(Xdi).data) == CuArray{Int32, 2, CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdf; word_size=64).data) == typeof(CuArray(Xdf).data) == CuArray{Float64, 2, CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdf; word_size=32).data) == typeof(CuArray{Float32}(Xdf).data) == CuArray{Float32, 2, CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdc; word_size=64).data) == typeof(CuArray(Xdc).data) == CuArray{ComplexF64, 2, CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdc; word_size=32).data) == typeof(CuArray{ComplexF32}(Xdc).data) == CuArray{ComplexF32, 2, CUDA.Mem.DeviceBuffer} - + @test typeof(cu(ψdi; word_size=64).data) == typeof(CuArray(ψdi).data) == CuArray{Int64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdi; word_size=32).data) == typeof(CuArray{Int32}(ψdi).data) == CuArray{Int32,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdf; word_size=64).data) == typeof(CuArray(ψdf).data) == CuArray{Float64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdf; word_size=32).data) == typeof(CuArray{Float32}(ψdf).data) == CuArray{Float32,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdc; word_size=64).data) == typeof(CuArray(ψdc).data) == CuArray{ComplexF64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdc; word_size=32).data) == typeof(CuArray{ComplexF32}(ψdc).data) == CuArray{ComplexF32,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdi; word_size=64).data) == typeof(CuArray(Xdi).data) == CuArray{Int64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdi; word_size=32).data) == typeof(CuArray{Int32}(Xdi).data) == CuArray{Int32,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdf; word_size=64).data) == typeof(CuArray(Xdf).data) == CuArray{Float64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdf; word_size=32).data) == typeof(CuArray{Float32}(Xdf).data) == CuArray{Float32,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdc; word_size=64).data) == typeof(CuArray(Xdc).data) == CuArray{ComplexF64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdc; word_size=32).data) == typeof(CuArray{ComplexF32}(Xdc).data) == CuArray{ComplexF32,2,CUDA.Mem.DeviceBuffer} + # type conversion of CUDA sparse arrays - @test typeof(cu(ψsi; word_size=64).data) == typeof(CuSparseVector(ψsi).data) == CuSparseVector{Int64, Int32} - @test typeof(cu(ψsi; word_size=32).data) == typeof(CuSparseVector{Int32}(ψsi).data) == CuSparseVector{Int32, Int32} - @test typeof(cu(ψsf; word_size=64).data) == typeof(CuSparseVector(ψsf).data) == CuSparseVector{Float64, Int32} - @test typeof(cu(ψsf; word_size=32).data) == typeof(CuSparseVector{Float32}(ψsf).data) == CuSparseVector{Float32, Int32} - @test typeof(cu(ψsc; word_size=64).data) == typeof(CuSparseVector(ψsc).data) == CuSparseVector{ComplexF64, Int32} - @test typeof(cu(ψsc; word_size=32).data) == typeof(CuSparseVector{ComplexF32}(ψsc).data) == CuSparseVector{ComplexF32, Int32} - @test typeof(cu(Xsi; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsi).data) == CuSparseMatrixCSC{Int64, Int32} - @test typeof(cu(Xsi; word_size=32).data) == typeof(CuSparseMatrixCSC{Int32}(Xsi).data) == CuSparseMatrixCSC{Int32, Int32} - @test typeof(cu(Xsf; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsf).data) == CuSparseMatrixCSC{Float64, Int32} - @test typeof(cu(Xsf; word_size=32).data) == typeof(CuSparseMatrixCSC{Float32}(Xsf).data) == CuSparseMatrixCSC{Float32, Int32} - @test typeof(cu(Xsc; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsc).data) == CuSparseMatrixCSC{ComplexF64, Int32} - @test typeof(cu(Xsc; word_size=32).data) == typeof(CuSparseMatrixCSC{ComplexF32}(Xsc).data) == CuSparseMatrixCSC{ComplexF32, Int32} - @test typeof(CuSparseMatrixCSR(Xsi).data) == CuSparseMatrixCSR{Int64, Int32} - @test typeof(CuSparseMatrixCSR{Int32}(Xsi).data) == CuSparseMatrixCSR{Int32, Int32} - @test typeof(CuSparseMatrixCSR(Xsf).data) == CuSparseMatrixCSR{Float64, Int32} - @test typeof(CuSparseMatrixCSR{Float32}(Xsf).data) == CuSparseMatrixCSR{Float32, Int32} - @test typeof(CuSparseMatrixCSR(Xsc).data) == CuSparseMatrixCSR{ComplexF64, Int32} - @test typeof(CuSparseMatrixCSR{ComplexF32}(Xsc).data) == CuSparseMatrixCSR{ComplexF32, Int32} + @test typeof(cu(ψsi; word_size=64).data) == typeof(CuSparseVector(ψsi).data) == CuSparseVector{Int64,Int32} + @test typeof(cu(ψsi; word_size=32).data) == typeof(CuSparseVector{Int32}(ψsi).data) == CuSparseVector{Int32,Int32} + @test typeof(cu(ψsf; word_size=64).data) == typeof(CuSparseVector(ψsf).data) == CuSparseVector{Float64,Int32} + @test typeof(cu(ψsf; word_size=32).data) == typeof(CuSparseVector{Float32}(ψsf).data) == CuSparseVector{Float32,Int32} + @test typeof(cu(ψsc; word_size=64).data) == typeof(CuSparseVector(ψsc).data) == CuSparseVector{ComplexF64,Int32} + @test typeof(cu(ψsc; word_size=32).data) == typeof(CuSparseVector{ComplexF32}(ψsc).data) == CuSparseVector{ComplexF32,Int32} + @test typeof(cu(Xsi; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsi).data) == CuSparseMatrixCSC{Int64,Int32} + @test typeof(cu(Xsi; word_size=32).data) == typeof(CuSparseMatrixCSC{Int32}(Xsi).data) == CuSparseMatrixCSC{Int32,Int32} + @test typeof(cu(Xsf; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsf).data) == CuSparseMatrixCSC{Float64,Int32} + @test typeof(cu(Xsf; word_size=32).data) == typeof(CuSparseMatrixCSC{Float32}(Xsf).data) == CuSparseMatrixCSC{Float32,Int32} + @test typeof(cu(Xsc; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsc).data) == CuSparseMatrixCSC{ComplexF64,Int32} + @test typeof(cu(Xsc; word_size=32).data) == typeof(CuSparseMatrixCSC{ComplexF32}(Xsc).data) == CuSparseMatrixCSC{ComplexF32,Int32} + @test typeof(CuSparseMatrixCSR(Xsi).data) == CuSparseMatrixCSR{Int64,Int32} + @test typeof(CuSparseMatrixCSR{Int32}(Xsi).data) == CuSparseMatrixCSR{Int32,Int32} + @test typeof(CuSparseMatrixCSR(Xsf).data) == CuSparseMatrixCSR{Float64,Int32} + @test typeof(CuSparseMatrixCSR{Float32}(Xsf).data) == CuSparseMatrixCSR{Float32,Int32} + @test typeof(CuSparseMatrixCSR(Xsc).data) == CuSparseMatrixCSR{ComplexF64,Int32} + @test typeof(CuSparseMatrixCSR{ComplexF32}(Xsc).data) == CuSparseMatrixCSR{ComplexF32,Int32} end diff --git a/test/dynamical-shifted-fock.jl b/test/dynamical-shifted-fock.jl index c24cdd14..6b766f09 100644 --- a/test/dynamical-shifted-fock.jl +++ b/test/dynamical-shifted-fock.jl @@ -1,98 +1,98 @@ @testset "Dynamical Shifted Fock" begin - F = 3 - Δ = 0.25 - κ = 1 + F = 3 + Δ = 0.25 + κ = 1 U = 0.01 - tlist = LinRange(0,25,300) + tlist = LinRange(0, 25, 300) # Single cavity case - N0 = 100 - a0 = destroy(N0) - H0 = Δ*a0'*a0 + F*(a0+a0') + U * a0'^2 * a0^2 - c_ops0 = [√(κ)*a0] + N0 = 100 + a0 = destroy(N0) + H0 = Δ * a0' * a0 + F * (a0 + a0') + U * a0'^2 * a0^2 + c_ops0 = [√(κ) * a0] α0 = 1.5 - ρ0 = coherent(N0, α0) - sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a0'*a0, a0], progress_bar=false) + ρ0 = coherent(N0, α0) + sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a0' * a0, a0], progress_bar=false) N = 5 a = destroy(N) function H_dsf(op_list, p) - Δ = p.Δ - F = p.F - U = p.U - a = op_list[1] - Δ*a'*a + F*(a + a') + U * a'^2 * a^2 + Δ = p.Δ + F = p.F + U = p.U + a = op_list[1] + Δ * a' * a + F * (a + a') + U * a'^2 * a^2 end function c_ops_dsf(op_list, p) - κ = p.κ - a = op_list[1] - [√κ * a] + κ = p.κ + a = op_list[1] + [√κ * a] end function e_ops_dsf(op_list, p) - a = op_list[1] - [a' * a, a] + a = op_list[1] + [a' * a, a] end op_list = [a] - ψ0 = fock(N, 0) + ψ0 = fock(N, 0) α0_l = [α0] dsf_params = (Δ=Δ, F=F, κ=κ, U=U) sol_dsf_me = dsf_mesolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress_bar=false) sol_dsf_mc = dsf_mcsolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress_bar=false, n_traj=500) - val_ss = abs2(sol0.expect[1,end]) - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_me.expect[1,:])) / (val_ss * length(tlist)) < 0.1 - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_mc.expect[1,:])) / (val_ss * length(tlist)) < 0.1 + val_ss = abs2(sol0.expect[1, end]) + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / (val_ss * length(tlist)) < 0.1 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / (val_ss * length(tlist)) < 0.1 # Two cavities case - F = 2 - Δ = 0.25 - κ = 1 + F = 2 + Δ = 0.25 + κ = 1 U = 0.01 J = 0.5 - tlist = LinRange(0,15,300) + tlist = LinRange(0, 15, 300) - N0 = 20 - a10 = kron(destroy(N0), qeye(N0)) - a20 = kron(qeye(N0), destroy(N0)) - H0 = Δ*a10'*a10 + Δ*a20'*a20 + U*a10'^2*a10^2 + U*a20'^2*a20^2 + F*(a10+a10') + J*(a10'*a20 + a10*a20') - c_ops0 = [√κ*a10, √κ*a20] + N0 = 20 + a10 = kron(destroy(N0), qeye(N0)) + a20 = kron(qeye(N0), destroy(N0)) + H0 = Δ * a10' * a10 + Δ * a20' * a20 + U * a10'^2 * a10^2 + U * a20'^2 * a20^2 + F * (a10 + a10') + J * (a10' * a20 + a10 * a20') + c_ops0 = [√κ * a10, √κ * a20] - ρ0 = kron(coherent(N0, α0), coherent(N0, α0)) - sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a10'*a10, a20'*a20], progress_bar=false) + ρ0 = kron(coherent(N0, α0), coherent(N0, α0)) + sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a10' * a10, a20' * a20], progress_bar=false) - N = 5 + N = 5 a1 = kron(destroy(N), qeye(N)) a2 = kron(qeye(N), destroy(N)) function H_dsf2(op_list, p) - Δ = p.Δ - F = p.F - U = p.U - J = p.J - a1, a2 = op_list - Δ*a1'*a1 + Δ*a2'*a2 + U*a1'^2*a1^2 + U*a2'^2*a2^2 + F*(a1 + a1') + J*(a1'*a2 + a1*a2') + Δ = p.Δ + F = p.F + U = p.U + J = p.J + a1, a2 = op_list + Δ * a1' * a1 + Δ * a2' * a2 + U * a1'^2 * a1^2 + U * a2'^2 * a2^2 + F * (a1 + a1') + J * (a1' * a2 + a1 * a2') end function c_ops_dsf2(op_list, p) - κ = p.κ - a1, a2 = op_list - [√κ * a1, √κ * a2] + κ = p.κ + a1, a2 = op_list + [√κ * a1, √κ * a2] end function e_ops_dsf2(op_list, p) - a1, a2 = op_list - [a1' * a1, a2' * a2] + a1, a2 = op_list + [a1' * a1, a2' * a2] end op_list = [a1, a2] - ψ0 = kron(fock(N, 0), fock(N, 0)) + ψ0 = kron(fock(N, 0), fock(N, 0)) α0_l = [α0, α0] dsf_params = (Δ=Δ, F=F, κ=κ, U=U, J=J) sol_dsf_me = dsf_mesolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress_bar=false) sol_dsf_mc = dsf_mcsolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress_bar=false, n_traj=500) - val_ss = abs2(sol0.expect[1,end]) - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_me.expect[1,:])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[1,:] .- sol_dsf_mc.expect[1,:])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2,:] .- sol_dsf_me.expect[2,:])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2,:] .- sol_dsf_mc.expect[2,:])) / (val_ss * length(tlist)) < 0.6 + val_ss = abs2(sol0.expect[1, end]) + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_me.expect[2, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_mc.expect[2, :])) / (val_ss * length(tlist)) < 0.6 end \ No newline at end of file diff --git a/test/dynamical_fock_dimension_mesolve.jl b/test/dynamical_fock_dimension_mesolve.jl index 858e8d53..84fe2617 100644 --- a/test/dynamical_fock_dimension_mesolve.jl +++ b/test/dynamical_fock_dimension_mesolve.jl @@ -29,7 +29,7 @@ maxdims = [150] ψ0 = fock(3, 0) dfd_params = (Δ=Δ, F=F, κ=κ) - sol = dfd_mesolve(H_dfd0, ψ0, t_l, c_ops_dfd0, maxdims, dfd_params, e_ops=e_ops_dfd0, progress_bar=false); + sol = dfd_mesolve(H_dfd0, ψ0, t_l, c_ops_dfd0, maxdims, dfd_params, e_ops=e_ops_dfd0, progress_bar=false) @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 @@ -103,5 +103,5 @@ sol = dfd_mesolve(H_dfd2, ψ0, t_l, c_ops_dfd2, maxdims, dfd_params, e_ops=e_ops_dfd2, progress_bar=false) @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) + - sum(abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16))) < 0.01 + sum(abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16))) < 0.01 end \ No newline at end of file diff --git a/test/eigenvalues_and_operators.jl b/test/eigenvalues_and_operators.jl index 2833be81..ca4ef657 100644 --- a/test/eigenvalues_and_operators.jl +++ b/test/eigenvalues_and_operators.jl @@ -2,15 +2,15 @@ σx = sigmax() result = eigenstates(σx, sparse=false) λd, ψd, Td = result - resstring = sprint((t, s) -> show(t, "text/plain", s), result) - valstring = sprint((t, s) -> show(t, "text/plain", s), result.values) + resstring = sprint((t, s) -> show(t, "text/plain", s), result) + valstring = sprint((t, s) -> show(t, "text/plain", s), result.values) vecsstring = sprint((t, s) -> show(t, "text/plain", s), result.vectors) λs, ψs, Ts = eigenstates(σx, sparse=true, k=2) λs1, ψs1, Ts1 = eigenstates(σx, sparse=true, k=1) @test all([ψ.type isa KetQuantumObject for ψ in ψd]) - @test typeof(Td) <: AbstractMatrix - @test typeof(Ts) <: AbstractMatrix + @test typeof(Td) <: AbstractMatrix + @test typeof(Ts) <: AbstractMatrix @test typeof(Ts1) <: AbstractMatrix @test all(abs.(eigenenergies(σx, sparse=false)) .≈ abs.(λd)) @test all(abs.(eigenenergies(σx, sparse=true, k=2)) .≈ abs.(λs)) @@ -32,7 +32,7 @@ vals_d, vecs_d, mat_d = eigenstates(H_d) vals_c, vecs_c, mat_c = eigenstates(H_c) - vals2, vecs2, mat2 = eigenstates(H_d, sparse=true, sigma=-0.9, k=10, krylovdim=30) + vals2, vecs2, mat2 = eigenstates(H_d, sparse=true, sigma=-0.9, k=10, krylovdim=30) sort!(vals_c, by=real) sort!(vals2, by=real) @@ -53,27 +53,27 @@ n_thermal = 0.01 H = ωc * a_d * a + ωb * b_d * b + g * (a + a_d) * (b + b_d) - c_ops = [√((1+n_thermal)*κ) * a, √κ * b, √(n_thermal*κ) * a_d] + c_ops = [√((1 + n_thermal) * κ) * a, √κ * b, √(n_thermal * κ) * a_d] L = liouvillian(H, c_ops) # 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)) - vals3, state3, vecs3 = eigsolve_al(liouvillian(H, c_ops), 1\(40*κ), k=10, krylovdim=50) + vals, _, vecs = eigsolve(L.data, sigma=0.01, k=10, krylovdim=50) + vals2, vecs2 = eigen(sparse_to_dense(L.data)) + vals3, state3, vecs3 = eigsolve_al(liouvillian(H, c_ops), 1 \ (40 * κ), k=10, krylovdim=50) idxs = sortperm(vals2, by=abs) vals2 = vals2[idxs][1:10] vecs2 = vecs2[:, idxs][:, 1:10] @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol=1e-7) @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol=1e-7) - @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im*angle(vecs[1,1])), vec2mat(vecs2[:, 1]), atol=1e-7) - @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im*angle(vecs[1,1])), vec2mat(vecs3[:, 1]), atol=1e-5) + @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs2[:, 1]), atol=1e-7) + @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs3[:, 1]), atol=1e-5) # eigen solve for QuantumObject result = eigenstates(L, sparse=true, sigma=0.01, k=10, krylovdim=50) vals, vecs = result - resstring = sprint((t, s) -> show(t, "text/plain", s), result) - valstring = sprint((t, s) -> show(t, "text/plain", s), result.values) + resstring = sprint((t, s) -> show(t, "text/plain", s), result) + valstring = sprint((t, s) -> show(t, "text/plain", s), result.values) vecsstring = sprint((t, s) -> show(t, "text/plain", s), result.vectors) @test resstring == "EigsolveResult: type=$(SuperOperator) dims=$(result.dims)\nvalues:\n$(valstring)\nvectors:\n$vecsstring" @@ -88,6 +88,6 @@ @test typeof(result.vectors) <: AbstractMatrix @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol=1e-7) @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol=1e-7) - @test isapprox(vec2mat(vecs[1]).data * exp(-1im*angle(vecs[1][1])), vec2mat(vecs2[1]).data, atol=1e-7) - @test isapprox(vec2mat(vecs[1]).data * exp(-1im*angle(vecs[1][1])), vec2mat(state3[1]).data, atol=1e-5) + @test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(vecs2[1]).data, atol=1e-7) + @test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(state3[1]).data, atol=1e-5) end \ No newline at end of file diff --git a/test/generalized_master_equation.jl b/test/generalized_master_equation.jl index 257d717e..1579affb 100644 --- a/test/generalized_master_equation.jl +++ b/test/generalized_master_equation.jl @@ -1,7 +1,7 @@ @testset "Generalized Master Equation" begin N_c = 30 N_trunc = 10 - tol=1e-14 + tol = 1e-14 a = kron(destroy(N_c), qeye(2)) sm = kron(qeye(N_c), sigmam()) @@ -15,30 +15,30 @@ 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) + Ω = dense_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(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)) # Standard liouvillian case - c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2] + c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2] L2 = liouvillian(H_d, c_ops) - @test (expect(Xp'*Xp, steadystate(L1)) < 1e-10 && expect(Xp'*Xp, steadystate(L2)) > 1e-3) + @test (expect(Xp' * Xp, steadystate(L1)) < 1e-10 && expect(Xp' * Xp, steadystate(L2)) > 1e-3) H = 1 * a' * a + 1 * sz / 2 + 1e-5 * (a * sp + a' * sm) 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) + Ω = dense_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(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)) - @test abs(expect(Xp'*Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < 1e-4 + @test abs(expect(Xp' * Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < 1e-4 end \ No newline at end of file diff --git a/test/low_rank_dynamics.jl b/test/low_rank_dynamics.jl index 8500aaae..1433a350 100644 --- a/test/low_rank_dynamics.jl +++ b/test/low_rank_dynamics.jl @@ -1,56 +1,56 @@ @testset "Low Rank Dynamics" begin # Define lattice - Nx,Ny = 2, 3 - latt = Lattice(Nx=Nx, Ny=Ny) - N_cut = 2 - N_modes = latt.N - N = N_cut^N_modes - M = Nx*Ny+1 + Nx, Ny = 2, 3 + latt = Lattice(Nx=Nx, Ny=Ny) + N_cut = 2 + N_modes = latt.N + N = N_cut^N_modes + M = Nx * Ny + 1 # Define initial state - ϕ = Vector{QuantumObject{Vector{ComplexF64}, KetQuantumObject}}(undef, M) - ϕ[1] = tensor(repeat([basis(2,0)], N_modes)...) - i=1 + ϕ = Vector{QuantumObject{Vector{ComplexF64},KetQuantumObject}}(undef, M) + ϕ[1] = tensor(repeat([basis(2, 0)], N_modes)...) + i = 1 for j in 1:N_modes - i+=1 - i<=M && (ϕ[i] = mb(sp, j, latt) * ϕ[1]) + i += 1 + i <= M && (ϕ[i] = mb(sp, j, latt) * ϕ[1]) end for k in 1:N_modes-1 - for l=k+1:N_modes - i+=1 - i<=M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1]) + for l = k+1:N_modes + i += 1 + i <= M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1]) end end for i in i+1:M - ϕ[i] = Qobj(rand(ComplexF64,size(ϕ[1])[1]), dims=ϕ[1].dims) + ϕ[i] = Qobj(rand(ComplexF64, size(ϕ[1])[1]), dims=ϕ[1].dims) normalize!(ϕ[i]) end - z = hcat(broadcast(x->x.data, ϕ)...) - B = Matrix(Diagonal([1+0im; zeros(M-1)])) - S = z'*z - B = B / tr(S*B) - ρ = Qobj(z*B*z', dims=ones(Int,N_modes)*N_cut) + z = hcat(broadcast(x -> x.data, ϕ)...) + B = Matrix(Diagonal([1 + 0im; zeros(M - 1)])) + S = z' * z + B = B / tr(S * B) + ρ = Qobj(z * B * z', dims=ones(Int, N_modes) * N_cut) # Define Hamiltonian and collapse operators - Jx = 0.9 + Jx = 0.9 Jy = 1.02 - Jz = 1. - hx = 0. - γ = 1 + Jz = 1.0 + hx = 0.0 + γ = 1 Sz = sum([mb(sz, i, latt) for i in 1:latt.N]) - tl = LinRange(0,10,100) + tl = LinRange(0, 10, 100) H, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc=pbc, order=1) e_ops = (Sz,) # Full solution - mesol = mesolve(H, ρ, tl, c_ops; e_ops=[e_ops...], progress_bar=false); + mesol = mesolve(H, ρ, tl, c_ops; e_ops=[e_ops...], progress_bar=false) A = Matrix(mesol.states[end].data) λ = eigvals(Hermitian(A)) - Strue = -sum(λ.*log2.(λ)) + Strue = -sum(λ .* log2.(λ)) # Low rank solution - function f_entropy(p,z,B) + function f_entropy(p, z, B) C = p.A0 σ = p.Bi mul!(C, z, sqrt(B)) @@ -60,22 +60,22 @@ return -sum(λ .* log2.(λ)) end - opt = LRMesolveOptions( - alg = Tsit5(), - err_max = 1e-3, - p0 = 0., - atol_inv = 1e-6, + opt = LRMesolveOptions( + alg=Tsit5(), + err_max=1e-3, + p0=0.0, + atol_inv=1e-6, adj_condition="variational", - Δt = 0.2, - progress = false + Δt=0.2, + progress=false ) lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops=e_ops, f_ops=(f_entropy,), opt=opt) # Test - m_me = real(mesol.expect[1,:]) - m_lr = real(lrsol.expvals[1,:]) - @test all(abs.((m_me .- m_lr)./m_me).<0.1) + m_me = real(mesol.expect[1, :]) + m_lr = real(lrsol.expvals[1, :]) + @test all(abs.((m_me .- m_lr) ./ m_me) .< 0.1) - S_lr = real(lrsol.funvals[1,end]) - @test abs((S_lr - Strue)/Strue) < 0.5 + S_lr = real(lrsol.funvals[1, end]) + @test abs((S_lr - Strue) / Strue) < 0.5 end \ No newline at end of file diff --git a/test/negativity_and_partial_transpose.jl b/test/negativity_and_partial_transpose.jl index 2a9bb93d..4c377b60 100644 --- a/test/negativity_and_partial_transpose.jl +++ b/test/negativity_and_partial_transpose.jl @@ -1,11 +1,11 @@ @testset "Negativity and Partial Transpose" begin # tests for negativity rho = (1 / 40) * Qobj([ - 15 1 1 15; - 1 5 -3 1; - 1 -3 5 1; - 15 1 1 15]; - dims = [2, 2] + 15 1 1 15; + 1 5 -3 1; + 1 -3 5 1; + 15 1 1 15]; + dims=[2, 2] ) Neg = negativity(rho, 1) @test Neg ≈ 0.25 @@ -15,7 +15,7 @@ # tests for partial transpose (PT) # A (24 * 24)-matrix which contains number 1 ~ 576 - A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims = [2, 3, 4]) + A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims=[2, 3, 4]) A_sparse = dense_to_sparse(A_dense) PT = (true, false) for s1 in PT diff --git a/test/permutation.jl b/test/permutation.jl index 33db2737..92e3859d 100644 --- a/test/permutation.jl +++ b/test/permutation.jl @@ -4,18 +4,18 @@ Δ = 0 G = 5 tg = 0 - θ = atan(tg) - U = sin(θ) + θ = atan(tg) + U = sin(θ) κ2 = cos(θ) - κ1 = 0. - κϕ = 1e-3 - nth = 0. + κ1 = 0.0 + κϕ = 1e-3 + nth = 0.0 - a = destroy(N) - ad = create(N) - H = -Δ*ad*a + G/2*(ad^2 + a^2) + U/2*(ad^2*a^2) - c_ops = [√(κ2)*a^2, √(κ1*(nth+1))*a, √(κ1*nth)*ad, √(κϕ)*ad*a] - L = liouvillian(H,c_ops) + a = destroy(N) + ad = create(N) + H = -Δ * ad * a + G / 2 * (ad^2 + a^2) + U / 2 * (ad^2 * a^2) + c_ops = [√(κ2) * a^2, √(κ1 * (nth + 1)) * a, √(κ1 * nth) * ad, √(κϕ) * ad * a] + L = liouvillian(H, c_ops) P, L_bd, block_sizes = bdf(L) blocks_list, block_indices = get_bdf_blocks(L_bd, block_sizes) diff --git a/test/quantum_objects.jl b/test/quantum_objects.jl index c27869e4..910a6865 100644 --- a/test/quantum_objects.jl +++ b/test/quantum_objects.jl @@ -9,10 +9,10 @@ N = 10 a = rand(ComplexF64, 10) # @test_logs (:warn, "The norm of the input data is not one.") QuantumObject(a) - @test_throws DomainError Qobj(a, type=Bra) - @test_throws DomainError Qobj(a, type=Operator) - @test_throws DomainError Qobj(a, type=SuperOperator) - @test_throws DomainError Qobj(a, type=OperatorBra) + @test_throws DomainError Qobj(a, type=Bra) + @test_throws DomainError Qobj(a, type=Operator) + @test_throws DomainError Qobj(a, type=SuperOperator) + @test_throws DomainError Qobj(a, type=OperatorBra) @test_throws DomainError Qobj(a', type=Ket) @test_throws DomainError Qobj(a', type=Operator) @test_throws DomainError Qobj(a', type=SuperOperator) @@ -57,9 +57,9 @@ @test_throws DimensionMismatch Qobj(a, dims=[2]) # Operator-Ket, Operator-Bra tests - H = 0.3 * sigmax() + 0.7 * sigmaz() - L = liouvillian(H) - ρ = Qobj(rand(ComplexF64, 2, 2)) + H = 0.3 * sigmax() + 0.7 * sigmaz() + L = liouvillian(H) + ρ = Qobj(rand(ComplexF64, 2, 2)) ρ_ket = mat2vec(ρ) ρ_bra = ρ_ket' @test ρ_bra == Qobj(mat2vec(ρ.data)', type=OperatorBra) @@ -78,7 +78,7 @@ @test isoperbra(ρ_bra) == true @test ρ_bra.dims == [2] @test ρ_ket.dims == [2] - @test H * ρ ≈ spre(H) * ρ + @test H * ρ ≈ spre(H) * ρ @test ρ * H ≈ spost(H) * ρ @test H * ρ * H ≈ sprepost(H, H) * ρ @test (L * ρ_ket).dims == [2] @@ -217,14 +217,14 @@ @test isapprox(abs(α), 3, atol=1e-5) && abs2(δψ[1]) > 0.999 # svdvals, Schatten p-norm - vd = Qobj( rand(ComplexF64, 10)) + vd = Qobj(rand(ComplexF64, 10)) vs = Qobj(sprand(ComplexF64, 100, 0.1)) - Md = Qobj( rand(ComplexF64, 10, 10)) + Md = Qobj(rand(ComplexF64, 10, 10)) Ms = Qobj(sprand(ComplexF64, 10, 10, 0.5)) @test svdvals(vd)[1] ≈ √(vd' * vd) @test svdvals(vs)[1] ≈ √(vs' * vs) - @test norm(Md, 1) ≈ sum(sqrt, abs.(eigenenergies(Md' * Md))) atol=1e-6 - @test norm(Ms, 1) ≈ sum(sqrt, abs.(eigenenergies(Ms' * Ms))) atol=1e-6 + @test norm(Md, 1) ≈ sum(sqrt, abs.(eigenenergies(Md' * Md))) atol = 1e-6 + @test norm(Ms, 1) ≈ sum(sqrt, abs.(eigenenergies(Ms' * Ms))) atol = 1e-6 # trace distance ψz0 = basis(2, 0) @@ -233,9 +233,9 @@ ρz1 = dense_to_sparse(ket2dm(ψz1)) ψx0 = sqrt(0.5) * (basis(2, 0) + basis(2, 1)) @test tracedist(ψz0, ψx0) ≈ sqrt(0.5) - @test tracedist(ρz0, ψz1) ≈ 1. - @test tracedist(ψz1, ρz0) ≈ 1. - @test tracedist(ρz0, ρz1) ≈ 1. + @test tracedist(ρz0, ψz1) ≈ 1.0 + @test tracedist(ψz1, ρz0) ≈ 1.0 + @test tracedist(ρz0, ρz1) ≈ 1.0 # Broadcasting a = destroy(20) @@ -270,14 +270,14 @@ @test typeof(Vector(vs).data) == Vector{Int64} @test typeof(Vector{ComplexF64}(vd).data) == Vector{ComplexF64} @test typeof(Vector{ComplexF64}(vs).data) == Vector{ComplexF64} - @test typeof(SparseVector(vd).data) == SparseVector{Int64, Int64} - @test typeof(SparseVector(vs).data) == SparseVector{Int64, Int64} - @test typeof(SparseVector{ComplexF64}(vs).data) == SparseVector{ComplexF64, Int64} + @test typeof(SparseVector(vd).data) == SparseVector{Int64,Int64} + @test typeof(SparseVector(vs).data) == SparseVector{Int64,Int64} + @test typeof(SparseVector{ComplexF64}(vs).data) == SparseVector{ComplexF64,Int64} @test typeof(Matrix(Md).data) == Matrix{Int64} @test typeof(Matrix(Ms).data) == Matrix{Int64} @test typeof(Matrix{ComplexF64}(Ms).data) == Matrix{ComplexF64} @test typeof(Matrix{ComplexF64}(Md).data) == Matrix{ComplexF64} - @test typeof(SparseMatrixCSC(Md).data) == SparseMatrixCSC{Int64, Int64} - @test typeof(SparseMatrixCSC(Ms).data) == SparseMatrixCSC{Int64, Int64} - @test typeof(SparseMatrixCSC{ComplexF64}(Ms).data) == SparseMatrixCSC{ComplexF64, Int64} + @test typeof(SparseMatrixCSC(Md).data) == SparseMatrixCSC{Int64,Int64} + @test typeof(SparseMatrixCSC(Ms).data) == SparseMatrixCSC{Int64,Int64} + @test typeof(SparseMatrixCSC{ComplexF64}(Ms).data) == SparseMatrixCSC{ComplexF64,Int64} end \ No newline at end of file diff --git a/test/steady_state.jl b/test/steady_state.jl index 8e34af08..7a2c06e8 100644 --- a/test/steady_state.jl +++ b/test/steady_state.jl @@ -17,7 +17,7 @@ e_ops = [a_d * a] psi0 = fock(N, 3) t_l = LinRange(0, 200, 1000) - H_t_f = TimeDependentOperatorSum([(t,p) -> sin(t)], [liouvillian(H_t)]) + H_t_f = TimeDependentOperatorSum([(t, p) -> sin(t)], [liouvillian(H_t)]) sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, H_t=H_t_f, alg=Vern7(), progress_bar=false) ρ_ss = steadystate_floquet(H, c_ops, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1) @test abs(sum(sol_me.expect[1, end-100:end]) / 101 - expect(e_ops[1], ρ_ss)) < 1e-2 From 74b01d9d14fbefd4438160022babb1aa6547c720 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 21 May 2024 00:22:44 +0200 Subject: [PATCH 2/4] Add GitHub Action --- .github/workflows/Format.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/Format.yml diff --git a/.github/workflows/Format.yml b/.github/workflows/Format.yml new file mode 100644 index 00000000..1e9382c0 --- /dev/null +++ b/.github/workflows/Format.yml @@ -0,0 +1,31 @@ +name: format-pr +on: + schedule: + - cron: '0 0 * * *' +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/cache@v1 + - name: Install JuliaFormatter and format + run: | + julia -e 'import Pkg; Pkg.add("JuliaFormatter")' + julia -e 'using JuliaFormatter; format(".")' + + # https://github.com/marketplace/actions/create-pull-request + # https://github.com/peter-evans/create-pull-request#reference-example + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: Format .jl files + title: 'Automatic JuliaFormatter.jl run' + branch: auto-juliaformatter-pr + delete-branch: true + labels: formatting, automated pr, no changelog + - name: Check outputs + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" \ No newline at end of file From 89e7ebd2768bf80b4b7a8cec6f8e26581cd84a19 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 21 May 2024 01:37:15 +0200 Subject: [PATCH 3/4] Custom formatter configs --- .JuliaFormatter.toml | 6 + benchmarks/correlations_and_spectrum.jl | 15 +- benchmarks/dynamical_fock_dimension.jl | 13 +- benchmarks/eigenvalues.jl | 5 +- benchmarks/timeevolution.jl | 58 ++- docs/make.jl | 54 +-- ext/QuantumToolboxCUDAExt.jl | 46 +- src/arnoldi.jl | 64 ++- src/correlations.jl | 116 +++-- src/eigsolve.jl | 343 ++++++++++---- src/general_functions.jl | 142 ++++-- src/negativity.jl | 27 +- src/permutation.jl | 9 +- src/progress_bar.jl | 29 +- src/quantum_object.jl | 573 +++++++++++++++++------ src/quantum_operators.jl | 63 ++- src/spin_lattice.jl | 46 +- src/versioninfo.jl | 56 +-- src/wigner.jl | 88 ++-- test/aqua.jl | 2 +- test/correlations_and_spectrum.jl | 11 +- test/cuda_ext.jl | 102 ++-- test/dynamical-shifted-fock.jl | 98 +++- test/dynamical_fock_dimension_mesolve.jl | 63 ++- test/eigenvalues_and_operators.jl | 69 ++- test/generalized_master_equation.jl | 12 +- test/jet.jl | 6 +- test/low_rank_dynamics.jl | 28 +- test/negativity_and_partial_transpose.jl | 18 +- test/progress_bar.jl | 2 +- test/quantum_objects.jl | 60 ++- test/steady_state.jl | 13 +- test/time_evolution_and_partial_trace.jl | 23 +- test/wigner.jl | 8 +- 34 files changed, 1608 insertions(+), 660 deletions(-) create mode 100644 .JuliaFormatter.toml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 00000000..fda0404a --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,6 @@ +always_for_in=true +remove_extra_newlines=true +long_to_short_function_def=true +format_docstrings=true +indent_submodule=true +format_markdown=true diff --git a/benchmarks/correlations_and_spectrum.jl b/benchmarks/correlations_and_spectrum.jl index 2d15d200..6743a059 100644 --- a/benchmarks/correlations_and_spectrum.jl +++ b/benchmarks/correlations_and_spectrum.jl @@ -8,11 +8,20 @@ function benchmark_correlations_and_spectrum() H = ω * a' * a c_ops = [sqrt(γ * (nth + 1)) * a, sqrt(γ * nth) * a'] - ω_l = range(0, 3, length=1000) + ω_l = range(0, 3, length = 1000) - SUITE["Correlations and Spectrum"]["FFT Correlation"] = @benchmarkable spectrum($H, $ω_l, $(a'), $a, $c_ops, solver=FFTCorrelation(), progress_bar=false) + SUITE["Correlations and Spectrum"]["FFT Correlation"] = @benchmarkable spectrum( + $H, + $ω_l, + $(a'), + $a, + $c_ops, + solver = FFTCorrelation(), + progress_bar = false, + ) - SUITE["Correlations and Spectrum"]["Exponential Series"] = @benchmarkable spectrum($H, $ω_l, $(a'), $a, $c_ops) + SUITE["Correlations and Spectrum"]["Exponential Series"] = + @benchmarkable spectrum($H, $ω_l, $(a'), $a, $c_ops) end benchmark_correlations_and_spectrum() \ No newline at end of file diff --git a/benchmarks/dynamical_fock_dimension.jl b/benchmarks/dynamical_fock_dimension.jl index b37f0180..46421b96 100644 --- a/benchmarks/dynamical_fock_dimension.jl +++ b/benchmarks/dynamical_fock_dimension.jl @@ -23,11 +23,20 @@ function benchmark_dfd() maxdims = [50, 50] ψ0 = tensor(fock(3, 0), fock(20, 15)) - dfd_params = (Δ=Δ, F=F, κ=κ, J=J) + dfd_params = (Δ = Δ, F = F, κ = κ, J = J) tlist = range(0, 15 / κ, 100) - SUITE["Time Evolution"]["Dynamical Fock Dimension"] = @benchmarkable dfd_mesolve(H_dfd2, $ψ0, $tlist, c_ops_dfd2, $maxdims, $dfd_params, e_ops=e_ops_dfd2, progress_bar=false) + SUITE["Time Evolution"]["Dynamical Fock Dimension"] = @benchmarkable dfd_mesolve( + H_dfd2, + $ψ0, + $tlist, + c_ops_dfd2, + $maxdims, + $dfd_params, + e_ops = e_ops_dfd2, + progress_bar = false, + ) end benchmark_dfd() \ No newline at end of file diff --git a/benchmarks/eigenvalues.jl b/benchmarks/eigenvalues.jl index dcb48e2c..950ef5f2 100644 --- a/benchmarks/eigenvalues.jl +++ b/benchmarks/eigenvalues.jl @@ -12,11 +12,12 @@ function benchmark_eigenvalues() n_thermal = 0.1 H = ωc * a_d * a + ωb * b_d * b + g * (a + a_d) * (b + b_d) - c_ops = [√((1+n_thermal)*κ) * a, √κ * b, √(n_thermal*κ) * a_d] + c_ops = [√((1 + n_thermal) * κ) * a, √κ * b, √(n_thermal * κ) * a_d] L = liouvillian(H, c_ops) SUITE["Eigenvalues"]["eigenstates"]["dense"] = @benchmarkable eigenstates($L) - SUITE["Eigenvalues"]["eigenstates"]["sparse"] = @benchmarkable eigenstates($L, sparse=true, sigma=0.01, k=5) + SUITE["Eigenvalues"]["eigenstates"]["sparse"] = + @benchmarkable eigenstates($L, sparse = true, sigma = 0.01, k = 5) end benchmark_eigenvalues() \ No newline at end of file diff --git a/benchmarks/timeevolution.jl b/benchmarks/timeevolution.jl index aa9e47fc..e5380cbf 100644 --- a/benchmarks/timeevolution.jl +++ b/benchmarks/timeevolution.jl @@ -4,44 +4,72 @@ function benchmark_timeevolution() g = 0.1 ωd = 0.99 F = 0.07 - + Δc = ωc - ωd Δq = ωq - ωd - + # Operators definition N = 20 # cutoff for the cavity Hilbert space a = tensor(destroy(N), qeye(2)) σm = tensor(qeye(N), sigmam()) σz = tensor(qeye(N), sigmaz()) - + # Hamiltonian H = Δc * a' * a + Δq * σz / 2 + g * (a' * σm + a * σm') + F * (a + a') - - e_ops = [a'*a, σz] - + + e_ops = [a' * a, σz] + # Initial state ψ0 = tensor(coherent(N, 0), fock(2, 1)) ## sesolve ## - + tlist = range(0, 2π * 10 / g, 1000) - - SUITE["Time Evolution"]["time-independent"]["sesolve"] = @benchmarkable sesolve($H, $ψ0, $tlist, e_ops=$e_ops, progress_bar=false) + + SUITE["Time Evolution"]["time-independent"]["sesolve"] = + @benchmarkable sesolve($H, $ψ0, $tlist, e_ops = $e_ops, progress_bar = false) ## mesolve ## nth = 0.01 γ = 0.05 c_ops = [sqrt(γ * (nth + 1)) * a, sqrt(γ * nth) * a', sqrt(γ) * σm] - - tlist = range(0, 10/γ, 100) - - SUITE["Time Evolution"]["time-independent"]["mesolve"] = @benchmarkable mesolve($H, $ψ0, $tlist, $c_ops, e_ops=$e_ops, progress_bar=false) + + tlist = range(0, 10 / γ, 100) + + SUITE["Time Evolution"]["time-independent"]["mesolve"] = @benchmarkable mesolve( + $H, + $ψ0, + $tlist, + $c_ops, + e_ops = $e_ops, + progress_bar = false, + ) ## mcsolve ## - SUITE["Time Evolution"]["time-independent"]["mcsolve"]["Serial"] = @benchmarkable mcsolve($H, $ψ0, $tlist, $c_ops, n_traj=100, e_ops=$e_ops, progress_bar=false, ensemble_method=EnsembleSerial()) - SUITE["Time Evolution"]["time-independent"]["mcsolve"]["Multithreaded"] = @benchmarkable mcsolve($H, $ψ0, $tlist, $c_ops, n_traj=100, e_ops=$e_ops, progress_bar=false, ensemble_method=EnsembleThreads()) + SUITE["Time Evolution"]["time-independent"]["mcsolve"]["Serial"] = + @benchmarkable mcsolve( + $H, + $ψ0, + $tlist, + $c_ops, + n_traj = 100, + e_ops = $e_ops, + progress_bar = false, + ensemble_method = EnsembleSerial(), + ) + SUITE["Time Evolution"]["time-independent"]["mcsolve"]["Multithreaded"] = + @benchmarkable mcsolve( + $H, + $ψ0, + $tlist, + $c_ops, + n_traj = 100, + e_ops = $e_ops, + progress_bar = false, + ensemble_method = EnsembleThreads(), + ) end benchmark_timeevolution() \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index 274e63de..97e1410a 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,43 +1,43 @@ using QuantumToolbox using Documenter -ENV["GKSwstype"] = "100" # enable headless mode for GR to suppress warnings when plotting - -DocMeta.setdocmeta!(QuantumToolbox, :DocTestSetup, :(using QuantumToolbox); recursive=true) +DocMeta.setdocmeta!( + QuantumToolbox, + :DocTestSetup, + :(using QuantumToolbox); + recursive = true, +) makedocs(; - modules=[QuantumToolbox], - authors="Alberto Mercurio", - repo=Remotes.GitHub("albertomercurio", "QuantumToolbox.jl"), - sitename="QuantumToolbox.jl", - format=Documenter.HTML(; - prettyurls=get(ENV, "CI", "false") == "true", - canonical="https://albertomercurio.github.io/QuantumToolbox.jl", - edit_link="main", - assets=String[], - mathengine=MathJax3(Dict( - :loader => Dict("load" => ["[tex]/physics"]), - :tex => Dict( - "inlineMath" => [["\$", "\$"], ["\\(", "\\)"]], - "tags" => "ams", - "packages" => ["base", "ams", "autoload", "physics"], + modules = [QuantumToolbox], + authors = "Alberto Mercurio", + repo = Remotes.GitHub("albertomercurio", "QuantumToolbox.jl"), + sitename = "QuantumToolbox.jl", + format = Documenter.HTML(; + prettyurls = get(ENV, "CI", "false") == "true", + canonical = "https://albertomercurio.github.io/QuantumToolbox.jl", + edit_link = "main", + assets = String[], + mathengine = MathJax3( + Dict( + :loader => Dict("load" => ["[tex]/physics"]), + :tex => Dict( + "inlineMath" => [["\$", "\$"], ["\\(", "\\)"]], + "tags" => "ams", + "packages" => ["base", "ams", "autoload", "physics"], + ), ), - )), + ), ), - pages=[ + pages = [ "index.md", "api.md", "Tutorials" => [ "Creation of the QuantulToolbox.jl logo" => "tutorials/logo.md", "Low Rank Master Equation" => "tutorials/lowrank.md", ], - "Benchmarks" => [ - "Benchmark History" => "benchmarks/benchmark_history.md", - ] + "Benchmarks" => ["Benchmark History" => "benchmarks/benchmark_history.md"], ], ) -deploydocs(; - repo="github.com/albertomercurio/QuantumToolbox.jl", - devbranch="main", -) +deploydocs(; repo = "github.com/albertomercurio/QuantumToolbox.jl", devbranch = "main") diff --git a/ext/QuantumToolboxCUDAExt.jl b/ext/QuantumToolboxCUDAExt.jl index a7410385..c06615ff 100644 --- a/ext/QuantumToolboxCUDAExt.jl +++ b/ext/QuantumToolboxCUDAExt.jl @@ -10,56 +10,64 @@ 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.dims) +CuArray(A::QuantumObject{Tq}) where {Tq<:Union{Vector,Matrix}} = + QuantumObject(CuArray(A.data), A.type, A.dims) @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.dims) +CuArray{T}(A::QuantumObject{Tq}) where {T,Tq<:Union{Vector,Matrix}} = + QuantumObject(CuArray{T}(A.data), A.type, A.dims) @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.dims) +CuSparseVector(A::QuantumObject{<:SparseVector}) = + QuantumObject(CuSparseVector(A.data), A.type, A.dims) @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.dims) +CuSparseVector{T}(A::QuantumObject{<:SparseVector}) where {T} = + QuantumObject(CuSparseVector{T}(A.data), A.type, A.dims) @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.dims) +CuSparseMatrixCSC(A::QuantumObject{<:SparseMatrixCSC}) = + QuantumObject(CuSparseMatrixCSC(A.data), A.type, A.dims) @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.dims) +CuSparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = + QuantumObject(CuSparseMatrixCSC{T}(A.data), A.type, A.dims) @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.dims) +CuSparseMatrixCSR(A::QuantumObject{<:SparseMatrixCSC}) = + QuantumObject(CuSparseMatrixCSR(A.data), A.type, A.dims) @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.dims) +CuSparseMatrixCSR{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = + QuantumObject(CuSparseMatrixCSR{T}(A.data), A.type, A.dims) @doc raw""" cu(A::QuantumObject; word_size::Int=32) @@ -70,16 +78,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 `32`. """ -cu(A::QuantumObject; word_size::Int=32) = ((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) +cu(A::QuantumObject; word_size::Int = 32) = + ((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) _change_eltype(::Type{T}, ::Val{64}) where {T<:Int} = Int64 _change_eltype(::Type{T}, ::Val{32}) where {T<:Int} = Int32 _change_eltype(::Type{T}, ::Val{64}) where {T<:AbstractFloat} = Float64 _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 +_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 end \ No newline at end of file diff --git a/src/arnoldi.jl b/src/arnoldi.jl index eaa7f9bf..c3d9ce64 100644 --- a/src/arnoldi.jl +++ b/src/arnoldi.jl @@ -1,22 +1,35 @@ export ArnoldiSpace, arnoldi, arnoldi!, arnoldi_init!, arnoldi_step! export expv!, expv -struct ArnoldiSpace{VT<:AbstractMatrix{<:BlasFloat},HT<:AbstractMatrix{<:BlasFloat},mT<:Integer} +struct ArnoldiSpace{ + VT<:AbstractMatrix{<:BlasFloat}, + HT<:AbstractMatrix{<:BlasFloat}, + mT<:Integer, +} V::VT H::HT Hcopy::HT m::mT end -function Base.copy(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}) where {T1<:BlasFloat} +function Base.copy( + AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, +) where {T1<:BlasFloat} ArnoldiSpace(copy(AS.V), copy(AS.H), copy(AS.Hcopy), AS.m) end -function Base.deepcopy(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}) where {T1<:BlasFloat} +function Base.deepcopy( + AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, +) where {T1<:BlasFloat} ArnoldiSpace(deepcopy(AS.V), deepcopy(AS.H), deepcopy(AS.Hcopy), AS.m) end -function arnoldi_init!(A, b::AbstractVector{T}, V::AbstractMatrix{T}, H::AbstractMatrix{T}) where {T<:BlasFloat} +function arnoldi_init!( + A, + b::AbstractVector{T}, + V::AbstractMatrix{T}, + H::AbstractMatrix{T}, +) where {T<:BlasFloat} v₁ = view(V, :, 1) v₂ = view(V, :, 2) v₁ .= b @@ -29,11 +42,16 @@ function arnoldi_init!(A, b::AbstractVector{T}, V::AbstractMatrix{T}, H::Abstrac v₂ ./= H[2, 1] end -function arnoldi_step!(A, V::AbstractMatrix{T}, H::AbstractMatrix{T}, i::TI) where {T<:BlasFloat,TI<:Integer} +function arnoldi_step!( + A, + V::AbstractMatrix{T}, + H::AbstractMatrix{T}, + i::TI, +) where {T<:BlasFloat,TI<:Integer} vᵢ = view(V, :, i) vᵢ₊₁ = view(V, :, i + 1) mul!(vᵢ₊₁, A, vᵢ) - for j = 1:i + for j in 1:i vⱼ = view(V, :, j) H[j, i] = dot(vⱼ, vᵢ₊₁) axpy!(-H[j, i], vⱼ, vᵢ₊₁) @@ -43,7 +61,11 @@ function arnoldi_step!(A, V::AbstractMatrix{T}, H::AbstractMatrix{T}, i::TI) whe return β end -function arnoldi!(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, A, b::AbstractVector{T2}) where {T1<:BlasFloat,T2<:BlasFloat} +function arnoldi!( + AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, + A, + b::AbstractVector{T2}, +) where {T1<:BlasFloat,T2<:BlasFloat} n = size(A, 2) V = AS.V H = AS.H @@ -53,7 +75,7 @@ function arnoldi!(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, A n == length(b) || throw(DimensionMismatch()) arnoldi_init!(A, b, V, H) - for i = 2:m + for i in 2:m arnoldi_step!(A, V, H, i) end return AS @@ -69,9 +91,12 @@ end ### EXPV TOOLS ### -function expv!(x::AbstractVector{T1}, AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, - t::T2, b::AbstractVector{T1}) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} - +function expv!( + x::AbstractVector{T1}, + AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, + t::T2, + b::AbstractVector{T1}, +) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} H = AS.H Hcopy = AS.Hcopy V = AS.V @@ -96,12 +121,23 @@ function expv!(x::AbstractVector{T1}, AS::ArnoldiSpace{<:AbstractMatrix{T1},<:Ab return x end -function expv!(x::AbstractVector{T1}, A, t::T2, b::AbstractVector{T1}; m::Int=min(30, cld(2 * length(b), 3))) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} +function expv!( + x::AbstractVector{T1}, + A, + t::T2, + b::AbstractVector{T1}; + m::Int = min(30, cld(2 * length(b), 3)), +) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} AS = arnoldi(A, b, m) expv!(x, AS, t, b) end -function expv(A, t::T1, b::AbstractVector{T2}; m::Int=min(30, cld(2 * length(b), 3))) where {T1<:BlasFloat,T2<:BlasFloat} +function expv( + A, + t::T1, + b::AbstractVector{T2}; + m::Int = min(30, cld(2 * length(b), 3)), +) where {T1<:BlasFloat,T2<:BlasFloat} x = similar(b) - expv!(x, A, t, b, m=m) + expv!(x, A, t, b, m = m) end \ No newline at end of file diff --git a/src/correlations.jl b/src/correlations.jl index 75448bb2..ba998347 100644 --- a/src/correlations.jl +++ b/src/correlations.jl @@ -10,7 +10,8 @@ struct ExponentialSeries <: SpectrumSolver calc_steadystate::Bool end -ExponentialSeries(; tol=1e-14, calc_steadystate=false) = ExponentialSeries(tol, calc_steadystate) +ExponentialSeries(; tol = 1e-14, calc_steadystate = false) = + ExponentialSeries(tol, calc_steadystate) @doc raw""" correlation_3op_2t(H::QuantumObject, @@ -26,24 +27,38 @@ ExponentialSeries(; tol=1e-14, calc_steadystate=false) = ExponentialSeries(tol, Returns the two-times correlation function of three operators ``\hat{A}``, ``\hat{B}`` and ``\hat{C}``: ``\expval{\hat{A}(t) \hat{B}(t + \tau) \hat{C}(t)}`` for a given initial state ``\ket{\psi_0}``. """ -function correlation_3op_2t(H::QuantumObject{<:AbstractArray{T1},HOpType}, +function correlation_3op_2t( + H::QuantumObject{<:AbstractArray{T1},HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, - t_l::AbstractVector, τ_l::AbstractVector, + t_l::AbstractVector, + τ_l::AbstractVector, A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, C::QuantumObject{<:AbstractArray{T5},OperatorQuantumObject}, - c_ops::AbstractVector=[]; - kwargs...) where {T1,T2,T3,T4,T5,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - - (H.dims == ψ0.dims && H.dims == A.dims && - H.dims == B.dims && H.dims == C.dims) || throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + c_ops::AbstractVector = []; + kwargs..., +) where { + T1, + T2, + T3, + T4, + T5, + HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, +} + (H.dims == ψ0.dims && H.dims == A.dims && H.dims == B.dims && H.dims == C.dims) || + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) kwargs2 = (; kwargs...) - kwargs2 = merge(kwargs2, (saveat=collect(t_l),)) + kwargs2 = merge(kwargs2, (saveat = collect(t_l),)) ρt = mesolve(H, ψ0, t_l, c_ops; kwargs2...).states - corr = map((t, ρ) -> mesolve(H, C * ρ * A, τ_l .+ t, c_ops, e_ops=[B]; kwargs...).expect[1, :], t_l, ρt) + corr = map( + (t, ρ) -> + mesolve(H, C * ρ * A, τ_l .+ t, c_ops, e_ops = [B]; kwargs...).expect[1, :], + t_l, + ρt, + ) corr end @@ -63,18 +78,25 @@ Returns the two-times correlation function of two operators ``\hat{A}`` and ``\h at different times ``\expval{\hat{A}(t + \tau) \hat{B}(t)}``. When ``reverse=true``, the correlation function is calculated as ``\expval{\hat{A}(t) \hat{B}(t + \tau)}``. """ -function correlation_2op_2t(H::QuantumObject{<:AbstractArray{T1},HOpType}, +function correlation_2op_2t( + H::QuantumObject{<:AbstractArray{T1},HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, t_l::AbstractVector, τ_l::AbstractVector, A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, - c_ops::AbstractVector=[]; - reverse::Bool=false, - kwargs...) where {T1,T2,T3,T4,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - - C = eye(prod(H.dims), dims=H.dims) + c_ops::AbstractVector = []; + reverse::Bool = false, + kwargs..., +) where { + T1, + T2, + T3, + T4, + HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, +} + C = eye(prod(H.dims), dims = H.dims) if reverse corr = correlation_3op_2t(H, ψ0, t_l, τ_l, A, B, C, c_ops; kwargs...) else @@ -98,17 +120,24 @@ Returns the one-time correlation function of two operators ``\hat{A}`` and ``\ha at different times ``\expval{\hat{A}(\tau) \hat{B}(0)}``. When ``reverse=true``, the correlation function is calculated as ``\expval{\hat{A}(0) \hat{B}(\tau)}``. """ -function correlation_2op_1t(H::QuantumObject{<:AbstractArray{T1},HOpType}, +function correlation_2op_1t( + H::QuantumObject{<:AbstractArray{T1},HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, τ_l::AbstractVector, A::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T4},OperatorQuantumObject}, - c_ops::AbstractVector=[]; - reverse::Bool=false, - kwargs...) where {T1,T2,T3,T4,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - - corr = correlation_2op_2t(H, ψ0, [0], τ_l, A, B, c_ops; reverse=reverse, kwargs...) + c_ops::AbstractVector = []; + reverse::Bool = false, + kwargs..., +) where { + T1, + T2, + T3, + T4, + HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, +} + corr = correlation_2op_2t(H, ψ0, [0], τ_l, A, B, c_ops; reverse = reverse, kwargs...) corr[:, 1] end @@ -124,35 +153,42 @@ end Returns the emission spectrum ``S(\omega) = \int_{-\infty}^\infty \expval{\hat{A}(\tau) \hat{B}(0)} e^{-i \omega \tau} d \tau``. """ -function spectrum(H::QuantumObject{MT1,HOpType}, +function spectrum( + H::QuantumObject{MT1,HOpType}, ω_list::AbstractVector, A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, - c_ops::Vector{QuantumObject{MT2,COpType}}=Vector{QuantumObject{MT1,HOpType}}([]); - solver::MySolver=ExponentialSeries(), - kwargs...) where {MT1<:AbstractMatrix,MT2<:AbstractMatrix,T2,T3, + c_ops::Vector{QuantumObject{MT2,COpType}} = Vector{QuantumObject{MT1,HOpType}}([]); + solver::MySolver = ExponentialSeries(), + kwargs..., +) where { + MT1<:AbstractMatrix, + MT2<:AbstractMatrix, + T2, + T3, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - MySolver<:SpectrumSolver} - + MySolver<:SpectrumSolver, +} return _spectrum(H, ω_list, A, B, c_ops, solver; kwargs...) end -function _spectrum(H::QuantumObject{<:AbstractArray{T1},HOpType}, +function _spectrum( + H::QuantumObject{<:AbstractArray{T1},HOpType}, ω_list::AbstractVector, A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, c_ops, solver::FFTCorrelation; - kwargs...) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + kwargs..., +) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} Nsamples = length(ω_list) ω_max = abs(maximum(ω_list)) dω = 2 * ω_max / (Nsamples - 1) ω_l = -ω_max:dω:ω_max T = 2π / (ω_l[2] - ω_l[1]) - τ_l = range(0, T, length=length(ω_l)) + τ_l = range(0, T, length = length(ω_l)) ρss = steadystate(H, c_ops) corr = correlation_2op_1t(H, ρss, τ_l, A, B, c_ops; kwargs...) @@ -162,15 +198,17 @@ function _spectrum(H::QuantumObject{<:AbstractArray{T1},HOpType}, return ω_l, 2 .* real.(S) end -function _spectrum(H::QuantumObject{<:AbstractArray{T1},HOpType}, +function _spectrum( + H::QuantumObject{<:AbstractArray{T1},HOpType}, ω_list::AbstractVector, A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject}, c_ops, solver::ExponentialSeries; - kwargs...) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - - (H.dims == A.dims == B.dims) || throw(DimensionMismatch("The dimensions of H, A and B must be the same")) + kwargs..., +) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} + (H.dims == A.dims == B.dims) || + throw(DimensionMismatch("The dimensions of H, A and B must be the same")) L = liouvillian(H, c_ops) diff --git a/src/eigsolve.jl b/src/eigsolve.jl index ddf71dbe..55bcb792 100644 --- a/src/eigsolve.jl +++ b/src/eigsolve.jl @@ -46,7 +46,11 @@ julia> T 0.707107+0.0im 0.707107+0.0im ``` """ -struct EigsolveResult{T1<:Vector{<:Number},T2<:AbstractMatrix{<:Number},ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} +struct EigsolveResult{ + T1<:Vector{<:Number}, + T2<:AbstractMatrix{<:Number}, + ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}, +} values::T1 vectors::T2 type::ObjType @@ -57,9 +61,22 @@ struct EigsolveResult{T1<:Vector{<:Number},T2<:AbstractMatrix{<:Number},ObjType< end Base.iterate(res::EigsolveResult) = (res.values, Val(:vector_list)) -Base.iterate(res::EigsolveResult{T1,T2,Nothing}, ::Val{:vector_list}) where {T1,T2} = ([res.vectors[:, k] for k in 1:length(res.values)], Val(:vectors)) -Base.iterate(res::EigsolveResult{T1,T2,OperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} = ([QuantumObject(res.vectors[:, k], Ket, res.dims) for k in 1:length(res.values)], Val(:vectors)) -Base.iterate(res::EigsolveResult{T1,T2,SuperOperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} = ([QuantumObject(res.vectors[:, k], OperatorKet, res.dims) for k in 1:length(res.values)], Val(:vectors)) +Base.iterate(res::EigsolveResult{T1,T2,Nothing}, ::Val{:vector_list}) where {T1,T2} = + ([res.vectors[:, k] for k in 1:length(res.values)], Val(:vectors)) +Base.iterate( + res::EigsolveResult{T1,T2,OperatorQuantumObject}, + ::Val{:vector_list}, +) where {T1,T2} = ( + [QuantumObject(res.vectors[:, k], Ket, res.dims) for k in 1:length(res.values)], + Val(:vectors), +) +Base.iterate( + res::EigsolveResult{T1,T2,SuperOperatorQuantumObject}, + ::Val{:vector_list}, +) where {T1,T2} = ( + [QuantumObject(res.vectors[:, k], OperatorKet, res.dims) for k in 1:length(res.values)], + Val(:vectors), +) Base.iterate(res::EigsolveResult, ::Val{:vectors}) = (res.vectors, Val(:done)) Base.iterate(res::EigsolveResult, ::Val{:done}) = nothing @@ -73,9 +90,7 @@ function Base.show(io::IO, res::EigsolveResult) end if VERSION < v"1.10" - for (hseqr, elty) in - ((:zhseqr_, :ComplexF64), - (:chseqr_, :ComplexF32)) + for (hseqr, elty) in ((:zhseqr_, :ComplexF64), (:chseqr_, :ComplexF32)) @eval begin # * .. Scalar Arguments .. # CHARACTER JOB, COMPZ @@ -83,8 +98,14 @@ if VERSION < v"1.10" # * .. # * .. Array Arguments .. # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) - function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Int, ihi::Int, - H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + function hseqr!( + job::AbstractChar, + compz::AbstractChar, + ilo::Int, + ihi::Int, + H::AbstractMatrix{$elty}, + Z::AbstractMatrix{$elty}, + ) require_one_based_indexing(H, Z) chkstride1(H) n = checksquare(H) @@ -95,15 +116,39 @@ if VERSION < v"1.10" work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) info = Ref{BlasInt}() - for i = 1:2 # first call returns lwork as work[1] - ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, - (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, - Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, - Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, - Ptr{BlasInt}), - job, compz, n, ilo, ihi, - H, ldh, w, Z, ldz, work, - lwork, info) + for i in 1:2 # first call returns lwork as work[1] + ccall( + (@blasfunc($hseqr), libblastrampoline), + Cvoid, + ( + Ref{UInt8}, + Ref{UInt8}, + Ref{BlasInt}, + Ref{BlasInt}, + Ref{BlasInt}, + Ptr{$elty}, + Ref{BlasInt}, + Ptr{$elty}, + Ptr{$elty}, + Ref{BlasInt}, + Ptr{$elty}, + Ref{BlasInt}, + Ptr{BlasInt}, + ), + job, + compz, + n, + ilo, + ihi, + H, + ldh, + w, + Z, + ldz, + work, + lwork, + info, + ) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) @@ -115,9 +160,7 @@ if VERSION < v"1.10" end end - for (hseqr, elty) in - ((:dhseqr_, :Float64), - (:shseqr_, :Float32)) + for (hseqr, elty) in ((:dhseqr_, :Float64), (:shseqr_, :Float32)) @eval begin # * .. Scalar Arguments .. # CHARACTER JOB, COMPZ @@ -125,8 +168,14 @@ if VERSION < v"1.10" # * .. # * .. Array Arguments .. # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) - function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Int, ihi::Int, - H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + function hseqr!( + job::AbstractChar, + compz::AbstractChar, + ilo::Int, + ihi::Int, + H::AbstractMatrix{$elty}, + Z::AbstractMatrix{$elty}, + ) require_one_based_indexing(H, Z) chkstride1(H) n = checksquare(H) @@ -138,15 +187,41 @@ if VERSION < v"1.10" work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) info = Ref{BlasInt}() - for i = 1:2 # first call returns lwork as work[1] - ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, - (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, - Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ptr{$elty}, - Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, - Ptr{BlasInt}), - job, compz, n, ilo, ihi, - H, ldh, wr, wi, Z, ldz, work, - lwork, info) + for i in 1:2 # first call returns lwork as work[1] + ccall( + (@blasfunc($hseqr), libblastrampoline), + Cvoid, + ( + Ref{UInt8}, + Ref{UInt8}, + Ref{BlasInt}, + Ref{BlasInt}, + Ref{BlasInt}, + Ptr{$elty}, + Ref{BlasInt}, + Ptr{$elty}, + Ptr{$elty}, + Ptr{$elty}, + Ref{BlasInt}, + Ptr{$elty}, + Ref{BlasInt}, + Ptr{BlasInt}, + ), + job, + compz, + n, + ilo, + ihi, + H, + ldh, + wr, + wi, + Z, + ldz, + work, + lwork, + info, + ) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) @@ -157,8 +232,10 @@ if VERSION < v"1.10" end end end - hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) - hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) + hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = + hseqr!('S', 'V', 1, size(H, 1), H, Z) + hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = + hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) end function _map_ldiv(linsolve, y, x) @@ -166,7 +243,11 @@ function _map_ldiv(linsolve, y, x) y .= LinearSolve.solve!(linsolve).u end -function _permuteschur!(T::AbstractMatrix{S}, Q::AbstractMatrix{S}, order::AbstractVector{<:Integer}) where {S<:BlasFloat} +function _permuteschur!( + T::AbstractMatrix{S}, + Q::AbstractMatrix{S}, + order::AbstractVector{<:Integer}, +) where {S<:BlasFloat} n = checksquare(T) p = collect(order) # makes copy cause will be overwritten @inbounds for i in eachindex(p) @@ -187,23 +268,33 @@ function _update_schur_eigs!(Hₘ, Uₘ, Uₘᵥ, f, m, β, sorted_vals) copyto!(Uₘ, Hₘ) LAPACK.orghr!(1, m, Uₘ, F.τ) Tₘ, Uₘ, values = hseqr!(Hₘ, Uₘ) - sortperm!(sorted_vals, values, by=abs, rev=true) + sortperm!(sorted_vals, values, by = abs, rev = true) _permuteschur!(Tₘ, Uₘ, sorted_vals) mul!(f, Uₘᵥ, β) return Tₘ, Uₘ end -function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k::Int=1, - m::Int=max(20, 2 * k + 1); tol::Real=1e-8, maxiter::Int=200) where {T<:BlasFloat,ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} - +function _eigsolve( + A, + b::AbstractVector{T}, + type::ObjType, + dims::Vector{Int}, + k::Int = 1, + m::Int = max(20, 2 * k + 1); + tol::Real = 1e-8, + maxiter::Int = 200, +) where { + T<:BlasFloat, + ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}, +} n = size(A, 2) V = similar(b, n, m + 1) H = zeros(T, m + 1, m) arnoldi_init!(A, b, V, H) - for i = 2:m + for i in 2:m β = arnoldi_step!(A, V, H, i) if β < tol && i > k m = i # happy breakdown @@ -279,7 +370,6 @@ function _eigsolve(A, b::AbstractVector{T}, type::ObjType, dims::Vector{Int}, k: return EigsolveResult(vals, vecs, type, dims, iter, numops, (iter < maxiter)) end - @doc raw""" function eigsolve(A::QuantumObject; v0::Union{Nothing,AbstractVector}=nothing, sigma::Union{Nothing, Real}=nothing, k::Int = 1, @@ -289,29 +379,51 @@ end Solve for the eigenvalues and eigenvectors of a matrix `A` using the Arnoldi method. The keyword arguments are passed to the linear solver. """ -function eigsolve(A::QuantumObject{<:AbstractMatrix}; v0::Union{Nothing,AbstractVector}=nothing, - sigma::Union{Nothing,Real}=nothing, k::Int=1, - krylovdim::Int=max(20, 2 * k + 1), tol::Real=1e-8, maxiter::Int=200, - solver::Union{Nothing,LinearSolve.SciMLLinearSolveAlgorithm}=nothing, kwargs...) - - return eigsolve(A.data; v0=v0, type=A.type, dims=A.dims, sigma=sigma, k=k, krylovdim=krylovdim, tol=tol, - maxiter=maxiter, solver=solver, kwargs...) +function eigsolve( + A::QuantumObject{<:AbstractMatrix}; + v0::Union{Nothing,AbstractVector} = nothing, + sigma::Union{Nothing,Real} = nothing, + k::Int = 1, + krylovdim::Int = max(20, 2 * k + 1), + tol::Real = 1e-8, + maxiter::Int = 200, + solver::Union{Nothing,LinearSolve.SciMLLinearSolveAlgorithm} = nothing, + kwargs..., +) + return eigsolve( + A.data; + v0 = v0, + type = A.type, + dims = A.dims, + sigma = sigma, + k = k, + krylovdim = krylovdim, + tol = tol, + maxiter = maxiter, + solver = solver, + kwargs..., + ) end - -function eigsolve(A; v0::Union{Nothing,AbstractVector}=nothing, - type::Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}=nothing, - dims::Vector{Int}=Int[], - sigma::Union{Nothing,Real}=nothing, k::Int=1, - krylovdim::Int=max(20, 2 * k + 1), tol::Real=1e-8, maxiter::Int=200, - solver::Union{Nothing,LinearSolve.SciMLLinearSolveAlgorithm}=nothing, kwargs...) - +function eigsolve( + A; + v0::Union{Nothing,AbstractVector} = nothing, + type::Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject} = nothing, + dims::Vector{Int} = Int[], + sigma::Union{Nothing,Real} = nothing, + k::Int = 1, + krylovdim::Int = max(20, 2 * k + 1), + tol::Real = 1e-8, + maxiter::Int = 200, + solver::Union{Nothing,LinearSolve.SciMLLinearSolveAlgorithm} = nothing, + kwargs..., +) T = eltype(A) isH = ishermitian(A) v0 === nothing && (v0 = normalize!(rand(T, size(A, 1)))) if sigma === nothing - res = _eigsolve(A, v0, type, dims, k, krylovdim, tol=tol, maxiter=maxiter) + res = _eigsolve(A, v0, type, dims, k, krylovdim, tol = tol, maxiter = maxiter) vals = res.values else Aₛ = A - sigma * I @@ -319,25 +431,30 @@ function eigsolve(A; v0::Union{Nothing,AbstractVector}=nothing, kwargs2 = (; kwargs...) condition = !haskey(kwargs2, :Pl) && typeof(A) <: SparseMatrixCSC - condition && (kwargs2 = merge(kwargs2, (Pl=ilu(Aₛ, τ=0.01),))) + condition && (kwargs2 = merge(kwargs2, (Pl = ilu(Aₛ, τ = 0.01),))) - !haskey(kwargs2, :abstol) && (kwargs2 = merge(kwargs2, (abstol=tol * 1e-6,))) - !haskey(kwargs2, :reltol) && (kwargs2 = merge(kwargs2, (reltol=tol * 1e-6,))) + !haskey(kwargs2, :abstol) && (kwargs2 = merge(kwargs2, (abstol = tol * 1e-6,))) + !haskey(kwargs2, :reltol) && (kwargs2 = merge(kwargs2, (reltol = tol * 1e-6,))) prob = LinearProblem(Aₛ, v0) linsolve = init(prob, solver; kwargs2...) Amap = LinearMap{T}((y, x) -> _map_ldiv(linsolve, y, x), length(v0)) - res = _eigsolve(Amap, v0, type, dims, k, krylovdim, tol=tol, maxiter=maxiter) + res = _eigsolve(Amap, v0, type, dims, k, krylovdim, tol = tol, maxiter = maxiter) vals = @. (1 + sigma * res.values) / res.values end - return EigsolveResult(vals, res.vectors, res.type, res.dims, res.iter, res.numops, res.converged) + return EigsolveResult( + vals, + res.vectors, + res.type, + res.dims, + res.iter, + res.numops, + res.converged, + ) end - - - @doc raw""" eigsolve_al(H::QuantumObject, T::Real, c_ops::AbstractVector=[]; @@ -375,23 +492,36 @@ Solve the eigenvalue problem for a Liouvillian superoperator `L` using the Arnol Faster-than-the-clock algorithm for the spectrum of time-independent and Floquet open quantum systems. Quantum, 6, 649. """ -function eigsolve_al(H::QuantumObject{MT1,HOpType}, - T::Real, c_ops::Vector{QuantumObject{MT2,COpType}}=Vector{QuantumObject{MT1,HOpType}}([]); - alg::OrdinaryDiffEqAlgorithm=Tsit5(), - H_t::Union{Nothing,Function}=nothing, - params::NamedTuple=NamedTuple(), - ρ0::AbstractMatrix=rand_dm(prod(H.dims)).data, - k::Int=1, - krylovdim::Int=min(10, size(H, 1)), - maxiter::Int=200, - eigstol::Real=1e-6, - kwargs...) where {MT1<:AbstractMatrix,MT2<:AbstractMatrix, +function eigsolve_al( + H::QuantumObject{MT1,HOpType}, + T::Real, + c_ops::Vector{QuantumObject{MT2,COpType}} = Vector{QuantumObject{MT1,HOpType}}([]); + alg::OrdinaryDiffEqAlgorithm = Tsit5(), + H_t::Union{Nothing,Function} = nothing, + params::NamedTuple = NamedTuple(), + ρ0::AbstractMatrix = rand_dm(prod(H.dims)).data, + k::Int = 1, + krylovdim::Int = min(10, size(H, 1)), + maxiter::Int = 200, + eigstol::Real = 1e-6, + kwargs..., +) where { + MT1<:AbstractMatrix, + MT2<:AbstractMatrix, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} L = liouvillian(H, c_ops) - prob = mesolveProblem(L, QuantumObject(ρ0, dims=H.dims), [0, T]; alg=alg, - H_t=H_t, params=params, progress_bar=false, kwargs...) + prob = mesolveProblem( + L, + QuantumObject(ρ0, dims = H.dims), + [0, T]; + alg = alg, + H_t = H_t, + params = params, + progress_bar = false, + kwargs..., + ) integrator = init(prob, alg) # prog = ProgressUnknown(desc="Applications:", showspeed = true, enabled=progress) @@ -402,9 +532,18 @@ function eigsolve_al(H::QuantumObject{MT1,HOpType}, integrator.u end - Lmap = LinearMap{eltype(MT1)}(arnoldi_lindblad_solve, size(L, 1), ismutating=false) - - res = _eigsolve(Lmap, mat2vec(ρ0), L.type, L.dims, k, krylovdim, maxiter=maxiter, tol=eigstol) + Lmap = LinearMap{eltype(MT1)}(arnoldi_lindblad_solve, size(L, 1), ismutating = false) + + res = _eigsolve( + Lmap, + mat2vec(ρ0), + L.type, + L.dims, + k, + krylovdim, + maxiter = maxiter, + tol = eigstol, + ) # finish!(prog) vals = similar(res.values) @@ -416,7 +555,15 @@ function eigsolve_al(H::QuantumObject{MT1,HOpType}, @. vecs[:, i] = vec * exp(-1im * angle(vec[1])) end - return EigsolveResult(vals, vecs, res.type, res.dims, res.iter, res.numops, res.converged) + return EigsolveResult( + vals, + vecs, + res.type, + res.dims, + res.iter, + res.numops, + res.converged, + ) end @doc raw""" @@ -458,9 +605,10 @@ julia> expect(H, ψ[1]) ≈ E[1] true ``` """ -function LinearAlgebra.eigen(A::QuantumObject{MT,OpType}; kwargs...) where -{MT<:AbstractMatrix,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - +function LinearAlgebra.eigen( + A::QuantumObject{MT,OpType}; + kwargs..., +) where {MT<:AbstractMatrix,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} 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 @@ -474,8 +622,11 @@ end Same as [`eigen(A::QuantumObject; kwargs...)`](@ref) but for only the eigenvalues. """ -LinearAlgebra.eigvals(A::QuantumObject{<:AbstractArray{T},OpType}; kwargs...) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eigvals(sparse_to_dense(A.data); kwargs...) +LinearAlgebra.eigvals( + A::QuantumObject{<:AbstractArray{T},OpType}; + kwargs..., +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + eigvals(sparse_to_dense(A.data); kwargs...) @doc raw""" eigenenergies(A::QuantumObject; sparse::Bool=false, kwargs...) @@ -490,8 +641,11 @@ Calculate the eigenenergies # Returns - `::Vector{<:Number}`: a list of eigenvalues """ -function eigenenergies(A::QuantumObject{<:AbstractArray{T},OpType}; sparse::Bool=false, kwargs...) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +function eigenenergies( + A::QuantumObject{<:AbstractArray{T},OpType}; + sparse::Bool = false, + kwargs..., +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} if !sparse return eigvals(A; kwargs...) else @@ -512,8 +666,11 @@ Calculate the eigenvalues and corresponding eigenvectors # Returns - `::EigsolveResult`: containing the eigenvalues, the eigenvectors, and some information from the solver. see also [`EigsolveResult`](@ref) """ -function eigenstates(A::QuantumObject{<:AbstractArray{T},OpType}; sparse::Bool=false, kwargs...) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +function eigenstates( + A::QuantumObject{<:AbstractArray{T},OpType}; + sparse::Bool = false, + kwargs..., +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} if !sparse return eigen(A; kwargs...) else diff --git a/src/general_functions.jl b/src/general_functions.jl index 6d90c627..029e7e4d 100644 --- a/src/general_functions.jl +++ b/src/general_functions.jl @@ -8,9 +8,10 @@ export row_major_reshape, tidyup, tidyup!, meshgrid, sparse_to_dense, dense_to_s """ row_major_reshape(Q::AbstractArray, shapes...) -Reshapes `Q` in the row-major order, as numpy. +Reshapes `Q` in the row-major order, as numpy. """ -row_major_reshape(Q::AbstractArray{T}, shapes...) where {T} = PermutedDimsArray(reshape(Q, reverse(shapes)...), (length(shapes):-1:1)) +row_major_reshape(Q::AbstractArray{T}, shapes...) where {T} = + PermutedDimsArray(reshape(Q, reverse(shapes)...), (length(shapes):-1:1)) """ meshgrid(x::AbstractVector, y::AbstractVector) @@ -18,8 +19,8 @@ row_major_reshape(Q::AbstractArray{T}, shapes...) where {T} = PermutedDimsArray( Equivalent to [numpy meshgrid](https://numpy.org/doc/stable/reference/generated/numpy.meshgrid.html). """ function meshgrid(x::AbstractVector{T}, y::AbstractVector{T}) where {T} - X = reshape(repeat(x, inner=length(y)), length(y), length(x)) - Y = repeat(y, outer=(1, length(x))) + X = reshape(repeat(x, inner = length(y)), length(y), length(x)) + Y = repeat(y, outer = (1, length(x))) X, Y end @@ -28,7 +29,8 @@ end Converts a sparse QuantumObject to a dense QuantumObject. """ -sparse_to_dense(A::QuantumObject{<:AbstractVecOrMat}) = QuantumObject(sparse_to_dense(A.data), A.type, A.dims) +sparse_to_dense(A::QuantumObject{<:AbstractVecOrMat}) = + QuantumObject(sparse_to_dense(A.data), A.type, A.dims) sparse_to_dense(A::MT) where {MT<:AbstractSparseMatrix} = Array(A) for op in (:Transpose, :Adjoint) @eval sparse_to_dense(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = Array(A) @@ -50,15 +52,16 @@ 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.dims) -function dense_to_sparse(A::MT, tol::Real=1e-10) where {MT<:AbstractMatrix} +dense_to_sparse(A::QuantumObject{<:AbstractVecOrMat}, tol::Real = 1e-10) = + QuantumObject(dense_to_sparse(A.data, tol), A.type, A.dims) +function dense_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 dense_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)) @@ -69,9 +72,11 @@ end Removes those elements of a QuantumObject `A` whose 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.dims) -tidyup(A::AbstractArray{T}, tol::T2=1e-14) where {T,T2<:Real} = @. T(abs(A) > tol) * A -tidyup(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T,T2<:Real} = droptol!(copy(A), tol) +tidyup(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = + QuantumObject(tidyup(A.data, tol), A.type, A.dims) +tidyup(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = @. T(abs(A) > tol) * A +tidyup(A::AbstractSparseMatrix{T}, tol::T2 = 1e-14) where {T,T2<:Real} = + droptol!(copy(A), tol) """ tidyup!(A::QuantumObject, tol::Real=1e-14) @@ -79,9 +84,11 @@ tidyup(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T,T2<:Real} = droptol!( Removes those elements of a QuantumObject `A` whose absolute value is less than `tol`. In-place version of [`tidyup`](#tidyup). """ -tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2=1e-14) where {T,T2<:Real} = (tidyup!(A.data, tol); A) -tidyup!(A::AbstractArray{T}, tol::T2=1e-14) where {T,T2<:Real} = @. A = T(abs(A) > tol) * A -tidyup!(A::AbstractSparseMatrix{T}, tol::T2=1e-14) where {T,T2<:Real} = droptol!(A, tol) +tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = + (tidyup!(A.data, tol); A) +tidyup!(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = + @. A = T(abs(A) > tol) * A +tidyup!(A::AbstractSparseMatrix{T}, tol::T2 = 1e-14) where {T,T2<:Real} = droptol!(A, tol) """ get_data(A::QuantumObject) @@ -90,7 +97,6 @@ Returns the data of a QuantumObject. """ get_data(A::QuantumObject) = A.data - """ mat2vec(A::AbstractMatrix) @@ -102,11 +108,11 @@ function mat2vec(A::MT) where {MT<:AbstractSparseMatrix} return sparsevec(i .+ (j .- 1) .* size(A, 1), v, prod(size(A))) end for op in (:Transpose, :Adjoint) - @eval mat2vec(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = mat2vec(sparse(A)) + @eval mat2vec(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = + mat2vec(sparse(A)) @eval mat2vec(A::$op{T,<:AbstractMatrix}) where {T<:BlasFloat} = mat2vec(Matrix(A)) end - """ vec2mat(A::AbstractVector) @@ -122,7 +128,8 @@ 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.dims) +vec2mat(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = + QuantumObject(vec2mat(A.data), Operator, A.dims) @doc raw""" gaussian(x::Number, μ::Number, σ::Number) @@ -173,24 +180,29 @@ Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true 0.0+0.0im 0.5+0.0im ``` """ -function ptrace(QO::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, sel::Vector{T2}) where -{T1,T2<:Integer} - +function ptrace( + QO::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, + sel::Vector{T2}, +) where {T1,T2<:Integer} length(QO.dims) == 1 && return QO ρtr, dkeep = _ptrace_ket(QO.data, QO.dims, sel) - return QuantumObject(ρtr, dims=dkeep) + return QuantumObject(ρtr, dims = dkeep) end -ptrace(QO::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, sel::Vector{T2}) where {T1,T2<:Integer} = ptrace(QO', sel) - -function ptrace(QO::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, sel::Vector{T2}) where -{T1,T2<:Integer} +ptrace( + QO::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, + sel::Vector{T2}, +) where {T1,T2<:Integer} = ptrace(QO', sel) +function ptrace( + QO::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + sel::Vector{T2}, +) where {T1,T2<:Integer} length(QO.dims) == 1 && return QO ρtr, dkeep = _ptrace_oper(QO.data, QO.dims, sel) - return QuantumObject(ρtr, dims=dkeep) + return QuantumObject(ρtr, dims = dkeep) end ptrace(QO::QuantumObject, sel::Int) = ptrace(QO, [sel]) @@ -238,7 +250,11 @@ 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{<:AbstractArray{T},OperatorQuantumObject}; + base::Int = 0, + tol::Real = 1e-15, +) where {T} vals = eigvals(ρ) indexes = abs.(vals) .> tol 1 ∉ indexes && return 0 @@ -251,11 +267,12 @@ end entanglement(QO::QuantumObject, sel::Vector) Calculates the entanglement by doing the partial trace of `QO`, selecting only the dimensions -with the indices contained in the `sel` vector, and then using the Von Neumann entropy [`entropy_vn`](@ref). +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}, sel::Vector{Int}) where -{T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} - +function entanglement( + QO::QuantumObject{<:AbstractArray{T},OpType}, + sel::Vector{Int}, +) where {T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}} ψ = normalize(QO) ρ_tr = ptrace(ψ, sel) entropy = entropy_vn(ρ_tr) @@ -284,17 +301,26 @@ julia> expect(a' * a, ψ) ≈ 3 true ``` """ -function expect(O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ψ::QuantumObject{<:AbstractArray{T2},KetQuantumObject}) where {T1,T2} +function expect( + O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + ψ::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, +) where {T1,T2} ψd = ψ.data Od = O.data return ishermitian(O) ? real(dot(ψd, Od, ψd)) : dot(ψd, Od, ψd) end -function expect(O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ψ::QuantumObject{<:AbstractArray{T2},BraQuantumObject}) where {T1,T2} +function expect( + O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + ψ::QuantumObject{<:AbstractArray{T2},BraQuantumObject}, +) where {T1,T2} ψd = ψ.data' Od = O.data return ishermitian(O) ? real(dot(ψd, Od, ψd)) : dot(ψd, Od, ψd) end -function expect(O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ρ::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} +function expect( + O::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + ρ::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, +) where {T1,T2} return ishermitian(O) ? real(tr(O * ρ)) : tr(O * ρ) end @@ -308,7 +334,9 @@ It returns both ``\alpha`` and the state ``\ket{\delta_\psi} = \exp ( \bar{\alpha} \hat{a} - \alpha \hat{a}^\dagger )``. The latter corresponds to the quantum fulctuations around the coherent state ``\ket{\alpha}``. """ -function get_coherence(ψ::QuantumObject{<:AbstractArray{T},StateOpType}) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} +function get_coherence( + ψ::QuantumObject{<:AbstractArray{T},StateOpType}, +) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} a = destroy(size(ψ, 1)) α = expect(a, ψ) D = exp(α * a' - conj(α) * a) @@ -336,11 +364,21 @@ 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}) where {T1,T2,ObjType1<:Union{KetQuantumObject,OperatorQuantumObject},ObjType2<:Union{KetQuantumObject,OperatorQuantumObject}} = norm(ket2dm(ρ) - ket2dm(σ), 1) / 2 - -function _ptrace_ket(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector{T2}) where -{T1,T2<:Integer} - +tracedist( + ρ::QuantumObject{<:AbstractArray{T1},ObjType1}, + σ::QuantumObject{<:AbstractArray{T2},ObjType2}, +) where { + T1, + T2, + ObjType1<:Union{KetQuantumObject,OperatorQuantumObject}, + ObjType2<:Union{KetQuantumObject,OperatorQuantumObject}, +} = norm(ket2dm(ρ) - ket2dm(σ), 1) / 2 + +function _ptrace_ket( + QO::AbstractArray{T1}, + dims::Vector{<:Integer}, + sel::Vector{T2}, +) where {T1,T2<:Integer} rd = dims nd = length(rd) @@ -358,9 +396,11 @@ function _ptrace_ket(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector return vmat * vmat', dkeep end -function _ptrace_oper(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector{T2}) where -{T1,T2<:Integer} - +function _ptrace_oper( + QO::AbstractArray{T1}, + dims::Vector{<:Integer}, + sel::Vector{T2}, +) where {T1,T2<:Integer} rd = dims nd = length(rd) @@ -380,7 +420,7 @@ function _ptrace_oper(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vecto # ρmat = row_major_reshape(ρmat, prod(dtrace), prod(dtrace), prod(dkeep), prod(dkeep)) # res = dropdims(mapslices(tr, ρmat, dims=(1,2)), dims=(1,2)) ρmat = reshape(ρmat, prod(dkeep), prod(dkeep), prod(dtrace), prod(dtrace)) - res = dropdims(mapslices(tr, ρmat, dims=(3, 4)), dims=(3, 4)) + res = dropdims(mapslices(tr, ρmat, dims = (3, 4)), dims = (3, 4)) return res, dkeep end @@ -406,7 +446,14 @@ function mat2vec(::Type{M}) where {M<:SparseMatrixCSC} return SparseVector{par[1],par[2]} end -function mat2vec(::Type{M}) where {M<:Union{Adjoint{<:BlasFloat,<:SparseMatrixCSC},Transpose{<:BlasFloat,<:SparseMatrixCSC}}} +function mat2vec( + ::Type{M}, +) where { + M<:Union{ + Adjoint{<:BlasFloat,<:SparseMatrixCSC}, + Transpose{<:BlasFloat,<:SparseMatrixCSC}, + }, +} T = M.parameters[2] par = T.parameters npar = length(par) @@ -419,4 +466,5 @@ end 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.dims) \ No newline at end of file +mat2vec(A::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = + QuantumObject(mat2vec(A.data), OperatorKet, A.dims) \ No newline at end of file diff --git a/src/negativity.jl b/src/negativity.jl index fa384c4a..415982b8 100644 --- a/src/negativity.jl +++ b/src/negativity.jl @@ -38,7 +38,7 @@ julia> negativity(ρ, 2) 0.4999999999999998 ``` """ -function negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool=false) +function negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool = false) mask = fill(false, length(ρ.dims)) try mask[subsys] = true @@ -68,7 +68,10 @@ 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{T,OperatorQuantumObject}, mask::Vector{Bool}) where {T} +function partial_transpose( + ρ::QuantumObject{T,OperatorQuantumObject}, + mask::Vector{Bool}, +) where {T} if length(mask) != length(ρ.dims) error("The length of \`mask\` should be equal to the length of \`ρ.dims\`.") end @@ -76,7 +79,10 @@ function partial_transpose(ρ::QuantumObject{T,OperatorQuantumObject}, mask::Vec end # for dense matrices -function _partial_transpose(ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject}, mask::Vector{Bool}) +function _partial_transpose( + ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject}, + mask::Vector{Bool}, +) mask2 = [1 + Int(i) for i in mask] # mask2 has elements with values equal to 1 or 2 # 1 - the subsystem don't need to be transposed @@ -85,18 +91,21 @@ function _partial_transpose(ρ::QuantumObject{<:AbstractArray,OperatorQuantumObj nsys = length(mask2) pt_dims = reshape(Vector(1:(2*nsys)), (nsys, 2)) pt_idx = [ - [pt_dims[n, mask2[n]] for n in 1:nsys]; # origin value in mask2 + [pt_dims[n, mask2[n]] for n in 1:nsys] # origin value in mask2 [pt_dims[n, 3-mask2[n]] for n in 1:nsys] # opposite value in mask2 (1 -> 2, and 2 -> 1) ] return QuantumObject( reshape(permutedims(reshape(ρ.data, (ρ.dims..., ρ.dims...)), pt_idx), size(ρ)), Operator, - ρ.dims + ρ.dims, ) end # for sparse matrices -function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray,OperatorQuantumObject}, mask::Vector{Bool}) +function _partial_transpose( + ρ::QuantumObject{<:AbstractSparseArray,OperatorQuantumObject}, + mask::Vector{Bool}, +) M, N = size(ρ) dimsTuple = Tuple(ρ.dims) colptr = ρ.data.colptr @@ -130,9 +139,5 @@ function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray,OperatorQuan end end - return QuantumObject( - sparse(I_pt, J_pt, V_pt, M, N), - Operator, - ρ.dims - ) + return QuantumObject(sparse(I_pt, J_pt, V_pt, M, N), Operator, ρ.dims) end \ No newline at end of file diff --git a/src/permutation.jl b/src/permutation.jl index 91c0e8ee..ee9672eb 100644 --- a/src/permutation.jl +++ b/src/permutation.jl @@ -11,7 +11,9 @@ function bdf(A::SparseMatrixCSC{T,M}) where {T,M} P, P * A * P', block_sizes end -function bdf(A::QuantumObject{SparseMatrixCSC{T,M},OpType}) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +function bdf( + A::QuantumObject{SparseMatrixCSC{T,M},OpType}, +) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} P, A_bd, block_sizes = bdf(A.data) P, QuantumObject(A_bd, A.type, A.dims), block_sizes end @@ -28,6 +30,9 @@ function get_bdf_blocks(A::SparseMatrixCSC{T,M}, block_sizes::Vector{Int}) where block_list, block_indices end -function get_bdf_blocks(A::QuantumObject{SparseMatrixCSC{T,M},OpType}, block_sizes::Vector{Int}) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +function get_bdf_blocks( + A::QuantumObject{SparseMatrixCSC{T,M},OpType}, + block_sizes::Vector{Int}, +) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} get_bdf_blocks(A.data, block_sizes) end \ No newline at end of file diff --git a/src/progress_bar.jl b/src/progress_bar.jl index dce1a625..86428810 100644 --- a/src/progress_bar.jl +++ b/src/progress_bar.jl @@ -8,11 +8,11 @@ mutable struct ProgressBar{CT,T1<:Integer,T2<:Real} start_time::T2 end -function ProgressBar(max_counts::Int; enable::Bool=true, bar_width::Int=30) +function ProgressBar(max_counts::Int; enable::Bool = true, bar_width::Int = 30) return ProgressBar(Threads.Atomic{Int}(0), max_counts, enable, bar_width, time()) end -function next!(p::ProgressBar, io::IO=stdout) +function next!(p::ProgressBar, io::IO = stdout) p.counter[] >= p.max_counts && return Threads.atomic_add!(p.counter, 1) @@ -25,23 +25,40 @@ function next!(p::ProgressBar, io::IO=stdout) start_time = p.start_time percentage = counter / max_counts - percentage_100 = lpad(round(100 * percentage, digits=1), 5, " ") + percentage_100 = lpad(round(100 * percentage, digits = 1), 5, " ") progress = floor(Int, bar_width * percentage) # Calculate the elapsed time in seconds elapsed_time = floor(Int, time() - start_time) # Convert the elapsed time into a string in hours, minutes and seconds - elapsed_time_str = string(elapsed_time ÷ 3600, "h ", lpad((elapsed_time % 3600) ÷ 60, 2, "0"), "m ", lpad(elapsed_time % 60, 2, "0"), "s") + elapsed_time_str = string( + elapsed_time ÷ 3600, + "h ", + lpad((elapsed_time % 3600) ÷ 60, 2, "0"), + "m ", + lpad(elapsed_time % 60, 2, "0"), + "s", + ) # Calculate the estimated time of arrival eta = floor(Int, elapsed_time / counter * (max_counts - counter)) # convert eta into a string in hours, minutes and seconds - eta_str = string(eta ÷ 3600, "h ", lpad((eta % 3600) ÷ 60, 2, "0"), "m ", lpad(eta % 60, 2, "0"), "s") + eta_str = string( + eta ÷ 3600, + "h ", + lpad((eta % 3600) ÷ 60, 2, "0"), + "m ", + lpad(eta % 60, 2, "0"), + "s", + ) # Construct the progress bar string bar = "[" * repeat("=", progress) * repeat(" ", bar_width - progress) * "]" - print(io, "\rProgress: $bar $percentage_100% --- Elapsed Time: $elapsed_time_str (ETA: $eta_str)") + print( + io, + "\rProgress: $bar $percentage_100% --- Elapsed Time: $elapsed_time_str (ETA: $eta_str)", + ) counter == p.max_counts && print(io, "\n") diff --git a/src/quantum_object.jl b/src/quantum_object.jl index 94734736..cf88698a 100644 --- a/src/quantum_object.jl +++ b/src/quantum_object.jl @@ -1,5 +1,11 @@ export AbstractQuantumObject, QuantumObject, Qobj -export QuantumObjectType, BraQuantumObject, KetQuantumObject, OperatorQuantumObject, OperatorBraQuantumObject, OperatorKetQuantumObject, SuperOperatorQuantumObject +export QuantumObjectType, + BraQuantumObject, + KetQuantumObject, + OperatorQuantumObject, + OperatorBraQuantumObject, + OperatorKetQuantumObject, + SuperOperatorQuantumObject export Bra, Ket, Operator, OperatorBra, OperatorKet, SuperOperator export isket, isbra, isoper, isoperbra, isoperket, issuper, ket2dm @@ -129,14 +135,24 @@ struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType} <: AbstractQu dims::Vector{Int} end -function QuantumObject(A::AbstractArray{T,N}; type::ObjType=nothing, dims=nothing) where {T,N,ObjType<:Union{Nothing,QuantumObjectType}} +function QuantumObject( + A::AbstractArray{T,N}; + type::ObjType = nothing, + dims = nothing, +) where {T,N,ObjType<:Union{Nothing,QuantumObjectType}} # only accept 1D- and 2D-array if N == 1 Size = (length(A), 1) else Size = size(A) - N > 2 ? throw(DomainError(Size, "The dimension of the array is not compatible with Quantum Object")) : nothing + N > 2 ? + throw( + DomainError( + Size, + "The dimension of the array is not compatible with Quantum Object", + ), + ) : nothing end # decide QuantumObjectType from the size of A @@ -148,7 +164,12 @@ function QuantumObject(A::AbstractArray{T,N}; type::ObjType=nothing, dims=nothin elseif Size[1] == 1 type = Bra else - throw(DomainError(Size, "The dimension of the array is not compatible with Quantum Object")) + throw( + DomainError( + Size, + "The dimension of the array is not compatible with Quantum Object", + ), + ) end end @@ -170,36 +191,103 @@ function QuantumObject(A::AbstractArray{T,N}; type::ObjType=nothing, dims=nothin end function _check_QuantumObject(type::KetQuantumObject, prod_dims::Int, m::Int, n::Int) - (n != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Ket type")) : nothing - prod_dims != m ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing + (n != 1) ? + throw( + DomainError((m, n), "The dimension of the array is not compatible with Ket type"), + ) : nothing + prod_dims != m ? + throw( + DimensionMismatch("The dims parameter does not fit the dimension of the Array."), + ) : nothing end function _check_QuantumObject(type::BraQuantumObject, prod_dims::Int, m::Int, n::Int) - (m != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Bra type")) : nothing - prod_dims != n ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing + (m != 1) ? + throw( + DomainError((m, n), "The dimension of the array is not compatible with Bra type"), + ) : nothing + prod_dims != n ? + throw( + DimensionMismatch("The dims parameter does not fit the dimension of the Array."), + ) : nothing end function _check_QuantumObject(type::OperatorQuantumObject, prod_dims::Int, m::Int, n::Int) - (m != n) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Operator type")) : nothing - prod_dims != m ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing + (m != n) ? + throw( + DomainError( + (m, n), + "The dimension of the array is not compatible with Operator type", + ), + ) : nothing + prod_dims != m ? + throw( + DimensionMismatch("The dims parameter does not fit the dimension of the Array."), + ) : nothing end -function _check_QuantumObject(type::SuperOperatorQuantumObject, prod_dims::Int, m::Int, n::Int) - (m != n) ? throw(DomainError((m, n), "The dimension of the array is not compatible with SuperOperator type")) : nothing - prod_dims != sqrt(m) ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing +function _check_QuantumObject( + type::SuperOperatorQuantumObject, + prod_dims::Int, + m::Int, + n::Int, +) + (m != n) ? + throw( + DomainError( + (m, n), + "The dimension of the array is not compatible with SuperOperator type", + ), + ) : nothing + prod_dims != sqrt(m) ? + throw( + DimensionMismatch("The dims parameter does not fit the dimension of the Array."), + ) : nothing end -function _check_QuantumObject(type::OperatorKetQuantumObject, prod_dims::Int, m::Int, n::Int) - (n != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with OperatorKet type")) : nothing - prod_dims != sqrt(m) ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing +function _check_QuantumObject( + type::OperatorKetQuantumObject, + prod_dims::Int, + m::Int, + n::Int, +) + (n != 1) ? + throw( + DomainError( + (m, n), + "The dimension of the array is not compatible with OperatorKet type", + ), + ) : nothing + prod_dims != sqrt(m) ? + throw( + DimensionMismatch("The dims parameter does not fit the dimension of the Array."), + ) : nothing end -function _check_QuantumObject(type::OperatorBraQuantumObject, prod_dims::Int, m::Int, n::Int) - (m != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with OperatorBra type")) : nothing - prod_dims != sqrt(n) ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing +function _check_QuantumObject( + type::OperatorBraQuantumObject, + prod_dims::Int, + m::Int, + n::Int, +) + (m != 1) ? + throw( + DomainError( + (m, n), + "The dimension of the array is not compatible with OperatorBra type", + ), + ) : nothing + prod_dims != sqrt(n) ? + throw( + DimensionMismatch("The dims parameter does not fit the dimension of the Array."), + ) : nothing end -function QuantumObject(A::QuantumObject{<:AbstractArray{T,N}}; type::ObjType=A.type, dims=A.dims) where {T,N,ObjType<:QuantumObjectType} +function QuantumObject( + A::QuantumObject{<:AbstractArray{T,N}}; + type::ObjType = A.type, + dims = A.dims, +) where {T,N,ObjType<:QuantumObjectType} N == 1 ? Size = (length(A), 1) : Size = size(A) _check_QuantumObject(type, prod(dims), Size[1], Size[2]) return QuantumObject(copy(A.data), type, dims) @@ -226,53 +314,70 @@ ket2dm(ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = Checks if the [`QuantumObject`](@ref) `A` is a [`BraQuantumObject`](@ref) state. """ -isbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: BraQuantumObject +isbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + OpType <: BraQuantumObject """ isket(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`KetQuantumObject`](@ref) state. """ -isket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: KetQuantumObject +isket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + OpType <: KetQuantumObject """ isoper(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorQuantumObject`](@ref) state. """ -isoper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: OperatorQuantumObject +isoper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + OpType <: OperatorQuantumObject """ isoperbra(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorBraQuantumObject`](@ref) state. """ -isoperbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: OperatorBraQuantumObject +isoperbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + OpType <: OperatorBraQuantumObject """ isoperket(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`OperatorKetQuantumObject`](@ref) state. """ -isoperket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: OperatorKetQuantumObject +isoperket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + OpType <: OperatorKetQuantumObject """ issuper(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`SuperOperatorQuantumObject`](@ref) state. """ -issuper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: SuperOperatorQuantumObject +issuper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + OpType <: SuperOperatorQuantumObject """ size(A::QuantumObject) Returns the size of the matrix or vector corresponding to the [`QuantumObject`](@ref) `A`. """ -Base.size(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = size(A.data) -Base.size(A::QuantumObject{<:AbstractArray{T},OpType}, inds...) where {T,OpType<:QuantumObjectType} = size(A.data, inds...) +Base.size(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + size(A.data) +Base.size( + A::QuantumObject{<:AbstractArray{T},OpType}, + inds..., +) where {T,OpType<:QuantumObjectType} = size(A.data, inds...) -Base.getindex(A::QuantumObject{<:AbstractArray{T},OpType}, inds...) where {T,OpType<:QuantumObjectType} = getindex(A.data, inds...) -Base.setindex!(A::QuantumObject{<:AbstractArray{T},OpType}, val, inds...) where {T,OpType<:QuantumObjectType} = setindex!(A.data, val, inds...) +Base.getindex( + A::QuantumObject{<:AbstractArray{T},OpType}, + inds..., +) where {T,OpType<:QuantumObjectType} = getindex(A.data, inds...) +Base.setindex!( + A::QuantumObject{<:AbstractArray{T},OpType}, + val, + inds..., +) where {T,OpType<:QuantumObjectType} = setindex!(A.data, val, inds...) """ eltype(A::QuantumObject) @@ -285,7 +390,11 @@ Base.eltype(A::QuantumObject) = eltype(A.data) Base.broadcastable(x::QuantumObject) = x.data for op in (:(+), :(-), :(*), :(/), :(^)) @eval begin - function Base.Broadcast.broadcasted(::typeof($op), x::QuantumObject, y::QuantumObject) + function Base.Broadcast.broadcasted( + ::typeof($op), + x::QuantumObject, + y::QuantumObject, + ) return QuantumObject(broadcast($op, x.data, y.data), x.type, x.dims) end @@ -297,11 +406,19 @@ for op in (:(+), :(-), :(*), :(/), :(^)) return QuantumObject(broadcast($op, x, y.data), y.type, y.dims) end - function Base.Broadcast.broadcasted(::typeof($op), x::QuantumObject, y::AbstractArray) + function Base.Broadcast.broadcasted( + ::typeof($op), + x::QuantumObject, + y::AbstractArray, + ) return QuantumObject(broadcast($op, x.data, y), x.type, x.dims) end - function Base.Broadcast.broadcasted(::typeof($op), x::AbstractArray, y::QuantumObject) + function Base.Broadcast.broadcasted( + ::typeof($op), + x::AbstractArray, + y::QuantumObject, + ) return QuantumObject(broadcast($op, x, y.data), y.type, y.dims) end end @@ -312,126 +429,237 @@ end Returns the length of the matrix or vector corresponding to the [`QuantumObject`](@ref) `A`. """ -Base.length(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = length(A.data) - -SparseArrays.sparse(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject(sparse(A.data), OpType(), A.dims) -SparseArrays.nnz(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = nnz(A.data) -SparseArrays.nonzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = nonzeros(A.data) -SparseArrays.rowvals(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = rowvals(A.data) -SparseArrays.droptol!(A::QuantumObject{<:AbstractSparseArray,OpType}, tol::Real) where {OpType<:QuantumObjectType} = (droptol!(A.data, tol); return A) -SparseArrays.dropzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = QuantumObject(dropzeros(A.data), A.type, A.dims) -SparseArrays.dropzeros!(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = (dropzeros!(A.data); return A) - -Base.isequal(A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}) where -{T,OpType<:QuantumObjectType} = isequal(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) -Base.isapprox(A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}) where -{T,OpType<:QuantumObjectType} = isapprox(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) -Base.:(==)(A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}) where -{T,OpType<:QuantumObjectType} = (A.data == B.data) && (A.type == B.type) && (A.dims == B.dims) - - -LinearAlgebra.Hermitian(A::QuantumObject{<:AbstractArray{T},OpType}, uplo::Symbol=:U) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +Base.length( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = length(A.data) + +SparseArrays.sparse( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = QuantumObject(sparse(A.data), OpType(), A.dims) +SparseArrays.nnz( + A::QuantumObject{<:AbstractSparseArray,OpType}, +) where {OpType<:QuantumObjectType} = nnz(A.data) +SparseArrays.nonzeros( + A::QuantumObject{<:AbstractSparseArray,OpType}, +) where {OpType<:QuantumObjectType} = nonzeros(A.data) +SparseArrays.rowvals( + A::QuantumObject{<:AbstractSparseArray,OpType}, +) where {OpType<:QuantumObjectType} = rowvals(A.data) +SparseArrays.droptol!( + A::QuantumObject{<:AbstractSparseArray,OpType}, + tol::Real, +) where {OpType<:QuantumObjectType} = (droptol!(A.data, tol); return A) +SparseArrays.dropzeros( + A::QuantumObject{<:AbstractSparseArray,OpType}, +) where {OpType<:QuantumObjectType} = QuantumObject(dropzeros(A.data), A.type, A.dims) +SparseArrays.dropzeros!( + A::QuantumObject{<:AbstractSparseArray,OpType}, +) where {OpType<:QuantumObjectType} = (dropzeros!(A.data); return A) + +Base.isequal( + A::QuantumObject{<:AbstractArray{T},OpType}, + B::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = + isequal(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) +Base.isapprox( + A::QuantumObject{<:AbstractArray{T},OpType}, + B::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = + isapprox(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) +Base.:(==)( + A::QuantumObject{<:AbstractArray{T},OpType}, + B::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = + (A.data == B.data) && (A.type == B.type) && (A.dims == B.dims) + +LinearAlgebra.Hermitian( + A::QuantumObject{<:AbstractArray{T},OpType}, + uplo::Symbol = :U, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(Hermitian(A.data, uplo), A.type, A.dims) -function Base.show(io::IO, QO::QuantumObject{<:AbstractArray{T},OpType}) where -{T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorBraQuantumObject,OperatorKetQuantumObject,SuperOperatorQuantumObject}} +function Base.show( + io::IO, + QO::QuantumObject{<:AbstractArray{T},OpType}, +) where { + T, + OpType<:Union{ + BraQuantumObject, + KetQuantumObject, + OperatorBraQuantumObject, + OperatorKetQuantumObject, + SuperOperatorQuantumObject, + }, +} op_data = QO.data - println(io, "Quantum Object: type=", QO.type, " dims=", QO.dims, " size=", size(op_data)) + println( + io, + "Quantum Object: type=", + QO.type, + " dims=", + QO.dims, + " size=", + size(op_data), + ) show(io, MIME("text/plain"), op_data) end -function Base.show(io::IO, QO::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:OperatorQuantumObject} +function Base.show( + io::IO, + QO::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:OperatorQuantumObject} op_data = QO.data - println(io, "Quantum Object: type=", QO.type, " dims=", QO.dims, " size=", size(op_data), " ishermitian=", ishermitian(op_data)) + println( + io, + "Quantum Object: type=", + QO.type, + " dims=", + QO.dims, + " size=", + size(op_data), + " ishermitian=", + ishermitian(op_data), + ) show(io, MIME("text/plain"), op_data) end for op in (:(+), :(-), :(*)) @eval begin - function LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where - {T1,T2,OpType<:QuantumObjectType} - - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + function LinearAlgebra.$op( + A::QuantumObject{<:AbstractArray{T1},OpType}, + B::QuantumObject{<:AbstractArray{T2},OpType}, + ) where {T1,T2,OpType<:QuantumObjectType} + A.dims != B.dims && throw( + ErrorException("The two operators are not of the same Hilbert dimension."), + ) QuantumObject($(op)(A.data, B.data), OpType(), A.dims) end - LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject($(op)(A.data), OpType(), A.dims) - - LinearAlgebra.$op(n::T1, A::QuantumObject{<:AbstractArray{T2},OpType}) where {T1<:Number,T2,OpType<:QuantumObjectType} = + LinearAlgebra.$op( + A::QuantumObject{<:AbstractArray{T},OpType}, + ) where {T,OpType<:QuantumObjectType} = + QuantumObject($(op)(A.data), OpType(), A.dims) + + LinearAlgebra.$op( + n::T1, + A::QuantumObject{<:AbstractArray{T2},OpType}, + ) where {T1<:Number,T2,OpType<:QuantumObjectType} = QuantumObject($(op)(n * I, A.data), OpType(), A.dims) - LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T1},OpType}, n::T2) where {T1,T2<:Number,OpType<:QuantumObjectType} = + LinearAlgebra.$op( + A::QuantumObject{<:AbstractArray{T1},OpType}, + n::T2, + ) where {T1,T2<:Number,OpType<:QuantumObjectType} = QuantumObject($(op)(A.data, n * I), OpType(), A.dims) end end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) QuantumObject(A.data * B.data, Ket, A.dims) end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) QuantumObject(A.data * B.data, Bra, A.dims) end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},BraQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},BraQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) QuantumObject(A.data * B.data, Operator, A.dims) end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) A.data * B.data end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) QuantumObject(vec2mat(A.data * mat2vec(B.data)), Operator, A.dims) end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) A.data * B.data end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) QuantumObject(A.data * B.data, OperatorKet, A.dims) end -function LinearAlgebra.:(*)(A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}) where {T1,T2} - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.:(*)( + A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, +) where {T1,T2} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) QuantumObject(A.data * B.data, OperatorBra, A.dims) end -LinearAlgebra.:(^)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} = +LinearAlgebra.:(^)( + A::QuantumObject{<:AbstractArray{T},OpType}, + n::T1, +) where {T,T1<:Number,OpType<:QuantumObjectType} = QuantumObject(^(A.data, n), OpType(), A.dims) -LinearAlgebra.:(/)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} = +LinearAlgebra.:(/)( + A::QuantumObject{<:AbstractArray{T},OpType}, + n::T1, +) where {T,T1<:Number,OpType<:QuantumObjectType} = QuantumObject(/(A.data, n), OpType(), A.dims) -function LinearAlgebra.dot(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where -{T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} - - A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) +function LinearAlgebra.dot( + A::QuantumObject{<:AbstractArray{T1},OpType}, + B::QuantumObject{<:AbstractArray{T2},OpType}, +) where {T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} + A.dims != B.dims && + throw(ErrorException("The two operators are not of the same Hilbert dimension.")) LinearAlgebra.dot(A.data, B.data) end Base.conj(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject(conj(A.data), OpType(), A.dims) -LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +LinearAlgebra.adjoint( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(adjoint(A.data), OpType(), A.dims) -LinearAlgebra.transpose(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +LinearAlgebra.transpose( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(transpose(A.data), OpType(), A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},KetQuantumObject}) where {T} = QuantumObject(adjoint(A.data), Bra, A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},BraQuantumObject}) where {T} = QuantumObject(adjoint(A.data), Ket, A.dims) -LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = - QuantumObject(adjoint(A.data), OperatorBra, A.dims) -LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorBraQuantumObject}) where {T} = - QuantumObject(adjoint(A.data), OperatorKet, A.dims) - -LinearAlgebra.inv(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = +LinearAlgebra.adjoint( + A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}, +) where {T} = QuantumObject(adjoint(A.data), OperatorBra, A.dims) +LinearAlgebra.adjoint( + A::QuantumObject{<:AbstractArray{T},OperatorBraQuantumObject}, +) where {T} = QuantumObject(adjoint(A.data), OperatorKet, A.dims) + +LinearAlgebra.inv( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(sparse(inv(Matrix(A.data))), OpType(), A.dims) """ @@ -455,7 +683,9 @@ julia> tr(a' * a) 190.0 + 0.0im ``` """ -LinearAlgebra.tr(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = tr(A.data) +LinearAlgebra.tr( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = tr(A.data) """ svdvals(A::QuantumObject) @@ -464,7 +694,8 @@ Return the singular values of a [`QuantumObject`](@ref) in descending order """ LinearAlgebra.svdvals(A::QuantumObject{<:AbstractVector}) = svdvals(A.data) LinearAlgebra.svdvals(A::QuantumObject{<:DenseMatrix}) = svdvals(A.data) -LinearAlgebra.svdvals(A::QuantumObject{<:AbstractSparseMatrix}) = svdvals(sparse_to_dense(A.data)) +LinearAlgebra.svdvals(A::QuantumObject{<:AbstractSparseMatrix}) = + svdvals(sparse_to_dense(A.data)) """ norm(A::QuantumObject, p::Real=2) @@ -495,18 +726,40 @@ julia> norm(ψ) 1.0 ``` """ -LinearAlgebra.norm(A::QuantumObject{<:AbstractArray{T},OpType}, p::Real=2) where {T,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorKetQuantumObject,OperatorBraQuantumObject}} = norm(A.data, p) -function LinearAlgebra.norm(A::QuantumObject{<:AbstractArray{T},OpType}, p::Real=2) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} +LinearAlgebra.norm( + A::QuantumObject{<:AbstractArray{T},OpType}, + p::Real = 2, +) where { + T, + OpType<:Union{ + KetQuantumObject, + BraQuantumObject, + OperatorKetQuantumObject, + OperatorBraQuantumObject, + }, +} = norm(A.data, p) +function LinearAlgebra.norm( + A::QuantumObject{<:AbstractArray{T},OpType}, + p::Real = 2, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} p == 2.0 && return norm(A.data, 2) return norm(svdvals(A), p) end -LinearAlgebra.normalize(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(normalize(A.data), OpType(), A.dims) -LinearAlgebra.normalize!(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - (normalize!(A.data); A) -LinearAlgebra.ishermitian(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = ishermitian(A.data) -LinearAlgebra.issymmetric(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = issymmetric(A.data) -LinearAlgebra.isposdef(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = isposdef(A.data) +LinearAlgebra.normalize( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = QuantumObject(normalize(A.data), OpType(), A.dims) +LinearAlgebra.normalize!( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = (normalize!(A.data); A) +LinearAlgebra.ishermitian( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = ishermitian(A.data) +LinearAlgebra.issymmetric( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = issymmetric(A.data) +LinearAlgebra.isposdef( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = isposdef(A.data) @doc raw""" kron(A::QuantumObject, B::QuantumObject) @@ -551,9 +804,10 @@ Quantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian= ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦ ``` """ -function LinearAlgebra.kron(A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}) where -{T1,T2,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} - +function LinearAlgebra.kron( + A::QuantumObject{<:AbstractArray{T1},OpType}, + B::QuantumObject{<:AbstractArray{T2},OpType}, +) where {T1,T2,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} QuantumObject(kron(A.data, B.data), OpType(), vcat(A.dims, B.dims)) end @@ -633,31 +887,52 @@ Quantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian= """ ⊗(A::QuantumObject, B::QuantumObject) = kron(A, B) -LinearAlgebra.triu!(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (triu!(A.data, k); A) -LinearAlgebra.tril!(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (tril!(A.data, k); A) -LinearAlgebra.triu(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(triu(A.data, k), OpType(), A.dims) -LinearAlgebra.tril(A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer=0) where -{T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(tril(A.data, k), OpType(), A.dims) +LinearAlgebra.triu!( + A::QuantumObject{<:AbstractArray{T},OpType}, + k::Integer = 0, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + (triu!(A.data, k); A) +LinearAlgebra.tril!( + A::QuantumObject{<:AbstractArray{T},OpType}, + k::Integer = 0, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + (tril!(A.data, k); A) +LinearAlgebra.triu( + A::QuantumObject{<:AbstractArray{T},OpType}, + k::Integer = 0, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + QuantumObject(triu(A.data, k), OpType(), A.dims) +LinearAlgebra.tril( + A::QuantumObject{<:AbstractArray{T},OpType}, + k::Integer = 0, +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + QuantumObject(tril(A.data, k), OpType(), A.dims) LinearAlgebra.lmul!(a::Number, B::QuantumObject{<:AbstractArray}) = (lmul!(a, B.data); B) LinearAlgebra.rmul!(B::QuantumObject{<:AbstractArray}, a::Number) = (rmul!(B.data, a); B) -@inline LinearAlgebra.mul!(y::AbstractVector{Ty}, A::QuantumObject{<:AbstractMatrix{Ta}}, x, α, β) where {Ty,Ta} = mul!(y, A.data, x, α, β) - - -LinearAlgebra.sqrt(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(sqrt(A.data), OpType(), A.dims) - -LinearAlgebra.exp(A::QuantumObject{<:AbstractMatrix{T},OpType}) where {T,OpType<:QuantumObjectType} = +@inline LinearAlgebra.mul!( + y::AbstractVector{Ty}, + A::QuantumObject{<:AbstractMatrix{Ta}}, + x, + α, + β, +) where {Ty,Ta} = mul!(y, A.data, x, α, β) + +LinearAlgebra.sqrt( + A::QuantumObject{<:AbstractArray{T},OpType}, +) where {T,OpType<:QuantumObjectType} = QuantumObject(sqrt(A.data), OpType(), A.dims) + +LinearAlgebra.exp( + A::QuantumObject{<:AbstractMatrix{T},OpType}, +) where {T,OpType<:QuantumObjectType} = QuantumObject(dense_to_sparse(exp(A.data)), OpType(), A.dims) -LinearAlgebra.exp(A::QuantumObject{<:AbstractSparseMatrix{T},OpType}) where {T,OpType<:QuantumObjectType} = - QuantumObject(_spexp(A.data), OpType(), A.dims) +LinearAlgebra.exp( + A::QuantumObject{<:AbstractSparseMatrix{T},OpType}, +) where {T,OpType<:QuantumObjectType} = QuantumObject(_spexp(A.data), OpType(), A.dims) -function _spexp(A::SparseMatrixCSC{T,M}; threshold=1e-14, nonzero_tol=1e-20) where {T,M} +function _spexp(A::SparseMatrixCSC{T,M}; threshold = 1e-14, nonzero_tol = 1e-20) where {T,M} m = checksquare(A) # Throws exception if not square mat_norm = norm(A, Inf) @@ -679,7 +954,7 @@ function _spexp(A::SparseMatrixCSC{T,M}; threshold=1e-14, nonzero_tol=1e-20) whe P += next_term n += 1 end - for n = 1:log2(scaling_factor) + for n in 1:log2(scaling_factor) P = P * P if nnz(P) / length(P) > 0.25 tidyup!(P, nonzero_tol) @@ -689,11 +964,19 @@ function _spexp(A::SparseMatrixCSC{T,M}; threshold=1e-14, nonzero_tol=1e-20) whe end # data type conversions -Base.Vector(A::QuantumObject{<:AbstractVector}) = QuantumObject(Vector(A.data), A.type, A.dims) -Base.Vector{T}(A::QuantumObject{<:AbstractVector}) where {T<:Number} = QuantumObject(Vector{T}(A.data), A.type, A.dims) -Base.Matrix(A::QuantumObject{<:AbstractMatrix}) = QuantumObject(Matrix(A.data), A.type, A.dims) -Base.Matrix{T}(A::QuantumObject{<:AbstractMatrix}) where {T<:Number} = QuantumObject(Matrix{T}(A.data), A.type, A.dims) -SparseArrays.SparseVector(A::QuantumObject{<:AbstractVector}) = QuantumObject(SparseVector(A.data), A.type, A.dims) -SparseArrays.SparseVector{T}(A::QuantumObject{<:SparseVector}) where {T<:Number} = QuantumObject(SparseVector{T}(A.data), A.type, A.dims) -SparseArrays.SparseMatrixCSC(A::QuantumObject{<:AbstractMatrix}) = QuantumObject(SparseMatrixCSC(A.data), A.type, A.dims) -SparseArrays.SparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T<:Number} = QuantumObject(SparseMatrixCSC{T}(A.data), A.type, A.dims) \ No newline at end of file +Base.Vector(A::QuantumObject{<:AbstractVector}) = + QuantumObject(Vector(A.data), A.type, A.dims) +Base.Vector{T}(A::QuantumObject{<:AbstractVector}) where {T<:Number} = + QuantumObject(Vector{T}(A.data), A.type, A.dims) +Base.Matrix(A::QuantumObject{<:AbstractMatrix}) = + QuantumObject(Matrix(A.data), A.type, A.dims) +Base.Matrix{T}(A::QuantumObject{<:AbstractMatrix}) where {T<:Number} = + QuantumObject(Matrix{T}(A.data), A.type, A.dims) +SparseArrays.SparseVector(A::QuantumObject{<:AbstractVector}) = + QuantumObject(SparseVector(A.data), A.type, A.dims) +SparseArrays.SparseVector{T}(A::QuantumObject{<:SparseVector}) where {T<:Number} = + QuantumObject(SparseVector{T}(A.data), A.type, A.dims) +SparseArrays.SparseMatrixCSC(A::QuantumObject{<:AbstractMatrix}) = + QuantumObject(SparseMatrixCSC(A.data), A.type, A.dims) +SparseArrays.SparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T<:Number} = + QuantumObject(SparseMatrixCSC{T}(A.data), A.type, A.dims) \ No newline at end of file diff --git a/src/quantum_operators.jl b/src/quantum_operators.jl index c336bd8d..08a3b7c7 100644 --- a/src/quantum_operators.jl +++ b/src/quantum_operators.jl @@ -16,8 +16,10 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{O}\right) \boldsymbol{\cdot} = The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -spre(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O, 1))) where {T} = - QuantumObject(kron(Id_cache, O.data), SuperOperator, O.dims) +spre( + O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, + Id_cache = I(size(O, 1)), +) where {T} = QuantumObject(kron(Id_cache, O.data), SuperOperator, O.dims) @doc raw""" spost(O::QuantumObject) @@ -31,7 +33,10 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{O}\right) \boldsymbol{\cdot} = The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -spost(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O, 1))) where {T} = +spost( + O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, + Id_cache = I(size(O, 1)), +) where {T} = QuantumObject(kron(sparse(transpose(sparse(O.data))), Id_cache), SuperOperator, O.dims) # TODO: fix the sparse conversion @doc raw""" @@ -43,8 +48,11 @@ of the density matrix operator respectively, ``\mathcal{O} \left( \hat{A}, \hat{ Since the density matrix is vectorized, this super-operator is always a matrix, obtained from ``\mathcal{O} \left(\hat{A}, \hat{B}\right) \boldsymbol{\cdot} = \text{spre}(A) * \text{spost}(B)``. """ -sprepost(A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}) where {T1,T2} = QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperator, A.dims) # TODO: fix the sparse conversion +sprepost( + A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, +) where {T1,T2} = + QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperator, A.dims) # TODO: fix the sparse conversion @doc raw""" lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1)) @@ -59,13 +67,19 @@ considering the density matrix ``\hat{\rho}`` in the vectorized form. The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -function lindblad_dissipator(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache=I(size(O, 1))) where {T} +function lindblad_dissipator( + O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, + Id_cache = I(size(O, 1)), +) where {T} Od_O = O' * O return sprepost(O, O') - spre(Od_O, Id_cache) / 2 - spost(Od_O, Id_cache) / 2 end # It is already a SuperOperator -lindblad_dissipator(O::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, Id_cache) where {T} = O +lindblad_dissipator( + O::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, + Id_cache, +) where {T} = O @doc raw""" destroy(N::Int) @@ -89,7 +103,8 @@ julia> fock(20, 3)' * a * fock(20, 4) 2.0 + 0.0im ``` """ -destroy(N::Int) = QuantumObject(spdiagm(1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) +destroy(N::Int) = + QuantumObject(spdiagm(1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) @doc raw""" create(N::Int) @@ -113,7 +128,8 @@ julia> fock(20, 4)' * a_d * fock(20, 3) 2.0 + 0.0im ``` """ -create(N::Int) = QuantumObject(spdiagm(-1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) +create(N::Int) = + QuantumObject(spdiagm(-1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) @doc raw""" sigmap() @@ -155,16 +171,24 @@ sigmaz() = sigmap() * sigmam() - sigmam() * sigmap() Identity operator ``\hat{\mathbb{1}}`` with Hilbert dimension `N`. """ -eye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where -{ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = QuantumObject(Diagonal(ones(ComplexF64, N)), type, dims) +eye( + N::Int; + type::ObjType = Operator, + dims::Vector{Int} = [N], +) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + QuantumObject(Diagonal(ones(ComplexF64, N)), type, dims) @doc raw""" qeye(N::Int; type=OperatorQuantumObject, dims=[N]) Identity operator ``\hat{\mathbb{1}}`` with Hilbert dimension `N`. """ -qeye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where -{ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eye(N, type=type, dims=dims) +qeye( + N::Int; + type::ObjType = Operator, + dims::Vector{Int} = [N], +) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = + eye(N, type = type, dims = dims) @doc raw""" fock(N::Int, pos::Int; dims::Vector{Int}=[N], sparse::Bool=false) @@ -172,7 +196,7 @@ qeye(N::Int; type::ObjType=Operator, dims::Vector{Int}=[N]) where Generates a fock state ``\ket{\psi}`` of dimension `N`. It is also possible to specify the list of dimensions `dims` if different subsystems are present. """ -function fock(N::Int, pos::Int; dims::Vector{Int}=[N], sparse::Bool=false) +function fock(N::Int, pos::Int; dims::Vector{Int} = [N], sparse::Bool = false) if sparse return QuantumObject(sparsevec([pos + 1], [1.0 + 0im], N), Ket, dims) else @@ -187,7 +211,7 @@ end Generates a fock state like [`fock`](@ref). """ -basis(N::Int, pos::Int; dims::Vector{Int}=[N]) = fock(N, pos, dims=dims) +basis(N::Int, pos::Int; dims::Vector{Int} = [N]) = fock(N, pos, dims = dims) @doc raw""" coherent(N::Real, α::T) @@ -218,7 +242,8 @@ end Generates the projection operator ``\hat{O} = \dyad{i}{j}`` with Hilbert space dimension `N`. """ -projection(N::Int, i::Int, j::Int) = QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N)) +projection(N::Int, i::Int, j::Int) = + QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N)) @doc raw""" sinm(O::QuantumObject) @@ -227,7 +252,8 @@ Generates the sine of the operator `O`, defined as ``\sin \left( \hat{O} \right) = \frac{e^{i \hat{O}} - e^{-i \hat{O}}}{2 i}`` """ -sinm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = -0.5im * (exp(1im * O) - exp(-1im * O)) +sinm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = + -0.5im * (exp(1im * O) - exp(-1im * O)) @doc raw""" cosm(O::QuantumObject) @@ -236,4 +262,5 @@ Generates the cosine of the operator `O`, defined as ``\cos \left( \hat{O} \right) = \frac{e^{i \hat{O}} + e^{-i \hat{O}}}{2}`` """ -cosm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = 0.5 * (exp(1im * O) + exp(-1im * O)) \ No newline at end of file +cosm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = + 0.5 * (exp(1im * O) + exp(-1im * O)) \ No newline at end of file diff --git a/src/spin_lattice.jl b/src/spin_lattice.jl index 7eb06c39..f73b59ee 100644 --- a/src/spin_lattice.jl +++ b/src/spin_lattice.jl @@ -16,14 +16,30 @@ Base.@kwdef struct Lattice{TN<:Integer,TLI<:LinearIndices,TCI<:CartesianIndices} end #Definition of many-body operators -function mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, i::Integer, N::Integer) where {T1} +function mb( + s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + i::Integer, + N::Integer, +) where {T1} T = s.dims[1] - QuantumObject(kron(eye(T^(i - 1)), s, eye(T^(N - i))); dims=fill(2, N)) + QuantumObject(kron(eye(T^(i - 1)), s, eye(T^(N - i))); dims = fill(2, N)) end -mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, i::Integer, latt::Lattice) where {T1} = mb(s, i, latt.N) -mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, row::Integer, col::Integer, latt::Lattice) where {T1} = mb(s, latt.idx[row, col], latt.N) -mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, x::CartesianIndex, latt::Lattice) where {T1} = mb(s, latt.idx[x], latt.N) - +mb( + s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + i::Integer, + latt::Lattice, +) where {T1} = mb(s, i, latt.N) +mb( + s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + row::Integer, + col::Integer, + latt::Lattice, +) where {T1} = mb(s, latt.idx[row, col], latt.N) +mb( + s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + x::CartesianIndex, + latt::Lattice, +) where {T1} = mb(s, latt.idx[x], latt.N) #Definition of nearest-neighbour sites on lattice pbc(i::Integer, N::Integer) = 1 + (i - 1 + N) % N @@ -31,17 +47,29 @@ obc(i::Integer, N::Integer) = (i >= 1 && i <= N) pbc(i::Vector{Int}, N::Integer) = pbc.(i, N) obc(i::Vector{Int}, N::Integer) = filter(x -> obc(x, N), i) -function nn(i::CartesianIndex, latt::Lattice, bc::Function; order::Integer=1) +function nn(i::CartesianIndex, latt::Lattice, bc::Function; order::Integer = 1) row = bc([i[1] + order, i[1] - order], latt.Nx) col = bc([i[2] + order, i[2] - order], latt.Ny) vcat([CartesianIndex(r, i[2]) for r in row], [CartesianIndex(i[1], c) for c in col]) end -function TFIM(Jx::Real, Jy::Real, Jz::Real, hx::Real, γ::Real, latt::Lattice; bc::Function=pbc, order::Integer=1) +function TFIM( + Jx::Real, + Jy::Real, + Jz::Real, + hx::Real, + γ::Real, + latt::Lattice; + bc::Function = pbc, + order::Integer = 1, +) S = [mb(sm, i, latt) for i in 1:latt.N] c_ops = sqrt(γ) .* S - op_sum(S::Vector{QuantumObject{SparseMatrixCSC{ComplexF64,Int64},OperatorQuantumObject}}, i::CartesianIndex) = S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nn(i, latt, bc; order=order)]]) + op_sum( + S::Vector{QuantumObject{SparseMatrixCSC{ComplexF64,Int64},OperatorQuantumObject}}, + i::CartesianIndex, + ) = S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nn(i, latt, bc; order = order)]]) H = 0 if (Jx != 0 || hx != 0) diff --git a/src/versioninfo.jl b/src/versioninfo.jl index f76cecfa..96637b7d 100644 --- a/src/versioninfo.jl +++ b/src/versioninfo.jl @@ -3,59 +3,53 @@ Command line output of information on QuantumToolbox, dependencies, and system information, same as [`QuantumToolbox.about`](@ref). """ -function versioninfo(io::IO=stdout) +function versioninfo(io::IO = stdout) cpu = Sys.cpu_info() BLAS_info = BLAS.get_config().loaded_libs[1] - Sys.iswindows() ? OS_name = "Windows" : Sys.isapple() ? OS_name = "macOS" : OS_name = Sys.KERNEL + Sys.iswindows() ? OS_name = "Windows" : + Sys.isapple() ? OS_name = "macOS" : OS_name = Sys.KERNEL # print introduction - println(io, + println( + io, "\n", " QuantumToolbox.jl: Quantum Toolbox in Julia\n", "≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n", "Copyright © QuTiP team 2022 and later.\n", "Current admin team:\n", - " Alberto Mercurio, Luca Gravina, Yi-Te Huang\n" + " Alberto Mercurio, Luca Gravina, Yi-Te Huang\n", ) # print package informations - println(io, + println( + io, "Package information:\n", "====================================\n", "QuantumToolbox Ver. $(_get_pkg_version("QuantumToolbox"))\n", "LinearSolve Ver. $(_get_pkg_version("LinearSolve"))\n", - "OrdinaryDiffEq Ver. $(_get_pkg_version("OrdinaryDiffEq"))\n" + "OrdinaryDiffEq Ver. $(_get_pkg_version("OrdinaryDiffEq"))\n", ) # print System informations - println(io, + println( + io, "System information:\n", "====================================\n", - "Julia Version: $(VERSION)" + "Julia Version: $(VERSION)", ) - println(io, - """OS : $(OS_name) ($(Sys.MACHINE))""" + println(io, """OS : $(OS_name) ($(Sys.MACHINE))""") + println(io, """CPU : $(length(cpu)) × $(cpu[1].model)""") + println(io, """Memory : $(round(Sys.total_memory() / 2 ^ 30, digits=3)) GB""") + println(io, """WORD_SIZE: $(Sys.WORD_SIZE)""") + println(io, """LIBM : $(Base.libm_name)""") + println( + io, + """LLVM : libLLVM-$(Base.libllvm_version) ($(Sys.JIT), $(Sys.CPU_NAME))""", ) - println(io, - """CPU : $(length(cpu)) × $(cpu[1].model)""" - ) - println(io, - """Memory : $(round(Sys.total_memory() / 2 ^ 30, digits=3)) GB""" - ) - println(io, - """WORD_SIZE: $(Sys.WORD_SIZE)""" - ) - println(io, - """LIBM : $(Base.libm_name)""" - ) - println(io, - """LLVM : libLLVM-$(Base.libllvm_version) ($(Sys.JIT), $(Sys.CPU_NAME))""" - ) - println(io, - """BLAS : $(basename(BLAS_info.libname)) ($(BLAS_info.interface))""" - ) - println(io, - """Threads : $(Threads.nthreads()) (on $(Sys.CPU_THREADS) virtual cores)""" + println(io, """BLAS : $(basename(BLAS_info.libname)) ($(BLAS_info.interface))""") + println( + io, + """Threads : $(Threads.nthreads()) (on $(Sys.CPU_THREADS) virtual cores)""", ) print(io, "\n") end @@ -65,7 +59,7 @@ end Command line output of information on QuantumToolbox, dependencies, and system information, same as [`QuantumToolbox.versioninfo`](@ref). """ -about(io::IO=stdout) = versioninfo(io) +about(io::IO = stdout) = versioninfo(io) function _get_pkg_version(pkg_name::String) D = Pkg.dependencies() diff --git a/src/wigner.jl b/src/wigner.jl index c1319d79..74bd064f 100644 --- a/src/wigner.jl +++ b/src/wigner.jl @@ -9,7 +9,7 @@ struct WignerLaguerre <: WignerSolver tol::Float64 end -WignerLaguerre(; parallel=false, tol=1e-14) = WignerLaguerre(parallel, tol) +WignerLaguerre(; parallel = false, tol = 1e-14) = WignerLaguerre(parallel, tol) @doc raw""" wigner(state::QuantumObject, xvec::AbstractVector, yvec::AbstractVector; g::Real=√2, @@ -24,11 +24,17 @@ expansion of the Wigner function, while the latter uses the Clenshaw algorithm. sparse matrices, while the Clenshaw algorithm is faster for dense matrices. The `WignerLaguerre` solver has an optional `parallel` parameter which defaults to `true` and uses multithreading to speed up the calculation. """ -function wigner(state::QuantumObject{<:AbstractArray{T},OpType}, xvec::AbstractVector, - yvec::AbstractVector; g::Real=√2, solver::MySolver=WignerLaguerre()) where -{T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}, - MySolver<:WignerSolver} - +function wigner( + state::QuantumObject{<:AbstractArray{T},OpType}, + xvec::AbstractVector, + yvec::AbstractVector; + g::Real = √2, + solver::MySolver = WignerLaguerre(), +) where { + T, + OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}, + MySolver<:WignerSolver, +} if isket(state) ρ = (state * state').data elseif isbra(state) @@ -40,9 +46,13 @@ function wigner(state::QuantumObject{<:AbstractArray{T},OpType}, xvec::AbstractV return _wigner(ρ, xvec, yvec, g, solver) end -function _wigner(ρ::AbstractArray, xvec::AbstractVector{T}, yvec::AbstractVector{T}, - g::Real, solver::WignerLaguerre) where {T<:BlasFloat} - +function _wigner( + ρ::AbstractArray, + xvec::AbstractVector{T}, + yvec::AbstractVector{T}, + g::Real, + solver::WignerLaguerre, +) where {T<:BlasFloat} g = convert(T, g) X, Y = meshgrid(xvec, yvec) A = g / 2 * (X + 1im * Y) @@ -52,9 +62,13 @@ function _wigner(ρ::AbstractArray, xvec::AbstractVector{T}, yvec::AbstractVecto return _wigner_laguerre(ρ, A, W, g, solver) end -function _wigner(ρ::AbstractArray{T1}, xvec::AbstractVector{T}, yvec::AbstractVector{T}, - g::Real, solver::WignerClenshaw) where {T1<:BlasFloat,T<:BlasFloat} - +function _wigner( + ρ::AbstractArray{T1}, + xvec::AbstractVector{T}, + yvec::AbstractVector{T}, + g::Real, + solver::WignerClenshaw, +) where {T1<:BlasFloat,T<:BlasFloat} g = convert(T, g) M = size(ρ, 1) X, Y = meshgrid(xvec, yvec) @@ -73,14 +87,28 @@ function _wigner(ρ::AbstractArray{T1}, xvec::AbstractVector{T}, yvec::AbstractV while L > 0 L -= 1 - ρdiag = _wig_laguerre_clenshaw!(res, L, B, lmul!(1 + Int(L != 0), diag(ρ, L)), y0, y1, y0_old) + ρdiag = _wig_laguerre_clenshaw!( + res, + L, + B, + lmul!(1 + Int(L != 0), diag(ρ, L)), + y0, + y1, + y0_old, + ) @. W = ρdiag + W * A / √(L + 1) end return @. real(W) * exp(-B / 2) * g^2 / 2 / π end -function _wigner_laguerre(ρ::AbstractSparseArray, A::AbstractArray, W::AbstractArray, g::Real, solver::WignerLaguerre) +function _wigner_laguerre( + ρ::AbstractSparseArray, + A::AbstractArray, + W::AbstractArray, + g::Real, + solver::WignerLaguerre, +) rows, cols, vals = findnz(ρ) B = @. 4 * abs2(A) @@ -94,10 +122,10 @@ function _wigner_laguerre(ρ::AbstractSparseArray, A::AbstractArray, W::Abstract Γ_mn = (1 + Int(m != n)) * sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) - @. Wtot[:, :, i] = real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * - _genlaguerre(m, n - m, B)) + @. Wtot[:, :, i] = + real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B)) end - W .= dropdims(sum(Wtot, dims=3), dims=3) + W .= dropdims(sum(Wtot, dims = 3), dims = 3) else for i in Iterators.filter(x -> x[2] >= x[1], zip(rows, cols, vals)) m, n, ρmn = i @@ -106,15 +134,20 @@ function _wigner_laguerre(ρ::AbstractSparseArray, A::AbstractArray, W::Abstract Γ_mn = (1 + Int(m != n)) * sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) - @. W += real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * - _genlaguerre(m, n - m, B)) + @. W += real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B)) end end return @. W * g^2 * exp(-B / 2) / 2 / π end -function _wigner_laguerre(ρ::AbstractArray, A::AbstractArray, W::AbstractArray, g::Real, solver::WignerLaguerre) +function _wigner_laguerre( + ρ::AbstractArray, + A::AbstractArray, + W::AbstractArray, + g::Real, + solver::WignerLaguerre, +) tol = solver.tol M = size(ρ, 1) B = @. 4 * abs2(A) @@ -131,8 +164,10 @@ function _wigner_laguerre(ρ::AbstractArray, A::AbstractArray, W::AbstractArray, Γ_mn = sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) - abs(ρmn) > tol && (@. W += 2 * real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * - _genlaguerre(m, n - m, B))) + abs(ρmn) > tol && (@. W += + 2 * real( + ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B), + )) end end end @@ -154,20 +189,17 @@ function _genlaguerre(n::Int, α::Number, x::T) where {T<:BlasFloat} α = convert(T, α) p0, p1 = one(T), -x + (α + 1) n == 0 && return p0 - for k = 1:n-1 + for k in 1:n-1 p1, p0 = ((2k + α + 1) / (k + 1) - x / (k + 1)) * p1 - (k + α) / (k + 1) * p0, p1 end p1 end -function check_inf(x::T) where {T} - if isinf(x) +check_inf(x::T) where {T} = if isinf(x) return x > zero(T) ? floatmax(T) : -floatmax(T) else return x end -end - function _wig_laguerre_clenshaw!(res, L::Int, x, c, y0, y1, y0_old) length(c) == 1 && return c[1] @@ -177,7 +209,7 @@ function _wig_laguerre_clenshaw!(res, L::Int, x, c, y0, y1, y0_old) y1 .= c[end] k = length(c) - for i in range(3, length(c), step=1) + for i in range(3, length(c), step = 1) k -= 1 copyto!(y0_old, y0) @. y0 = c[end+1-i] - y1 * sqrt((k - 1) * (L + k - 1) / ((L + k) * k)) diff --git a/test/aqua.jl b/test/aqua.jl index 1ffd4984..4d0ba935 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -1,5 +1,5 @@ using Aqua @testset "Code quality (Aqua.jl)" begin - Aqua.test_all(QuantumToolbox; ambiguities=false,) + Aqua.test_all(QuantumToolbox; ambiguities = false) end \ No newline at end of file diff --git a/test/correlations_and_spectrum.jl b/test/correlations_and_spectrum.jl index e1183d8e..6c3434b6 100644 --- a/test/correlations_and_spectrum.jl +++ b/test/correlations_and_spectrum.jl @@ -3,8 +3,9 @@ H = a' * a c_ops = [sqrt(0.1 * (0.01 + 1)) * a, sqrt(0.1 * (0.01)) * a'] - ω_l = range(0, 3, length=1000) - ω_l1, spec1 = spectrum(H, ω_l, a', a, c_ops, solver=FFTCorrelation(), progress_bar=false) + ω_l = range(0, 3, length = 1000) + ω_l1, spec1 = + spectrum(H, ω_l, a', a, c_ops, solver = FFTCorrelation(), progress_bar = false) ω_l2, spec2 = spectrum(H, ω_l, a', a, c_ops) spec1 = spec1 ./ maximum(spec1) spec2 = spec2 ./ maximum(spec2) @@ -13,6 +14,8 @@ test_func2 = maximum(real.(spec2)) * (0.1 / 2)^2 ./ ((ω_l2 .- 1) .^ 2 .+ (0.1 / 2)^2) idxs1 = test_func1 .> 0.05 idxs2 = test_func2 .> 0.05 - @test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < 0.01 - @test sum(abs2.(spec2[idxs2] .- test_func2[idxs2])) / sum(abs2.(test_func2[idxs2])) < 0.01 + @test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < + 0.01 + @test sum(abs2.(spec2[idxs2] .- test_func2[idxs2])) / sum(abs2.(test_func2[idxs2])) < + 0.01 end \ No newline at end of file diff --git a/test/cuda_ext.jl b/test/cuda_ext.jl index 93f9c54b..329567f3 100644 --- a/test/cuda_ext.jl +++ b/test/cuda_ext.jl @@ -5,7 +5,6 @@ QuantumToolbox.about() CUDA.versioninfo() @testset "CUDA Extension" begin - ψdi = Qobj(Int64[1, 0]) ψdf = Qobj(Float64[1, 0]) ψdc = Qobj(ComplexF64[1, 0]) @@ -20,39 +19,88 @@ CUDA.versioninfo() Xsf = dense_to_sparse(Xdf) Xsc = dense_to_sparse(Xdc) - @test_throws DomainError cu(ψdi; word_size=16) + @test_throws DomainError cu(ψdi; word_size = 16) # type conversion of CUDA dense arrays - @test typeof(cu(ψdi; word_size=64).data) == typeof(CuArray(ψdi).data) == CuArray{Int64,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdi; word_size=32).data) == typeof(CuArray{Int32}(ψdi).data) == CuArray{Int32,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdf; word_size=64).data) == typeof(CuArray(ψdf).data) == CuArray{Float64,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdf; word_size=32).data) == typeof(CuArray{Float32}(ψdf).data) == CuArray{Float32,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdc; word_size=64).data) == typeof(CuArray(ψdc).data) == CuArray{ComplexF64,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdc; word_size=32).data) == typeof(CuArray{ComplexF32}(ψdc).data) == CuArray{ComplexF32,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdi; word_size=64).data) == typeof(CuArray(Xdi).data) == CuArray{Int64,2,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdi; word_size=32).data) == typeof(CuArray{Int32}(Xdi).data) == CuArray{Int32,2,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdf; word_size=64).data) == typeof(CuArray(Xdf).data) == CuArray{Float64,2,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdf; word_size=32).data) == typeof(CuArray{Float32}(Xdf).data) == CuArray{Float32,2,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdc; word_size=64).data) == typeof(CuArray(Xdc).data) == CuArray{ComplexF64,2,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdc; word_size=32).data) == typeof(CuArray{ComplexF32}(Xdc).data) == CuArray{ComplexF32,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdi; word_size = 64).data) == + typeof(CuArray(ψdi).data) == + CuArray{Int64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdi; word_size = 32).data) == + typeof(CuArray{Int32}(ψdi).data) == + CuArray{Int32,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdf; word_size = 64).data) == + typeof(CuArray(ψdf).data) == + CuArray{Float64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdf; word_size = 32).data) == + typeof(CuArray{Float32}(ψdf).data) == + CuArray{Float32,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdc; word_size = 64).data) == + typeof(CuArray(ψdc).data) == + CuArray{ComplexF64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdc; word_size = 32).data) == + typeof(CuArray{ComplexF32}(ψdc).data) == + CuArray{ComplexF32,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdi; word_size = 64).data) == + typeof(CuArray(Xdi).data) == + CuArray{Int64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdi; word_size = 32).data) == + typeof(CuArray{Int32}(Xdi).data) == + CuArray{Int32,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdf; word_size = 64).data) == + typeof(CuArray(Xdf).data) == + CuArray{Float64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdf; word_size = 32).data) == + typeof(CuArray{Float32}(Xdf).data) == + CuArray{Float32,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdc; word_size = 64).data) == + typeof(CuArray(Xdc).data) == + CuArray{ComplexF64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdc; word_size = 32).data) == + typeof(CuArray{ComplexF32}(Xdc).data) == + CuArray{ComplexF32,2,CUDA.Mem.DeviceBuffer} # type conversion of CUDA sparse arrays - @test typeof(cu(ψsi; word_size=64).data) == typeof(CuSparseVector(ψsi).data) == CuSparseVector{Int64,Int32} - @test typeof(cu(ψsi; word_size=32).data) == typeof(CuSparseVector{Int32}(ψsi).data) == CuSparseVector{Int32,Int32} - @test typeof(cu(ψsf; word_size=64).data) == typeof(CuSparseVector(ψsf).data) == CuSparseVector{Float64,Int32} - @test typeof(cu(ψsf; word_size=32).data) == typeof(CuSparseVector{Float32}(ψsf).data) == CuSparseVector{Float32,Int32} - @test typeof(cu(ψsc; word_size=64).data) == typeof(CuSparseVector(ψsc).data) == CuSparseVector{ComplexF64,Int32} - @test typeof(cu(ψsc; word_size=32).data) == typeof(CuSparseVector{ComplexF32}(ψsc).data) == CuSparseVector{ComplexF32,Int32} - @test typeof(cu(Xsi; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsi).data) == CuSparseMatrixCSC{Int64,Int32} - @test typeof(cu(Xsi; word_size=32).data) == typeof(CuSparseMatrixCSC{Int32}(Xsi).data) == CuSparseMatrixCSC{Int32,Int32} - @test typeof(cu(Xsf; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsf).data) == CuSparseMatrixCSC{Float64,Int32} - @test typeof(cu(Xsf; word_size=32).data) == typeof(CuSparseMatrixCSC{Float32}(Xsf).data) == CuSparseMatrixCSC{Float32,Int32} - @test typeof(cu(Xsc; word_size=64).data) == typeof(CuSparseMatrixCSC(Xsc).data) == CuSparseMatrixCSC{ComplexF64,Int32} - @test typeof(cu(Xsc; word_size=32).data) == typeof(CuSparseMatrixCSC{ComplexF32}(Xsc).data) == CuSparseMatrixCSC{ComplexF32,Int32} + @test typeof(cu(ψsi; word_size = 64).data) == + typeof(CuSparseVector(ψsi).data) == + CuSparseVector{Int64,Int32} + @test typeof(cu(ψsi; word_size = 32).data) == + typeof(CuSparseVector{Int32}(ψsi).data) == + CuSparseVector{Int32,Int32} + @test typeof(cu(ψsf; word_size = 64).data) == + typeof(CuSparseVector(ψsf).data) == + CuSparseVector{Float64,Int32} + @test typeof(cu(ψsf; word_size = 32).data) == + typeof(CuSparseVector{Float32}(ψsf).data) == + CuSparseVector{Float32,Int32} + @test typeof(cu(ψsc; word_size = 64).data) == + typeof(CuSparseVector(ψsc).data) == + CuSparseVector{ComplexF64,Int32} + @test typeof(cu(ψsc; word_size = 32).data) == + typeof(CuSparseVector{ComplexF32}(ψsc).data) == + CuSparseVector{ComplexF32,Int32} + @test typeof(cu(Xsi; word_size = 64).data) == + typeof(CuSparseMatrixCSC(Xsi).data) == + CuSparseMatrixCSC{Int64,Int32} + @test typeof(cu(Xsi; word_size = 32).data) == + typeof(CuSparseMatrixCSC{Int32}(Xsi).data) == + CuSparseMatrixCSC{Int32,Int32} + @test typeof(cu(Xsf; word_size = 64).data) == + typeof(CuSparseMatrixCSC(Xsf).data) == + CuSparseMatrixCSC{Float64,Int32} + @test typeof(cu(Xsf; word_size = 32).data) == + typeof(CuSparseMatrixCSC{Float32}(Xsf).data) == + CuSparseMatrixCSC{Float32,Int32} + @test typeof(cu(Xsc; word_size = 64).data) == + typeof(CuSparseMatrixCSC(Xsc).data) == + CuSparseMatrixCSC{ComplexF64,Int32} + @test typeof(cu(Xsc; word_size = 32).data) == + typeof(CuSparseMatrixCSC{ComplexF32}(Xsc).data) == + CuSparseMatrixCSC{ComplexF32,Int32} @test typeof(CuSparseMatrixCSR(Xsi).data) == CuSparseMatrixCSR{Int64,Int32} @test typeof(CuSparseMatrixCSR{Int32}(Xsi).data) == CuSparseMatrixCSR{Int32,Int32} @test typeof(CuSparseMatrixCSR(Xsf).data) == CuSparseMatrixCSR{Float64,Int32} @test typeof(CuSparseMatrixCSR{Float32}(Xsf).data) == CuSparseMatrixCSR{Float32,Int32} @test typeof(CuSparseMatrixCSR(Xsc).data) == CuSparseMatrixCSR{ComplexF64,Int32} - @test typeof(CuSparseMatrixCSR{ComplexF32}(Xsc).data) == CuSparseMatrixCSR{ComplexF32,Int32} + @test typeof(CuSparseMatrixCSR{ComplexF32}(Xsc).data) == + CuSparseMatrixCSR{ComplexF32,Int32} end diff --git a/test/dynamical-shifted-fock.jl b/test/dynamical-shifted-fock.jl index 6b766f09..509988ac 100644 --- a/test/dynamical-shifted-fock.jl +++ b/test/dynamical-shifted-fock.jl @@ -14,7 +14,7 @@ α0 = 1.5 ρ0 = coherent(N0, α0) - sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a0' * a0, a0], progress_bar=false) + sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops = [a0' * a0, a0], progress_bar = false) N = 5 a = destroy(N) @@ -37,13 +37,36 @@ op_list = [a] ψ0 = fock(N, 0) α0_l = [α0] - dsf_params = (Δ=Δ, F=F, κ=κ, U=U) + dsf_params = (Δ = Δ, F = F, κ = κ, U = U) - sol_dsf_me = dsf_mesolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress_bar=false) - sol_dsf_mc = dsf_mcsolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops=e_ops_dsf, progress_bar=false, n_traj=500) + sol_dsf_me = dsf_mesolve( + H_dsf, + ψ0, + tlist, + c_ops_dsf, + op_list, + α0_l, + dsf_params, + e_ops = e_ops_dsf, + progress_bar = false, + ) + sol_dsf_mc = dsf_mcsolve( + H_dsf, + ψ0, + tlist, + c_ops_dsf, + op_list, + α0_l, + dsf_params, + e_ops = e_ops_dsf, + progress_bar = false, + n_traj = 500, + ) val_ss = abs2(sol0.expect[1, end]) - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / (val_ss * length(tlist)) < 0.1 - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / (val_ss * length(tlist)) < 0.1 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / + (val_ss * length(tlist)) < 0.1 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / + (val_ss * length(tlist)) < 0.1 # Two cavities case F = 2 @@ -56,11 +79,24 @@ N0 = 20 a10 = kron(destroy(N0), qeye(N0)) a20 = kron(qeye(N0), destroy(N0)) - H0 = Δ * a10' * a10 + Δ * a20' * a20 + U * a10'^2 * a10^2 + U * a20'^2 * a20^2 + F * (a10 + a10') + J * (a10' * a20 + a10 * a20') + H0 = + Δ * a10' * a10 + + Δ * a20' * a20 + + U * a10'^2 * a10^2 + + U * a20'^2 * a20^2 + + F * (a10 + a10') + + J * (a10' * a20 + a10 * a20') c_ops0 = [√κ * a10, √κ * a20] ρ0 = kron(coherent(N0, α0), coherent(N0, α0)) - sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops=[a10' * a10, a20' * a20], progress_bar=false) + sol0 = mesolve( + H0, + ρ0, + tlist, + c_ops0, + e_ops = [a10' * a10, a20' * a20], + progress_bar = false, + ) N = 5 a1 = kron(destroy(N), qeye(N)) @@ -71,7 +107,12 @@ U = p.U J = p.J a1, a2 = op_list - Δ * a1' * a1 + Δ * a2' * a2 + U * a1'^2 * a1^2 + U * a2'^2 * a2^2 + F * (a1 + a1') + J * (a1' * a2 + a1 * a2') + Δ * a1' * a1 + + Δ * a2' * a2 + + U * a1'^2 * a1^2 + + U * a2'^2 * a2^2 + + F * (a1 + a1') + + J * (a1' * a2 + a1 * a2') end function c_ops_dsf2(op_list, p) κ = p.κ @@ -85,14 +126,39 @@ op_list = [a1, a2] ψ0 = kron(fock(N, 0), fock(N, 0)) α0_l = [α0, α0] - dsf_params = (Δ=Δ, F=F, κ=κ, U=U, J=J) + dsf_params = (Δ = Δ, F = F, κ = κ, U = U, J = J) - sol_dsf_me = dsf_mesolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress_bar=false) - sol_dsf_mc = dsf_mcsolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops=e_ops_dsf2, progress_bar=false, n_traj=500) + sol_dsf_me = dsf_mesolve( + H_dsf2, + ψ0, + tlist, + c_ops_dsf2, + op_list, + α0_l, + dsf_params, + e_ops = e_ops_dsf2, + progress_bar = false, + ) + sol_dsf_mc = dsf_mcsolve( + H_dsf2, + ψ0, + tlist, + c_ops_dsf2, + op_list, + α0_l, + dsf_params, + e_ops = e_ops_dsf2, + progress_bar = false, + n_traj = 500, + ) val_ss = abs2(sol0.expect[1, end]) - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_me.expect[2, :])) / (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_mc.expect[2, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / + (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / + (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_me.expect[2, :])) / + (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_mc.expect[2, :])) / + (val_ss * length(tlist)) < 0.6 end \ No newline at end of file diff --git a/test/dynamical_fock_dimension_mesolve.jl b/test/dynamical_fock_dimension_mesolve.jl index 84fe2617..2ef46bbc 100644 --- a/test/dynamical_fock_dimension_mesolve.jl +++ b/test/dynamical_fock_dimension_mesolve.jl @@ -1,7 +1,7 @@ ### DYNAMICAL FOCK DIMENSION ### @testset "Dynamical Fock Dimension" begin F, Δ, κ = 5, 0.25, 1 - t_l = range(0, 15, length=100) + t_l = range(0, 15, length = 100) N0 = 140 a0 = destroy(N0) @@ -9,7 +9,7 @@ c_ops0 = [√κ * a0] e_ops0 = [a0' * a0] ψ00 = fock(N0, 0) - sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress_bar=false) + sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops = e_ops0, progress_bar = false) function H_dfd0(dims, p) Δ = p.Δ @@ -28,10 +28,21 @@ end maxdims = [150] ψ0 = fock(3, 0) - dfd_params = (Δ=Δ, F=F, κ=κ) - sol = dfd_mesolve(H_dfd0, ψ0, t_l, c_ops_dfd0, maxdims, dfd_params, e_ops=e_ops_dfd0, progress_bar=false) + dfd_params = (Δ = Δ, F = F, κ = κ) + sol = dfd_mesolve( + H_dfd0, + ψ0, + t_l, + c_ops_dfd0, + maxdims, + dfd_params, + e_ops = e_ops_dfd0, + progress_bar = false, + ) - @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 + @test sum( + abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16)), + ) < 0.01 ###################### @@ -40,7 +51,7 @@ c_ops0 = [√κ * a0] e_ops0 = [a0' * a0] ψ00 = fock(N0, 50) - sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress_bar=false) + sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops = e_ops0, progress_bar = false) function H_dfd1(dims, p) Δ = p.Δ @@ -59,11 +70,21 @@ end maxdims = [150] ψ0 = fock(70, 50) - dfd_params = (Δ=Δ, F=F, κ=κ) - sol = dfd_mesolve(H_dfd1, ψ0, t_l, c_ops_dfd1, maxdims, dfd_params, e_ops=e_ops_dfd1, progress_bar=false) - - @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 + dfd_params = (Δ = Δ, F = F, κ = κ) + sol = dfd_mesolve( + H_dfd1, + ψ0, + t_l, + c_ops_dfd1, + maxdims, + dfd_params, + e_ops = e_ops_dfd1, + progress_bar = false, + ) + @test sum( + abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16)), + ) < 0.01 ###################### @@ -76,7 +97,7 @@ c_ops0 = [√κ * a0, √κ * a1] e_ops0 = [a0' * a0, a1' * a1] ψ00 = kron(fock(N0, 0), fock(N1, 15)) - sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops=e_ops0, progress_bar=false) + sol0 = mesolve(H0, ψ00, t_l, c_ops0, e_ops = e_ops0, progress_bar = false) function H_dfd2(dims, p) Δ = p.Δ @@ -99,9 +120,21 @@ end maxdims = [50, 50] ψ0 = kron(fock(3, 0), fock(20, 15)) - dfd_params = (Δ=Δ, F=F, κ=κ, J=J) - sol = dfd_mesolve(H_dfd2, ψ0, t_l, c_ops_dfd2, maxdims, dfd_params, e_ops=e_ops_dfd2, progress_bar=false) + dfd_params = (Δ = Δ, F = F, κ = κ, J = J) + sol = dfd_mesolve( + H_dfd2, + ψ0, + t_l, + c_ops_dfd2, + maxdims, + dfd_params, + e_ops = e_ops_dfd2, + progress_bar = false, + ) - @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) + - sum(abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16))) < 0.01 + @test sum( + abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16)), + ) + sum( + abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16)), + ) < 0.01 end \ No newline at end of file diff --git a/test/eigenvalues_and_operators.jl b/test/eigenvalues_and_operators.jl index ca4ef657..590395b9 100644 --- a/test/eigenvalues_and_operators.jl +++ b/test/eigenvalues_and_operators.jl @@ -1,20 +1,21 @@ @testset "Eigenvalues and Operators" begin σx = sigmax() - result = eigenstates(σx, sparse=false) + result = eigenstates(σx, sparse = false) λd, ψd, Td = result resstring = sprint((t, s) -> show(t, "text/plain", s), result) valstring = sprint((t, s) -> show(t, "text/plain", s), result.values) vecsstring = sprint((t, s) -> show(t, "text/plain", s), result.vectors) - λs, ψs, Ts = eigenstates(σx, sparse=true, k=2) - λs1, ψs1, Ts1 = eigenstates(σx, sparse=true, k=1) + λs, ψs, Ts = eigenstates(σx, sparse = true, k = 2) + λs1, ψs1, Ts1 = eigenstates(σx, sparse = true, k = 1) @test all([ψ.type isa KetQuantumObject for ψ in ψd]) @test typeof(Td) <: AbstractMatrix @test typeof(Ts) <: AbstractMatrix @test typeof(Ts1) <: AbstractMatrix - @test all(abs.(eigenenergies(σx, sparse=false)) .≈ abs.(λd)) - @test all(abs.(eigenenergies(σx, sparse=true, k=2)) .≈ abs.(λs)) - @test resstring == "EigsolveResult: type=$(Operator) dims=$(result.dims)\nvalues:\n$(valstring)\nvectors:\n$vecsstring" + @test all(abs.(eigenenergies(σx, sparse = false)) .≈ abs.(λd)) + @test all(abs.(eigenenergies(σx, sparse = true, k = 2)) .≈ abs.(λs)) + @test resstring == + "EigsolveResult: type=$(Operator) dims=$(result.dims)\nvalues:\n$(valstring)\nvectors:\n$vecsstring" N = 30 a = kron(destroy(N), qeye(2)) @@ -32,14 +33,14 @@ vals_d, vecs_d, mat_d = eigenstates(H_d) vals_c, vecs_c, mat_c = eigenstates(H_c) - vals2, vecs2, mat2 = eigenstates(H_d, sparse=true, sigma=-0.9, k=10, krylovdim=30) - sort!(vals_c, by=real) - sort!(vals2, by=real) + vals2, vecs2, mat2 = + eigenstates(H_d, sparse = true, sigma = -0.9, k = 10, krylovdim = 30) + sort!(vals_c, by = real) + sort!(vals2, by = real) @test sum(real.(vals_d[1:20]) .- real.(vals_c[1:20])) / 20 < 1e-3 @test sum(real.(vals_d[1:10]) .- real.(vals2[1:10])) / 20 < 1e-3 - N = 5 a = kron(destroy(N), qeye(N)) a_d = a' @@ -57,28 +58,38 @@ L = liouvillian(H, c_ops) # eigen solve for general matrices - vals, _, vecs = eigsolve(L.data, sigma=0.01, k=10, krylovdim=50) + vals, _, vecs = eigsolve(L.data, sigma = 0.01, k = 10, krylovdim = 50) vals2, vecs2 = eigen(sparse_to_dense(L.data)) - vals3, state3, vecs3 = eigsolve_al(liouvillian(H, c_ops), 1 \ (40 * κ), k=10, krylovdim=50) - idxs = sortperm(vals2, by=abs) + vals3, state3, vecs3 = + eigsolve_al(liouvillian(H, c_ops), 1 \ (40 * κ), k = 10, krylovdim = 50) + idxs = sortperm(vals2, by = abs) vals2 = vals2[idxs][1:10] vecs2 = vecs2[:, idxs][:, 1:10] - @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol=1e-7) - @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol=1e-7) - @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs2[:, 1]), atol=1e-7) - @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs3[:, 1]), atol=1e-5) + @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol = 1e-7) + @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol = 1e-7) + @test isapprox( + vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), + vec2mat(vecs2[:, 1]), + atol = 1e-7, + ) + @test isapprox( + vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), + vec2mat(vecs3[:, 1]), + atol = 1e-5, + ) # eigen solve for QuantumObject - result = eigenstates(L, sparse=true, sigma=0.01, k=10, krylovdim=50) + result = eigenstates(L, sparse = true, sigma = 0.01, k = 10, krylovdim = 50) vals, vecs = result resstring = sprint((t, s) -> show(t, "text/plain", s), result) valstring = sprint((t, s) -> show(t, "text/plain", s), result.values) vecsstring = sprint((t, s) -> show(t, "text/plain", s), result.vectors) - @test resstring == "EigsolveResult: type=$(SuperOperator) dims=$(result.dims)\nvalues:\n$(valstring)\nvectors:\n$vecsstring" + @test resstring == + "EigsolveResult: type=$(SuperOperator) dims=$(result.dims)\nvalues:\n$(valstring)\nvectors:\n$vecsstring" - vals2, vecs2 = eigenstates(L, sparse=false) - idxs = sortperm(vals2, by=abs) + vals2, vecs2 = eigenstates(L, sparse = false) + idxs = sortperm(vals2, by = abs) vals2 = vals2[idxs][1:10] vecs2 = vecs2[idxs][1:10] @@ -86,8 +97,16 @@ @test result.dims == L.dims @test all([v.type isa OperatorKetQuantumObject for v in vecs]) @test typeof(result.vectors) <: AbstractMatrix - @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol=1e-7) - @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol=1e-7) - @test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(vecs2[1]).data, atol=1e-7) - @test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(state3[1]).data, atol=1e-5) + @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol = 1e-7) + @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol = 1e-7) + @test isapprox( + vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), + vec2mat(vecs2[1]).data, + atol = 1e-7, + ) + @test isapprox( + vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), + vec2mat(state3[1]).data, + atol = 1e-5, + ) end \ No newline at end of file diff --git a/test/generalized_master_equation.jl b/test/generalized_master_equation.jl index 1579affb..8c2f0bd7 100644 --- a/test/generalized_master_equation.jl +++ b/test/generalized_master_equation.jl @@ -14,7 +14,7 @@ fields = [sqrt(0.01) * (a + a'), sqrt(0.01) * sx] Tlist = [0, 0.0] - E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc=N_trunc, tol=tol) + 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) H_d = Qobj(dense_to_sparse((U'*H*U)[1:N_trunc, 1:N_trunc], tol)) @@ -26,13 +26,16 @@ c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2] L2 = liouvillian(H_d, c_ops) - @test (expect(Xp' * Xp, steadystate(L1)) < 1e-10 && expect(Xp' * Xp, steadystate(L2)) > 1e-3) + @test ( + expect(Xp' * Xp, steadystate(L1)) < 1e-10 && + expect(Xp' * Xp, steadystate(L2)) > 1e-3 + ) H = 1 * a' * a + 1 * sz / 2 + 1e-5 * (a * sp + a' * sm) Tlist = [0.2, 0.0] - E, U, L1 = liouvillian_generalized(H, fields, Tlist, N_trunc=N_trunc, tol=tol) + 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) H_d = Qobj(dense_to_sparse((U'*H*U)[1:N_trunc, 1:N_trunc], tol)) @@ -40,5 +43,6 @@ 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)) - @test abs(expect(Xp' * Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < 1e-4 + @test abs(expect(Xp' * Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < + 1e-4 end \ No newline at end of file diff --git a/test/jet.jl b/test/jet.jl index b9c482c4..6fc91a32 100644 --- a/test/jet.jl +++ b/test/jet.jl @@ -1,5 +1,9 @@ using JET @testset "Code quality (JET.jl)" begin - JET.test_package(QuantumToolbox; target_defined_modules=true, ignore_missing_comparison=true) + JET.test_package( + QuantumToolbox; + target_defined_modules = true, + ignore_missing_comparison = true, + ) end \ No newline at end of file diff --git a/test/low_rank_dynamics.jl b/test/low_rank_dynamics.jl index 1433a350..7a66bd7f 100644 --- a/test/low_rank_dynamics.jl +++ b/test/low_rank_dynamics.jl @@ -1,7 +1,7 @@ @testset "Low Rank Dynamics" begin # Define lattice Nx, Ny = 2, 3 - latt = Lattice(Nx=Nx, Ny=Ny) + latt = Lattice(Nx = Nx, Ny = Ny) N_cut = 2 N_modes = latt.N N = N_cut^N_modes @@ -16,20 +16,20 @@ i <= M && (ϕ[i] = mb(sp, j, latt) * ϕ[1]) end for k in 1:N_modes-1 - for l = k+1:N_modes + for l in k+1:N_modes i += 1 i <= M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1]) end end for i in i+1:M - ϕ[i] = Qobj(rand(ComplexF64, size(ϕ[1])[1]), dims=ϕ[1].dims) + ϕ[i] = Qobj(rand(ComplexF64, size(ϕ[1])[1]), dims = ϕ[1].dims) normalize!(ϕ[i]) end z = hcat(broadcast(x -> x.data, ϕ)...) B = Matrix(Diagonal([1 + 0im; zeros(M - 1)])) S = z' * z B = B / tr(S * B) - ρ = Qobj(z * B * z', dims=ones(Int, N_modes) * N_cut) + ρ = Qobj(z * B * z', dims = ones(Int, N_modes) * N_cut) # Define Hamiltonian and collapse operators Jx = 0.9 @@ -40,11 +40,11 @@ Sz = sum([mb(sz, i, latt) for i in 1:latt.N]) tl = LinRange(0, 10, 100) - H, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc=pbc, order=1) + H, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc = pbc, order = 1) e_ops = (Sz,) # Full solution - mesol = mesolve(H, ρ, tl, c_ops; e_ops=[e_ops...], progress_bar=false) + mesol = mesolve(H, ρ, tl, c_ops; e_ops = [e_ops...], progress_bar = false) A = Matrix(mesol.states[end].data) λ = eigvals(Hermitian(A)) Strue = -sum(λ .* log2.(λ)) @@ -61,15 +61,15 @@ end opt = LRMesolveOptions( - alg=Tsit5(), - err_max=1e-3, - p0=0.0, - atol_inv=1e-6, - adj_condition="variational", - Δt=0.2, - progress=false + alg = Tsit5(), + err_max = 1e-3, + p0 = 0.0, + atol_inv = 1e-6, + adj_condition = "variational", + Δt = 0.2, + progress = false, ) - lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops=e_ops, f_ops=(f_entropy,), opt=opt) + lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops = e_ops, f_ops = (f_entropy,), opt = opt) # Test m_me = real(mesol.expect[1, :]) diff --git a/test/negativity_and_partial_transpose.jl b/test/negativity_and_partial_transpose.jl index 4c377b60..e347f171 100644 --- a/test/negativity_and_partial_transpose.jl +++ b/test/negativity_and_partial_transpose.jl @@ -1,21 +1,23 @@ @testset "Negativity and Partial Transpose" begin # tests for negativity - rho = (1 / 40) * Qobj([ - 15 1 1 15; - 1 5 -3 1; - 1 -3 5 1; - 15 1 1 15]; - dims=[2, 2] + rho = (1 / 40) * Qobj( + [ + 15 1 1 15 + 1 5 -3 1 + 1 -3 5 1 + 15 1 1 15 + ]; + dims = [2, 2], ) Neg = negativity(rho, 1) @test Neg ≈ 0.25 @test negativity(rho, 2) ≈ Neg - @test negativity(rho, 1; logarithmic=true) ≈ log2(2 * Neg + 1) + @test negativity(rho, 1; logarithmic = true) ≈ log2(2 * Neg + 1) @test_throws ErrorException negativity(rho, 3) # tests for partial transpose (PT) # A (24 * 24)-matrix which contains number 1 ~ 576 - A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims=[2, 3, 4]) + A_dense = Qobj(reshape(1:(24^2), (24, 24)), dims = [2, 3, 4]) A_sparse = dense_to_sparse(A_dense) PT = (true, false) for s1 in PT diff --git a/test/progress_bar.jl b/test/progress_bar.jl index 9ad0f1f1..8a1f84cb 100644 --- a/test/progress_bar.jl +++ b/test/progress_bar.jl @@ -1,7 +1,7 @@ @testset "Progress Bar" begin bar_width = 30 strLength = 67 + bar_width # including "\r" in the beginning of the string - prog = ProgressBar(bar_width, enable=true, bar_width=bar_width) + prog = ProgressBar(bar_width, enable = true, bar_width = bar_width) for p in 1:bar_width output = sprint((t, s) -> next!(s, t), prog) diff --git a/test/quantum_objects.jl b/test/quantum_objects.jl index 910a6865..93a903f1 100644 --- a/test/quantum_objects.jl +++ b/test/quantum_objects.jl @@ -2,23 +2,23 @@ # unsupported size of array for a in [rand(ComplexF64, 3, 2), rand(ComplexF64, 2, 2, 2)] for t in [nothing, Ket, Bra, Operator, SuperOperator, OperatorBra, OperatorKet] - @test_throws DomainError Qobj(a, type=t) + @test_throws DomainError Qobj(a, type = t) end end N = 10 a = rand(ComplexF64, 10) # @test_logs (:warn, "The norm of the input data is not one.") QuantumObject(a) - @test_throws DomainError Qobj(a, type=Bra) - @test_throws DomainError Qobj(a, type=Operator) - @test_throws DomainError Qobj(a, type=SuperOperator) - @test_throws DomainError Qobj(a, type=OperatorBra) - @test_throws DomainError Qobj(a', type=Ket) - @test_throws DomainError Qobj(a', type=Operator) - @test_throws DomainError Qobj(a', type=SuperOperator) - @test_throws DomainError Qobj(a', type=OperatorKet) - @test_throws DimensionMismatch Qobj(a, dims=[2]) - @test_throws DimensionMismatch Qobj(a', dims=[2]) + @test_throws DomainError Qobj(a, type = Bra) + @test_throws DomainError Qobj(a, type = Operator) + @test_throws DomainError Qobj(a, type = SuperOperator) + @test_throws DomainError Qobj(a, type = OperatorBra) + @test_throws DomainError Qobj(a', type = Ket) + @test_throws DomainError Qobj(a', type = Operator) + @test_throws DomainError Qobj(a', type = SuperOperator) + @test_throws DomainError Qobj(a', type = OperatorKet) + @test_throws DimensionMismatch Qobj(a, dims = [2]) + @test_throws DimensionMismatch Qobj(a', dims = [2]) a2 = Qobj(a') a3 = Qobj(a) @test isket(a2) == false @@ -39,7 +39,7 @@ a = sprand(ComplexF64, 100, 100, 0.1) a2 = Qobj(a) - a3 = Qobj(a, type=SuperOperator) + a3 = Qobj(a, type = SuperOperator) @test isket(a2) == false @test isbra(a2) == false @@ -53,8 +53,8 @@ @test issuper(a3) == true @test isoperket(a3) == false @test isoperbra(a3) == false - @test_throws DimensionMismatch Qobj(a, dims=[2]) - @test_throws DimensionMismatch Qobj(a, dims=[2]) + @test_throws DimensionMismatch Qobj(a, dims = [2]) + @test_throws DimensionMismatch Qobj(a, dims = [2]) # Operator-Ket, Operator-Bra tests H = 0.3 * sigmax() + 0.7 * sigmaz() @@ -62,7 +62,7 @@ ρ = Qobj(rand(ComplexF64, 2, 2)) ρ_ket = mat2vec(ρ) ρ_bra = ρ_ket' - @test ρ_bra == Qobj(mat2vec(ρ.data)', type=OperatorBra) + @test ρ_bra == Qobj(mat2vec(ρ.data)', type = OperatorBra) @test ρ == vec2mat(ρ_ket) @test isket(ρ_ket) == false @test isbra(ρ_ket) == false @@ -85,8 +85,8 @@ @test L * ρ_ket ≈ -1im * (+(spre(H) * ρ_ket) - spost(H) * ρ_ket) @test (ρ_bra * L')' == L * ρ_ket @test sum((conj(ρ) .* ρ).data) ≈ dot(ρ_ket, ρ_ket) ≈ ρ_bra * ρ_ket - @test_throws DimensionMismatch Qobj(ρ_ket.data, type=OperatorKet, dims=[4]) - @test_throws DimensionMismatch Qobj(ρ_bra.data, type=OperatorBra, dims=[4]) + @test_throws DimensionMismatch Qobj(ρ_ket.data, type = OperatorKet, dims = [4]) + @test_throws DimensionMismatch Qobj(ρ_bra.data, type = OperatorBra, dims = [4]) a = Array(a) a4 = Qobj(a) @@ -174,7 +174,8 @@ a_dims = a.dims a_size = size(a) a_isherm = ishermitian(a) - @test opstring == "Quantum Object: type=Operator dims=$a_dims size=$a_size ishermitian=$a_isherm\n$datastring" + @test opstring == + "Quantum Object: type=Operator dims=$a_dims size=$a_size ishermitian=$a_isherm\n$datastring" a = spre(a) opstring = sprint((t, s) -> show(t, "text/plain", s), a) @@ -182,39 +183,44 @@ a_dims = a.dims a_size = size(a) a_isherm = ishermitian(a) - @test opstring == "Quantum Object: type=SuperOperator dims=$a_dims size=$a_size\n$datastring" + @test opstring == + "Quantum Object: type=SuperOperator dims=$a_dims size=$a_size\n$datastring" opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) ψ_dims = ψ.dims ψ_size = size(ψ) - @test opstring == "Quantum Object: type=Ket dims=$ψ_dims size=$ψ_size\n$datastring" + @test opstring == + "Quantum Object: type=Ket dims=$ψ_dims size=$ψ_size\n$datastring" ψ = ψ' opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) ψ_dims = ψ.dims ψ_size = size(ψ) - @test opstring == "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" + @test opstring == + "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" - ψ2 = Qobj(rand(ComplexF64, 4), type=OperatorKet) + ψ2 = Qobj(rand(ComplexF64, 4), type = OperatorKet) opstring = sprint((t, s) -> show(t, "text/plain", s), ψ2) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ2.data) ψ2_dims = ψ2.dims ψ2_size = size(ψ2) - @test opstring == "Quantum Object: type=OperatorKet dims=$ψ2_dims size=$ψ2_size\n$datastring" + @test opstring == + "Quantum Object: type=OperatorKet dims=$ψ2_dims size=$ψ2_size\n$datastring" ψ2 = ψ2' opstring = sprint((t, s) -> show(t, "text/plain", s), ψ2) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ2.data) ψ2_dims = ψ2.dims ψ2_size = size(ψ2) - @test opstring == "Quantum Object: type=OperatorBra dims=$ψ2_dims size=$ψ2_size\n$datastring" + @test opstring == + "Quantum Object: type=OperatorBra dims=$ψ2_dims size=$ψ2_size\n$datastring" # get coherence ψ = coherent(30, 3) α, δψ = get_coherence(ψ) - @test isapprox(abs(α), 3, atol=1e-5) && abs2(δψ[1]) > 0.999 + @test isapprox(abs(α), 3, atol = 1e-5) && abs2(δψ[1]) > 0.999 # svdvals, Schatten p-norm vd = Qobj(rand(ComplexF64, 10)) @@ -241,7 +247,9 @@ a = destroy(20) for op in ((+), (-), (*), (^)) A = broadcast(op, a, a) - @test A.data == broadcast(op, a.data, a.data) && A.type == a.type && A.dims == a.dims + @test A.data == broadcast(op, a.data, a.data) && + A.type == a.type && + A.dims == a.dims A = broadcast(op, 2.1, a) @test A.data == broadcast(op, 2.1, a.data) && A.type == a.type && A.dims == a.dims diff --git a/test/steady_state.jl b/test/steady_state.jl index 7a2c06e8..5d09bfc1 100644 --- a/test/steady_state.jl +++ b/test/steady_state.jl @@ -7,7 +7,7 @@ e_ops = [a_d * a] psi0 = fock(N, 3) t_l = LinRange(0, 200, 1000) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, progress_bar=false) + sol_me = mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, progress_bar = false) ρ_ss = steadystate(H, c_ops) @test abs(sol_me.expect[1, end] - expect(e_ops[1], ρ_ss)) < 1e-3 @@ -18,7 +18,16 @@ psi0 = fock(N, 3) t_l = LinRange(0, 200, 1000) H_t_f = TimeDependentOperatorSum([(t, p) -> sin(t)], [liouvillian(H_t)]) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, H_t=H_t_f, alg=Vern7(), progress_bar=false) + sol_me = mesolve( + H, + psi0, + t_l, + c_ops, + e_ops = e_ops, + H_t = H_t_f, + alg = Vern7(), + progress_bar = false, + ) ρ_ss = steadystate_floquet(H, c_ops, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1) @test abs(sum(sol_me.expect[1, end-100:end]) / 101 - expect(e_ops[1], ρ_ss)) < 1e-2 end \ No newline at end of file diff --git a/test/time_evolution_and_partial_trace.jl b/test/time_evolution_and_partial_trace.jl index 03cf86b5..3a8cd181 100644 --- a/test/time_evolution_and_partial_trace.jl +++ b/test/time_evolution_and_partial_trace.jl @@ -10,7 +10,7 @@ psi0 = kron(fock(N, 0), fock(2, 0)) t_l = LinRange(0, 1000, 1000) e_ops = [a_d * a] - sol = sesolve(H, psi0, t_l, e_ops=e_ops, alg=Vern7(), progress_bar=false) + sol = sesolve(H, psi0, t_l, e_ops = e_ops, alg = Vern7(), progress_bar = false) @test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1 @test ptrace(sol.states[end], 1) ≈ ptrace(ket2dm(sol.states[end]), 1) @test ptrace(sol.states[end]', 1) ≈ ptrace(sol.states[end], 1) @@ -22,8 +22,9 @@ e_ops = [a_d * a] psi0 = basis(N, 3) t_l = LinRange(0, 100, 1000) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=e_ops, alg=Vern7(), progress_bar=false) - sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj=500, e_ops=e_ops, progress_bar=false) + sol_me = + mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, alg = Vern7(), progress_bar = false) + sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj = 500, e_ops = e_ops, progress_bar = false) @test sum(abs.(sol_mc.expect .- sol_me.expect)) / length(t_l) < 0.1 sp1 = kron(sigmap(), qeye(2)) @@ -44,8 +45,18 @@ psi0_2 = normalize(fock(2, 0) + fock(2, 1)) psi0 = kron(psi0_1, psi0_2) t_l = LinRange(0, 20 / γ1, 1000) - sol_me = mesolve(H, psi0, t_l, c_ops, e_ops=[sp1 * sm1, sp2 * sm2], progress_bar=false) - sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj=500, e_ops=[sp1 * sm1, sp2 * sm2], progress_bar=false) + sol_me = + mesolve(H, psi0, t_l, c_ops, e_ops = [sp1 * sm1, sp2 * sm2], progress_bar = false) + sol_mc = mcsolve( + H, + psi0, + t_l, + c_ops, + n_traj = 500, + e_ops = [sp1 * sm1, sp2 * sm2], + progress_bar = false, + ) @test sum(abs.(sol_mc.expect[1:2, :] .- sol_me.expect[1:2, :])) / length(t_l) < 0.1 - @test expect(sp1 * sm1, sol_me.states[end]) ≈ expect(sigmap() * sigmam(), ptrace(sol_me.states[end], 1)) + @test expect(sp1 * sm1, sol_me.states[end]) ≈ + expect(sigmap() * sigmam(), ptrace(sol_me.states[end], 1)) end \ No newline at end of file diff --git a/test/wigner.jl b/test/wigner.jl index aede10d4..47c8ee38 100644 --- a/test/wigner.jl +++ b/test/wigner.jl @@ -5,10 +5,10 @@ xvec = LinRange(-3, 3, 300) yvec = LinRange(-3, 3, 300) - wig = wigner(ψ, xvec, yvec, solver=WignerLaguerre(tol=1e-6)) - wig2 = wigner(ρ, xvec, yvec, solver=WignerLaguerre(parallel=false)) - wig3 = wigner(ρ, xvec, yvec, solver=WignerLaguerre(parallel=true)) - wig4 = wigner(ψ, xvec, yvec, solver=WignerClenshaw()) + wig = wigner(ψ, xvec, yvec, solver = WignerLaguerre(tol = 1e-6)) + wig2 = wigner(ρ, xvec, yvec, solver = WignerLaguerre(parallel = false)) + wig3 = wigner(ρ, xvec, yvec, solver = WignerLaguerre(parallel = true)) + wig4 = wigner(ψ, xvec, yvec, solver = WignerClenshaw()) @test sqrt(sum(abs.(wig2 .- wig)) / length(wig)) < 1e-3 @test sqrt(sum(abs.(wig3 .- wig)) / length(wig)) < 1e-3 From a17139f495cd72a73f0a029e5f2e4f5eeacfbee6 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 21 May 2024 09:52:30 +0200 Subject: [PATCH 4/4] Minor changes --- .JuliaFormatter.toml | 2 + .../{Format.yml => JuliaFormatter.yml} | 2 +- docs/make.jl | 7 +- ext/QuantumToolboxCUDAExt.jl | 29 +- src/arnoldi.jl | 40 +- src/correlations.jl | 19 +- src/eigsolve.jl | 72 +-- src/general_functions.jl | 56 +-- src/negativity.jl | 15 +- src/permutation.jl | 8 +- src/progress_bar.jl | 16 +- src/quantum_object.jl | 399 +++++---------- src/quantum_operators.jl | 39 +- src/spin_lattice.jl | 50 +- src/time_evolution/lr_mesolve.jl | 185 ++++--- src/time_evolution/mcsolve.jl | 342 ++++++++----- src/time_evolution/mesolve.jl | 172 ++++--- src/time_evolution/sesolve.jl | 153 +++--- src/time_evolution/time_evolution.jl | 219 +++++--- .../time_evolution_dynamical.jl | 475 ++++++++++++------ src/versioninfo.jl | 22 +- src/wigner.jl | 45 +- test/correlations_and_spectrum.jl | 9 +- test/cuda_ext.jl | 39 +- test/dynamical-shifted-fock.jl | 75 +-- test/dynamical_fock_dimension_mesolve.jl | 66 +-- test/eigenvalues_and_operators.jl | 30 +- test/generalized_master_equation.jl | 8 +- test/jet.jl | 6 +- test/quantum_objects.jl | 19 +- test/steady_state.jl | 11 +- test/time_evolution_and_partial_trace.jl | 19 +- 32 files changed, 1294 insertions(+), 1355 deletions(-) rename .github/workflows/{Format.yml => JuliaFormatter.yml} (97%) diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index fda0404a..72a0d993 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,6 +1,8 @@ +margin=120 always_for_in=true remove_extra_newlines=true long_to_short_function_def=true +always_use_return=true format_docstrings=true indent_submodule=true format_markdown=true diff --git a/.github/workflows/Format.yml b/.github/workflows/JuliaFormatter.yml similarity index 97% rename from .github/workflows/Format.yml rename to .github/workflows/JuliaFormatter.yml index 1e9382c0..13aba6b8 100644 --- a/.github/workflows/Format.yml +++ b/.github/workflows/JuliaFormatter.yml @@ -1,4 +1,4 @@ -name: format-pr +name: JuliaFormatter PR on: schedule: - cron: '0 0 * * *' diff --git a/docs/make.jl b/docs/make.jl index 97e1410a..1d45f8c7 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,12 +1,7 @@ using QuantumToolbox using Documenter -DocMeta.setdocmeta!( - QuantumToolbox, - :DocTestSetup, - :(using QuantumToolbox); - recursive = true, -) +DocMeta.setdocmeta!(QuantumToolbox, :DocTestSetup, :(using QuantumToolbox); recursive = true) makedocs(; modules = [QuantumToolbox], diff --git a/ext/QuantumToolboxCUDAExt.jl b/ext/QuantumToolboxCUDAExt.jl index c06615ff..4e104c0a 100644 --- a/ext/QuantumToolboxCUDAExt.jl +++ b/ext/QuantumToolboxCUDAExt.jl @@ -10,40 +10,35 @@ 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.dims) +CuArray(A::QuantumObject{Tq}) where {Tq<:Union{Vector,Matrix}} = QuantumObject(CuArray(A.data), A.type, A.dims) @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.dims) +CuArray{T}(A::QuantumObject{Tq}) where {T,Tq<:Union{Vector,Matrix}} = QuantumObject(CuArray{T}(A.data), A.type, A.dims) @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.dims) +CuSparseVector(A::QuantumObject{<:SparseVector}) = QuantumObject(CuSparseVector(A.data), A.type, A.dims) @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.dims) +CuSparseVector{T}(A::QuantumObject{<:SparseVector}) where {T} = QuantumObject(CuSparseVector{T}(A.data), A.type, A.dims) @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.dims) +CuSparseMatrixCSC(A::QuantumObject{<:SparseMatrixCSC}) = QuantumObject(CuSparseMatrixCSC(A.data), A.type, A.dims) @doc raw""" CuSparseMatrixCSC{T}(A::QuantumObject) @@ -58,8 +53,7 @@ CuSparseMatrixCSC{T}(A::QuantumObject{<:SparseMatrixCSC}) where {T} = 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.dims) +CuSparseMatrixCSR(A::QuantumObject{<:SparseMatrixCSC}) = QuantumObject(CuSparseMatrixCSR(A.data), A.type, A.dims) @doc raw""" CuSparseMatrixCSR(A::QuantumObject) @@ -81,10 +75,7 @@ Return a new [`QuantumObject`](@ref) where `A.data` is in the type of `CUDA` arr cu(A::QuantumObject; word_size::Int = 32) = ((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}}} = +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) @@ -95,9 +86,7 @@ _change_eltype(::Type{T}, ::Val{64}) where {T<:Int} = Int64 _change_eltype(::Type{T}, ::Val{32}) where {T<:Int} = Int32 _change_eltype(::Type{T}, ::Val{64}) where {T<:AbstractFloat} = Float64 _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 +_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 end \ No newline at end of file diff --git a/src/arnoldi.jl b/src/arnoldi.jl index c3d9ce64..354818f8 100644 --- a/src/arnoldi.jl +++ b/src/arnoldi.jl @@ -1,35 +1,22 @@ export ArnoldiSpace, arnoldi, arnoldi!, arnoldi_init!, arnoldi_step! export expv!, expv -struct ArnoldiSpace{ - VT<:AbstractMatrix{<:BlasFloat}, - HT<:AbstractMatrix{<:BlasFloat}, - mT<:Integer, -} +struct ArnoldiSpace{VT<:AbstractMatrix{<:BlasFloat},HT<:AbstractMatrix{<:BlasFloat},mT<:Integer} V::VT H::HT Hcopy::HT m::mT end -function Base.copy( - AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, -) where {T1<:BlasFloat} - ArnoldiSpace(copy(AS.V), copy(AS.H), copy(AS.Hcopy), AS.m) +function Base.copy(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}) where {T1<:BlasFloat} + return ArnoldiSpace(copy(AS.V), copy(AS.H), copy(AS.Hcopy), AS.m) end -function Base.deepcopy( - AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}, -) where {T1<:BlasFloat} - ArnoldiSpace(deepcopy(AS.V), deepcopy(AS.H), deepcopy(AS.Hcopy), AS.m) +function Base.deepcopy(AS::ArnoldiSpace{<:AbstractMatrix{T1},<:AbstractMatrix{T1}}) where {T1<:BlasFloat} + return ArnoldiSpace(deepcopy(AS.V), deepcopy(AS.H), deepcopy(AS.Hcopy), AS.m) end -function arnoldi_init!( - A, - b::AbstractVector{T}, - V::AbstractMatrix{T}, - H::AbstractMatrix{T}, -) where {T<:BlasFloat} +function arnoldi_init!(A, b::AbstractVector{T}, V::AbstractMatrix{T}, H::AbstractMatrix{T}) where {T<:BlasFloat} v₁ = view(V, :, 1) v₂ = view(V, :, 2) v₁ .= b @@ -39,15 +26,10 @@ function arnoldi_init!( H[1, 1] = dot(v₁, v₂) axpy!(-H[1, 1], v₁, v₂) H[2, 1] = norm(v₂) - v₂ ./= H[2, 1] + return v₂ ./= H[2, 1] end -function arnoldi_step!( - A, - V::AbstractMatrix{T}, - H::AbstractMatrix{T}, - i::TI, -) where {T<:BlasFloat,TI<:Integer} +function arnoldi_step!(A, V::AbstractMatrix{T}, H::AbstractMatrix{T}, i::TI) where {T<:BlasFloat,TI<:Integer} vᵢ = view(V, :, i) vᵢ₊₁ = view(V, :, i + 1) mul!(vᵢ₊₁, A, vᵢ) @@ -86,7 +68,7 @@ function arnoldi(A, b::AbstractVector{T}, m::Integer) where {T<:BlasFloat} V = similar(b, n, m + 1) H = zeros(T, m + 1, m) AS = ArnoldiSpace(V, H, copy(H), m) - arnoldi!(AS, A, b) + return arnoldi!(AS, A, b) end ### EXPV TOOLS ### @@ -129,7 +111,7 @@ function expv!( m::Int = min(30, cld(2 * length(b), 3)), ) where {T1<:BlasFloat,T2<:Union{BlasFloat,BlasInt}} AS = arnoldi(A, b, m) - expv!(x, AS, t, b) + return expv!(x, AS, t, b) end function expv( @@ -139,5 +121,5 @@ function expv( m::Int = min(30, cld(2 * length(b), 3)), ) where {T1<:BlasFloat,T2<:BlasFloat} x = similar(b) - expv!(x, A, t, b, m = m) + return expv!(x, A, t, b, m = m) end \ No newline at end of file diff --git a/src/correlations.jl b/src/correlations.jl index ba998347..e9172b60 100644 --- a/src/correlations.jl +++ b/src/correlations.jl @@ -10,8 +10,7 @@ struct ExponentialSeries <: SpectrumSolver calc_steadystate::Bool end -ExponentialSeries(; tol = 1e-14, calc_steadystate = false) = - ExponentialSeries(tol, calc_steadystate) +ExponentialSeries(; tol = 1e-14, calc_steadystate = false) = ExponentialSeries(tol, calc_steadystate) @doc raw""" correlation_3op_2t(H::QuantumObject, @@ -53,14 +52,9 @@ function correlation_3op_2t( kwargs2 = merge(kwargs2, (saveat = collect(t_l),)) ρt = mesolve(H, ψ0, t_l, c_ops; kwargs2...).states - corr = map( - (t, ρ) -> - mesolve(H, C * ρ * A, τ_l .+ t, c_ops, e_ops = [B]; kwargs...).expect[1, :], - t_l, - ρt, - ) + corr = map((t, ρ) -> mesolve(H, C * ρ * A, τ_l .+ t, c_ops, e_ops = [B]; kwargs...).expect[1, :], t_l, ρt) - corr + return corr end @doc raw""" @@ -103,7 +97,7 @@ function correlation_2op_2t( corr = correlation_3op_2t(H, ψ0, t_l, τ_l, C, A, B, c_ops; kwargs...) end - reduce(hcat, corr) + return reduce(hcat, corr) end @doc raw""" @@ -139,7 +133,7 @@ function correlation_2op_1t( } corr = correlation_2op_2t(H, ψ0, [0], τ_l, A, B, c_ops; reverse = reverse, kwargs...) - corr[:, 1] + return corr[:, 1] end @doc raw""" @@ -207,8 +201,7 @@ function _spectrum( solver::ExponentialSeries; kwargs..., ) where {T1,T2,T3,HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - (H.dims == A.dims == B.dims) || - throw(DimensionMismatch("The dimensions of H, A and B must be the same")) + (H.dims == A.dims == B.dims) || throw(DimensionMismatch("The dimensions of H, A and B must be the same")) L = liouvillian(H, c_ops) diff --git a/src/eigsolve.jl b/src/eigsolve.jl index 55bcb792..ec347932 100644 --- a/src/eigsolve.jl +++ b/src/eigsolve.jl @@ -63,20 +63,10 @@ end Base.iterate(res::EigsolveResult) = (res.values, Val(:vector_list)) Base.iterate(res::EigsolveResult{T1,T2,Nothing}, ::Val{:vector_list}) where {T1,T2} = ([res.vectors[:, k] for k in 1:length(res.values)], Val(:vectors)) -Base.iterate( - res::EigsolveResult{T1,T2,OperatorQuantumObject}, - ::Val{:vector_list}, -) where {T1,T2} = ( - [QuantumObject(res.vectors[:, k], Ket, res.dims) for k in 1:length(res.values)], - Val(:vectors), -) -Base.iterate( - res::EigsolveResult{T1,T2,SuperOperatorQuantumObject}, - ::Val{:vector_list}, -) where {T1,T2} = ( - [QuantumObject(res.vectors[:, k], OperatorKet, res.dims) for k in 1:length(res.values)], - Val(:vectors), -) +Base.iterate(res::EigsolveResult{T1,T2,OperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} = + ([QuantumObject(res.vectors[:, k], Ket, res.dims) for k in 1:length(res.values)], Val(:vectors)) +Base.iterate(res::EigsolveResult{T1,T2,SuperOperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} = + ([QuantumObject(res.vectors[:, k], OperatorKet, res.dims) for k in 1:length(res.values)], Val(:vectors)) Base.iterate(res::EigsolveResult, ::Val{:vectors}) = (res.vectors, Val(:done)) Base.iterate(res::EigsolveResult, ::Val{:done}) = nothing @@ -86,7 +76,7 @@ function Base.show(io::IO, res::EigsolveResult) show(io, MIME("text/plain"), res.values) print(io, "\n") println(io, "vectors:") - show(io, MIME("text/plain"), res.vectors) + return show(io, MIME("text/plain"), res.vectors) end if VERSION < v"1.10" @@ -155,7 +145,7 @@ if VERSION < v"1.10" resize!(work, lwork) end end - H, Z, w + return H, Z, w end end end @@ -228,19 +218,17 @@ if VERSION < v"1.10" resize!(work, lwork) end end - H, Z, complex.(wr, wi) + return H, Z, complex.(wr, wi) end end end - hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = - hseqr!('S', 'V', 1, size(H, 1), H, Z) - hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = - hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) + hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) + hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) end function _map_ldiv(linsolve, y, x) linsolve.b .= x - y .= LinearSolve.solve!(linsolve).u + return y .= LinearSolve.solve!(linsolve).u end function _permuteschur!( @@ -284,10 +272,7 @@ function _eigsolve( m::Int = max(20, 2 * k + 1); tol::Real = 1e-8, maxiter::Int = 200, -) where { - T<:BlasFloat, - ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}, -} +) where {T<:BlasFloat,ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject}} n = size(A, 2) V = similar(b, n, m + 1) H = zeros(T, m + 1, m) @@ -444,15 +429,7 @@ function eigsolve( vals = @. (1 + sigma * res.values) / res.values end - return EigsolveResult( - vals, - res.vectors, - res.type, - res.dims, - res.iter, - res.numops, - res.converged, - ) + return EigsolveResult(vals, res.vectors, res.type, res.dims, res.iter, res.numops, res.converged) end @doc raw""" @@ -529,21 +506,12 @@ function eigsolve_al( function arnoldi_lindblad_solve(ρ) reinit!(integrator, ρ) solve!(integrator) - integrator.u + return integrator.u end Lmap = LinearMap{eltype(MT1)}(arnoldi_lindblad_solve, size(L, 1), ismutating = false) - res = _eigsolve( - Lmap, - mat2vec(ρ0), - L.type, - L.dims, - k, - krylovdim, - maxiter = maxiter, - tol = eigstol, - ) + res = _eigsolve(Lmap, mat2vec(ρ0), L.type, L.dims, k, krylovdim, maxiter = maxiter, tol = eigstol) # finish!(prog) vals = similar(res.values) @@ -555,15 +523,7 @@ function eigsolve_al( @. vecs[:, i] = vec * exp(-1im * angle(vec[1])) end - return EigsolveResult( - vals, - vecs, - res.type, - res.dims, - res.iter, - res.numops, - res.converged, - ) + return EigsolveResult(vals, vecs, res.type, res.dims, res.iter, res.numops, res.converged) end @doc raw""" @@ -614,7 +574,7 @@ function LinearAlgebra.eigen( E::mat2vec(sparse_to_dense(MT)) = F.values U::sparse_to_dense(MT) = F.vectors - EigsolveResult(E, U, A.type, A.dims, 0, 0, true) + return EigsolveResult(E, U, A.type, A.dims, 0, 0, true) end @doc raw""" diff --git a/src/general_functions.jl b/src/general_functions.jl index 029e7e4d..3d15f484 100644 --- a/src/general_functions.jl +++ b/src/general_functions.jl @@ -21,7 +21,7 @@ Equivalent to [numpy meshgrid](https://numpy.org/doc/stable/reference/generated/ function meshgrid(x::AbstractVector{T}, y::AbstractVector{T}) where {T} X = reshape(repeat(x, inner = length(y)), length(y), length(x)) Y = repeat(y, outer = (1, length(x))) - X, Y + return X, Y end """ @@ -29,8 +29,7 @@ end Converts a sparse QuantumObject to a dense QuantumObject. """ -sparse_to_dense(A::QuantumObject{<:AbstractVecOrMat}) = - QuantumObject(sparse_to_dense(A.data), A.type, A.dims) +sparse_to_dense(A::QuantumObject{<:AbstractVecOrMat}) = QuantumObject(sparse_to_dense(A.data), A.type, A.dims) sparse_to_dense(A::MT) where {MT<:AbstractSparseMatrix} = Array(A) for op in (:Transpose, :Adjoint) @eval sparse_to_dense(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = Array(A) @@ -75,8 +74,7 @@ Removes those elements of a QuantumObject `A` whose absolute value is less than tidyup(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = QuantumObject(tidyup(A.data, tol), A.type, A.dims) tidyup(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = @. T(abs(A) > tol) * A -tidyup(A::AbstractSparseMatrix{T}, tol::T2 = 1e-14) where {T,T2<:Real} = - droptol!(copy(A), tol) +tidyup(A::AbstractSparseMatrix{T}, tol::T2 = 1e-14) where {T,T2<:Real} = droptol!(copy(A), tol) """ tidyup!(A::QuantumObject, tol::Real=1e-14) @@ -84,10 +82,8 @@ tidyup(A::AbstractSparseMatrix{T}, tol::T2 = 1e-14) where {T,T2<:Real} = Removes those elements of a QuantumObject `A` whose absolute value is less than `tol`. In-place version of [`tidyup`](#tidyup). """ -tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = - (tidyup!(A.data, tol); A) -tidyup!(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = - @. A = T(abs(A) > tol) * A +tidyup!(A::QuantumObject{<:AbstractArray{T}}, tol::T2 = 1e-14) where {T,T2<:Real} = (tidyup!(A.data, tol); A) +tidyup!(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = @. A = T(abs(A) > tol) * A tidyup!(A::AbstractSparseMatrix{T}, tol::T2 = 1e-14) where {T,T2<:Real} = droptol!(A, tol) """ @@ -108,8 +104,7 @@ function mat2vec(A::MT) where {MT<:AbstractSparseMatrix} return sparsevec(i .+ (j .- 1) .* size(A, 1), v, prod(size(A))) end for op in (:Transpose, :Adjoint) - @eval mat2vec(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = - mat2vec(sparse(A)) + @eval mat2vec(A::$op{T,<:AbstractSparseMatrix}) where {T<:BlasFloat} = mat2vec(sparse(A)) @eval mat2vec(A::$op{T,<:AbstractMatrix}) where {T<:BlasFloat} = mat2vec(Matrix(A)) end @@ -120,7 +115,7 @@ Converts a vector to a matrix. """ function vec2mat(A::AbstractVector) newsize = isqrt(length(A)) - reshape(A, newsize, newsize) + return reshape(A, newsize, newsize) end @doc raw""" @@ -180,25 +175,17 @@ Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true 0.0+0.0im 0.5+0.0im ``` """ -function ptrace( - QO::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, - sel::Vector{T2}, -) where {T1,T2<:Integer} +function ptrace(QO::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, sel::Vector{T2}) where {T1,T2<:Integer} length(QO.dims) == 1 && return QO ρtr, dkeep = _ptrace_ket(QO.data, QO.dims, sel) return QuantumObject(ρtr, dims = dkeep) end -ptrace( - QO::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, - sel::Vector{T2}, -) where {T1,T2<:Integer} = ptrace(QO', sel) +ptrace(QO::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, sel::Vector{T2}) where {T1,T2<:Integer} = + ptrace(QO', sel) -function ptrace( - QO::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - sel::Vector{T2}, -) where {T1,T2<:Integer} +function ptrace(QO::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, sel::Vector{T2}) where {T1,T2<:Integer} length(QO.dims) == 1 && return QO ρtr, dkeep = _ptrace_oper(QO.data, QO.dims, sel) @@ -341,7 +328,7 @@ function get_coherence( α = expect(a, ψ) D = exp(α * a' - conj(α) * a) - α, D' * ψ + return α, D' * ψ end @doc raw""" @@ -374,11 +361,7 @@ tracedist( ObjType2<:Union{KetQuantumObject,OperatorQuantumObject}, } = norm(ket2dm(ρ) - ket2dm(σ), 1) / 2 -function _ptrace_ket( - QO::AbstractArray{T1}, - dims::Vector{<:Integer}, - sel::Vector{T2}, -) where {T1,T2<:Integer} +function _ptrace_ket(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector{T2}) where {T1,T2<:Integer} rd = dims nd = length(rd) @@ -396,11 +379,7 @@ function _ptrace_ket( return vmat * vmat', dkeep end -function _ptrace_oper( - QO::AbstractArray{T1}, - dims::Vector{<:Integer}, - sel::Vector{T2}, -) where {T1,T2<:Integer} +function _ptrace_oper(QO::AbstractArray{T1}, dims::Vector{<:Integer}, sel::Vector{T2}) where {T1,T2<:Integer} rd = dims nd = length(rd) @@ -448,12 +427,7 @@ end function mat2vec( ::Type{M}, -) where { - M<:Union{ - Adjoint{<:BlasFloat,<:SparseMatrixCSC}, - Transpose{<:BlasFloat,<:SparseMatrixCSC}, - }, -} +) where {M<:Union{Adjoint{<:BlasFloat,<:SparseMatrixCSC},Transpose{<:BlasFloat,<:SparseMatrixCSC}}} T = M.parameters[2] par = T.parameters npar = length(par) diff --git a/src/negativity.jl b/src/negativity.jl index 415982b8..69d75a96 100644 --- a/src/negativity.jl +++ b/src/negativity.jl @@ -68,10 +68,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{T,OperatorQuantumObject}, - mask::Vector{Bool}, -) where {T} +function partial_transpose(ρ::QuantumObject{T,OperatorQuantumObject}, mask::Vector{Bool}) where {T} if length(mask) != length(ρ.dims) error("The length of \`mask\` should be equal to the length of \`ρ.dims\`.") end @@ -79,10 +76,7 @@ function partial_transpose( end # for dense matrices -function _partial_transpose( - ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject}, - mask::Vector{Bool}, -) +function _partial_transpose(ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject}, mask::Vector{Bool}) mask2 = [1 + Int(i) for i in mask] # mask2 has elements with values equal to 1 or 2 # 1 - the subsystem don't need to be transposed @@ -102,10 +96,7 @@ function _partial_transpose( end # for sparse matrices -function _partial_transpose( - ρ::QuantumObject{<:AbstractSparseArray,OperatorQuantumObject}, - mask::Vector{Bool}, -) +function _partial_transpose(ρ::QuantumObject{<:AbstractSparseArray,OperatorQuantumObject}, mask::Vector{Bool}) M, N = size(ρ) dimsTuple = Tuple(ρ.dims) colptr = ρ.data.colptr diff --git a/src/permutation.jl b/src/permutation.jl index ee9672eb..86d62b28 100644 --- a/src/permutation.jl +++ b/src/permutation.jl @@ -8,14 +8,14 @@ function bdf(A::SparseMatrixCSC{T,M}) where {T,M} P = sparse(1:n, reduce(vcat, idxs), ones(n), n, n) block_sizes = map(length, idxs) - P, P * A * P', block_sizes + return P, P * A * P', block_sizes end function bdf( A::QuantumObject{SparseMatrixCSC{T,M},OpType}, ) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} P, A_bd, block_sizes = bdf(A.data) - P, QuantumObject(A_bd, A.type, A.dims), block_sizes + return P, QuantumObject(A_bd, A.type, A.dims), block_sizes end function get_bdf_blocks(A::SparseMatrixCSC{T,M}, block_sizes::Vector{Int}) where {T,M} @@ -27,12 +27,12 @@ function get_bdf_blocks(A::SparseMatrixCSC{T,M}, block_sizes::Vector{Int}) where push!(block_indices, idx) push!(block_list, A[idx:idx-1+block_sizes[i], idx:idx-1+block_sizes[i]]) end - block_list, block_indices + return block_list, block_indices end function get_bdf_blocks( A::QuantumObject{SparseMatrixCSC{T,M},OpType}, block_sizes::Vector{Int}, ) where {T,M,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - get_bdf_blocks(A.data, block_sizes) + return get_bdf_blocks(A.data, block_sizes) end \ No newline at end of file diff --git a/src/progress_bar.jl b/src/progress_bar.jl index 86428810..616dc8bb 100644 --- a/src/progress_bar.jl +++ b/src/progress_bar.jl @@ -43,24 +43,14 @@ function next!(p::ProgressBar, io::IO = stdout) # Calculate the estimated time of arrival eta = floor(Int, elapsed_time / counter * (max_counts - counter)) # convert eta into a string in hours, minutes and seconds - eta_str = string( - eta ÷ 3600, - "h ", - lpad((eta % 3600) ÷ 60, 2, "0"), - "m ", - lpad(eta % 60, 2, "0"), - "s", - ) + eta_str = string(eta ÷ 3600, "h ", lpad((eta % 3600) ÷ 60, 2, "0"), "m ", lpad(eta % 60, 2, "0"), "s") # Construct the progress bar string bar = "[" * repeat("=", progress) * repeat(" ", bar_width - progress) * "]" - print( - io, - "\rProgress: $bar $percentage_100% --- Elapsed Time: $elapsed_time_str (ETA: $eta_str)", - ) + print(io, "\rProgress: $bar $percentage_100% --- Elapsed Time: $elapsed_time_str (ETA: $eta_str)") counter == p.max_counts && print(io, "\n") - flush(io) + return flush(io) end \ No newline at end of file diff --git a/src/quantum_object.jl b/src/quantum_object.jl index cf88698a..c5496f5b 100644 --- a/src/quantum_object.jl +++ b/src/quantum_object.jl @@ -146,13 +146,7 @@ function QuantumObject( Size = (length(A), 1) else Size = size(A) - N > 2 ? - throw( - DomainError( - Size, - "The dimension of the array is not compatible with Quantum Object", - ), - ) : nothing + N > 2 ? throw(DomainError(Size, "The dimension of the array is not compatible with Quantum Object")) : nothing end # decide QuantumObjectType from the size of A @@ -164,12 +158,7 @@ function QuantumObject( elseif Size[1] == 1 type = Bra else - throw( - DomainError( - Size, - "The dimension of the array is not compatible with Quantum Object", - ), - ) + throw(DomainError(Size, "The dimension of the array is not compatible with Quantum Object")) end end @@ -191,96 +180,42 @@ function QuantumObject( end function _check_QuantumObject(type::KetQuantumObject, prod_dims::Int, m::Int, n::Int) - (n != 1) ? - throw( - DomainError((m, n), "The dimension of the array is not compatible with Ket type"), - ) : nothing - prod_dims != m ? - throw( - DimensionMismatch("The dims parameter does not fit the dimension of the Array."), - ) : nothing + (n != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Ket type")) : nothing + return prod_dims != m ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : + nothing end function _check_QuantumObject(type::BraQuantumObject, prod_dims::Int, m::Int, n::Int) - (m != 1) ? - throw( - DomainError((m, n), "The dimension of the array is not compatible with Bra type"), - ) : nothing - prod_dims != n ? - throw( - DimensionMismatch("The dims parameter does not fit the dimension of the Array."), - ) : nothing + (m != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Bra type")) : nothing + return prod_dims != n ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : + nothing end function _check_QuantumObject(type::OperatorQuantumObject, prod_dims::Int, m::Int, n::Int) - (m != n) ? - throw( - DomainError( - (m, n), - "The dimension of the array is not compatible with Operator type", - ), - ) : nothing - prod_dims != m ? - throw( - DimensionMismatch("The dims parameter does not fit the dimension of the Array."), - ) : nothing + (m != n) ? throw(DomainError((m, n), "The dimension of the array is not compatible with Operator type")) : nothing + return prod_dims != m ? throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : + nothing end -function _check_QuantumObject( - type::SuperOperatorQuantumObject, - prod_dims::Int, - m::Int, - n::Int, -) - (m != n) ? - throw( - DomainError( - (m, n), - "The dimension of the array is not compatible with SuperOperator type", - ), - ) : nothing - prod_dims != sqrt(m) ? - throw( - DimensionMismatch("The dims parameter does not fit the dimension of the Array."), - ) : nothing +function _check_QuantumObject(type::SuperOperatorQuantumObject, prod_dims::Int, m::Int, n::Int) + (m != n) ? throw(DomainError((m, n), "The dimension of the array is not compatible with SuperOperator type")) : + nothing + return prod_dims != sqrt(m) ? + throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing end -function _check_QuantumObject( - type::OperatorKetQuantumObject, - prod_dims::Int, - m::Int, - n::Int, -) - (n != 1) ? - throw( - DomainError( - (m, n), - "The dimension of the array is not compatible with OperatorKet type", - ), - ) : nothing - prod_dims != sqrt(m) ? - throw( - DimensionMismatch("The dims parameter does not fit the dimension of the Array."), - ) : nothing +function _check_QuantumObject(type::OperatorKetQuantumObject, prod_dims::Int, m::Int, n::Int) + (n != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with OperatorKet type")) : + nothing + return prod_dims != sqrt(m) ? + throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing end -function _check_QuantumObject( - type::OperatorBraQuantumObject, - prod_dims::Int, - m::Int, - n::Int, -) - (m != 1) ? - throw( - DomainError( - (m, n), - "The dimension of the array is not compatible with OperatorBra type", - ), - ) : nothing - prod_dims != sqrt(n) ? - throw( - DimensionMismatch("The dims parameter does not fit the dimension of the Array."), - ) : nothing +function _check_QuantumObject(type::OperatorBraQuantumObject, prod_dims::Int, m::Int, n::Int) + (m != 1) ? throw(DomainError((m, n), "The dimension of the array is not compatible with OperatorBra type")) : + nothing + return prod_dims != sqrt(n) ? + throw(DimensionMismatch("The dims parameter does not fit the dimension of the Array.")) : nothing end function QuantumObject( @@ -314,16 +249,14 @@ ket2dm(ρ::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = Checks if the [`QuantumObject`](@ref) `A` is a [`BraQuantumObject`](@ref) state. """ -isbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - OpType <: BraQuantumObject +isbra(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: BraQuantumObject """ isket(A::QuantumObject) Checks if the [`QuantumObject`](@ref) `A` is a [`KetQuantumObject`](@ref) state. """ -isket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - OpType <: KetQuantumObject +isket(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = OpType <: KetQuantumObject """ isoper(A::QuantumObject) @@ -362,22 +295,14 @@ issuper(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObj Returns the size of the matrix or vector corresponding to the [`QuantumObject`](@ref) `A`. """ -Base.size(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = - size(A.data) -Base.size( - A::QuantumObject{<:AbstractArray{T},OpType}, - inds..., -) where {T,OpType<:QuantumObjectType} = size(A.data, inds...) +Base.size(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = size(A.data) +Base.size(A::QuantumObject{<:AbstractArray{T},OpType}, inds...) where {T,OpType<:QuantumObjectType} = + size(A.data, inds...) -Base.getindex( - A::QuantumObject{<:AbstractArray{T},OpType}, - inds..., -) where {T,OpType<:QuantumObjectType} = getindex(A.data, inds...) -Base.setindex!( - A::QuantumObject{<:AbstractArray{T},OpType}, - val, - inds..., -) where {T,OpType<:QuantumObjectType} = setindex!(A.data, val, inds...) +Base.getindex(A::QuantumObject{<:AbstractArray{T},OpType}, inds...) where {T,OpType<:QuantumObjectType} = + getindex(A.data, inds...) +Base.setindex!(A::QuantumObject{<:AbstractArray{T},OpType}, val, inds...) where {T,OpType<:QuantumObjectType} = + setindex!(A.data, val, inds...) """ eltype(A::QuantumObject) @@ -390,11 +315,7 @@ Base.eltype(A::QuantumObject) = eltype(A.data) Base.broadcastable(x::QuantumObject) = x.data for op in (:(+), :(-), :(*), :(/), :(^)) @eval begin - function Base.Broadcast.broadcasted( - ::typeof($op), - x::QuantumObject, - y::QuantumObject, - ) + function Base.Broadcast.broadcasted(::typeof($op), x::QuantumObject, y::QuantumObject) return QuantumObject(broadcast($op, x.data, y.data), x.type, x.dims) end @@ -406,19 +327,11 @@ for op in (:(+), :(-), :(*), :(/), :(^)) return QuantumObject(broadcast($op, x, y.data), y.type, y.dims) end - function Base.Broadcast.broadcasted( - ::typeof($op), - x::QuantumObject, - y::AbstractArray, - ) + function Base.Broadcast.broadcasted(::typeof($op), x::QuantumObject, y::AbstractArray) return QuantumObject(broadcast($op, x.data, y), x.type, x.dims) end - function Base.Broadcast.broadcasted( - ::typeof($op), - x::AbstractArray, - y::QuantumObject, - ) + function Base.Broadcast.broadcasted(::typeof($op), x::AbstractArray, y::QuantumObject) return QuantumObject(broadcast($op, x, y.data), y.type, y.dims) end end @@ -429,48 +342,33 @@ end Returns the length of the matrix or vector corresponding to the [`QuantumObject`](@ref) `A`. """ -Base.length( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = length(A.data) - -SparseArrays.sparse( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = QuantumObject(sparse(A.data), OpType(), A.dims) -SparseArrays.nnz( - A::QuantumObject{<:AbstractSparseArray,OpType}, -) where {OpType<:QuantumObjectType} = nnz(A.data) -SparseArrays.nonzeros( - A::QuantumObject{<:AbstractSparseArray,OpType}, -) where {OpType<:QuantumObjectType} = nonzeros(A.data) -SparseArrays.rowvals( - A::QuantumObject{<:AbstractSparseArray,OpType}, -) where {OpType<:QuantumObjectType} = rowvals(A.data) -SparseArrays.droptol!( - A::QuantumObject{<:AbstractSparseArray,OpType}, - tol::Real, -) where {OpType<:QuantumObjectType} = (droptol!(A.data, tol); return A) -SparseArrays.dropzeros( - A::QuantumObject{<:AbstractSparseArray,OpType}, -) where {OpType<:QuantumObjectType} = QuantumObject(dropzeros(A.data), A.type, A.dims) -SparseArrays.dropzeros!( - A::QuantumObject{<:AbstractSparseArray,OpType}, -) where {OpType<:QuantumObjectType} = (dropzeros!(A.data); return A) +Base.length(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = length(A.data) + +SparseArrays.sparse(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + QuantumObject(sparse(A.data), OpType(), A.dims) +SparseArrays.nnz(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = nnz(A.data) +SparseArrays.nonzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = + nonzeros(A.data) +SparseArrays.rowvals(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = rowvals(A.data) +SparseArrays.droptol!(A::QuantumObject{<:AbstractSparseArray,OpType}, tol::Real) where {OpType<:QuantumObjectType} = + (droptol!(A.data, tol); return A) +SparseArrays.dropzeros(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = + QuantumObject(dropzeros(A.data), A.type, A.dims) +SparseArrays.dropzeros!(A::QuantumObject{<:AbstractSparseArray,OpType}) where {OpType<:QuantumObjectType} = + (dropzeros!(A.data); return A) Base.isequal( A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = - isequal(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) +) where {T,OpType<:QuantumObjectType} = isequal(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) Base.isapprox( A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = - isapprox(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) +) where {T,OpType<:QuantumObjectType} = isapprox(A.data, B.data) && isequal(A.type, B.type) && isequal(A.dims, B.dims) Base.:(==)( A::QuantumObject{<:AbstractArray{T},OpType}, B::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = - (A.data == B.data) && (A.type == B.type) && (A.dims == B.dims) +) where {T,OpType<:QuantumObjectType} = (A.data == B.data) && (A.type == B.type) && (A.dims == B.dims) LinearAlgebra.Hermitian( A::QuantumObject{<:AbstractArray{T},OpType}, @@ -492,22 +390,11 @@ function Base.show( }, } op_data = QO.data - println( - io, - "Quantum Object: type=", - QO.type, - " dims=", - QO.dims, - " size=", - size(op_data), - ) - show(io, MIME("text/plain"), op_data) + println(io, "Quantum Object: type=", QO.type, " dims=", QO.dims, " size=", size(op_data)) + return show(io, MIME("text/plain"), op_data) end -function Base.show( - io::IO, - QO::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:OperatorQuantumObject} +function Base.show(io::IO, QO::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:OperatorQuantumObject} op_data = QO.data println( io, @@ -520,7 +407,7 @@ function Base.show( " ishermitian=", ishermitian(op_data), ) - show(io, MIME("text/plain"), op_data) + return show(io, MIME("text/plain"), op_data) end for op in (:(+), :(-), :(*)) @@ -529,26 +416,20 @@ for op in (:(+), :(-), :(*)) A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}, ) where {T1,T2,OpType<:QuantumObjectType} - A.dims != B.dims && throw( - ErrorException("The two operators are not of the same Hilbert dimension."), - ) - QuantumObject($(op)(A.data, B.data), OpType(), A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject($(op)(A.data, B.data), OpType(), A.dims) end - LinearAlgebra.$op( - A::QuantumObject{<:AbstractArray{T},OpType}, - ) where {T,OpType<:QuantumObjectType} = + LinearAlgebra.$op(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject($(op)(A.data), OpType(), A.dims) LinearAlgebra.$op( n::T1, A::QuantumObject{<:AbstractArray{T2},OpType}, - ) where {T1<:Number,T2,OpType<:QuantumObjectType} = - QuantumObject($(op)(n * I, A.data), OpType(), A.dims) + ) where {T1<:Number,T2,OpType<:QuantumObjectType} = QuantumObject($(op)(n * I, A.data), OpType(), A.dims) LinearAlgebra.$op( A::QuantumObject{<:AbstractArray{T1},OpType}, n::T2, - ) where {T1,T2<:Number,OpType<:QuantumObjectType} = - QuantumObject($(op)(A.data, n * I), OpType(), A.dims) + ) where {T1,T2<:Number,OpType<:QuantumObjectType} = QuantumObject($(op)(A.data, n * I), OpType(), A.dims) end end @@ -556,84 +437,69 @@ function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, Ket, A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject(A.data * B.data, Ket, A.dims) end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, Bra, A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject(A.data * B.data, Bra, A.dims) end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},KetQuantumObject}, B::QuantumObject{<:AbstractArray{T2},BraQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, Operator, A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject(A.data * B.data, Operator, A.dims) end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},BraQuantumObject}, B::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - A.data * B.data + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return A.data * B.data end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(vec2mat(A.data * mat2vec(B.data)), Operator, A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject(vec2mat(A.data * mat2vec(B.data)), Operator, A.dims) end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - A.data * B.data + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return A.data * B.data end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T2},OperatorKetQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, OperatorKet, A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject(A.data * B.data, OperatorKet, A.dims) end function LinearAlgebra.:(*)( A::QuantumObject{<:AbstractArray{T1},OperatorBraQuantumObject}, B::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, ) where {T1,T2} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - QuantumObject(A.data * B.data, OperatorBra, A.dims) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return QuantumObject(A.data * B.data, OperatorBra, A.dims) end -LinearAlgebra.:(^)( - A::QuantumObject{<:AbstractArray{T},OpType}, - n::T1, -) where {T,T1<:Number,OpType<:QuantumObjectType} = +LinearAlgebra.:(^)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} = QuantumObject(^(A.data, n), OpType(), A.dims) -LinearAlgebra.:(/)( - A::QuantumObject{<:AbstractArray{T},OpType}, - n::T1, -) where {T,T1<:Number,OpType<:QuantumObjectType} = +LinearAlgebra.:(/)(A::QuantumObject{<:AbstractArray{T},OpType}, n::T1) where {T,T1<:Number,OpType<:QuantumObjectType} = QuantumObject(/(A.data, n), OpType(), A.dims) function LinearAlgebra.dot( A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}, ) where {T1<:Number,T2<:Number,OpType<:Union{KetQuantumObject,OperatorKetQuantumObject}} - A.dims != B.dims && - throw(ErrorException("The two operators are not of the same Hilbert dimension.")) - LinearAlgebra.dot(A.data, B.data) + A.dims != B.dims && throw(ErrorException("The two operators are not of the same Hilbert dimension.")) + return LinearAlgebra.dot(A.data, B.data) end Base.conj(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = @@ -650,12 +516,10 @@ LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},KetQuantumObject}) whe QuantumObject(adjoint(A.data), Bra, A.dims) LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},BraQuantumObject}) where {T} = QuantumObject(adjoint(A.data), Ket, A.dims) -LinearAlgebra.adjoint( - A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}, -) where {T} = QuantumObject(adjoint(A.data), OperatorBra, A.dims) -LinearAlgebra.adjoint( - A::QuantumObject{<:AbstractArray{T},OperatorBraQuantumObject}, -) where {T} = QuantumObject(adjoint(A.data), OperatorKet, A.dims) +LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorKetQuantumObject}) where {T} = + QuantumObject(adjoint(A.data), OperatorBra, A.dims) +LinearAlgebra.adjoint(A::QuantumObject{<:AbstractArray{T},OperatorBraQuantumObject}) where {T} = + QuantumObject(adjoint(A.data), OperatorKet, A.dims) LinearAlgebra.inv( A::QuantumObject{<:AbstractArray{T},OpType}, @@ -694,8 +558,7 @@ Return the singular values of a [`QuantumObject`](@ref) in descending order """ LinearAlgebra.svdvals(A::QuantumObject{<:AbstractVector}) = svdvals(A.data) LinearAlgebra.svdvals(A::QuantumObject{<:DenseMatrix}) = svdvals(A.data) -LinearAlgebra.svdvals(A::QuantumObject{<:AbstractSparseMatrix}) = - svdvals(sparse_to_dense(A.data)) +LinearAlgebra.svdvals(A::QuantumObject{<:AbstractSparseMatrix}) = svdvals(sparse_to_dense(A.data)) """ norm(A::QuantumObject, p::Real=2) @@ -729,15 +592,8 @@ julia> norm(ψ) LinearAlgebra.norm( A::QuantumObject{<:AbstractArray{T},OpType}, p::Real = 2, -) where { - T, - OpType<:Union{ - KetQuantumObject, - BraQuantumObject, - OperatorKetQuantumObject, - OperatorBraQuantumObject, - }, -} = norm(A.data, p) +) where {T,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorKetQuantumObject,OperatorBraQuantumObject}} = + norm(A.data, p) function LinearAlgebra.norm( A::QuantumObject{<:AbstractArray{T},OpType}, p::Real = 2, @@ -745,21 +601,16 @@ function LinearAlgebra.norm( p == 2.0 && return norm(A.data, 2) return norm(svdvals(A), p) end -LinearAlgebra.normalize( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = QuantumObject(normalize(A.data), OpType(), A.dims) -LinearAlgebra.normalize!( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = (normalize!(A.data); A) -LinearAlgebra.ishermitian( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = ishermitian(A.data) -LinearAlgebra.issymmetric( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = issymmetric(A.data) -LinearAlgebra.isposdef( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = isposdef(A.data) +LinearAlgebra.normalize(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + QuantumObject(normalize(A.data), OpType(), A.dims) +LinearAlgebra.normalize!(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + (normalize!(A.data); A) +LinearAlgebra.ishermitian(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + ishermitian(A.data) +LinearAlgebra.issymmetric(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + issymmetric(A.data) +LinearAlgebra.isposdef(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + isposdef(A.data) @doc raw""" kron(A::QuantumObject, B::QuantumObject) @@ -808,7 +659,7 @@ function LinearAlgebra.kron( A::QuantumObject{<:AbstractArray{T1},OpType}, B::QuantumObject{<:AbstractArray{T2},OpType}, ) where {T1,T2,OpType<:Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject}} - QuantumObject(kron(A.data, B.data), OpType(), vcat(A.dims, B.dims)) + return QuantumObject(kron(A.data, B.data), OpType(), vcat(A.dims, B.dims)) end @doc raw""" @@ -890,13 +741,11 @@ Quantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian= LinearAlgebra.triu!( A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer = 0, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = - (triu!(A.data, k); A) +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (triu!(A.data, k); A) LinearAlgebra.tril!( A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer = 0, -) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = - (tril!(A.data, k); A) +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (tril!(A.data, k); A) LinearAlgebra.triu( A::QuantumObject{<:AbstractArray{T},OpType}, k::Integer = 0, @@ -911,26 +760,17 @@ LinearAlgebra.tril( LinearAlgebra.lmul!(a::Number, B::QuantumObject{<:AbstractArray}) = (lmul!(a, B.data); B) LinearAlgebra.rmul!(B::QuantumObject{<:AbstractArray}, 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{Ty}, A::QuantumObject{<:AbstractMatrix{Ta}}, x, α, β) where {Ty,Ta} = + mul!(y, A.data, x, α, β) -LinearAlgebra.sqrt( - A::QuantumObject{<:AbstractArray{T},OpType}, -) where {T,OpType<:QuantumObjectType} = QuantumObject(sqrt(A.data), OpType(), A.dims) +LinearAlgebra.sqrt(A::QuantumObject{<:AbstractArray{T},OpType}) where {T,OpType<:QuantumObjectType} = + QuantumObject(sqrt(A.data), OpType(), A.dims) -LinearAlgebra.exp( - A::QuantumObject{<:AbstractMatrix{T},OpType}, -) where {T,OpType<:QuantumObjectType} = +LinearAlgebra.exp(A::QuantumObject{<:AbstractMatrix{T},OpType}) where {T,OpType<:QuantumObjectType} = QuantumObject(dense_to_sparse(exp(A.data)), OpType(), A.dims) -LinearAlgebra.exp( - A::QuantumObject{<:AbstractSparseMatrix{T},OpType}, -) where {T,OpType<:QuantumObjectType} = QuantumObject(_spexp(A.data), OpType(), A.dims) +LinearAlgebra.exp(A::QuantumObject{<:AbstractSparseMatrix{T},OpType}) where {T,OpType<:QuantumObjectType} = + QuantumObject(_spexp(A.data), OpType(), A.dims) function _spexp(A::SparseMatrixCSC{T,M}; threshold = 1e-14, nonzero_tol = 1e-20) where {T,M} m = checksquare(A) # Throws exception if not square @@ -960,20 +800,15 @@ function _spexp(A::SparseMatrixCSC{T,M}; threshold = 1e-14, nonzero_tol = 1e-20) tidyup!(P, nonzero_tol) end end - P + return P end # data type conversions -Base.Vector(A::QuantumObject{<:AbstractVector}) = - QuantumObject(Vector(A.data), A.type, A.dims) -Base.Vector{T}(A::QuantumObject{<:AbstractVector}) where {T<:Number} = - QuantumObject(Vector{T}(A.data), A.type, A.dims) -Base.Matrix(A::QuantumObject{<:AbstractMatrix}) = - QuantumObject(Matrix(A.data), A.type, A.dims) -Base.Matrix{T}(A::QuantumObject{<:AbstractMatrix}) where {T<:Number} = - QuantumObject(Matrix{T}(A.data), A.type, A.dims) -SparseArrays.SparseVector(A::QuantumObject{<:AbstractVector}) = - QuantumObject(SparseVector(A.data), A.type, A.dims) +Base.Vector(A::QuantumObject{<:AbstractVector}) = QuantumObject(Vector(A.data), A.type, A.dims) +Base.Vector{T}(A::QuantumObject{<:AbstractVector}) where {T<:Number} = QuantumObject(Vector{T}(A.data), A.type, A.dims) +Base.Matrix(A::QuantumObject{<:AbstractMatrix}) = QuantumObject(Matrix(A.data), A.type, A.dims) +Base.Matrix{T}(A::QuantumObject{<:AbstractMatrix}) where {T<:Number} = QuantumObject(Matrix{T}(A.data), A.type, A.dims) +SparseArrays.SparseVector(A::QuantumObject{<:AbstractVector}) = QuantumObject(SparseVector(A.data), A.type, A.dims) SparseArrays.SparseVector{T}(A::QuantumObject{<:SparseVector}) where {T<:Number} = QuantumObject(SparseVector{T}(A.data), A.type, A.dims) SparseArrays.SparseMatrixCSC(A::QuantumObject{<:AbstractMatrix}) = diff --git a/src/quantum_operators.jl b/src/quantum_operators.jl index 08a3b7c7..cf539262 100644 --- a/src/quantum_operators.jl +++ b/src/quantum_operators.jl @@ -16,10 +16,8 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{O}\right) \boldsymbol{\cdot} = The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -spre( - O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, - Id_cache = I(size(O, 1)), -) where {T} = QuantumObject(kron(Id_cache, O.data), SuperOperator, O.dims) +spre(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache = I(size(O, 1))) where {T} = + QuantumObject(kron(Id_cache, O.data), SuperOperator, O.dims) @doc raw""" spost(O::QuantumObject) @@ -33,10 +31,7 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{O}\right) \boldsymbol{\cdot} = The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -spost( - O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, - Id_cache = I(size(O, 1)), -) where {T} = +spost(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}, Id_cache = I(size(O, 1))) where {T} = QuantumObject(kron(sparse(transpose(sparse(O.data))), Id_cache), SuperOperator, O.dims) # TODO: fix the sparse conversion @doc raw""" @@ -51,8 +46,7 @@ a matrix, obtained from ``\mathcal{O} \left(\hat{A}, \hat{B}\right) \boldsymbol{ sprepost( A::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, B::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject}, -) where {T1,T2} = - QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperator, A.dims) # TODO: fix the sparse conversion +) where {T1,T2} = QuantumObject(kron(sparse(transpose(sparse(B.data))), A.data), SuperOperator, A.dims) # TODO: fix the sparse conversion @doc raw""" lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1)) @@ -76,10 +70,7 @@ function lindblad_dissipator( end # It is already a SuperOperator -lindblad_dissipator( - O::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, - Id_cache, -) where {T} = O +lindblad_dissipator(O::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, Id_cache) where {T} = O @doc raw""" destroy(N::Int) @@ -103,8 +94,7 @@ julia> fock(20, 3)' * a * fock(20, 4) 2.0 + 0.0im ``` """ -destroy(N::Int) = - QuantumObject(spdiagm(1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) +destroy(N::Int) = QuantumObject(spdiagm(1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) @doc raw""" create(N::Int) @@ -128,8 +118,7 @@ julia> fock(20, 4)' * a_d * fock(20, 3) 2.0 + 0.0im ``` """ -create(N::Int) = - QuantumObject(spdiagm(-1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) +create(N::Int) = QuantumObject(spdiagm(-1 => Array{ComplexF64}(sqrt.(1:N-1))), Operator, [N]) @doc raw""" sigmap() @@ -187,8 +176,7 @@ qeye( N::Int; type::ObjType = Operator, dims::Vector{Int} = [N], -) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = - eye(N, type = type, dims = dims) +) where {ObjType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = eye(N, type = type, dims = dims) @doc raw""" fock(N::Int, pos::Int; dims::Vector{Int}=[N], sparse::Bool=false) @@ -234,7 +222,7 @@ function rand_dm(N::Integer; kwargs...) ρ = rand(ComplexF64, N, N) ρ *= ρ' ρ /= tr(ρ) - QuantumObject(ρ; kwargs...) + return QuantumObject(ρ; kwargs...) end @doc raw""" @@ -242,8 +230,7 @@ end Generates the projection operator ``\hat{O} = \dyad{i}{j}`` with Hilbert space dimension `N`. """ -projection(N::Int, i::Int, j::Int) = - QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N)) +projection(N::Int, i::Int, j::Int) = QuantumObject(sparse([i + 1], [j + 1], [1.0 + 0.0im], N, N)) @doc raw""" sinm(O::QuantumObject) @@ -252,8 +239,7 @@ Generates the sine of the operator `O`, defined as ``\sin \left( \hat{O} \right) = \frac{e^{i \hat{O}} - e^{-i \hat{O}}}{2 i}`` """ -sinm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = - -0.5im * (exp(1im * O) - exp(-1im * O)) +sinm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = -0.5im * (exp(1im * O) - exp(-1im * O)) @doc raw""" cosm(O::QuantumObject) @@ -262,5 +248,4 @@ Generates the cosine of the operator `O`, defined as ``\cos \left( \hat{O} \right) = \frac{e^{i \hat{O}} + e^{-i \hat{O}}}{2}`` """ -cosm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = - 0.5 * (exp(1im * O) + exp(-1im * O)) \ No newline at end of file +cosm(O::QuantumObject{<:AbstractArray{T},OperatorQuantumObject}) where {T} = 0.5 * (exp(1im * O) + exp(-1im * O)) \ No newline at end of file diff --git a/src/spin_lattice.jl b/src/spin_lattice.jl index f73b59ee..cf3ba11d 100644 --- a/src/spin_lattice.jl +++ b/src/spin_lattice.jl @@ -16,30 +16,15 @@ Base.@kwdef struct Lattice{TN<:Integer,TLI<:LinearIndices,TCI<:CartesianIndices} end #Definition of many-body operators -function mb( - s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - i::Integer, - N::Integer, -) where {T1} +function mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, i::Integer, N::Integer) where {T1} T = s.dims[1] - QuantumObject(kron(eye(T^(i - 1)), s, eye(T^(N - i))); dims = fill(2, N)) + return QuantumObject(kron(eye(T^(i - 1)), s, eye(T^(N - i))); dims = fill(2, N)) end -mb( - s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - i::Integer, - latt::Lattice, -) where {T1} = mb(s, i, latt.N) -mb( - s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - row::Integer, - col::Integer, - latt::Lattice, -) where {T1} = mb(s, latt.idx[row, col], latt.N) -mb( - s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, - x::CartesianIndex, - latt::Lattice, -) where {T1} = mb(s, latt.idx[x], latt.N) +mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, i::Integer, latt::Lattice) where {T1} = mb(s, i, latt.N) +mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, row::Integer, col::Integer, latt::Lattice) where {T1} = + mb(s, latt.idx[row, col], latt.N) +mb(s::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, x::CartesianIndex, latt::Lattice) where {T1} = + mb(s, latt.idx[x], latt.N) #Definition of nearest-neighbour sites on lattice pbc(i::Integer, N::Integer) = 1 + (i - 1 + N) % N @@ -50,26 +35,15 @@ obc(i::Vector{Int}, N::Integer) = filter(x -> obc(x, N), i) function nn(i::CartesianIndex, latt::Lattice, bc::Function; order::Integer = 1) row = bc([i[1] + order, i[1] - order], latt.Nx) col = bc([i[2] + order, i[2] - order], latt.Ny) - vcat([CartesianIndex(r, i[2]) for r in row], [CartesianIndex(i[1], c) for c in col]) + return vcat([CartesianIndex(r, i[2]) for r in row], [CartesianIndex(i[1], c) for c in col]) end -function TFIM( - Jx::Real, - Jy::Real, - Jz::Real, - hx::Real, - γ::Real, - latt::Lattice; - bc::Function = pbc, - order::Integer = 1, -) +function TFIM(Jx::Real, Jy::Real, Jz::Real, hx::Real, γ::Real, latt::Lattice; bc::Function = pbc, order::Integer = 1) S = [mb(sm, i, latt) for i in 1:latt.N] c_ops = sqrt(γ) .* S - op_sum( - S::Vector{QuantumObject{SparseMatrixCSC{ComplexF64,Int64},OperatorQuantumObject}}, - i::CartesianIndex, - ) = S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nn(i, latt, bc; order = order)]]) + op_sum(S::Vector{QuantumObject{SparseMatrixCSC{ComplexF64,Int64},OperatorQuantumObject}}, i::CartesianIndex) = + S[latt.lin_idx[i]] * sum(S[latt.lin_idx[nn(i, latt, bc; order = order)]]) H = 0 if (Jx != 0 || hx != 0) @@ -85,5 +59,5 @@ function TFIM( S .= [mb(sz, i, latt) for i in 1:latt.N] H += Jz / 2 * mapreduce(i -> op_sum(S, i), +, latt.car_idx) end - H, c_ops + return H, c_ops end; diff --git a/src/time_evolution/lr_mesolve.jl b/src/time_evolution/lr_mesolve.jl index 1615b7f0..a8b662cb 100644 --- a/src/time_evolution/lr_mesolve.jl +++ b/src/time_evolution/lr_mesolve.jl @@ -27,26 +27,36 @@ struct LRMesolveOptions{AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} end function LRMesolveOptions(; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - progress::Bool=true, - err_max::Real=0.0, - p0::Real=0.0, - atol_inv::Real=1e-4, - M_max::Integer=typemax(Int), - compute_Si::Bool=true, - _is_dynamical::Bool=err_max > 0, - adj_condition::String="variational", - Δt::Real=0.0 + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + progress::Bool = true, + err_max::Real = 0.0, + p0::Real = 0.0, + atol_inv::Real = 1e-4, + M_max::Integer = typemax(Int), + compute_Si::Bool = true, + _is_dynamical::Bool = err_max > 0, + adj_condition::String = "variational", + Δt::Real = 0.0, ) - return LRMesolveOptions{typeof(alg)}(alg, progress, err_max, p0, atol_inv, M_max, compute_Si, _is_dynamical, adj_condition, Δt) + return LRMesolveOptions{typeof(alg)}( + alg, + progress, + err_max, + p0, + atol_inv, + M_max, + compute_Si, + _is_dynamical, + adj_condition, + Δt, + ) end - #=======================================================# # ADDITIONAL FUNCTIONS #=======================================================# -select(x::Real, xarr::AbstractArray, retval=false) = retval ? xarr[argmin(abs.(x .- xarr))] : argmin(abs.(x .- xarr)) +select(x::Real, xarr::AbstractArray, retval = false) = retval ? xarr[argmin(abs.(x .- xarr))] : argmin(abs.(x .- xarr)) """ _pinv!(A, T1, T2; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T @@ -66,7 +76,13 @@ select(x::Real, xarr::AbstractArray, retval=false) = retval ? xarr[argmin(abs.(x rtol : Real Relative tolerance for the calculation of the pseudo-inverse. """ -function _pinv!(A::AbstractMatrix{T}, T1::AbstractMatrix{T}, T2::AbstractMatrix{T}; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T)))) * min(size(A)...)) * iszero(atol)) where {T} +function _pinv!( + A::AbstractMatrix{T}, + T1::AbstractMatrix{T}, + T2::AbstractMatrix{T}; + atol::Real = 0.0, + rtol::Real = (eps(real(float(oneunit(T)))) * min(size(A)...)) * iszero(atol), +) where {T} if isdiag(A) idxA = diagind(A) diagA = view(A, idxA) @@ -79,10 +95,9 @@ function _pinv!(A::AbstractMatrix{T}, T1::AbstractMatrix{T}, T2::AbstractMatrix{ λ = max(rtol * maximum(SVD.S), atol) SVD.S .= pinv.(SVD.S) .* 1 ./ (1 .+ (λ ./ SVD.S) .^ 6) mul!(T2, Diagonal(SVD.S), SVD.U') - mul!(T1, SVD.Vt', T2) + return mul!(T1, SVD.Vt', T2) end - """ _calculate_expectation!(p,z,B,idx) where T Calculates the expectation values and function values of the operators and functions in p.e_ops and p.f_ops, respectively, and stores them in p.expvals and p.funvals. @@ -121,7 +136,6 @@ function _calculate_expectation!(p, z, B, idx) end end - #=======================================================# # SAVING FUNCTIONS #=======================================================# @@ -130,12 +144,10 @@ function _periodicsave_func(integrator) ip = integrator.p ip.u_save .= integrator.u ip.scalars[2] = integrator.t - u_modified!(integrator, false) + return u_modified!(integrator, false) end -function _save_control_lr_mesolve(u, t, integrator) - t in integrator.p.t_l -end +_save_control_lr_mesolve(u, t, integrator) = t in integrator.p.t_l function _save_affect_lr_mesolve!(integrator) ip = integrator.p @@ -150,10 +162,9 @@ function _save_affect_lr_mesolve!(integrator) print("\rProgress: $(round(Int, 100*idx/length(ip.t_l)))%") flush(stdout) end - u_modified!(integrator, false) + return u_modified!(integrator, false) end - #=======================================================# # CALLBACK FUNCTIONS #=======================================================# @@ -186,7 +197,7 @@ function _adjM_condition_ratio(u, t, integrator) p = abs.(eigvals(σ)) err = p[1] / p[end] - (err >= opt.err_max && M < N && M < opt.M_max) + return (err >= opt.err_max && M < N && M < opt.M_max) end """ @@ -208,7 +219,7 @@ function _adjM_condition_variational(u, t, integrator) N, M = ip.N, ip.M err = abs(ip.scalars[1] * sqrt(ip.M)) - (err >= opt.err_max && M < N && M < opt.M_max) + return (err >= opt.err_max && M < N && M < opt.M_max) end """ @@ -234,20 +245,33 @@ function _adjM_affect!(integrator) normalize!(ψ) z = hcat(z, ψ) - B = cat(B, opt.p0, dims=(1, 2)) + B = cat(B, opt.p0, dims = (1, 2)) resize!(integrator, length(z) + length(B)) integrator.u[1:length(z)] .= z[:] integrator.u[length(z)+1:end] .= B[:] end - integrator.p = merge(integrator.p, (M=ip.M + 1, L_tilde=similar(z), A0=similar(z), Bi=similar(B), L=similar(B), temp_MM=similar(B), S=similar(B), Si=similar(B),)) + integrator.p = merge( + integrator.p, + ( + M = ip.M + 1, + L_tilde = similar(z), + A0 = similar(z), + Bi = similar(B), + L = similar(B), + temp_MM = similar(B), + S = similar(B), + Si = similar(B), + ), + ) mul!(integrator.p.S, z', z) - !(opt.compute_Si) && (integrator.p.Si .= _pinv!(Hermitian(integrator.p.S), integrator.temp_MM, integrator.L, atol=opt.atol_inv)) + !(opt.compute_Si) && + (integrator.p.Si .= _pinv!(Hermitian(integrator.p.S), integrator.temp_MM, integrator.L, atol = opt.atol_inv)) if Δt > 0 - integrator.p = merge(integrator.p, (u_save=copy(integrator.u),)) + integrator.p = merge(integrator.p, (u_save = copy(integrator.u),)) t0 = ip.scalars[2] - reinit!(integrator, integrator.u; t0=t0, erase_sol=false) + reinit!(integrator, integrator.u; t0 = t0, erase_sol = false) if length(integrator.sol.t) > 1 idx = findlast(integrator.sol.t .<= t0) @@ -258,7 +282,6 @@ function _adjM_affect!(integrator) end end - #=======================================================# # DYNAMICAL EVOLUTION EQUATIONS #=======================================================# @@ -303,8 +326,8 @@ function dBdz!(du, u, p, t) mul!(A0, z, B) # Calculate inverse - opt.compute_Si && (Si .= _pinv!(Hermitian(S), temp_MM, L, atol=opt.atol_inv)) - Bi .= _pinv!(Hermitian(B), temp_MM, L, atol=opt.atol_inv) + opt.compute_Si && (Si .= _pinv!(Hermitian(S), temp_MM, L, atol = opt.atol_inv)) + Bi .= _pinv!(Hermitian(B), temp_MM, L, atol = opt.atol_inv) # Calculate the effective Hamiltonian part of L_tilde mul!(dz, H, A0) @@ -334,10 +357,9 @@ function dBdz!(du, u, p, t) mul!(dB, temp_MM, Si) temp_MM .= Si lmul!(p.scalars[1], temp_MM) - dB .-= temp_MM + return dB .-= temp_MM end - #=======================================================# # PROBLEM FORMULATION #=======================================================# @@ -367,8 +389,17 @@ end kwargs : NamedTuple Additional keyword arguments for the ODEProblem. """ -function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2,2}, B::AbstractArray{T2,2}, t_l::AbstractVector, c_ops::AbstractVector=[]; - e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} +function lr_mesolveProblem( + H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + z::AbstractArray{T2,2}, + B::AbstractArray{T2,2}, + t_l::AbstractVector, + c_ops::AbstractVector = []; + e_ops::Tuple = (), + f_ops::Tuple = (), + opt::LRMesolveOptions{AlgType} = LRMesolveOptions(), + kwargs..., +) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} # Formulation of problem H -= 0.5im * sum([Γ' * Γ for Γ in c_ops]) @@ -382,26 +413,53 @@ function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumO Ml = Array{Int64}(undef, length(t_l)) # Initialization of parameters. Scalars represents in order: Tr(S^{-1}L), t0 - p = (N=size(z, 1), M=size(z, 2), H=H, Γ=c_ops, e_ops=e_ops, f_ops=f_ops, opt=opt, t_l=t_l, - expvals=expvals, funvals=funvals, Ml=Ml, - L_tilde=similar(z), A0=similar(z), Bi=similar(B), L=similar(B), temp_MM=similar(B), S=similar(B), Si=similar(B), - u_save=vcat(vec(z), vec(B)), scalars=[0.0, t_l[1]],) + p = ( + N = size(z, 1), + M = size(z, 2), + H = H, + Γ = c_ops, + e_ops = e_ops, + f_ops = f_ops, + opt = opt, + t_l = t_l, + expvals = expvals, + funvals = funvals, + Ml = Ml, + L_tilde = similar(z), + A0 = similar(z), + Bi = similar(B), + L = similar(B), + temp_MM = similar(B), + S = similar(B), + Si = similar(B), + u_save = vcat(vec(z), vec(B)), + scalars = [0.0, t_l[1]], + ) mul!(p.S, z', z) - p.Si .= pinv(Hermitian(p.S), atol=opt.atol_inv) + p.Si .= pinv(Hermitian(p.S), atol = opt.atol_inv) # Initialization of Callbacks kwargs2 = kwargs if !isempty(e_ops) || !isempty(f_ops) _calculate_expectation!(p, z, B, 1) - cb_save = DiscreteCallback(_save_control_lr_mesolve, _save_affect_lr_mesolve!, save_positions=(false, false)) - kwargs2 = merge(kwargs2, haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_save, kwargs2[:callback])) : Dict(:callback => cb_save)) + cb_save = DiscreteCallback(_save_control_lr_mesolve, _save_affect_lr_mesolve!, save_positions = (false, false)) + kwargs2 = merge( + kwargs2, + haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_save, kwargs2[:callback])) : + Dict(:callback => cb_save), + ) end if opt.is_dynamical if opt.Δt > 0 - cb_periodicsave = PeriodicCallback(_periodicsave_func, opt.Δt, final_affect=true, save_positions=(false, false)) - kwargs2 = merge(kwargs2, haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_periodicsave, kwargs2[:callback])) : Dict(:callback => cb_periodicsave)) + cb_periodicsave = + PeriodicCallback(_periodicsave_func, opt.Δt, final_affect = true, save_positions = (false, false)) + kwargs2 = merge( + kwargs2, + haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_periodicsave, kwargs2[:callback])) : + Dict(:callback => cb_periodicsave), + ) end if opt.adj_condition == "variational" @@ -411,8 +469,12 @@ function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumO else error("adj_condition must be either 'variational' or 'ratio'") end - cb_adjM = DiscreteCallback(adj_condition_function, _adjM_affect!, save_positions=(false, false)) - kwargs2 = merge(kwargs2, haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_adjM, kwargs2[:callback])) : Dict(:callback => cb_adjM)) + cb_adjM = DiscreteCallback(adj_condition_function, _adjM_affect!, save_positions = (false, false)) + kwargs2 = merge( + kwargs2, + haskey(kwargs2, :callback) ? Dict(:callback => CallbackSet(cb_adjM, kwargs2[:callback])) : + Dict(:callback => cb_adjM), + ) end # Initialization of ODEProblem's kwargs @@ -425,25 +487,28 @@ function lr_mesolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumO return ODEProblem(dBdz!, p.u_save, tspan, p; kwargs2...) end -function lr_mesolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, z::AbstractArray{T2,2}, B::AbstractArray{T2,2}, t_l::AbstractVector, c_ops::AbstractVector=[]; - e_ops::Tuple=(), f_ops::Tuple=(), opt::LRMesolveOptions{AlgType}=LRMesolveOptions(), kwargs...) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} - - prob = lr_mesolveProblem(H, z, B, t_l, c_ops; e_ops=e_ops, f_ops=f_ops, opt=opt, kwargs...) +function lr_mesolve( + H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, + z::AbstractArray{T2,2}, + B::AbstractArray{T2,2}, + t_l::AbstractVector, + c_ops::AbstractVector = []; + e_ops::Tuple = (), + f_ops::Tuple = (), + opt::LRMesolveOptions{AlgType} = LRMesolveOptions(), + kwargs..., +) where {T1,T2,AlgType<:OrdinaryDiffEq.OrdinaryDiffEqAlgorithm} + prob = lr_mesolveProblem(H, z, B, t_l, c_ops; e_ops = e_ops, f_ops = f_ops, opt = opt, kwargs...) return lr_mesolve(prob; kwargs...) end - #=======================================================# # OUTPUT GENNERATION #=======================================================# -function get_z(u::AbstractArray{T}, N::Integer, M::Integer) where {T} - reshape(view(u, 1:M*N), N, M) -end +get_z(u::AbstractArray{T}, N::Integer, M::Integer) where {T} = reshape(view(u, 1:M*N), N, M) -function get_B(u::AbstractArray{T}, N::Integer, M::Integer) where {T} - reshape(view(u, (M*N+1):length(u)), M, M) -end +get_B(u::AbstractArray{T}, N::Integer, M::Integer) where {T} = reshape(view(u, (M*N+1):length(u)), M, M) """ lr_mesolve(prob::ODEProblem; kwargs...) @@ -457,7 +522,7 @@ end Additional keyword arguments for the ODEProblem. """ function lr_mesolve(prob::ODEProblem; kwargs...) - sol = solve(prob, prob.p.opt.alg, tstops=prob.p.t_l) + sol = solve(prob, prob.p.opt.alg, tstops = prob.p.t_l) prob.p.opt.progress && print("\n") N = prob.p.N diff --git a/src/time_evolution/mcsolve.jl b/src/time_evolution/mcsolve.jl index 4db42ceb..d06049f1 100644 --- a/src/time_evolution/mcsolve.jl +++ b/src/time_evolution/mcsolve.jl @@ -17,7 +17,7 @@ function _save_func_mcsolve(integrator) @. expvals[:, progr.counter[]+1] = _expect(e_ops) end next!(progr) - u_modified!(integrator, false) + return u_modified!(integrator, false) end function LindbladJumpAffect!(integrator) @@ -62,33 +62,43 @@ function _mcsolve_prob_func(prob, i, repeat) seeds = internal_params.seeds !isnothing(seeds) && Random.seed!(seeds[i]) - prm = merge(internal_params, (expvals=similar(internal_params.expvals), - cache_mc=similar(internal_params.cache_mc), weights_mc=similar(internal_params.weights_mc), - cumsum_weights_mc=similar(internal_params.weights_mc), random_n=Ref(rand()), progr_mc=ProgressBar(size(internal_params.expvals, 2), enable=false), jump_times_which_idx=Ref(1), - jump_times=similar(internal_params.jump_times), jump_which=similar(internal_params.jump_which))) - - remake(prob, p=prm) + prm = merge( + internal_params, + ( + expvals = similar(internal_params.expvals), + cache_mc = similar(internal_params.cache_mc), + weights_mc = similar(internal_params.weights_mc), + cumsum_weights_mc = similar(internal_params.weights_mc), + random_n = Ref(rand()), + progr_mc = ProgressBar(size(internal_params.expvals, 2), enable = false), + jump_times_which_idx = Ref(1), + jump_times = similar(internal_params.jump_times), + jump_which = similar(internal_params.jump_which), + ), + ) + + return remake(prob, p = prm) end function _mcsolve_output_func(sol, i) resize!(sol.prob.p.jump_times, sol.prob.p.jump_times_which_idx[] - 1) resize!(sol.prob.p.jump_which, sol.prob.p.jump_times_which_idx[] - 1) - (sol, false) + return (sol, false) end function _mcsolve_generate_statistics(sol, i, times, states, expvals_all, jump_times, jump_which) sol_i = sol[:, i] - sol_u = haskey(sol_i.prob.kwargs, :save_idxs) ? sol_i.u : [QuantumObject(sol_i.u[i], dims=sol_i.prob.p.Hdims) for i in 1:length(sol_i.u)] + sol_u = + haskey(sol_i.prob.kwargs, :save_idxs) ? sol_i.u : + [QuantumObject(sol_i.u[i], dims = sol_i.prob.p.Hdims) for i in 1:length(sol_i.u)] copyto!(view(expvals_all, i, :, :), sol_i.prob.p.expvals) times[i] = sol_i.t states[i] = sol_u jump_times[i] = sol_i.prob.p.jump_times - jump_which[i] = sol_i.prob.p.jump_which + return jump_which[i] = sol_i.prob.p.jump_which end - - """ mcsolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, @@ -105,33 +115,36 @@ Generates the ODEProblem for a single trajectory of the Monte Carlo wave functio time evolution of an open quantum system. # Arguments -- `H::QuantumObject`: Hamiltonian of the system. -- `ψ0::QuantumObject`: Initial state of the system. -- `t_l::AbstractVector`: List of times at which to save the state of the system. -- `c_ops::Vector`: List of collapse operators. -- `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. -- `e_ops::Vector`: List of operators for which to calculate expectation values. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. -- `params::NamedTuple`: Dictionary of parameters to pass to the solver. -- `seeds::Union{Nothing, Vector{Int}}`: List of seeds for the random number generator. Length must be equal to the number of trajectories provided. -- `jump_callback::LindbladJumpCallbackType`: The Jump Callback type: Discrete or Continuous. -- `kwargs...`: Additional keyword arguments to pass to the solver. + + - `H::QuantumObject`: Hamiltonian of the system. + - `ψ0::QuantumObject`: Initial state of the system. + - `t_l::AbstractVector`: List of times at which to save the state of the system. + - `c_ops::Vector`: List of collapse operators. + - `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. + - `e_ops::Vector`: List of operators for which to calculate expectation values. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. + - `params::NamedTuple`: Dictionary of parameters to pass to the solver. + - `seeds::Union{Nothing, Vector{Int}}`: List of seeds for the random number generator. Length must be equal to the number of trajectories provided. + - `jump_callback::LindbladJumpCallbackType`: The Jump Callback type: Discrete or Continuous. + - `kwargs...`: Additional keyword arguments to pass to the solver. # Returns -- `prob::ODEProblem`: The ODEProblem for the Monte Carlo wave function time evolution. + + - `prob::ODEProblem`: The ODEProblem for the Monte Carlo wave function time evolution. """ -function mcsolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, +function mcsolveProblem( + H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[]; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - seeds::Union{Nothing,Vector{Int}}=nothing, - jump_callback::TJC=ContinuousLindbladJumpCallback(), - kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} - + c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[]; + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + seeds::Union{Nothing,Vector{Int}} = nothing, + jump_callback::TJC = ContinuousLindbladJumpCallback(), + kwargs..., +) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} H_eff = H - T2(0.5im) * mapreduce(op -> op' * op, +, c_ops) e_ops2 = Vector{Te}(undef, length(e_ops)) @@ -148,51 +161,71 @@ function mcsolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, jump_times = Vector{Float64}(undef, jump_times_which_init_size) jump_which = Vector{Int16}(undef, jump_times_which_init_size) - params2 = (expvals=expvals, e_ops_mc=e_ops2, - is_empty_e_ops_mc=isempty(e_ops), - progr_mc=ProgressBar(length(t_l), enable=false), seeds=seeds, - random_n=Ref(rand()), c_ops=get_data.(c_ops), cache_mc=cache_mc, - weights_mc=weights_mc, cumsum_weights_mc=cumsum_weights_mc, - jump_times=jump_times, jump_which=jump_which, - jump_times_which_init_size=jump_times_which_init_size, - jump_times_which_idx=Ref(1), params...) - - mcsolveProblem(H_eff, ψ0, t_l, alg, H_t, params2, jump_callback; kwargs...) + params2 = ( + expvals = expvals, + e_ops_mc = e_ops2, + is_empty_e_ops_mc = isempty(e_ops), + progr_mc = ProgressBar(length(t_l), enable = false), + seeds = seeds, + random_n = Ref(rand()), + c_ops = get_data.(c_ops), + cache_mc = cache_mc, + weights_mc = weights_mc, + cumsum_weights_mc = cumsum_weights_mc, + jump_times = jump_times, + jump_which = jump_which, + jump_times_which_init_size = jump_times_which_init_size, + jump_times_which_idx = Ref(1), + params..., + ) + + return mcsolveProblem(H_eff, ψ0, t_l, alg, H_t, params2, jump_callback; kwargs...) end -function mcsolveProblem(H_eff::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, +function mcsolveProblem( + H_eff::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, H_t::Union{Nothing,Function,TimeDependentOperatorSum}, params::NamedTuple, jump_callback::DiscreteLindbladJumpCallback; - kwargs...) where {T1,T2} - - cb1 = DiscreteCallback(LindbladJumpDiscreteCondition, LindbladJumpAffect!, save_positions=(false, false)) - cb2 = PresetTimeCallback(t_l, _save_func_mcsolve, save_positions=(false, false)) + kwargs..., +) where {T1,T2} + cb1 = DiscreteCallback(LindbladJumpDiscreteCondition, LindbladJumpAffect!, save_positions = (false, false)) + cb2 = PresetTimeCallback(t_l, _save_func_mcsolve, save_positions = (false, false)) kwargs2 = (; kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb1, cb2, kwargs2.callback),)) : merge(kwargs2, (callback=CallbackSet(cb1, cb2),)) + kwargs2 = + haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb1, cb2, kwargs2.callback),)) : + merge(kwargs2, (callback = CallbackSet(cb1, cb2),)) - sesolveProblem(H_eff, ψ0, t_l; alg=alg, H_t=H_t, params=params, kwargs2...) + return sesolveProblem(H_eff, ψ0, t_l; alg = alg, H_t = H_t, params = params, kwargs2...) end -function mcsolveProblem(H_eff::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, +function mcsolveProblem( + H_eff::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, H_t::Union{Nothing,Function,TimeDependentOperatorSum}, params::NamedTuple, jump_callback::ContinuousLindbladJumpCallback; - kwargs...) where {T1,T2} - - cb1 = ContinuousCallback(LindbladJumpContinuousCondition, LindbladJumpAffect!, nothing, - interp_points=jump_callback.interp_points, save_positions=(false, false)) - cb2 = PresetTimeCallback(t_l, _save_func_mcsolve, save_positions=(false, false)) + kwargs..., +) where {T1,T2} + cb1 = ContinuousCallback( + LindbladJumpContinuousCondition, + LindbladJumpAffect!, + nothing, + interp_points = jump_callback.interp_points, + save_positions = (false, false), + ) + cb2 = PresetTimeCallback(t_l, _save_func_mcsolve, save_positions = (false, false)) kwargs2 = (; kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb1, cb2, kwargs2.callback),)) : merge(kwargs2, (callback=CallbackSet(cb1, cb2),)) + kwargs2 = + haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb1, cb2, kwargs2.callback),)) : + merge(kwargs2, (callback = CallbackSet(cb1, cb2),)) - sesolveProblem(H_eff, ψ0, t_l; alg=alg, H_t=H_t, params=params, kwargs2...) + return sesolveProblem(H_eff, ψ0, t_l; alg = alg, H_t = H_t, params = params, kwargs2...) end """ @@ -213,43 +246,56 @@ Generates the ODEProblem for an ensemble of trajectories of the Monte Carlo wave time evolution of an open quantum system. # Arguments -- `H::QuantumObject`: Hamiltonian of the system. -- `ψ0::QuantumObject`: Initial state of the system. -- `t_l::AbstractVector`: List of times at which to save the state of the system. -- `c_ops::Vector`: List of collapse operators. -- `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. -- `e_ops::Vector`: List of operators for which to calculate expectation values. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. -- `params::NamedTuple`: Dictionary of parameters to pass to the solver. -- `seeds::Union{Nothing, Vector{Int}}`: List of seeds for the random number generator. Length must be equal to the number of trajectories provided. -- `jump_callback::LindbladJumpCallbackType`: The Jump Callback type: Discrete or Continuous. -- `prob_func::Function`: Function to use for generating the ODEProblem. -- `output_func::Function`: Function to use for generating the output of a single trajectory. -- `kwargs...`: Additional keyword arguments to pass to the solver. + + - `H::QuantumObject`: Hamiltonian of the system. + - `ψ0::QuantumObject`: Initial state of the system. + - `t_l::AbstractVector`: List of times at which to save the state of the system. + - `c_ops::Vector`: List of collapse operators. + - `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. + - `e_ops::Vector`: List of operators for which to calculate expectation values. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. + - `params::NamedTuple`: Dictionary of parameters to pass to the solver. + - `seeds::Union{Nothing, Vector{Int}}`: List of seeds for the random number generator. Length must be equal to the number of trajectories provided. + - `jump_callback::LindbladJumpCallbackType`: The Jump Callback type: Discrete or Continuous. + - `prob_func::Function`: Function to use for generating the ODEProblem. + - `output_func::Function`: Function to use for generating the output of a single trajectory. + - `kwargs...`: Additional keyword arguments to pass to the solver. # Returns -- `prob::EnsembleProblem with ODEProblem`: The Ensemble ODEProblem for the Monte Carlo -wave function time evolution. + + - `prob::EnsembleProblem with ODEProblem`: The Ensemble ODEProblem for the Monte Carlo + wave function time evolution. """ -function mcsolveEnsembleProblem(H::QuantumObject{MT1,OperatorQuantumObject}, +function mcsolveEnsembleProblem( + H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[]; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - jump_callback::TJC=ContinuousLindbladJumpCallback(), - seeds::Union{Nothing,Vector{Int}}=nothing, - prob_func::Function=_mcsolve_prob_func, - output_func::Function=_mcsolve_output_func, - kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} - - prob_mc = mcsolveProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, seeds=seeds, jump_callback=jump_callback, kwargs...) - - ensemble_prob = EnsembleProblem(prob_mc, prob_func=prob_func, - output_func=output_func, safetycopy=false) + c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[]; + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + jump_callback::TJC = ContinuousLindbladJumpCallback(), + seeds::Union{Nothing,Vector{Int}} = nothing, + prob_func::Function = _mcsolve_prob_func, + output_func::Function = _mcsolve_output_func, + kwargs..., +) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} + prob_mc = mcsolveProblem( + H, + ψ0, + t_l, + c_ops; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + seeds = seeds, + jump_callback = jump_callback, + kwargs..., + ) + + ensemble_prob = EnsembleProblem(prob_mc, prob_func = prob_func, output_func = output_func, safetycopy = false) return ensemble_prob end @@ -271,71 +317,93 @@ end Time evolution of an open quantum system using quantum trajectories. # Arguments -- `H::QuantumObject`: Hamiltonian of the system. -- `ψ0::QuantumObject`: Initial state of the system. -- `t_l::AbstractVector`: List of times at which to save the state of the system. -- `c_ops::Vector`: List of collapse operators. -- `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. -- `e_ops::Vector`: List of operators for which to calculate expectation values. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. -- `params::NamedTuple`: Dictionary of parameters to pass to the solver. -- `seeds::Union{Nothing, Vector{Int}}`: List of seeds for the random number generator. Length must be equal to the number of trajectories provided. -- `n_traj::Int`: Number of trajectories to use. -- `ensemble_method`: Ensemble method to use. -- `jump_callback::LindbladJumpCallbackType`: The Jump Callback type: Discrete or Continuous. -- `prob_func::Function`: Function to use for generating the ODEProblem. -- `output_func::Function`: Function to use for generating the output of a single trajectory. -- `kwargs...`: Additional keyword arguments to pass to the solver. + + - `H::QuantumObject`: Hamiltonian of the system. + - `ψ0::QuantumObject`: Initial state of the system. + - `t_l::AbstractVector`: List of times at which to save the state of the system. + - `c_ops::Vector`: List of collapse operators. + - `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. + - `e_ops::Vector`: List of operators for which to calculate expectation values. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. + - `params::NamedTuple`: Dictionary of parameters to pass to the solver. + - `seeds::Union{Nothing, Vector{Int}}`: List of seeds for the random number generator. Length must be equal to the number of trajectories provided. + - `n_traj::Int`: Number of trajectories to use. + - `ensemble_method`: Ensemble method to use. + - `jump_callback::LindbladJumpCallbackType`: The Jump Callback type: Discrete or Continuous. + - `prob_func::Function`: Function to use for generating the ODEProblem. + - `output_func::Function`: Function to use for generating the output of a single trajectory. + - `kwargs...`: Additional keyword arguments to pass to the solver. # Returns -- `sol::TimeEvolutionMCSol`: The solution of the time evolution. + + - `sol::TimeEvolutionMCSol`: The solution of the time evolution. # Notes + `ensemble_method` can be one of `EnsembleThreads()`, `EnsembleSerial()`, `EnsembleDistributed()`. """ -function mcsolve(H::QuantumObject{MT1,OperatorQuantumObject}, +function mcsolve( + H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[]; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - seeds::Union{Nothing,Vector{Int}}=nothing, - n_traj::Int=1, - ensemble_method=EnsembleThreads(), - jump_callback::TJC=ContinuousLindbladJumpCallback(), - prob_func::Function=_mcsolve_prob_func, - output_func::Function=_mcsolve_output_func, - kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} - + c_ops::Vector{QuantumObject{Tc,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[]; + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + seeds::Union{Nothing,Vector{Int}} = nothing, + n_traj::Int = 1, + ensemble_method = EnsembleThreads(), + jump_callback::TJC = ContinuousLindbladJumpCallback(), + prob_func::Function = _mcsolve_prob_func, + output_func::Function = _mcsolve_output_func, + kwargs..., +) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix,TJC<:LindbladJumpCallbackType} if !isnothing(seeds) && length(seeds) != n_traj throw(ArgumentError("Length of seeds must match n_traj ($n_traj), but got $(length(seeds))")) end - ens_prob_mc = mcsolveEnsembleProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, seeds=seeds, jump_callback=jump_callback, prob_func=prob_func, - output_func=output_func, kwargs...) - - return mcsolve(ens_prob_mc; alg=alg, n_traj=n_traj, ensemble_method=ensemble_method, kwargs...) + ens_prob_mc = mcsolveEnsembleProblem( + H, + ψ0, + t_l, + c_ops; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + seeds = seeds, + jump_callback = jump_callback, + prob_func = prob_func, + output_func = output_func, + kwargs..., + ) + + return mcsolve(ens_prob_mc; alg = alg, n_traj = n_traj, ensemble_method = ensemble_method, kwargs...) end -function mcsolve(ens_prob_mc::EnsembleProblem; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - n_traj::Int=1, - ensemble_method=EnsembleThreads(), - kwargs...) - - sol = solve(ens_prob_mc, alg, ensemble_method, trajectories=n_traj) +function mcsolve( + ens_prob_mc::EnsembleProblem; + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + n_traj::Int = 1, + ensemble_method = EnsembleThreads(), + kwargs..., +) + sol = solve(ens_prob_mc, alg, ensemble_method, trajectories = n_traj) expvals_all = Array{ComplexF64}(undef, length(sol), size(sol[:, 1].prob.p.expvals)...) times = Vector{Vector{Float64}}(undef, length(sol)) - states = haskey(sol[:, 1].prob.kwargs, :save_idxs) ? Vector{Vector{eltype(sol[:, 1].u[1])}}(undef, length(sol)) : Vector{Vector{QuantumObject}}(undef, length(sol)) + states = + haskey(sol[:, 1].prob.kwargs, :save_idxs) ? Vector{Vector{eltype(sol[:, 1].u[1])}}(undef, length(sol)) : + Vector{Vector{QuantumObject}}(undef, length(sol)) jump_times = Vector{Vector{Float64}}(undef, length(sol)) jump_which = Vector{Vector{Int16}}(undef, length(sol)) - foreach(i -> _mcsolve_generate_statistics(sol, i, times, states, expvals_all, jump_times, jump_which), eachindex(sol)) - expvals = dropdims(sum(expvals_all, dims=1), dims=1) ./ length(sol) + foreach( + i -> _mcsolve_generate_statistics(sol, i, times, states, expvals_all, jump_times, jump_which), + eachindex(sol), + ) + expvals = dropdims(sum(expvals_all, dims = 1), dims = 1) ./ length(sol) - TimeEvolutionMCSol(times, states, expvals, expvals_all, jump_times, jump_which) + return TimeEvolutionMCSol(times, states, expvals, expvals_all, jump_times, jump_which) end \ No newline at end of file diff --git a/src/time_evolution/mesolve.jl b/src/time_evolution/mesolve.jl index b3058c27..cacd9fd5 100644 --- a/src/time_evolution/mesolve.jl +++ b/src/time_evolution/mesolve.jl @@ -16,14 +16,14 @@ function _save_func_mesolve(integrator) @. expvals[:, progr.counter[]+1] = _expect(e_ops) end next!(progr) - u_modified!(integrator, false) + return u_modified!(integrator, false) end mesolve_ti_dudt!(du, u, p, t) = mul!(du, p.L, u) function mesolve_td_dudt!(du, u, p, t) mul!(du, p.L, u) L_t = p.H_t(t, p) - mul!(du, L_t, u, 1, 1) + return mul!(du, L_t, u, 1, 1) end """ @@ -40,34 +40,42 @@ end Generates the ODEProblem for the master equation time evolution of an open quantum system. # Arguments -- `H::QuantumObject`: The Hamiltonian or the Liouvillian of the system. -- `ψ0::QuantumObject`: The initial state of the system. -- `t_l::AbstractVector`: The time list of the evolution. -- `c_ops::AbstractVector=[]`: The list of the collapse operators. -- `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5()`: The algorithm used for the time evolution. -- `e_ops::AbstractVector=[]`: The list of the operators for which the expectation values are calculated. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing`: The time-dependent Hamiltonian or Liouvillian. -- `params::NamedTuple=NamedTuple()`: The parameters of the time evolution. -- `progress_bar::Bool=true`: Whether to show the progress bar. -- `kwargs...`: The keyword arguments for the ODEProblem. + + - `H::QuantumObject`: The Hamiltonian or the Liouvillian of the system. + - `ψ0::QuantumObject`: The initial state of the system. + - `t_l::AbstractVector`: The time list of the evolution. + - `c_ops::AbstractVector=[]`: The list of the collapse operators. + - `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5()`: The algorithm used for the time evolution. + - `e_ops::AbstractVector=[]`: The list of the operators for which the expectation values are calculated. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing`: The time-dependent Hamiltonian or Liouvillian. + - `params::NamedTuple=NamedTuple()`: The parameters of the time evolution. + - `progress_bar::Bool=true`: Whether to show the progress bar. + - `kwargs...`: The keyword arguments for the ODEProblem. # Returns -- `prob::ODEProblem`: The ODEProblem for the master equation time evolution. + + - `prob::ODEProblem`: The ODEProblem for the master equation time evolution. """ -function mesolveProblem(H::QuantumObject{MT1,HOpType}, +function mesolveProblem( + H::QuantumObject{MT1,HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, t_l, - c_ops::Vector{QuantumObject{Tc,COpType}}=QuantumObject{MT1,HOpType}[]; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - progress_bar::Bool=true, - kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix, + c_ops::Vector{QuantumObject{Tc,COpType}} = QuantumObject{MT1,HOpType}[]; + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + progress_bar::Bool = true, + kwargs..., +) where { + MT1<:AbstractMatrix, + T2, + Tc<:AbstractMatrix, + Te<:AbstractMatrix, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, - COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject},} - + COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} H.dims != ψ0.dims && throw(ErrorException("The two operators don't have the same Hilbert dimension.")) is_time_dependent = !(H_t === nothing) @@ -75,29 +83,56 @@ function mesolveProblem(H::QuantumObject{MT1,HOpType}, ρ0 = mat2vec(ket2dm(ψ0).data) L = liouvillian(H, c_ops).data - progr = ProgressBar(length(t_l), enable=progress_bar) + progr = ProgressBar(length(t_l), enable = progress_bar) expvals = Array{ComplexF64}(undef, length(e_ops), length(t_l)) e_ops2 = @. mat2vec(adjoint(get_data(e_ops))) - p = (L=L, progr=progr, Hdims=H.dims, e_ops=e_ops2, expvals=expvals, H_t=H_t, is_empty_e_ops=isempty(e_ops), params...) - - default_values = (abstol=1e-7, reltol=1e-5, saveat=[t_l[end]]) + p = ( + L = L, + progr = progr, + Hdims = H.dims, + e_ops = e_ops2, + expvals = expvals, + H_t = H_t, + is_empty_e_ops = isempty(e_ops), + params..., + ) + + default_values = (abstol = 1e-7, reltol = 1e-5, saveat = [t_l[end]]) kwargs2 = merge(default_values, kwargs) if !isempty(e_ops) || progress_bar - cb1 = PresetTimeCallback(t_l, _save_func_mesolve, save_positions=(false, false)) - kwargs2 = haskey(kwargs, :callback) ? merge(kwargs2, (callback=CallbackSet(kwargs2.callback, cb1),)) : merge(kwargs2, (callback=cb1,)) + cb1 = PresetTimeCallback(t_l, _save_func_mesolve, save_positions = (false, false)) + kwargs2 = + haskey(kwargs, :callback) ? merge(kwargs2, (callback = CallbackSet(kwargs2.callback, cb1),)) : + merge(kwargs2, (callback = cb1,)) end tspan = (t_l[1], t_l[end]) - _mesolveProblem(L, ρ0, tspan, alg, Val(is_time_dependent), p; kwargs2...) + return _mesolveProblem(L, ρ0, tspan, alg, Val(is_time_dependent), p; kwargs2...) end -function _mesolveProblem(L::AbstractMatrix{<:T1}, ρ0::AbstractVector{<:T2}, tspan::Tuple, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, is_time_dependent::Val{false}, p; kwargs...) where {T1,T2} - ODEProblem{true,SciMLBase.FullSpecialize}(mesolve_ti_dudt!, ρ0, tspan, p; kwargs...) +function _mesolveProblem( + L::AbstractMatrix{<:T1}, + ρ0::AbstractVector{<:T2}, + tspan::Tuple, + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, + is_time_dependent::Val{false}, + p; + kwargs..., +) where {T1,T2} + return ODEProblem{true,SciMLBase.FullSpecialize}(mesolve_ti_dudt!, ρ0, tspan, p; kwargs...) end -function _mesolveProblem(L::AbstractMatrix{<:T1}, ρ0::AbstractVector{<:T2}, tspan::Tuple, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, is_time_dependent::Val{true}, p; kwargs...) where {T1,T2} - ODEProblem{true,SciMLBase.FullSpecialize}(mesolve_td_dudt!, ρ0, tspan, p; kwargs...) +function _mesolveProblem( + L::AbstractMatrix{<:T1}, + ρ0::AbstractVector{<:T2}, + tspan::Tuple, + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, + is_time_dependent::Val{true}, + p; + kwargs..., +) where {T1,T2} + return ODEProblem{true,SciMLBase.FullSpecialize}(mesolve_td_dudt!, ρ0, tspan, p; kwargs...) end """ @@ -114,42 +149,59 @@ end Time evolution of an open quantum system using master equation. # Arguments -- `H::QuantumObject`: Hamiltonian of Liouvillian of the system. -- `ψ0::QuantumObject`: Initial state of the system. -- `t_l::AbstractVector`: List of times at which to save the state of the system. -- `c_ops::AbstractVector`: List of collapse operators. -- `alg::OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. -- `e_ops::AbstractVector`: List of operators for which to calculate expectation values. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. -- `params::NamedTuple`: Named Tuple of parameters to pass to the solver. -- `progress_bar::Bool`: Whether to show the progress bar. -- `kwargs...`: Additional keyword arguments to pass to the solver. + + - `H::QuantumObject`: Hamiltonian of Liouvillian of the system. + - `ψ0::QuantumObject`: Initial state of the system. + - `t_l::AbstractVector`: List of times at which to save the state of the system. + - `c_ops::AbstractVector`: List of collapse operators. + - `alg::OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. + - `e_ops::AbstractVector`: List of operators for which to calculate expectation values. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. + - `params::NamedTuple`: Named Tuple of parameters to pass to the solver. + - `progress_bar::Bool`: Whether to show the progress bar. + - `kwargs...`: Additional keyword arguments to pass to the solver. # Returns -- `sol::TimeEvolutionSol`: The solution of the time evolution. + + - `sol::TimeEvolutionSol`: The solution of the time evolution. """ -function mesolve(H::QuantumObject{MT1,HOpType}, +function mesolve( + H::QuantumObject{MT1,HOpType}, ψ0::QuantumObject{<:AbstractArray{T2},StateOpType}, t_l::AbstractVector, - c_ops::Vector{QuantumObject{Tc,COpType}}=QuantumObject{MT1,HOpType}[]; - alg::OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - progress_bar::Bool=true, - kwargs...) where {MT1<:AbstractMatrix,T2,Tc<:AbstractMatrix,Te<:AbstractMatrix, + c_ops::Vector{QuantumObject{Tc,COpType}} = QuantumObject{MT1,HOpType}[]; + alg::OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{Te,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + progress_bar::Bool = true, + kwargs..., +) where { + MT1<:AbstractMatrix, + T2, + Tc<:AbstractMatrix, + Te<:AbstractMatrix, HOpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}, - COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - - prob = mesolveProblem(H, ψ0, t_l, c_ops; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, progress_bar=progress_bar, kwargs...) + COpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} + prob = mesolveProblem( + H, + ψ0, + t_l, + c_ops; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + progress_bar = progress_bar, + kwargs..., + ) return mesolve(prob, alg; kwargs...) end -function mesolve(prob::ODEProblem, alg::OrdinaryDiffEqAlgorithm=Tsit5(); kwargs...) - +function mesolve(prob::ODEProblem, alg::OrdinaryDiffEqAlgorithm = Tsit5(); kwargs...) sol = solve(prob, alg) return _mesolve_sol(sol; kwargs...) @@ -157,7 +209,7 @@ end function _mesolve_sol(sol; kwargs...) Hdims = sol.prob.p.Hdims - ρt = !haskey(kwargs, :save_idxs) ? map(ϕ -> QuantumObject(vec2mat(ϕ), dims=Hdims), sol.u) : sol.u + ρt = !haskey(kwargs, :save_idxs) ? map(ϕ -> QuantumObject(vec2mat(ϕ), dims = Hdims), sol.u) : sol.u return TimeEvolutionSol(sol.t, ρt, sol.prob.p.expvals) end \ No newline at end of file diff --git a/src/time_evolution/sesolve.jl b/src/time_evolution/sesolve.jl index d50b8de5..f5abcc2d 100644 --- a/src/time_evolution/sesolve.jl +++ b/src/time_evolution/sesolve.jl @@ -1,6 +1,5 @@ export sesolveProblem, sesolve - function _save_func_sesolve(integrator) internal_params = integrator.p progr = internal_params.progr @@ -14,14 +13,14 @@ function _save_func_sesolve(integrator) @. expvals[:, progr.counter[]+1] = _expect(e_ops) end next!(progr) - u_modified!(integrator, false) + return u_modified!(integrator, false) end sesolve_ti_dudt!(du, u, p, t) = mul!(du, p.U, u) function sesolve_td_dudt!(du, u, p, t) mul!(du, p.U, u) H_t = p.H_t(t, p) - mul!(du, H_t, u, -1im, 1) + return mul!(du, H_t, u, -1im, 1) end """ @@ -38,29 +37,32 @@ end Generates the ODEProblem for the Schrödinger time evolution of a quantum system. # Arguments -- `H::QuantumObject`: The Hamiltonian of the system. -- `ψ0::QuantumObject`: The initial state of the system. -- `t_l::AbstractVector`: The time list of the evolution. -- `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: The algorithm used for the time evolution. -- `e_ops::AbstractVector`: The list of operators to be evaluated during the evolution. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: The time-dependent Hamiltonian of the system. If `nothing`, the Hamiltonian is time-independent. -- `params::NamedTuple`: The parameters of the system. -- `progress_bar::Bool`: Whether to show the progress bar. -- `kwargs...`: The keyword arguments passed to the `ODEProblem` constructor. + + - `H::QuantumObject`: The Hamiltonian of the system. + - `ψ0::QuantumObject`: The initial state of the system. + - `t_l::AbstractVector`: The time list of the evolution. + - `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: The algorithm used for the time evolution. + - `e_ops::AbstractVector`: The list of operators to be evaluated during the evolution. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: The time-dependent Hamiltonian of the system. If `nothing`, the Hamiltonian is time-independent. + - `params::NamedTuple`: The parameters of the system. + - `progress_bar::Bool`: Whether to show the progress bar. + - `kwargs...`: The keyword arguments passed to the `ODEProblem` constructor. # Returns -- `prob`: The `ODEProblem` for the Schrödinger time evolution of the system. + + - `prob`: The `ODEProblem` for the Schrödinger time evolution of the system. """ -function sesolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, +function sesolveProblem( + H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{MT2,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - progress_bar::Bool=true, - kwargs...) where {MT1<:AbstractMatrix,T2,MT2<:AbstractMatrix} - + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{MT2,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + progress_bar::Bool = true, + kwargs..., +) where {MT1<:AbstractMatrix,T2,MT2<:AbstractMatrix} H.dims != ψ0.dims && throw(ErrorException("The two operators don't have the same Hilbert dimension.")) is_time_dependent = !(H_t === nothing) @@ -68,29 +70,56 @@ function sesolveProblem(H::QuantumObject{MT1,OperatorQuantumObject}, ϕ0 = get_data(ψ0) U = -1im * get_data(H) - progr = ProgressBar(length(t_l), enable=progress_bar) + progr = ProgressBar(length(t_l), enable = progress_bar) expvals = Array{ComplexF64}(undef, length(e_ops), length(t_l)) e_ops2 = get_data.(e_ops) - p = (U=U, e_ops=e_ops2, expvals=expvals, progr=progr, Hdims=H.dims, H_t=H_t, is_empty_e_ops=isempty(e_ops), params...) - - default_values = (abstol=1e-7, reltol=1e-5, saveat=[t_l[end]]) + p = ( + U = U, + e_ops = e_ops2, + expvals = expvals, + progr = progr, + Hdims = H.dims, + H_t = H_t, + is_empty_e_ops = isempty(e_ops), + params..., + ) + + default_values = (abstol = 1e-7, reltol = 1e-5, saveat = [t_l[end]]) kwargs2 = merge(default_values, kwargs) if !isempty(e_ops) || progress_bar - cb1 = PresetTimeCallback(t_l, _save_func_sesolve, save_positions=(false, false)) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(kwargs2.callback, cb1),)) : merge(kwargs2, (callback=cb1,)) + cb1 = PresetTimeCallback(t_l, _save_func_sesolve, save_positions = (false, false)) + kwargs2 = + haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(kwargs2.callback, cb1),)) : + merge(kwargs2, (callback = cb1,)) end tspan = (t_l[1], t_l[end]) - _sesolveProblem(U, ϕ0, tspan, alg, Val(is_time_dependent), p; kwargs2...) + return _sesolveProblem(U, ϕ0, tspan, alg, Val(is_time_dependent), p; kwargs2...) end -function _sesolveProblem(U::AbstractMatrix{<:T1}, ϕ0::AbstractVector{<:T2}, tspan::Tuple, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, is_time_dependent::Val{false}, p; kwargs...) where {T1,T2} - ODEProblem{true,SciMLBase.FullSpecialize}(sesolve_ti_dudt!, ϕ0, tspan, p; kwargs...) +function _sesolveProblem( + U::AbstractMatrix{<:T1}, + ϕ0::AbstractVector{<:T2}, + tspan::Tuple, + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, + is_time_dependent::Val{false}, + p; + kwargs..., +) where {T1,T2} + return ODEProblem{true,SciMLBase.FullSpecialize}(sesolve_ti_dudt!, ϕ0, tspan, p; kwargs...) end -function _sesolveProblem(U::AbstractMatrix{<:T1}, ϕ0::AbstractVector{<:T2}, tspan::Tuple, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, is_time_dependent::Val{true}, p; kwargs...) where {T1,T2} - ODEProblem{true,SciMLBase.FullSpecialize}(sesolve_td_dudt!, ϕ0, tspan, p; kwargs...) +function _sesolveProblem( + U::AbstractMatrix{<:T1}, + ϕ0::AbstractVector{<:T2}, + tspan::Tuple, + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm, + is_time_dependent::Val{true}, + p; + kwargs..., +) where {T1,T2} + return ODEProblem{true,SciMLBase.FullSpecialize}(sesolve_td_dudt!, ϕ0, tspan, p; kwargs...) end """ @@ -107,37 +136,47 @@ end Time evolution of a closed quantum system using the Schrödinger equation. # Arguments -- `H::QuantumObject`: Hamiltonian of the system. -- `ψ0::QuantumObject`: Initial state of the system. -- `t_l::AbstractVector`: List of times at which to save the state of the system. -- `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. -- `e_ops::AbstractVector`: List of operators for which to calculate expectation values. -- `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. -- `params::NamedTuple`: Dictionary of parameters to pass to the solver. -- `progress_bar::Bool`: Whether to show the progress bar. -- `kwargs...`: Additional keyword arguments to pass to the solver. - -- Returns -- `sol::TimeEvolutionSol`: The solution of the time evolution. + + - `H::QuantumObject`: Hamiltonian of the system. + + - `ψ0::QuantumObject`: Initial state of the system. + - `t_l::AbstractVector`: List of times at which to save the state of the system. + - `alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm`: Algorithm to use for the time evolution. + - `e_ops::AbstractVector`: List of operators for which to calculate expectation values. + - `H_t::Union{Nothing,Function,TimeDependentOperatorSum}`: Time-dependent part of the Hamiltonian. + - `params::NamedTuple`: Dictionary of parameters to pass to the solver. + - `progress_bar::Bool`: Whether to show the progress bar. + - `kwargs...`: Additional keyword arguments to pass to the solver. + - Returns + - `sol::TimeEvolutionSol`: The solution of the time evolution. """ -function sesolve(H::QuantumObject{MT1,OperatorQuantumObject}, +function sesolve( + H::QuantumObject{MT1,OperatorQuantumObject}, ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject}, t_l::AbstractVector; - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Vector{QuantumObject{MT2,OperatorQuantumObject}}=QuantumObject{MT1,OperatorQuantumObject}[], - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - progress_bar::Bool=true, - kwargs...) where {MT1<:AbstractMatrix,T2,MT2<:AbstractMatrix} - - prob = sesolveProblem(H, ψ0, t_l; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, progress_bar=progress_bar, kwargs...) + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Vector{QuantumObject{MT2,OperatorQuantumObject}} = QuantumObject{MT1,OperatorQuantumObject}[], + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + progress_bar::Bool = true, + kwargs..., +) where {MT1<:AbstractMatrix,T2,MT2<:AbstractMatrix} + prob = sesolveProblem( + H, + ψ0, + t_l; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + progress_bar = progress_bar, + kwargs..., + ) return sesolve(prob, alg; kwargs...) end -function sesolve(prob::ODEProblem, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(); kwargs...) - +function sesolve(prob::ODEProblem, alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(); kwargs...) sol = solve(prob, alg) return _sesolve_sol(sol; kwargs...) @@ -145,7 +184,7 @@ end function _sesolve_sol(sol; kwargs...) Hdims = sol.prob.p.Hdims - ψt = !haskey(kwargs, :save_idxs) ? map(ϕ -> QuantumObject(ϕ, dims=Hdims), sol.u) : sol.u + ψt = !haskey(kwargs, :save_idxs) ? map(ϕ -> QuantumObject(ϕ, dims = Hdims), sol.u) : sol.u return TimeEvolutionSol(sol.t, ψt, sol.prob.p.expvals) end \ No newline at end of file diff --git a/src/time_evolution/time_evolution.jl b/src/time_evolution/time_evolution.jl index d2549fc7..36870d0c 100644 --- a/src/time_evolution/time_evolution.jl +++ b/src/time_evolution/time_evolution.jl @@ -23,8 +23,14 @@ struct TimeEvolutionSol{TT<:Vector{<:Real},TS<:AbstractVector,TE<:Matrix{Complex expect::TE end -struct TimeEvolutionMCSol{TT<:Vector{<:Vector{<:Real}},TS<:AbstractVector,TE<:Matrix{ComplexF64}, - TEA<:Array{ComplexF64,3},TJT<:Vector{<:Vector{<:Real}},TJW<:Vector{<:Vector{<:Integer}}} +struct TimeEvolutionMCSol{ + TT<:Vector{<:Vector{<:Real}}, + TS<:AbstractVector, + TE<:Matrix{ComplexF64}, + TEA<:Array{ComplexF64,3}, + TJT<:Vector{<:Vector{<:Real}}, + TJW<:Vector{<:Vector{<:Integer}}, +} times::TT states::TS expect::TE @@ -33,7 +39,7 @@ struct TimeEvolutionMCSol{TT<:Vector{<:Vector{<:Real}},TS<:AbstractVector,TE<:Ma jump_which::TJW end -LiouvillianDirectSolver(; tol=1e-16) = LiouvillianDirectSolver(tol) +LiouvillianDirectSolver(; tol = 1e-16) = LiouvillianDirectSolver(tol) abstract type LindbladJumpCallbackType end @@ -41,10 +47,9 @@ struct ContinuousLindbladJumpCallback <: LindbladJumpCallbackType interp_points::Int end -struct DiscreteLindbladJumpCallback <: LindbladJumpCallbackType -end +struct DiscreteLindbladJumpCallback <: LindbladJumpCallbackType end -ContinuousLindbladJumpCallback(; interp_points::Int=10) = ContinuousLindbladJumpCallback(interp_points) +ContinuousLindbladJumpCallback(; interp_points::Int = 10) = ContinuousLindbladJumpCallback(interp_points) ## Sum of operators @@ -52,15 +57,19 @@ struct OperatorSum{CT<:Vector{<:Number},OT<:Vector{<:QuantumObject}} <: Abstract coefficients::CT operators::OT function OperatorSum(coefficients::CT, operators::OT) where {CT<:Vector{<:Number},OT<:Vector{<:QuantumObject}} - length(coefficients) == length(operators) || throw(DimensionMismatch("The number of coefficients must be the same as the number of operators.")) + length(coefficients) == length(operators) || + throw(DimensionMismatch("The number of coefficients must be the same as the number of operators.")) # Check if all the operators have the same dimensions dims = operators[1].dims optype = operators[1].type - mapreduce(x -> x.dims == dims && x.type == optype, &, operators) || throw(DimensionMismatch("All the operators must have the same dimensions.")) - T = promote_type(mapreduce(x -> eltype(x.data), promote_type, operators), - mapreduce(eltype, promote_type, coefficients)) + mapreduce(x -> x.dims == dims && x.type == optype, &, operators) || + throw(DimensionMismatch("All the operators must have the same dimensions.")) + T = promote_type( + mapreduce(x -> eltype(x.data), promote_type, operators), + mapreduce(eltype, promote_type, coefficients), + ) coefficients2 = T.(coefficients) - new{Vector{T},OT}(coefficients2, operators) + return new{Vector{T},OT}(coefficients2, operators) end end @@ -71,8 +80,9 @@ Base.copy(A::OperatorSum) = OperatorSum(copy(A.coefficients), copy(A.operators)) Base.deepcopy(A::OperatorSum) = OperatorSum(deepcopy(A.coefficients), deepcopy(A.operators)) function update_coefficients!(A::OperatorSum, coefficients) - length(A.coefficients) == length(coefficients) || throw(DimensionMismatch("The number of coefficients must be the same as the number of operators.")) - A.coefficients .= coefficients + length(A.coefficients) == length(coefficients) || + throw(DimensionMismatch("The number of coefficients must be the same as the number of operators.")) + return A.coefficients .= coefficients end @inline function LinearAlgebra.mul!(y::AbstractVector{T}, A::OperatorSum, x::AbstractVector, α, β) where {T} @@ -82,7 +92,7 @@ end A.coefficients[i] == 0 && continue mul!(y, A.operators[i], x, α * A.coefficients[i], 1) end - y + return y end struct TimeDependentOperatorSum{CFT,OST<:OperatorSum} @@ -90,7 +100,12 @@ struct TimeDependentOperatorSum{CFT,OST<:OperatorSum} operator_sum::OST end -function TimeDependentOperatorSum(coefficient_functions, operators::Vector{<:QuantumObject}; params=nothing, init_time=0.0) +function TimeDependentOperatorSum( + coefficient_functions, + operators::Vector{<:QuantumObject}; + params = nothing, + init_time = 0.0, +) # promote the type of the coefficients and the operators. Remember that the coefficient_functions si a vector of functions and the operators is a vector of QuantumObjects coefficients = [f(init_time, params) for f in coefficient_functions] operator_sum = OperatorSum(coefficients, operators) @@ -110,12 +125,11 @@ end (A::TimeDependentOperatorSum)(t, params) = (update_coefficients!(A, t, params); A) @inline function LinearAlgebra.mul!(y::AbstractVector, A::TimeDependentOperatorSum, x::AbstractVector, α, β) - mul!(y, A.operator_sum, x, α, β) + return mul!(y, A.operator_sum, x, α, β) end ####################################### - ### LIOUVILLIAN AND STEADYSTATE ### @doc raw""" liouvillian(H::QuantumObject, c_ops::AbstractVector, Id_cache=I(prod(H.dims)) @@ -127,44 +141,68 @@ where ``\mathcal{D}[\hat{O}_i] \cdot = \hat{O}_i \cdot \hat{O}_i^\dagger - \frac The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension. """ -function liouvillian(H::QuantumObject{MT1,OpType1}, - c_ops::Vector{QuantumObject{MT2,OpType2}}=Vector{QuantumObject{MT1,OpType1}}([]), - Id_cache=I(prod(H.dims))) where {MT1<:AbstractMatrix,MT2<:AbstractMatrix, +function liouvillian( + H::QuantumObject{MT1,OpType1}, + c_ops::Vector{QuantumObject{MT2,OpType2}} = Vector{QuantumObject{MT1,OpType1}}([]), + Id_cache = I(prod(H.dims)), +) where { + MT1<:AbstractMatrix, + MT2<:AbstractMatrix, OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} L = liouvillian(H, Id_cache) for c_op in c_ops L += lindblad_dissipator(c_op, Id_cache) end - L + return L end -liouvillian(H::QuantumObject{MT1,OperatorQuantumObject}, Id_cache::Diagonal=I(prod(H.dims))) where {MT1<:AbstractMatrix} = -1im * (spre(H, Id_cache) - spost(H, Id_cache)) +liouvillian( + H::QuantumObject{MT1,OperatorQuantumObject}, + Id_cache::Diagonal = I(prod(H.dims)), +) where {MT1<:AbstractMatrix} = -1im * (spre(H, Id_cache) - spost(H, Id_cache)) liouvillian(H::QuantumObject{MT1,SuperOperatorQuantumObject}, Id_cache::Diagonal) where {MT1<:AbstractMatrix} = H - -function liouvillian_floquet(L₀::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, +function liouvillian_floquet( + L₀::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, Lₚ::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, Lₘ::QuantumObject{<:AbstractArray{T3},SuperOperatorQuantumObject}, - ω::Real; n_max::Int=4, solver::LiouvillianSolver=LiouvillianDirectSolver()) where {T1,T2,T3} - - ((L₀.dims == Lₚ.dims) && (L₀.dims == Lₘ.dims)) || throw(ErrorException("The operators are not of the same Hilbert dimension.")) - - _liouvillian_floquet(L₀, Lₚ, Lₘ, ω, solver, n_max=n_max) + ω::Real; + n_max::Int = 4, + solver::LiouvillianSolver = LiouvillianDirectSolver(), +) where {T1,T2,T3} + ((L₀.dims == Lₚ.dims) && (L₀.dims == Lₘ.dims)) || + throw(ErrorException("The operators are not of the same Hilbert dimension.")) + + return _liouvillian_floquet(L₀, Lₚ, Lₘ, ω, solver, n_max = n_max) end -function liouvillian_floquet(H::QuantumObject{<:AbstractArray{T1},OpType1}, +function liouvillian_floquet( + H::QuantumObject{<:AbstractArray{T1},OpType1}, c_ops::AbstractVector, Hₚ::QuantumObject{<:AbstractArray{T2},OpType2}, Hₘ::QuantumObject{<:AbstractArray{T3},OpType3}, - ω::Real; n_max::Int=4, solver::LiouvillianSolver=LiouvillianDirectSolver()) where {T1,T2,T3, + ω::Real; + n_max::Int = 4, + solver::LiouvillianSolver = LiouvillianDirectSolver(), +) where { + T1, + T2, + T3, OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - - liouvillian_floquet(liouvillian(H, c_ops), liouvillian(Hₚ), liouvillian(Hₘ), ω, solver=solver, n_max=n_max) + OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} + return liouvillian_floquet( + liouvillian(H, c_ops), + liouvillian(Hₚ), + liouvillian(Hₘ), + ω, + solver = solver, + n_max = n_max, + ) end @doc raw""" @@ -175,9 +213,14 @@ 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}, fields::Vector, - T_list::Vector{<:Real}; N_trunc::Int=size(H, 1), tol::Real=1e-12, σ_filter::Union{Nothing,Real}=nothing) where {MT<:AbstractMatrix} - +function liouvillian_generalized( + H::QuantumObject{MT,OperatorQuantumObject}, + fields::Vector, + T_list::Vector{<:Real}; + N_trunc::Int = size(H, 1), + 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 == size(H, 1) ? H.dims : [N_trunc] @@ -185,14 +228,14 @@ function liouvillian_generalized(H::QuantumObject{MT,OperatorQuantumObject}, fie E = real.(result.values[1:N_trunc]) U = QuantumObject(result.vectors, result.type, result.dims) - H_d = QuantumObject(Diagonal(complex(E)), dims=dims) + H_d = QuantumObject(Diagonal(complex(E)), dims = dims) Ω = E' .- E Ωp = triu(dense_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, σ), dims=dims) + F1 = QuantumObject(gaussian.(Ω, 0, σ), dims = dims) F1 = dense_to_sparse(F1, tol) # Filter in the Liouville space @@ -216,23 +259,30 @@ function liouvillian_generalized(H::QuantumObject{MT,OperatorQuantumObject}, fie # Ohmic reservoir N_th = n_th.(Ωp, T_list[i]) - Sp₀ = QuantumObject(triu(X_op, 1), dims=dims) - Sp₁ = QuantumObject(droptol!((@. Ωp * N_th * Sp₀.data), tol), dims=dims) - Sp₂ = QuantumObject(droptol!((@. Ωp * (1 + N_th) * Sp₀.data), tol), dims=dims) + Sp₀ = QuantumObject(triu(X_op, 1), dims = dims) + Sp₁ = QuantumObject(droptol!((@. Ωp * N_th * Sp₀.data), tol), dims = dims) + Sp₂ = QuantumObject(droptol!((@. Ωp * (1 + N_th) * Sp₀.data), tol), dims = dims) # S0 = QuantumObject( spdiagm(diag(X_op)), dims=dims ) - L += 1 / 2 * (F2 .* (sprepost(Sp₁', Sp₀) + sprepost(Sp₀', Sp₁)) - spre(F1 .* (Sp₀ * Sp₁')) - spost(F1 .* (Sp₁ * Sp₀'))) - L += 1 / 2 * (F2 .* (sprepost(Sp₂, Sp₀') + sprepost(Sp₀, Sp₂')) - spre(F1 .* (Sp₀' * Sp₂)) - spost(F1 .* (Sp₂' * Sp₀))) + L += + 1 / 2 * + (F2 .* (sprepost(Sp₁', Sp₀) + sprepost(Sp₀', Sp₁)) - spre(F1 .* (Sp₀ * Sp₁')) - spost(F1 .* (Sp₁ * Sp₀'))) + L += + 1 / 2 * + (F2 .* (sprepost(Sp₂, Sp₀') + sprepost(Sp₀, Sp₂')) - spre(F1 .* (Sp₀' * Sp₂)) - spost(F1 .* (Sp₂' * Sp₀))) end return E, U, L end -function _liouvillian_floquet(L₀::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, +function _liouvillian_floquet( + L₀::QuantumObject{<:AbstractArray{T1},SuperOperatorQuantumObject}, Lₚ::QuantumObject{<:AbstractArray{T2},SuperOperatorQuantumObject}, Lₘ::QuantumObject{<:AbstractArray{T3},SuperOperatorQuantumObject}, - ω::Real, solver::LiouvillianDirectSolver; n_max::Int=4) where {T1,T2,T3} - + ω::Real, + solver::LiouvillianDirectSolver; + n_max::Int = 4, +) where {T1,T2,T3} L_0 = L₀.data L_p = Lₚ.data L_m = Lₘ.data @@ -251,22 +301,26 @@ function _liouvillian_floquet(L₀::QuantumObject{<:AbstractArray{T1},SuperOpera return QuantumObject(dense_to_sparse(L_0 + L_m * S + L_p * T, solver.tol), SuperOperator, L₀.dims) end -function steadystate(L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}; - solver::SteadyStateSolver=SteadyStateDirectSolver()) where {T} - - _steadystate(L, solver) +function steadystate( + L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}; + solver::SteadyStateSolver = SteadyStateDirectSolver(), +) where {T} + return _steadystate(L, solver) end -function steadystate(H::QuantumObject{<:AbstractArray{T},OpType}, c_ops::Vector, - solver::SteadyStateSolver=SteadyStateDirectSolver()) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - +function steadystate( + H::QuantumObject{<:AbstractArray{T},OpType}, + c_ops::Vector, + solver::SteadyStateSolver = SteadyStateDirectSolver(), +) where {T,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} L = liouvillian(H, c_ops) - steadystate(L, solver=solver) + return steadystate(L, solver = solver) end -function _steadystate(L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, - solver::SteadyStateSolver) where {T} - +function _steadystate( + L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumObject}, + solver::SteadyStateSolver, +) where {T} L_tmp = copy(L.data) N = prod(L.dims) weight = norm(L_tmp, 1) / length(L_tmp) @@ -278,7 +332,7 @@ function _steadystate(L::QuantumObject{<:AbstractArray{T},SuperOperatorQuantumOb ρss_vec = L_tmp \ v0 ρss = reshape(ρss_vec, N, N) ρss = (ρss + ρss') / 2 # Hermitianize - QuantumObject(ρss, Operator, L.dims) + return QuantumObject(ρss, Operator, L.dims) end @doc raw""" @@ -297,32 +351,49 @@ as ``e^{i \\omega t}`` and `H_m` oscillates as ``e^{-i \\omega t}``. `lf_solver` is the solver used to solve the effective Liouvillian, and `ss_solver` is the solver used to solve the steady state. """ -function steadystate_floquet(H_0::QuantumObject{<:AbstractArray{T1},OpType1}, - c_ops::AbstractVector, H_p::QuantumObject{<:AbstractArray{T2},OpType2}, +function steadystate_floquet( + H_0::QuantumObject{<:AbstractArray{T1},OpType1}, + c_ops::AbstractVector, + H_p::QuantumObject{<:AbstractArray{T2},OpType2}, H_m::QuantumObject{<:AbstractArray{T3},OpType3}, - ω::Real; n_max::Int=4, lf_solver::LiouvillianSolver=LiouvillianDirectSolver(), - ss_solver::SteadyStateSolver=SteadyStateDirectSolver()) where {T1,T2,T3,OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + ω::Real; + n_max::Int = 4, + lf_solver::LiouvillianSolver = LiouvillianDirectSolver(), + ss_solver::SteadyStateSolver = SteadyStateDirectSolver(), +) where { + T1, + T2, + T3, + OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} L_0 = liouvillian(H_0, c_ops) L_p = liouvillian(H_p) L_m = liouvillian(H_m) - steadystate(liouvillian_floquet(L_0, L_p, L_m, ω, n_max=n_max, solver=lf_solver), solver=ss_solver) + return steadystate(liouvillian_floquet(L_0, L_p, L_m, ω, n_max = n_max, solver = lf_solver), solver = ss_solver) end -function steadystate_floquet(H_0::QuantumObject{<:AbstractArray{T1},OpType1}, +function steadystate_floquet( + H_0::QuantumObject{<:AbstractArray{T1},OpType1}, H_p::QuantumObject{<:AbstractArray{T2},OpType2}, H_m::QuantumObject{<:AbstractArray{T3},OpType3}, - ω::Real; n_max::Int=4, lf_solver::LiouvillianSolver=LiouvillianDirectSolver(), - ss_solver::SteadyStateSolver=SteadyStateDirectSolver()) where {T1,T2,T3,OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, + ω::Real; + n_max::Int = 4, + lf_solver::LiouvillianSolver = LiouvillianDirectSolver(), + ss_solver::SteadyStateSolver = SteadyStateDirectSolver(), +) where { + T1, + T2, + T3, + OpType1<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, OpType2<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, - OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} - + OpType3<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}, +} L_0 = liouvillian(H_0) L_p = liouvillian(H_p) L_m = liouvillian(H_m) - steadystate(liouvillian_floquet(L_0, L_p, L_m, ω, n_max=n_max, solver=lf_solver), solver=ss_solver) + return steadystate(liouvillian_floquet(L_0, L_p, L_m, ω, n_max = n_max, solver = lf_solver), solver = ss_solver) end \ No newline at end of file diff --git a/src/time_evolution/time_evolution_dynamical.jl b/src/time_evolution/time_evolution_dynamical.jl index 14b855b6..da5683da 100644 --- a/src/time_evolution/time_evolution_dynamical.jl +++ b/src/time_evolution/time_evolution_dynamical.jl @@ -2,7 +2,12 @@ export dfd_mesolve, dsf_mesolve, dsf_mcsolve ### DYNAMICAL FOCK DIMENSION ### -function _reduce_dims(QO::AbstractArray{T}, dims::Vector{<:Integer}, sel::AbstractVector, reduce::AbstractVector) where {T} +function _reduce_dims( + QO::AbstractArray{T}, + dims::Vector{<:Integer}, + sel::AbstractVector, + reduce::AbstractVector, +) where {T} rd = dims nd = length(rd) rd_new = zero(rd) @@ -19,10 +24,15 @@ function _reduce_dims(QO::AbstractArray{T}, dims::Vector{<:Integer}, sel::Abstra ρmat = reshape(ρmat2, prod(rd_new), prod(rd_new)) end - ρmat + return ρmat end -function _increase_dims(QO::AbstractArray{T}, dims::Vector{<:Integer}, sel::AbstractVector, increase::AbstractVector) where {T} +function _increase_dims( + QO::AbstractArray{T}, + dims::Vector{<:Integer}, + sel::AbstractVector, + increase::AbstractVector, +) where {T} rd = dims nd = length(rd) rd_new = zero(rd) @@ -45,7 +55,7 @@ function _increase_dims(QO::AbstractArray{T}, dims::Vector{<:Integer}, sel::Abst ρmat = reshape(ρmat2, prod(rd_new), prod(rd_new)) end - ρmat + return ρmat end _dfd_set_pillow(dim)::Int = min(max(round(Int, 0.02 * dim), 1), 20) @@ -77,7 +87,7 @@ function _DFDIncreaseReduceCondition(u, t, integrator) end end end - any(increase_list) || any(reduce_list) + return any(increase_list) || any(reduce_list) end function _DFDIncreaseReduceAffect!(integrator) @@ -121,21 +131,25 @@ function _DFDIncreaseReduceAffect!(integrator) resize!(integrator, size(L, 1)) copyto!(integrator.u, mat2vec(ρt)) - integrator.p = merge(internal_params, (L=L, e_ops=e_ops2, - dfd_ρt_cache=similar(integrator.u))) + return integrator.p = merge(internal_params, (L = L, e_ops = e_ops2, dfd_ρt_cache = similar(integrator.u))) end -function dfd_mesolveProblem(H::Function, ψ0::QuantumObject{<:AbstractArray{T1},StateOpType}, - t_l::AbstractVector, c_ops::Function, maxdims::Vector{T2}, - dfd_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(dim_list) -> Vector{Vector{T1}}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - tol_list::Vector{<:Number}=fill(1e-8, length(maxdims)), - kwargs...) where {T1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - - length(ψ0.dims) != length(maxdims) && throw(DimensionMismatch("'dim_list' and 'maxdims' do not have the same dimension.")) +function dfd_mesolveProblem( + H::Function, + ψ0::QuantumObject{<:AbstractArray{T1},StateOpType}, + t_l::AbstractVector, + c_ops::Function, + maxdims::Vector{T2}, + dfd_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (dim_list) -> Vector{Vector{T1}}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + tol_list::Vector{<:Number} = fill(1e-8, length(maxdims)), + kwargs..., +) where {T1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} + length(ψ0.dims) != length(maxdims) && + throw(DimensionMismatch("'dim_list' and 'maxdims' do not have the same dimension.")) dim_list = deepcopy(ψ0.dims) H₀ = H(dim_list, dfd_params) @@ -148,18 +162,32 @@ function dfd_mesolveProblem(H::Function, ψ0::QuantumObject{<:AbstractArray{T1}, increase_list = zeros(Bool, length(dim_list)) pillow_list = _dfd_set_pillow.(dim_list) - params2 = merge(params, (H_fun=H, c_ops_fun=c_ops, e_ops_fun=e_ops, - dim_list=dim_list, maxdims=maxdims, tol_list=tol_list, - reduce_list=reduce_list, increase_list=increase_list, pillow_list=pillow_list, - dim_list_evo_times=dim_list_evo_times, dim_list_evo=dim_list_evo, - dfd_ρt_cache=similar(ψ0.data, length(ψ0.data)^2), dfd_params=dfd_params)) - - cb_dfd = DiscreteCallback(_DFDIncreaseReduceCondition, _DFDIncreaseReduceAffect!, save_positions=(false, false)) + params2 = merge( + params, + ( + H_fun = H, + c_ops_fun = c_ops, + e_ops_fun = e_ops, + dim_list = dim_list, + maxdims = maxdims, + tol_list = tol_list, + reduce_list = reduce_list, + increase_list = increase_list, + pillow_list = pillow_list, + dim_list_evo_times = dim_list_evo_times, + dim_list_evo = dim_list_evo, + dfd_ρt_cache = similar(ψ0.data, length(ψ0.data)^2), + dfd_params = dfd_params, + ), + ) + + cb_dfd = DiscreteCallback(_DFDIncreaseReduceCondition, _DFDIncreaseReduceAffect!, save_positions = (false, false)) kwargs2 = (; kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb_dfd, kwargs2.callback),)) : merge(kwargs2, (callback=cb_dfd,)) + kwargs2 = + haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb_dfd, kwargs2.callback),)) : + merge(kwargs2, (callback = cb_dfd,)) - mesolveProblem(H₀, ψ0, t_l, c_ops₀; e_ops=e_ops₀, alg=alg, H_t=H_t, - params=params2, kwargs2...) + return mesolveProblem(H₀, ψ0, t_l, c_ops₀; e_ops = e_ops₀, alg = alg, H_t = H_t, params = params2, kwargs2...) end """ @@ -175,34 +203,50 @@ end Time evolution of an open quantum system using master equation, dynamically changing the dimension of the Hilbert subspaces. """ -function dfd_mesolve(H::Function, ψ0::QuantumObject{<:AbstractArray{T1},StateOpType}, - t_l::AbstractVector, c_ops::Function, maxdims::Vector{T2}, - dfd_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(dim_list) -> Vector{Vector{T1}}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - tol_list::Vector{<:Number}=fill(1e-8, length(maxdims)), - kwargs...) where {T1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} - - dfd_prob = dfd_mesolveProblem(H, ψ0, t_l, c_ops, maxdims, dfd_params; alg=alg, e_ops=e_ops, H_t=H_t, - params=params, tol_list=tol_list, kwargs...) +function dfd_mesolve( + H::Function, + ψ0::QuantumObject{<:AbstractArray{T1},StateOpType}, + t_l::AbstractVector, + c_ops::Function, + maxdims::Vector{T2}, + dfd_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (dim_list) -> Vector{Vector{T1}}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + tol_list::Vector{<:Number} = fill(1e-8, length(maxdims)), + kwargs..., +) where {T1,T2<:Integer,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject}} + dfd_prob = dfd_mesolveProblem( + H, + ψ0, + t_l, + c_ops, + maxdims, + dfd_params; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + tol_list = tol_list, + kwargs..., + ) sol = solve(dfd_prob, alg) - ρt = map(i -> QuantumObject(vec2mat(sol.u[i]), dims=sol.prob.p.dim_list_evo[searchsortedlast(sol.prob.p.dim_list_evo_times, sol.t[i])]), eachindex(sol.t)) + ρt = map( + i -> QuantumObject( + vec2mat(sol.u[i]), + dims = sol.prob.p.dim_list_evo[searchsortedlast(sol.prob.p.dim_list_evo_times, sol.t[i])], + ), + eachindex(sol.t), + ) return TimeEvolutionSol(sol.t, ρt, sol.prob.p.expvals) end - - - # Dynamical Shifted Fock mesolve - - - function _DSF_mesolve_Condition(u, t, integrator) internal_params = integrator.p op_l_vec = internal_params.op_l_vec @@ -217,7 +261,7 @@ function _DSF_mesolve_Condition(u, t, integrator) condition = true end end - condition + return condition end function _DSF_mesolve_Affect!(integrator) @@ -278,23 +322,25 @@ function _DSF_mesolve_Affect!(integrator) e_ops2 = e_ops(op_l2, dsf_params) _mat2vec_data = op -> mat2vec(get_data(op)') @. e_ops_vec = _mat2vec_data(e_ops2) - copyto!(internal_params.L, liouvillian(H(op_l2, dsf_params), c_ops(op_l2, dsf_params), dsf_identity).data) + return copyto!(internal_params.L, liouvillian(H(op_l2, dsf_params), c_ops(op_l2, dsf_params), dsf_identity).data) end -function dsf_mesolveProblem(H::Function, +function dsf_mesolveProblem( + H::Function, ψ0::QuantumObject{<:AbstractArray{T},StateOpType}, - t_l::AbstractVector, c_ops::Function, + t_l::AbstractVector, + c_ops::Function, op_list::Vector{TOl}, - α0_l::Vector{<:Number}=zeros(length(op_list)), - dsf_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list, p) -> Vector{TOl}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - krylov_dim::Int=min(5, cld(length(ket2dm(ψ0).data), 3)), - kwargs...) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} - + α0_l::Vector{<:Number} = zeros(length(op_list)), + dsf_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (op_list, p) -> Vector{TOl}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + δα_list::Vector{<:Real} = fill(0.2, length(op_list)), + krylov_dim::Int = min(5, cld(length(ket2dm(ψ0).data), 3)), + kwargs..., +) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} op_l = op_list H₀ = H(op_l .+ α0_l, dsf_params) c_ops₀ = c_ops(op_l .+ α0_l, dsf_params) @@ -309,20 +355,42 @@ function dsf_mesolveProblem(H::Function, dsf_displace_cache_left_dag = map(op -> Qobj(kron(sparse(op.data'), dsf_identity)), op_l) dsf_displace_cache_right = map(op -> Qobj(kron(dsf_identity, op.data)), op_l) dsf_displace_cache_right_dag = map(op -> Qobj(kron(dsf_identity, sparse(op.data'))), op_l) - dsf_displace_cache_full = OperatorSum(zeros(length(op_l) * 4), vcat(dsf_displace_cache_left, dsf_displace_cache_left_dag, dsf_displace_cache_right, dsf_displace_cache_right_dag)) + dsf_displace_cache_full = OperatorSum( + zeros(length(op_l) * 4), + vcat( + dsf_displace_cache_left, + dsf_displace_cache_left_dag, + dsf_displace_cache_right, + dsf_displace_cache_right_dag, + ), + ) params2 = params - params2 = merge(params, (H_fun=H, c_ops_fun=c_ops, e_ops_fun=e_ops, - op_l=op_l, op_l_vec=op_l_vec, αt_list=αt_list, δα_list=δα_list, - dsf_cache=similar(ψ0.data, length(ψ0.data)^2), expv_cache=expv_cache, - dsf_identity=dsf_identity, dsf_params=dsf_params, - dsf_displace_cache_full=dsf_displace_cache_full)) - - cb_dsf = DiscreteCallback(_DSF_mesolve_Condition, _DSF_mesolve_Affect!, save_positions=(false, false)) + params2 = merge( + params, + ( + H_fun = H, + c_ops_fun = c_ops, + e_ops_fun = e_ops, + op_l = op_l, + op_l_vec = op_l_vec, + αt_list = αt_list, + δα_list = δα_list, + dsf_cache = similar(ψ0.data, length(ψ0.data)^2), + expv_cache = expv_cache, + dsf_identity = dsf_identity, + dsf_params = dsf_params, + dsf_displace_cache_full = dsf_displace_cache_full, + ), + ) + + cb_dsf = DiscreteCallback(_DSF_mesolve_Condition, _DSF_mesolve_Affect!, save_positions = (false, false)) kwargs2 = (; kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb_dsf, kwargs2.callback),)) : merge(kwargs2, (callback=cb_dsf,)) + kwargs2 = + haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb_dsf, kwargs2.callback),)) : + merge(kwargs2, (callback = cb_dsf,)) - mesolveProblem(H₀, ψ0, t_l, c_ops₀; e_ops=e_ops₀, alg=alg, H_t=H_t, params=params2, kwargs2...) + return mesolveProblem(H₀, ψ0, t_l, c_ops₀; e_ops = e_ops₀, alg = alg, H_t = H_t, params = params2, kwargs2...) end """ @@ -342,50 +410,78 @@ end Time evolution of an open quantum system using master equation and the Dynamical Shifted Fock algorithm. """ -function dsf_mesolve(H::Function, +function dsf_mesolve( + H::Function, ψ0::QuantumObject{<:AbstractArray{T},StateOpType}, - t_l::AbstractVector, c_ops::Function, + t_l::AbstractVector, + c_ops::Function, op_list::Vector{TOl}, - α0_l::Vector{<:Number}=zeros(length(op_list)), - dsf_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list, p) -> Vector{TOl}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - krylov_dim::Int=min(5, cld(length(ket2dm(ψ0).data), 3)), - kwargs...) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} - - dsf_prob = dsf_mesolveProblem(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, H_t=H_t, - params=params, δα_list=δα_list, krylov_dim=krylov_dim, kwargs...) - - return mesolve(dsf_prob; alg=alg, kwargs...) + α0_l::Vector{<:Number} = zeros(length(op_list)), + dsf_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (op_list, p) -> Vector{TOl}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + δα_list::Vector{<:Real} = fill(0.2, length(op_list)), + krylov_dim::Int = min(5, cld(length(ket2dm(ψ0).data), 3)), + kwargs..., +) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} + dsf_prob = dsf_mesolveProblem( + H, + ψ0, + t_l, + c_ops, + op_list, + α0_l, + dsf_params; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + δα_list = δα_list, + krylov_dim = krylov_dim, + kwargs..., + ) + + return mesolve(dsf_prob; alg = alg, kwargs...) end -function dsf_mesolve(H::Function, +function dsf_mesolve( + H::Function, ψ0::QuantumObject{<:AbstractArray{T},StateOpType}, t_l::AbstractVector, op_list::Vector{TOl}, - α0_l::Vector{<:Number}=zeros(length(op_list)), - dsf_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list, p) -> Vector{TOl}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - krylov_dim::Int=min(5, cld(length(ket2dm(ψ0).data), 3)), - kwargs...) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} - + α0_l::Vector{<:Number} = zeros(length(op_list)), + dsf_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (op_list, p) -> Vector{TOl}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + δα_list::Vector{<:Real} = fill(0.2, length(op_list)), + krylov_dim::Int = min(5, cld(length(ket2dm(ψ0).data), 3)), + kwargs..., +) where {T,StateOpType<:Union{KetQuantumObject,OperatorQuantumObject},TOl} c_ops = op_list -> Vector{TOl}([]) - return dsf_mesolve(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, H_t=H_t, - params=params, δα_list=δα_list, krylov_dim=krylov_dim, kwargs...) + return dsf_mesolve( + H, + ψ0, + t_l, + c_ops, + op_list, + α0_l, + dsf_params; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + δα_list = δα_list, + krylov_dim = krylov_dim, + kwargs..., + ) end - # Dynamical Shifted Fock mcsolve - - function _DSF_mcsolve_Condition(u, t, integrator) internal_params = integrator.p op_l = internal_params.op_l @@ -402,7 +498,7 @@ function _DSF_mcsolve_Condition(u, t, integrator) condition = true end end - condition + return condition end function _DSF_mcsolve_Affect!(integrator) @@ -460,39 +556,58 @@ function _DSF_mcsolve_Affect!(integrator) @. e_ops0 = get_data(e_ops2) @. c_ops0 = get_data(c_ops2) H_eff = H(op_l2, dsf_params).data - lmul!(convert(eltype(ψt), 0.5im), mapreduce(op -> op' * op, +, c_ops0)) - mul!(internal_params.U, -1im, H_eff) + return mul!(internal_params.U, -1im, H_eff) end function _dsf_mcsolve_prob_func(prob, i, repeat) internal_params = prob.p - prm = merge(internal_params, (U=copy(internal_params.U), e_ops_mc=copy(internal_params.e_ops_mc), - c_ops=copy(internal_params.c_ops), expvals=similar(internal_params.expvals), - cache_mc=similar(internal_params.cache_mc), weights_mc=similar(internal_params.weights_mc), - cumsum_weights_mc=similar(internal_params.weights_mc), random_n=Ref(rand()), progr_mc=ProgressBar(size(internal_params.expvals, 2), enable=false), jump_times_which_idx=Ref(1), - jump_times=similar(internal_params.jump_times), jump_which=similar(internal_params.jump_which), - αt_list=copy(internal_params.αt_list), dsf_cache1=similar(internal_params.dsf_cache1), - dsf_cache2=similar(internal_params.dsf_cache2), expv_cache=copy(internal_params.expv_cache), - dsf_displace_cache_full=OperatorSum(copy(internal_params.dsf_displace_cache_full.coefficients), internal_params.dsf_displace_cache_full.operators))) - - remake(prob, p=prm) + prm = merge( + internal_params, + ( + U = copy(internal_params.U), + e_ops_mc = copy(internal_params.e_ops_mc), + c_ops = copy(internal_params.c_ops), + expvals = similar(internal_params.expvals), + cache_mc = similar(internal_params.cache_mc), + weights_mc = similar(internal_params.weights_mc), + cumsum_weights_mc = similar(internal_params.weights_mc), + random_n = Ref(rand()), + progr_mc = ProgressBar(size(internal_params.expvals, 2), enable = false), + jump_times_which_idx = Ref(1), + jump_times = similar(internal_params.jump_times), + jump_which = similar(internal_params.jump_which), + αt_list = copy(internal_params.αt_list), + dsf_cache1 = similar(internal_params.dsf_cache1), + dsf_cache2 = similar(internal_params.dsf_cache2), + expv_cache = copy(internal_params.expv_cache), + dsf_displace_cache_full = OperatorSum( + copy(internal_params.dsf_displace_cache_full.coefficients), + internal_params.dsf_displace_cache_full.operators, + ), + ), + ) + + return remake(prob, p = prm) end -function dsf_mcsolveEnsembleProblem(H::Function, +function dsf_mcsolveEnsembleProblem( + H::Function, ψ0::QuantumObject{<:AbstractArray{T},KetQuantumObject}, - t_l::AbstractVector, c_ops::Function, + t_l::AbstractVector, + c_ops::Function, op_list::Vector{TOl}, - α0_l::Vector{<:Number}=zeros(length(op_list)), - dsf_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list, p) -> Vector{TOl}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - jump_callback::TJC=ContinuousLindbladJumpCallback(), - krylov_dim::Int=min(5, cld(length(ψ0.data), 3)), - kwargs...) where {T,TOl,TJC<:LindbladJumpCallbackType} - + α0_l::Vector{<:Number} = zeros(length(op_list)), + dsf_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (op_list, p) -> Vector{TOl}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + δα_list::Vector{<:Real} = fill(0.2, length(op_list)), + jump_callback::TJC = ContinuousLindbladJumpCallback(), + krylov_dim::Int = min(5, cld(length(ψ0.data), 3)), + kwargs..., +) where {T,TOl,TJC<:LindbladJumpCallbackType} op_l = op_list H₀ = H(op_l .+ α0_l, dsf_params) c_ops₀ = c_ops(op_l .+ α0_l, dsf_params) @@ -505,19 +620,42 @@ function dsf_mcsolveEnsembleProblem(H::Function, dsf_displace_cache_dag = map(op -> Qobj(sparse(op.data')), op_l) dsf_displace_cache_full = OperatorSum(zeros(length(op_l) * 2), vcat(dsf_displace_cache, dsf_displace_cache_dag)) - - params2 = merge(params, (H_fun=H, c_ops_fun=c_ops, e_ops_fun=e_ops, - op_l=op_l, αt_list=αt_list, δα_list=δα_list, - dsf_cache1=similar(ψ0.data), dsf_cache2=similar(ψ0.data), - expv_cache=expv_cache, dsf_params=dsf_params, dsf_displace_cache_full=dsf_displace_cache_full)) - - cb_dsf = DiscreteCallback(_DSF_mcsolve_Condition, _DSF_mcsolve_Affect!, save_positions=(false, false)) + params2 = merge( + params, + ( + H_fun = H, + c_ops_fun = c_ops, + e_ops_fun = e_ops, + op_l = op_l, + αt_list = αt_list, + δα_list = δα_list, + dsf_cache1 = similar(ψ0.data), + dsf_cache2 = similar(ψ0.data), + expv_cache = expv_cache, + dsf_params = dsf_params, + dsf_displace_cache_full = dsf_displace_cache_full, + ), + ) + + cb_dsf = DiscreteCallback(_DSF_mcsolve_Condition, _DSF_mcsolve_Affect!, save_positions = (false, false)) kwargs2 = (; kwargs...) - kwargs2 = haskey(kwargs2, :callback) ? merge(kwargs2, (callback=CallbackSet(cb_dsf, kwargs2.callback),)) : merge(kwargs2, (callback=cb_dsf,)) - - mcsolveEnsembleProblem(H₀, ψ0, t_l, c_ops₀; e_ops=e_ops₀, alg=alg, H_t=H_t, - params=params2, jump_callback=jump_callback, - prob_func=_dsf_mcsolve_prob_func, kwargs2...) + kwargs2 = + haskey(kwargs2, :callback) ? merge(kwargs2, (callback = CallbackSet(cb_dsf, kwargs2.callback),)) : + merge(kwargs2, (callback = cb_dsf,)) + + return mcsolveEnsembleProblem( + H₀, + ψ0, + t_l, + c_ops₀; + e_ops = e_ops₀, + alg = alg, + H_t = H_t, + params = params2, + jump_callback = jump_callback, + prob_func = _dsf_mcsolve_prob_func, + kwargs2..., + ) end """ @@ -541,27 +679,42 @@ end Time evolution of a quantum system using the Monte Carlo wave function method and the Dynamical Shifted Fock algorithm. """ -function dsf_mcsolve(H::Function, +function dsf_mcsolve( + H::Function, ψ0::QuantumObject{<:AbstractArray{T},KetQuantumObject}, - t_l::AbstractVector, c_ops::Function, + t_l::AbstractVector, + c_ops::Function, op_list::Vector{TOl}, - α0_l::Vector{<:Number}=zeros(length(op_list)), - dsf_params::NamedTuple=NamedTuple(); - alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm=Tsit5(), - e_ops::Function=(op_list, p) -> Vector{TOl}([]), - H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing, - params::NamedTuple=NamedTuple(), - δα_list::Vector{<:Real}=fill(0.2, length(op_list)), - n_traj::Int=1, - ensemble_method=EnsembleThreads(), - jump_callback::TJC=ContinuousLindbladJumpCallback(), - krylov_dim::Int=min(5, cld(length(ψ0.data), 3)), - kwargs...) where {T,TOl,TJC<:LindbladJumpCallbackType} - - - ens_prob_mc = dsf_mcsolveEnsembleProblem(H, ψ0, t_l, c_ops, op_list, α0_l, dsf_params; alg=alg, e_ops=e_ops, - H_t=H_t, params=params, δα_list=δα_list, - jump_callback=jump_callback, krylov_dim=krylov_dim, kwargs...) - - return mcsolve(ens_prob_mc; alg=alg, n_traj=n_traj, ensemble_method=ensemble_method, kwargs...) + α0_l::Vector{<:Number} = zeros(length(op_list)), + dsf_params::NamedTuple = NamedTuple(); + alg::OrdinaryDiffEq.OrdinaryDiffEqAlgorithm = Tsit5(), + e_ops::Function = (op_list, p) -> Vector{TOl}([]), + H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing, + params::NamedTuple = NamedTuple(), + δα_list::Vector{<:Real} = fill(0.2, length(op_list)), + n_traj::Int = 1, + ensemble_method = EnsembleThreads(), + jump_callback::TJC = ContinuousLindbladJumpCallback(), + krylov_dim::Int = min(5, cld(length(ψ0.data), 3)), + kwargs..., +) where {T,TOl,TJC<:LindbladJumpCallbackType} + ens_prob_mc = dsf_mcsolveEnsembleProblem( + H, + ψ0, + t_l, + c_ops, + op_list, + α0_l, + dsf_params; + alg = alg, + e_ops = e_ops, + H_t = H_t, + params = params, + δα_list = δα_list, + jump_callback = jump_callback, + krylov_dim = krylov_dim, + kwargs..., + ) + + return mcsolve(ens_prob_mc; alg = alg, n_traj = n_traj, ensemble_method = ensemble_method, kwargs...) end \ No newline at end of file diff --git a/src/versioninfo.jl b/src/versioninfo.jl index 96637b7d..f878a086 100644 --- a/src/versioninfo.jl +++ b/src/versioninfo.jl @@ -6,8 +6,7 @@ Command line output of information on QuantumToolbox, dependencies, and system i function versioninfo(io::IO = stdout) cpu = Sys.cpu_info() BLAS_info = BLAS.get_config().loaded_libs[1] - Sys.iswindows() ? OS_name = "Windows" : - Sys.isapple() ? OS_name = "macOS" : OS_name = Sys.KERNEL + Sys.iswindows() ? OS_name = "Windows" : Sys.isapple() ? OS_name = "macOS" : OS_name = Sys.KERNEL # print introduction println( @@ -31,27 +30,16 @@ function versioninfo(io::IO = stdout) ) # print System informations - println( - io, - "System information:\n", - "====================================\n", - "Julia Version: $(VERSION)", - ) + println(io, "System information:\n", "====================================\n", "Julia Version: $(VERSION)") println(io, """OS : $(OS_name) ($(Sys.MACHINE))""") println(io, """CPU : $(length(cpu)) × $(cpu[1].model)""") println(io, """Memory : $(round(Sys.total_memory() / 2 ^ 30, digits=3)) GB""") println(io, """WORD_SIZE: $(Sys.WORD_SIZE)""") println(io, """LIBM : $(Base.libm_name)""") - println( - io, - """LLVM : libLLVM-$(Base.libllvm_version) ($(Sys.JIT), $(Sys.CPU_NAME))""", - ) + println(io, """LLVM : libLLVM-$(Base.libllvm_version) ($(Sys.JIT), $(Sys.CPU_NAME))""") println(io, """BLAS : $(basename(BLAS_info.libname)) ($(BLAS_info.interface))""") - println( - io, - """Threads : $(Threads.nthreads()) (on $(Sys.CPU_THREADS) virtual cores)""", - ) - print(io, "\n") + println(io, """Threads : $(Threads.nthreads()) (on $(Sys.CPU_THREADS) virtual cores)""") + return print(io, "\n") end """ diff --git a/src/wigner.jl b/src/wigner.jl index 74bd064f..d2f0b7cb 100644 --- a/src/wigner.jl +++ b/src/wigner.jl @@ -30,11 +30,7 @@ function wigner( yvec::AbstractVector; g::Real = √2, solver::MySolver = WignerLaguerre(), -) where { - T, - OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject}, - MySolver<:WignerSolver, -} +) where {T,OpType<:Union{BraQuantumObject,KetQuantumObject,OperatorQuantumObject},MySolver<:WignerSolver} if isket(state) ρ = (state * state').data elseif isbra(state) @@ -87,28 +83,14 @@ function _wigner( while L > 0 L -= 1 - ρdiag = _wig_laguerre_clenshaw!( - res, - L, - B, - lmul!(1 + Int(L != 0), diag(ρ, L)), - y0, - y1, - y0_old, - ) + ρdiag = _wig_laguerre_clenshaw!(res, L, B, lmul!(1 + Int(L != 0), diag(ρ, L)), y0, y1, y0_old) @. W = ρdiag + W * A / √(L + 1) end return @. real(W) * exp(-B / 2) * g^2 / 2 / π end -function _wigner_laguerre( - ρ::AbstractSparseArray, - A::AbstractArray, - W::AbstractArray, - g::Real, - solver::WignerLaguerre, -) +function _wigner_laguerre(ρ::AbstractSparseArray, A::AbstractArray, W::AbstractArray, g::Real, solver::WignerLaguerre) rows, cols, vals = findnz(ρ) B = @. 4 * abs2(A) @@ -122,8 +104,7 @@ function _wigner_laguerre( Γ_mn = (1 + Int(m != n)) * sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) - @. Wtot[:, :, i] = - real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B)) + @. Wtot[:, :, i] = real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B)) end W .= dropdims(sum(Wtot, dims = 3), dims = 3) else @@ -141,13 +122,7 @@ function _wigner_laguerre( return @. W * g^2 * exp(-B / 2) / 2 / π end -function _wigner_laguerre( - ρ::AbstractArray, - A::AbstractArray, - W::AbstractArray, - g::Real, - solver::WignerLaguerre, -) +function _wigner_laguerre(ρ::AbstractArray, A::AbstractArray, W::AbstractArray, g::Real, solver::WignerLaguerre) tol = solver.tol M = size(ρ, 1) B = @. 4 * abs2(A) @@ -164,10 +139,7 @@ function _wigner_laguerre( Γ_mn = sqrt(exp(loggamma(m + 1) - loggamma(n + 1))) # Is this a good trick? Γ_mn = check_inf(Γ_mn) - abs(ρmn) > tol && (@. W += - 2 * real( - ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B), - )) + abs(ρmn) > tol && (@. W += 2 * real(ρmn * (-1)^m * (2 * A)^(n - m) * Γ_mn * _genlaguerre(m, n - m, B))) end end end @@ -192,10 +164,11 @@ function _genlaguerre(n::Int, α::Number, x::T) where {T<:BlasFloat} for k in 1:n-1 p1, p0 = ((2k + α + 1) / (k + 1) - x / (k + 1)) * p1 - (k + α) / (k + 1) * p0, p1 end - p1 + return p1 end -check_inf(x::T) where {T} = if isinf(x) +check_inf(x::T) where {T} = + if isinf(x) return x > zero(T) ? floatmax(T) : -floatmax(T) else return x diff --git a/test/correlations_and_spectrum.jl b/test/correlations_and_spectrum.jl index 6c3434b6..985eb155 100644 --- a/test/correlations_and_spectrum.jl +++ b/test/correlations_and_spectrum.jl @@ -4,8 +4,7 @@ c_ops = [sqrt(0.1 * (0.01 + 1)) * a, sqrt(0.1 * (0.01)) * a'] ω_l = range(0, 3, length = 1000) - ω_l1, spec1 = - spectrum(H, ω_l, a', a, c_ops, solver = FFTCorrelation(), progress_bar = false) + ω_l1, spec1 = spectrum(H, ω_l, a', a, c_ops, solver = FFTCorrelation(), progress_bar = false) ω_l2, spec2 = spectrum(H, ω_l, a', a, c_ops) spec1 = spec1 ./ maximum(spec1) spec2 = spec2 ./ maximum(spec2) @@ -14,8 +13,6 @@ test_func2 = maximum(real.(spec2)) * (0.1 / 2)^2 ./ ((ω_l2 .- 1) .^ 2 .+ (0.1 / 2)^2) idxs1 = test_func1 .> 0.05 idxs2 = test_func2 .> 0.05 - @test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < - 0.01 - @test sum(abs2.(spec2[idxs2] .- test_func2[idxs2])) / sum(abs2.(test_func2[idxs2])) < - 0.01 + @test sum(abs2.(spec1[idxs1] .- test_func1[idxs1])) / sum(abs2.(test_func1[idxs1])) < 0.01 + @test sum(abs2.(spec2[idxs2] .- test_func2[idxs2])) / sum(abs2.(test_func2[idxs2])) < 0.01 end \ No newline at end of file diff --git a/test/cuda_ext.jl b/test/cuda_ext.jl index 329567f3..c054f268 100644 --- a/test/cuda_ext.jl +++ b/test/cuda_ext.jl @@ -22,15 +22,11 @@ CUDA.versioninfo() @test_throws DomainError cu(ψdi; word_size = 16) # type conversion of CUDA dense arrays - @test typeof(cu(ψdi; word_size = 64).data) == - typeof(CuArray(ψdi).data) == - CuArray{Int64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdi; word_size = 64).data) == typeof(CuArray(ψdi).data) == CuArray{Int64,1,CUDA.Mem.DeviceBuffer} @test typeof(cu(ψdi; word_size = 32).data) == typeof(CuArray{Int32}(ψdi).data) == CuArray{Int32,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(ψdf; word_size = 64).data) == - typeof(CuArray(ψdf).data) == - CuArray{Float64,1,CUDA.Mem.DeviceBuffer} + @test typeof(cu(ψdf; word_size = 64).data) == typeof(CuArray(ψdf).data) == CuArray{Float64,1,CUDA.Mem.DeviceBuffer} @test typeof(cu(ψdf; word_size = 32).data) == typeof(CuArray{Float32}(ψdf).data) == CuArray{Float32,1,CUDA.Mem.DeviceBuffer} @@ -40,15 +36,11 @@ CUDA.versioninfo() @test typeof(cu(ψdc; word_size = 32).data) == typeof(CuArray{ComplexF32}(ψdc).data) == CuArray{ComplexF32,1,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdi; word_size = 64).data) == - typeof(CuArray(Xdi).data) == - CuArray{Int64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdi; word_size = 64).data) == typeof(CuArray(Xdi).data) == CuArray{Int64,2,CUDA.Mem.DeviceBuffer} @test typeof(cu(Xdi; word_size = 32).data) == typeof(CuArray{Int32}(Xdi).data) == CuArray{Int32,2,CUDA.Mem.DeviceBuffer} - @test typeof(cu(Xdf; word_size = 64).data) == - typeof(CuArray(Xdf).data) == - CuArray{Float64,2,CUDA.Mem.DeviceBuffer} + @test typeof(cu(Xdf; word_size = 64).data) == typeof(CuArray(Xdf).data) == CuArray{Float64,2,CUDA.Mem.DeviceBuffer} @test typeof(cu(Xdf; word_size = 32).data) == typeof(CuArray{Float32}(Xdf).data) == CuArray{Float32,2,CUDA.Mem.DeviceBuffer} @@ -60,27 +52,17 @@ CUDA.versioninfo() CuArray{ComplexF32,2,CUDA.Mem.DeviceBuffer} # type conversion of CUDA sparse arrays - @test typeof(cu(ψsi; word_size = 64).data) == - typeof(CuSparseVector(ψsi).data) == - CuSparseVector{Int64,Int32} - @test typeof(cu(ψsi; word_size = 32).data) == - typeof(CuSparseVector{Int32}(ψsi).data) == - CuSparseVector{Int32,Int32} - @test typeof(cu(ψsf; word_size = 64).data) == - typeof(CuSparseVector(ψsf).data) == - CuSparseVector{Float64,Int32} + @test typeof(cu(ψsi; word_size = 64).data) == typeof(CuSparseVector(ψsi).data) == CuSparseVector{Int64,Int32} + @test typeof(cu(ψsi; word_size = 32).data) == typeof(CuSparseVector{Int32}(ψsi).data) == CuSparseVector{Int32,Int32} + @test typeof(cu(ψsf; word_size = 64).data) == typeof(CuSparseVector(ψsf).data) == CuSparseVector{Float64,Int32} @test typeof(cu(ψsf; word_size = 32).data) == typeof(CuSparseVector{Float32}(ψsf).data) == CuSparseVector{Float32,Int32} - @test typeof(cu(ψsc; word_size = 64).data) == - typeof(CuSparseVector(ψsc).data) == - CuSparseVector{ComplexF64,Int32} + @test typeof(cu(ψsc; word_size = 64).data) == typeof(CuSparseVector(ψsc).data) == CuSparseVector{ComplexF64,Int32} @test typeof(cu(ψsc; word_size = 32).data) == typeof(CuSparseVector{ComplexF32}(ψsc).data) == CuSparseVector{ComplexF32,Int32} - @test typeof(cu(Xsi; word_size = 64).data) == - typeof(CuSparseMatrixCSC(Xsi).data) == - CuSparseMatrixCSC{Int64,Int32} + @test typeof(cu(Xsi; word_size = 64).data) == typeof(CuSparseMatrixCSC(Xsi).data) == CuSparseMatrixCSC{Int64,Int32} @test typeof(cu(Xsi; word_size = 32).data) == typeof(CuSparseMatrixCSC{Int32}(Xsi).data) == CuSparseMatrixCSC{Int32,Int32} @@ -101,6 +83,5 @@ CUDA.versioninfo() @test typeof(CuSparseMatrixCSR(Xsf).data) == CuSparseMatrixCSR{Float64,Int32} @test typeof(CuSparseMatrixCSR{Float32}(Xsf).data) == CuSparseMatrixCSR{Float32,Int32} @test typeof(CuSparseMatrixCSR(Xsc).data) == CuSparseMatrixCSR{ComplexF64,Int32} - @test typeof(CuSparseMatrixCSR{ComplexF32}(Xsc).data) == - CuSparseMatrixCSR{ComplexF32,Int32} + @test typeof(CuSparseMatrixCSR{ComplexF32}(Xsc).data) == CuSparseMatrixCSR{ComplexF32,Int32} end diff --git a/test/dynamical-shifted-fock.jl b/test/dynamical-shifted-fock.jl index 509988ac..b3668bd5 100644 --- a/test/dynamical-shifted-fock.jl +++ b/test/dynamical-shifted-fock.jl @@ -23,33 +23,24 @@ F = p.F U = p.U a = op_list[1] - Δ * a' * a + F * (a + a') + U * a'^2 * a^2 + return Δ * a' * a + F * (a + a') + U * a'^2 * a^2 end function c_ops_dsf(op_list, p) κ = p.κ a = op_list[1] - [√κ * a] + return [√κ * a] end function e_ops_dsf(op_list, p) a = op_list[1] - [a' * a, a] + return [a' * a, a] end op_list = [a] ψ0 = fock(N, 0) α0_l = [α0] dsf_params = (Δ = Δ, F = F, κ = κ, U = U) - sol_dsf_me = dsf_mesolve( - H_dsf, - ψ0, - tlist, - c_ops_dsf, - op_list, - α0_l, - dsf_params, - e_ops = e_ops_dsf, - progress_bar = false, - ) + sol_dsf_me = + dsf_mesolve(H_dsf, ψ0, tlist, c_ops_dsf, op_list, α0_l, dsf_params, e_ops = e_ops_dsf, progress_bar = false) sol_dsf_mc = dsf_mcsolve( H_dsf, ψ0, @@ -63,10 +54,8 @@ n_traj = 500, ) val_ss = abs2(sol0.expect[1, end]) - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / - (val_ss * length(tlist)) < 0.1 - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / - (val_ss * length(tlist)) < 0.1 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / (val_ss * length(tlist)) < 0.1 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / (val_ss * length(tlist)) < 0.1 # Two cavities case F = 2 @@ -89,14 +78,7 @@ c_ops0 = [√κ * a10, √κ * a20] ρ0 = kron(coherent(N0, α0), coherent(N0, α0)) - sol0 = mesolve( - H0, - ρ0, - tlist, - c_ops0, - e_ops = [a10' * a10, a20' * a20], - progress_bar = false, - ) + sol0 = mesolve(H0, ρ0, tlist, c_ops0, e_ops = [a10' * a10, a20' * a20], progress_bar = false) N = 5 a1 = kron(destroy(N), qeye(N)) @@ -107,38 +89,29 @@ U = p.U J = p.J a1, a2 = op_list - Δ * a1' * a1 + - Δ * a2' * a2 + - U * a1'^2 * a1^2 + - U * a2'^2 * a2^2 + - F * (a1 + a1') + - J * (a1' * a2 + a1 * a2') + return Δ * a1' * a1 + + Δ * a2' * a2 + + U * a1'^2 * a1^2 + + U * a2'^2 * a2^2 + + F * (a1 + a1') + + J * (a1' * a2 + a1 * a2') end function c_ops_dsf2(op_list, p) κ = p.κ a1, a2 = op_list - [√κ * a1, √κ * a2] + return [√κ * a1, √κ * a2] end function e_ops_dsf2(op_list, p) a1, a2 = op_list - [a1' * a1, a2' * a2] + return [a1' * a1, a2' * a2] end op_list = [a1, a2] ψ0 = kron(fock(N, 0), fock(N, 0)) α0_l = [α0, α0] dsf_params = (Δ = Δ, F = F, κ = κ, U = U, J = J) - sol_dsf_me = dsf_mesolve( - H_dsf2, - ψ0, - tlist, - c_ops_dsf2, - op_list, - α0_l, - dsf_params, - e_ops = e_ops_dsf2, - progress_bar = false, - ) + sol_dsf_me = + dsf_mesolve(H_dsf2, ψ0, tlist, c_ops_dsf2, op_list, α0_l, dsf_params, e_ops = e_ops_dsf2, progress_bar = false) sol_dsf_mc = dsf_mcsolve( H_dsf2, ψ0, @@ -153,12 +126,8 @@ ) val_ss = abs2(sol0.expect[1, end]) - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / - (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / - (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_me.expect[2, :])) / - (val_ss * length(tlist)) < 0.6 - @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_mc.expect[2, :])) / - (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_me.expect[1, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[1, :] .- sol_dsf_mc.expect[1, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_me.expect[2, :])) / (val_ss * length(tlist)) < 0.6 + @test sum(abs2.(sol0.expect[2, :] .- sol_dsf_mc.expect[2, :])) / (val_ss * length(tlist)) < 0.6 end \ No newline at end of file diff --git a/test/dynamical_fock_dimension_mesolve.jl b/test/dynamical_fock_dimension_mesolve.jl index 2ef46bbc..e124b670 100644 --- a/test/dynamical_fock_dimension_mesolve.jl +++ b/test/dynamical_fock_dimension_mesolve.jl @@ -15,34 +15,23 @@ Δ = p.Δ F = p.F a = destroy(dims[1]) - Δ * a' * a + F * (a + a') + return Δ * a' * a + F * (a + a') end function c_ops_dfd0(dims, p) κ = p.κ a = destroy(dims[1]) - [√κ * a] + return [√κ * a] end function e_ops_dfd0(dims, p) a = destroy(dims[1]) - [a' * a] + return [a' * a] end maxdims = [150] ψ0 = fock(3, 0) dfd_params = (Δ = Δ, F = F, κ = κ) - sol = dfd_mesolve( - H_dfd0, - ψ0, - t_l, - c_ops_dfd0, - maxdims, - dfd_params, - e_ops = e_ops_dfd0, - progress_bar = false, - ) + sol = dfd_mesolve(H_dfd0, ψ0, t_l, c_ops_dfd0, maxdims, dfd_params, e_ops = e_ops_dfd0, progress_bar = false) - @test sum( - abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16)), - ) < 0.01 + @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 ###################### @@ -57,34 +46,23 @@ Δ = p.Δ F = p.F a = destroy(dims[1]) - Δ * a' * a + F * (a + a') + return Δ * a' * a + F * (a + a') end function c_ops_dfd1(dims, p) κ = p.κ a = destroy(dims[1]) - [√κ * a] + return [√κ * a] end function e_ops_dfd1(dims, p) a = destroy(dims[1]) - [a' * a] + return [a' * a] end maxdims = [150] ψ0 = fock(70, 50) dfd_params = (Δ = Δ, F = F, κ = κ) - sol = dfd_mesolve( - H_dfd1, - ψ0, - t_l, - c_ops_dfd1, - maxdims, - dfd_params, - e_ops = e_ops_dfd1, - progress_bar = false, - ) + sol = dfd_mesolve(H_dfd1, ψ0, t_l, c_ops_dfd1, maxdims, dfd_params, e_ops = e_ops_dfd1, progress_bar = false) - @test sum( - abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16)), - ) < 0.01 + @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) < 0.01 ###################### @@ -105,36 +83,24 @@ J = p.J a = kron(destroy(dims[1]), qeye(dims[2])) b = kron(qeye(dims[1]), destroy(dims[2])) - Δ * a' * a + F * (a + a') + Δ * b' * b + J * (a' * b + a * b') + return Δ * a' * a + F * (a + a') + Δ * b' * b + J * (a' * b + a * b') end function c_ops_dfd2(dims, p) κ = p.κ a = kron(destroy(dims[1]), qeye(dims[2])) b = kron(qeye(dims[1]), destroy(dims[2])) - [√κ * a, √κ * b] + return [√κ * a, √κ * b] end function e_ops_dfd2(dims, p) a = kron(destroy(dims[1]), qeye(dims[2])) b = kron(qeye(dims[1]), destroy(dims[2])) - [a' * a, b' * b] + return [a' * a, b' * b] end maxdims = [50, 50] ψ0 = kron(fock(3, 0), fock(20, 15)) dfd_params = (Δ = Δ, F = F, κ = κ, J = J) - sol = dfd_mesolve( - H_dfd2, - ψ0, - t_l, - c_ops_dfd2, - maxdims, - dfd_params, - e_ops = e_ops_dfd2, - progress_bar = false, - ) + sol = dfd_mesolve(H_dfd2, ψ0, t_l, c_ops_dfd2, maxdims, dfd_params, e_ops = e_ops_dfd2, progress_bar = false) - @test sum( - abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16)), - ) + sum( - abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16)), - ) < 0.01 + @test sum(abs.((sol.expect[1, :] .- sol0.expect[1, :]) ./ (sol0.expect[1, :] .+ 1e-16))) + + sum(abs.((sol.expect[2, :] .- sol0.expect[2, :]) ./ (sol0.expect[2, :] .+ 1e-16))) < 0.01 end \ No newline at end of file diff --git a/test/eigenvalues_and_operators.jl b/test/eigenvalues_and_operators.jl index 590395b9..4e7dd554 100644 --- a/test/eigenvalues_and_operators.jl +++ b/test/eigenvalues_and_operators.jl @@ -33,8 +33,7 @@ vals_d, vecs_d, mat_d = eigenstates(H_d) vals_c, vecs_c, mat_c = eigenstates(H_c) - vals2, vecs2, mat2 = - eigenstates(H_d, sparse = true, sigma = -0.9, k = 10, krylovdim = 30) + vals2, vecs2, mat2 = eigenstates(H_d, sparse = true, sigma = -0.9, k = 10, krylovdim = 30) sort!(vals_c, by = real) sort!(vals2, by = real) @@ -60,24 +59,15 @@ # 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)) - vals3, state3, vecs3 = - eigsolve_al(liouvillian(H, c_ops), 1 \ (40 * κ), k = 10, krylovdim = 50) + vals3, state3, vecs3 = eigsolve_al(liouvillian(H, c_ops), 1 \ (40 * κ), k = 10, krylovdim = 50) idxs = sortperm(vals2, by = abs) vals2 = vals2[idxs][1:10] vecs2 = vecs2[:, idxs][:, 1:10] @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol = 1e-7) @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol = 1e-7) - @test isapprox( - vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), - vec2mat(vecs2[:, 1]), - atol = 1e-7, - ) - @test isapprox( - vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), - vec2mat(vecs3[:, 1]), - atol = 1e-5, - ) + @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs2[:, 1]), atol = 1e-7) + @test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs3[:, 1]), atol = 1e-5) # eigen solve for QuantumObject result = eigenstates(L, sparse = true, sigma = 0.01, k = 10, krylovdim = 50) @@ -99,14 +89,6 @@ @test typeof(result.vectors) <: AbstractMatrix @test isapprox(sum(abs2, vals), sum(abs2, vals2), atol = 1e-7) @test isapprox(abs2(vals2[1]), abs2(vals3[1]), atol = 1e-7) - @test isapprox( - vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), - vec2mat(vecs2[1]).data, - atol = 1e-7, - ) - @test isapprox( - vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), - vec2mat(state3[1]).data, - atol = 1e-5, - ) + @test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(vecs2[1]).data, atol = 1e-7) + @test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(state3[1]).data, atol = 1e-5) end \ No newline at end of file diff --git a/test/generalized_master_equation.jl b/test/generalized_master_equation.jl index 8c2f0bd7..a87d016e 100644 --- a/test/generalized_master_equation.jl +++ b/test/generalized_master_equation.jl @@ -26,10 +26,7 @@ c_ops = [sqrt(0.01) * a2, sqrt(0.01) * sm2] L2 = liouvillian(H_d, c_ops) - @test ( - expect(Xp' * Xp, steadystate(L1)) < 1e-10 && - expect(Xp' * Xp, steadystate(L2)) > 1e-3 - ) + @test (expect(Xp' * Xp, steadystate(L1)) < 1e-10 && expect(Xp' * Xp, steadystate(L2)) > 1e-3) H = 1 * a' * a + 1 * sz / 2 + 1e-5 * (a * sp + a' * sm) @@ -43,6 +40,5 @@ 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)) - @test abs(expect(Xp' * Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < - 1e-4 + @test abs(expect(Xp' * Xp, steadystate(L1)) - n_th(1, Tlist[1])) / n_th(1, Tlist[1]) < 1e-4 end \ No newline at end of file diff --git a/test/jet.jl b/test/jet.jl index 6fc91a32..5025f30b 100644 --- a/test/jet.jl +++ b/test/jet.jl @@ -1,9 +1,5 @@ using JET @testset "Code quality (JET.jl)" begin - JET.test_package( - QuantumToolbox; - target_defined_modules = true, - ignore_missing_comparison = true, - ) + JET.test_package(QuantumToolbox; target_defined_modules = true, ignore_missing_comparison = true) end \ No newline at end of file diff --git a/test/quantum_objects.jl b/test/quantum_objects.jl index 93a903f1..9d888569 100644 --- a/test/quantum_objects.jl +++ b/test/quantum_objects.jl @@ -183,39 +183,34 @@ a_dims = a.dims a_size = size(a) a_isherm = ishermitian(a) - @test opstring == - "Quantum Object: type=SuperOperator dims=$a_dims size=$a_size\n$datastring" + @test opstring == "Quantum Object: type=SuperOperator dims=$a_dims size=$a_size\n$datastring" opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) ψ_dims = ψ.dims ψ_size = size(ψ) - @test opstring == - "Quantum Object: type=Ket dims=$ψ_dims size=$ψ_size\n$datastring" + @test opstring == "Quantum Object: type=Ket dims=$ψ_dims size=$ψ_size\n$datastring" ψ = ψ' opstring = sprint((t, s) -> show(t, "text/plain", s), ψ) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ.data) ψ_dims = ψ.dims ψ_size = size(ψ) - @test opstring == - "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" + @test opstring == "Quantum Object: type=Bra dims=$ψ_dims size=$ψ_size\n$datastring" ψ2 = Qobj(rand(ComplexF64, 4), type = OperatorKet) opstring = sprint((t, s) -> show(t, "text/plain", s), ψ2) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ2.data) ψ2_dims = ψ2.dims ψ2_size = size(ψ2) - @test opstring == - "Quantum Object: type=OperatorKet dims=$ψ2_dims size=$ψ2_size\n$datastring" + @test opstring == "Quantum Object: type=OperatorKet dims=$ψ2_dims size=$ψ2_size\n$datastring" ψ2 = ψ2' opstring = sprint((t, s) -> show(t, "text/plain", s), ψ2) datastring = sprint((t, s) -> show(t, "text/plain", s), ψ2.data) ψ2_dims = ψ2.dims ψ2_size = size(ψ2) - @test opstring == - "Quantum Object: type=OperatorBra dims=$ψ2_dims size=$ψ2_size\n$datastring" + @test opstring == "Quantum Object: type=OperatorBra dims=$ψ2_dims size=$ψ2_size\n$datastring" # get coherence ψ = coherent(30, 3) @@ -247,9 +242,7 @@ a = destroy(20) for op in ((+), (-), (*), (^)) A = broadcast(op, a, a) - @test A.data == broadcast(op, a.data, a.data) && - A.type == a.type && - A.dims == a.dims + @test A.data == broadcast(op, a.data, a.data) && A.type == a.type && A.dims == a.dims A = broadcast(op, 2.1, a) @test A.data == broadcast(op, 2.1, a.data) && A.type == a.type && A.dims == a.dims diff --git a/test/steady_state.jl b/test/steady_state.jl index 5d09bfc1..75b7d653 100644 --- a/test/steady_state.jl +++ b/test/steady_state.jl @@ -18,16 +18,7 @@ psi0 = fock(N, 3) t_l = LinRange(0, 200, 1000) H_t_f = TimeDependentOperatorSum([(t, p) -> sin(t)], [liouvillian(H_t)]) - sol_me = mesolve( - H, - psi0, - t_l, - c_ops, - e_ops = e_ops, - H_t = H_t_f, - alg = Vern7(), - progress_bar = false, - ) + sol_me = mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, H_t = H_t_f, alg = Vern7(), progress_bar = false) ρ_ss = steadystate_floquet(H, c_ops, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1) @test abs(sum(sol_me.expect[1, end-100:end]) / 101 - expect(e_ops[1], ρ_ss)) < 1e-2 end \ No newline at end of file diff --git a/test/time_evolution_and_partial_trace.jl b/test/time_evolution_and_partial_trace.jl index 3a8cd181..2944d32e 100644 --- a/test/time_evolution_and_partial_trace.jl +++ b/test/time_evolution_and_partial_trace.jl @@ -22,8 +22,7 @@ e_ops = [a_d * a] psi0 = basis(N, 3) t_l = LinRange(0, 100, 1000) - sol_me = - mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, alg = Vern7(), progress_bar = false) + sol_me = mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, alg = Vern7(), progress_bar = false) sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj = 500, e_ops = e_ops, progress_bar = false) @test sum(abs.(sol_mc.expect .- sol_me.expect)) / length(t_l) < 0.1 @@ -45,18 +44,8 @@ psi0_2 = normalize(fock(2, 0) + fock(2, 1)) psi0 = kron(psi0_1, psi0_2) t_l = LinRange(0, 20 / γ1, 1000) - sol_me = - mesolve(H, psi0, t_l, c_ops, e_ops = [sp1 * sm1, sp2 * sm2], progress_bar = false) - sol_mc = mcsolve( - H, - psi0, - t_l, - c_ops, - n_traj = 500, - e_ops = [sp1 * sm1, sp2 * sm2], - progress_bar = false, - ) + sol_me = mesolve(H, psi0, t_l, c_ops, e_ops = [sp1 * sm1, sp2 * sm2], progress_bar = false) + sol_mc = mcsolve(H, psi0, t_l, c_ops, n_traj = 500, e_ops = [sp1 * sm1, sp2 * sm2], progress_bar = false) @test sum(abs.(sol_mc.expect[1:2, :] .- sol_me.expect[1:2, :])) / length(t_l) < 0.1 - @test expect(sp1 * sm1, sol_me.states[end]) ≈ - expect(sigmap() * sigmam(), ptrace(sol_me.states[end], 1)) + @test expect(sp1 * sm1, sol_me.states[end]) ≈ expect(sigmap() * sigmam(), ptrace(sol_me.states[end], 1)) end \ No newline at end of file