From d773b0e7c97d1c6cbe2cc287a93a168735200041 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 17 Feb 2025 13:02:04 +0100 Subject: [PATCH 1/5] All working except the type inference --- src/QuantumToolbox.jl | 2 +- .../callback_helpers/callback_helpers.jl | 18 +- .../mcsolve_callback_helpers.jl | 30 +- .../mesolve_callback_helpers.jl | 8 +- .../sesolve_callback_helpers.jl | 8 +- .../smesolve_callback_helpers.jl | 10 +- .../ssesolve_callback_helpers.jl | 10 +- test/core-test/time_evolution.jl | 364 +++++++++--------- 8 files changed, 225 insertions(+), 225 deletions(-) diff --git a/src/QuantumToolbox.jl b/src/QuantumToolbox.jl index e4835221b..d06979dda 100644 --- a/src/QuantumToolbox.jl +++ b/src/QuantumToolbox.jl @@ -53,7 +53,7 @@ import SciMLOperators: concretize import LinearSolve: LinearProblem, SciMLLinearSolveAlgorithm, KrylovJL_MINRES, KrylovJL_GMRES import DiffEqBase: get_tstops -import DiffEqCallbacks: PeriodicCallback, PresetTimeCallback, TerminateSteadyState +import DiffEqCallbacks: PeriodicCallback, FunctionCallingCallback, FunctionCallingAffect, TerminateSteadyState import OrdinaryDiffEqCore: OrdinaryDiffEqAlgorithm import OrdinaryDiffEqTsit5: Tsit5 import DiffEqNoiseProcess: RealWienerProcess!, RealWienerProcess diff --git a/src/time_evolution/callback_helpers/callback_helpers.jl b/src/time_evolution/callback_helpers/callback_helpers.jl index 4170635a8..9f628767d 100644 --- a/src/time_evolution/callback_helpers/callback_helpers.jl +++ b/src/time_evolution/callback_helpers/callback_helpers.jl @@ -56,8 +56,8 @@ function _generate_save_callback(e_ops, tlist, progress_bar, method) expvals = e_ops isa Nothing ? nothing : Array{ComplexF64}(undef, length(e_ops), length(tlist)) - _save_affect! = method(e_ops_data, progr, Ref(1), expvals) - return PresetTimeCallback(tlist, _save_affect!, save_positions = (false, false)) + _save_func = method(e_ops_data, progr, Ref(1), expvals) + return FunctionCallingCallback(_save_func, funcat=tlist) end function _generate_stochastic_save_callback(e_ops, sc_ops, tlist, store_measurement, progress_bar, method) @@ -69,8 +69,8 @@ function _generate_stochastic_save_callback(e_ops, sc_ops, tlist, store_measurem expvals = e_ops isa Nothing ? nothing : Array{ComplexF64}(undef, length(e_ops), length(tlist)) m_expvals = getVal(store_measurement) ? Array{Float64}(undef, length(sc_ops), length(tlist) - 1) : nothing - _save_affect! = method(store_measurement, e_ops_data, m_ops_data, progr, Ref(1), expvals, m_expvals) - return PresetTimeCallback(tlist, _save_affect!, save_positions = (false, false)) + _save_func = method(store_measurement, e_ops_data, m_ops_data, progr, Ref(1), expvals, m_expvals) + return FunctionCallingCallback(_save_func, funcat=tlist) end ## @@ -98,20 +98,20 @@ function _get_m_expvals(integrator::AbstractODESolution, method::Type{SF}) where if cb isa Nothing return nothing else - return cb.affect!.m_expvals + return cb.affect!.func.m_expvals end end #= With this function we extract the e_ops from the SaveFuncMCSolve `affect!` function of the callback of the integrator. - This callback can only be a PresetTimeCallback (DiscreteCallback). + This callback can only be a FunctionCallingCallback (DiscreteCallback). =# function _get_e_ops(integrator::AbstractODEIntegrator, method::Type{SF}) where {SF<:AbstractSaveFunc} cb = _get_save_callback(integrator, method) if cb isa Nothing return nothing else - return cb.affect!.e_ops + return cb.affect!.func.e_ops end end @@ -121,7 +121,7 @@ function _get_expvals(sol::AbstractODESolution, method::Type{SF}) where {SF<:Abs if cb isa Nothing return nothing else - return cb.affect!.expvals + return cb.affect!.func.expvals end end @@ -151,7 +151,7 @@ function _get_save_callback(cb::CallbackSet, method::Type{SF}) where {SF<:Abstra end end function _get_save_callback(cb::DiscreteCallback, ::Type{SF}) where {SF<:AbstractSaveFunc} - if typeof(cb.affect!) <: AbstractSaveFunc + if typeof(cb.affect!) <: FunctionCallingAffect && typeof(cb.affect!.func) <: AbstractSaveFunc return cb end return nothing diff --git a/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl b/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl index b0095e705..52ae1dc45 100644 --- a/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl @@ -8,7 +8,7 @@ struct SaveFuncMCSolve{TE,IT,TEXPV} <: AbstractSaveFunc expvals::TEXPV end -(f::SaveFuncMCSolve)(integrator) = _save_func_mcsolve(integrator, f.e_ops, f.iter, f.expvals) +(f::SaveFuncMCSolve)(u, t, integrator) = _save_func_mcsolve(u, integrator, f.e_ops, f.iter, f.expvals) _get_save_callback_idx(cb, ::Type{SaveFuncMCSolve}) = _mcsolve_has_continuous_jump(cb) ? 1 : 2 @@ -52,10 +52,10 @@ end ## -function _save_func_mcsolve(integrator, e_ops, iter, expvals) +function _save_func_mcsolve(u, integrator, e_ops, iter, expvals) cache_mc = _mc_get_jump_callback(integrator).affect!.cache_mc - copyto!(cache_mc, integrator.u) + copyto!(cache_mc, u) normalize!(cache_mc) ψ = cache_mc _expect = op -> dot(ψ, op, ψ) @@ -114,8 +114,8 @@ function _generate_mcsolve_kwargs(ψ0, T, e_ops, tlist, c_ops, jump_callback, rn else expvals = Array{ComplexF64}(undef, length(e_ops), length(tlist)) - _save_affect! = SaveFuncMCSolve(get_data.(e_ops), Ref(1), expvals) - cb2 = PresetTimeCallback(tlist, _save_affect!, save_positions = (false, false)) + _save_func = SaveFuncMCSolve(get_data.(e_ops), Ref(1), expvals) + cb2 = FunctionCallingCallback(_save_func, funcat=tlist) kwargs2 = haskey(kwargs, :callback) ? merge(kwargs, (callback = CallbackSet(cb1, cb2, kwargs.callback),)) : merge(kwargs, (callback = CallbackSet(cb1, cb2),)) @@ -214,11 +214,11 @@ function _mcsolve_initialize_callbacks(cb::CallbackSet, tlist, traj_rng) if _mcsolve_has_continuous_jump(cb) idx = 1 - if cb_discrete[idx].affect! isa SaveFuncMCSolve - e_ops = cb_discrete[idx].affect!.e_ops - expvals = similar(cb_discrete[idx].affect!.expvals) - _save_affect! = SaveFuncMCSolve(e_ops, Ref(1), expvals) - cb_save = (PresetTimeCallback(tlist, _save_affect!, save_positions = (false, false)),) + if cb_discrete[idx].affect!.func isa SaveFuncMCSolve + e_ops = cb_discrete[idx].affect!.func.e_ops + expvals = similar(cb_discrete[idx].affect!.func.expvals) + _save_func = SaveFuncMCSolve(e_ops, Ref(1), expvals) + cb_save = (FunctionCallingCallback(_save_func, funcat=tlist),) else cb_save = () end @@ -229,11 +229,11 @@ function _mcsolve_initialize_callbacks(cb::CallbackSet, tlist, traj_rng) return CallbackSet((cb_jump, cb_continuous[2:end]...), (cb_save..., cb_discrete[2:end]...)) else idx = 2 - if cb_discrete[idx].affect! isa SaveFuncMCSolve - e_ops = cb_discrete[idx].affect!.e_ops - expvals = similar(cb_discrete[idx].affect!.expvals) - _save_affect! = SaveFuncMCSolve(e_ops, Ref(1), expvals) - cb_save = (PresetTimeCallback(tlist, _save_affect!, save_positions = (false, false)),) + if cb_discrete[idx].affect!.func isa SaveFuncMCSolve + e_ops = cb_discrete[idx].affect!.func.e_ops + expvals = similar(cb_discrete[idx].affect!.func.expvals) + _save_func = SaveFuncMCSolve(e_ops, Ref(1), expvals) + cb_save = (FunctionCallingCallback(_save_func, funcat=tlist),) else cb_save = () end diff --git a/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl b/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl index ee253d765..b6b448211 100644 --- a/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl @@ -9,7 +9,7 @@ struct SaveFuncMESolve{TE,PT<:Union{Nothing,ProgressBar},IT,TEXPV<:Union{Nothing expvals::TEXPV end -(f::SaveFuncMESolve)(integrator) = _save_func_mesolve(integrator, f.e_ops, f.progr, f.iter, f.expvals) +(f::SaveFuncMESolve)(u, t, integrator) = _save_func_mesolve(u, integrator, f.e_ops, f.progr, f.iter, f.expvals) (f::SaveFuncMESolve{Nothing})(integrator) = _save_func(integrator, f.progr) _get_e_ops_data(e_ops, ::Type{SaveFuncMESolve}) = [_generate_mesolve_e_op(op) for op in e_ops] # Broadcasting generates type instabilities on Julia v1.10 @@ -17,12 +17,12 @@ _get_e_ops_data(e_ops, ::Type{SaveFuncMESolve}) = [_generate_mesolve_e_op(op) fo ## # When e_ops is a list of operators -function _save_func_mesolve(integrator, e_ops, progr, iter, expvals) +function _save_func_mesolve(u, integrator, e_ops, progr, iter, expvals) # This is equivalent to tr(op * ρ), when both are matrices. # The advantage of using this convention is that We don't need # to reshape u to make it a matrix, but we reshape the e_ops once. - ρ = integrator.u + ρ = u _expect = op -> dot(op, ρ) @. expvals[:, iter[]] = _expect(e_ops) iter[] += 1 @@ -35,7 +35,7 @@ function _mesolve_callbacks_new_e_ops!(integrator::AbstractODEIntegrator, e_ops) if cb isa Nothing return nothing else - cb.affect!.e_ops .= e_ops # Only works if e_ops is a Vector of operators + cb.affect!.func.e_ops .= e_ops # Only works if e_ops is a Vector of operators return nothing end end diff --git a/src/time_evolution/callback_helpers/sesolve_callback_helpers.jl b/src/time_evolution/callback_helpers/sesolve_callback_helpers.jl index e5205ffc6..2bbff8bf0 100644 --- a/src/time_evolution/callback_helpers/sesolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/sesolve_callback_helpers.jl @@ -9,16 +9,16 @@ struct SaveFuncSESolve{TE,PT<:Union{Nothing,ProgressBar},IT,TEXPV<:Union{Nothing expvals::TEXPV end -(f::SaveFuncSESolve)(integrator) = _save_func_sesolve(integrator, f.e_ops, f.progr, f.iter, f.expvals) -(f::SaveFuncSESolve{Nothing})(integrator) = _save_func(integrator, f.progr) # Common for both mesolve and sesolve +(f::SaveFuncSESolve)(u, t, integrator) = _save_func_sesolve(u, integrator, f.e_ops, f.progr, f.iter, f.expvals) +(f::SaveFuncSESolve{Nothing})(u, t, integrator) = _save_func(integrator, f.progr) # Common for both mesolve and sesolve _get_e_ops_data(e_ops, ::Type{SaveFuncSESolve}) = get_data.(e_ops) ## # When e_ops is a list of operators -function _save_func_sesolve(integrator, e_ops, progr, iter, expvals) - ψ = integrator.u +function _save_func_sesolve(u, integrator, e_ops, progr, iter, expvals) + ψ = u _expect = op -> dot(ψ, op, ψ) @. expvals[:, iter[]] = _expect(e_ops) iter[] += 1 diff --git a/src/time_evolution/callback_helpers/smesolve_callback_helpers.jl b/src/time_evolution/callback_helpers/smesolve_callback_helpers.jl index ab14bf81b..6fb39c14b 100644 --- a/src/time_evolution/callback_helpers/smesolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/smesolve_callback_helpers.jl @@ -20,9 +20,9 @@ struct SaveFuncSMESolve{ m_expvals::TMEXPV end -(f::SaveFuncSMESolve)(integrator) = - _save_func_smesolve(integrator, f.e_ops, f.m_ops, f.progr, f.iter, f.expvals, f.m_expvals) -(f::SaveFuncSMESolve{false,Nothing})(integrator) = _save_func(integrator, f.progr) # Common for both all solvers +(f::SaveFuncSMESolve)(u, t, integrator) = + _save_func_smesolve(u, integrator, f.e_ops, f.m_ops, f.progr, f.iter, f.expvals, f.m_expvals) +(f::SaveFuncSMESolve{false,Nothing})(u, t, integrator) = _save_func(integrator, f.progr) # Common for both all solvers _get_e_ops_data(e_ops, ::Type{SaveFuncSMESolve}) = _get_e_ops_data(e_ops, SaveFuncMESolve) _get_m_ops_data(sc_ops, ::Type{SaveFuncSMESolve}) = @@ -31,12 +31,12 @@ _get_m_ops_data(sc_ops, ::Type{SaveFuncSMESolve}) = ## # When e_ops is a list of operators -function _save_func_smesolve(integrator, e_ops, m_ops, progr, iter, expvals, m_expvals) +function _save_func_smesolve(u, integrator, e_ops, m_ops, progr, iter, expvals, m_expvals) # This is equivalent to tr(op * ρ), when both are matrices. # The advantage of using this convention is that We don't need # to reshape u to make it a matrix, but we reshape the e_ops once. - ρ = integrator.u + ρ = u _expect = op -> dot(op, ρ) diff --git a/src/time_evolution/callback_helpers/ssesolve_callback_helpers.jl b/src/time_evolution/callback_helpers/ssesolve_callback_helpers.jl index bd20d2d2c..c84cd7e5e 100644 --- a/src/time_evolution/callback_helpers/ssesolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/ssesolve_callback_helpers.jl @@ -20,9 +20,9 @@ struct SaveFuncSSESolve{ m_expvals::TMEXPV end -(f::SaveFuncSSESolve)(integrator) = - _save_func_ssesolve(integrator, f.e_ops, f.m_ops, f.progr, f.iter, f.expvals, f.m_expvals) -(f::SaveFuncSSESolve{false,Nothing})(integrator) = _save_func(integrator, f.progr) # Common for both all solvers +(f::SaveFuncSSESolve)(u, t, integrator) = + _save_func_ssesolve(u, integrator, f.e_ops, f.m_ops, f.progr, f.iter, f.expvals, f.m_expvals) +(f::SaveFuncSSESolve{false,Nothing})(u, t, integrator) = _save_func(integrator, f.progr) # Common for both all solvers _get_e_ops_data(e_ops, ::Type{SaveFuncSSESolve}) = get_data.(e_ops) _get_m_ops_data(sc_ops, ::Type{SaveFuncSSESolve}) = map(op -> Hermitian(get_data(op) + get_data(op)'), sc_ops) @@ -32,8 +32,8 @@ _get_save_callback_idx(cb, ::Type{SaveFuncSSESolve}) = 2 # The first one is the ## # When e_ops is a list of operators -function _save_func_ssesolve(integrator, e_ops, m_ops, progr, iter, expvals, m_expvals) - ψ = integrator.u +function _save_func_ssesolve(u, integrator, e_ops, m_ops, progr, iter, expvals, m_expvals) + ψ = u _expect = op -> dot(ψ, op, ψ) diff --git a/test/core-test/time_evolution.jl b/test/core-test/time_evolution.jl index 55be066a3..bafc07007 100644 --- a/test/core-test/time_evolution.jl +++ b/test/core-test/time_evolution.jl @@ -447,188 +447,188 @@ @test allocs_tot < 570000 # TODO: Fix this high number of allocations end - @testset "Type Inference mesolve" begin - coef(p, t) = exp(-t) - ad_t = QobjEvo(a', coef) - @inferred mesolveProblem(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) - @inferred mesolveProblem(H, ψ0, [0, 10], c_ops, e_ops = e_ops, progress_bar = Val(false)) - @inferred mesolveProblem(H, ψ0_int, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) - @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) - @inferred mesolve(H, ψ0, tlist, c_ops, progress_bar = Val(false)) - @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, saveat = tlist, progress_bar = Val(false)) - @inferred mesolve(H, ψ0, tlist, (a, ad_t), e_ops = (a' * a, a'), progress_bar = Val(false)) # We test the type inference for Tuple - @inferred mesolve(H_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) - @inferred mesolve(H_td2, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) - @inferred mesolve(L_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) - end - - @testset "Type Inference mcsolve" begin - @inferred mcsolveEnsembleProblem( - H, - ψ0, - tlist, - c_ops, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - rng = rng, - ) - @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, e_ops = e_ops, progress_bar = Val(false), rng = rng) - @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, progress_bar = Val(true), rng = rng) - @inferred mcsolve(H, ψ0, [0, 10], c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) - @inferred mcsolve(H, ψ0_int, tlist, c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) - @inferred mcsolve( - H, - ψ0, - tlist, - (a, a'), - e_ops = (a' * a, a'), - ntraj = 5, - progress_bar = Val(false), - rng = rng, - ) # We test the type inference for Tuple of different types - @inferred mcsolve( - H_td, - ψ0, - tlist, - c_ops, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - params = p, - rng = rng, - ) - end - - @testset "Type Inference ssesolve" begin - c_ops_tuple = Tuple(c_ops) # To avoid type instability, we must have a Tuple instead of a Vector - @inferred ssesolveEnsembleProblem( - H, - ψ0, - tlist, - c_ops_tuple, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - rng = rng, - ) - @inferred ssesolve( - H, - ψ0, - tlist, - c_ops_tuple, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - rng = rng, - ) - @inferred ssesolve(H, ψ0, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(true), rng = rng) - @inferred ssesolve(H, ψ0, [0, 10], c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) - @inferred ssesolve(H, ψ0_int, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) - @inferred ssesolve( - H, - ψ0, - tlist, - c_ops_tuple, - ntraj = 5, - e_ops = (a' * a, a'), - progress_bar = Val(false), - rng = rng, - ) # We test the type inference for Tuple of different types - @inferred ssesolve( - H_td, - ψ0, - tlist, - c_ops_tuple, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - params = p, - rng = rng, - ) - end - - @testset "Type Inference smesolve" begin - # To avoid type instability, we must have a Tuple instead of a Vector - c_ops_sme_tuple = Tuple(c_ops_sme) - sc_ops_sme_tuple = Tuple(sc_ops_sme) - c_ops_sme2_tuple = Tuple(c_ops_sme2) - sc_ops_sme2_tuple = sc_ops_sme2 # This is an `AbstractQuantumObject` - @inferred smesolveEnsembleProblem( - H, - ψ0, - tlist, - c_ops_sme_tuple, - sc_ops_sme_tuple, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - rng = rng, - ) - @inferred smesolve( - H, - ψ0, - tlist, - c_ops_sme_tuple, - sc_ops_sme_tuple, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - rng = rng, - ) - @inferred smesolve( - H, - ψ0, - tlist, - c_ops_sme2_tuple, - sc_ops_sme2_tuple, - ntraj = 5, - e_ops = e_ops, - progress_bar = Val(false), - rng = rng, - ) - @inferred smesolve( - H, - ψ0, - tlist, - c_ops_sme_tuple, - sc_ops_sme_tuple, - ntraj = 5, - progress_bar = Val(true), - rng = rng, - ) - @inferred smesolve( - H, - ψ0, - [0, 10], - c_ops_sme_tuple, - sc_ops_sme_tuple, - ntraj = 5, - progress_bar = Val(false), - rng = rng, - ) - @inferred smesolve( - H, - ψ0_int, - tlist, - c_ops_sme_tuple, - sc_ops_sme_tuple, - ntraj = 5, - progress_bar = Val(false), - rng = rng, - ) - @inferred smesolve( - H, - ψ0, - tlist, - c_ops_sme_tuple, - sc_ops_sme_tuple, - ntraj = 5, - e_ops = (a' * a, a'), - progress_bar = Val(false), - rng = rng, - ) # We test the type inference for Tuple of different types - end + # @testset "Type Inference mesolve" begin + # coef(p, t) = exp(-t) + # ad_t = QobjEvo(a', coef) + # @inferred mesolveProblem(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) + # @inferred mesolveProblem(H, ψ0, [0, 10], c_ops, e_ops = e_ops, progress_bar = Val(false)) + # @inferred mesolveProblem(H, ψ0_int, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) + # @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) + # @inferred mesolve(H, ψ0, tlist, c_ops, progress_bar = Val(false)) + # @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, saveat = tlist, progress_bar = Val(false)) + # @inferred mesolve(H, ψ0, tlist, (a, ad_t), e_ops = (a' * a, a'), progress_bar = Val(false)) # We test the type inference for Tuple + # @inferred mesolve(H_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) + # @inferred mesolve(H_td2, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) + # @inferred mesolve(L_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) + # end + + # @testset "Type Inference mcsolve" begin + # @inferred mcsolveEnsembleProblem( + # H, + # ψ0, + # tlist, + # c_ops, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, e_ops = e_ops, progress_bar = Val(false), rng = rng) + # @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, progress_bar = Val(true), rng = rng) + # @inferred mcsolve(H, ψ0, [0, 10], c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) + # @inferred mcsolve(H, ψ0_int, tlist, c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) + # @inferred mcsolve( + # H, + # ψ0, + # tlist, + # (a, a'), + # e_ops = (a' * a, a'), + # ntraj = 5, + # progress_bar = Val(false), + # rng = rng, + # ) # We test the type inference for Tuple of different types + # @inferred mcsolve( + # H_td, + # ψ0, + # tlist, + # c_ops, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # params = p, + # rng = rng, + # ) + # end + + # @testset "Type Inference ssesolve" begin + # c_ops_tuple = Tuple(c_ops) # To avoid type instability, we must have a Tuple instead of a Vector + # @inferred ssesolveEnsembleProblem( + # H, + # ψ0, + # tlist, + # c_ops_tuple, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred ssesolve( + # H, + # ψ0, + # tlist, + # c_ops_tuple, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred ssesolve(H, ψ0, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(true), rng = rng) + # @inferred ssesolve(H, ψ0, [0, 10], c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) + # @inferred ssesolve(H, ψ0_int, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) + # @inferred ssesolve( + # H, + # ψ0, + # tlist, + # c_ops_tuple, + # ntraj = 5, + # e_ops = (a' * a, a'), + # progress_bar = Val(false), + # rng = rng, + # ) # We test the type inference for Tuple of different types + # @inferred ssesolve( + # H_td, + # ψ0, + # tlist, + # c_ops_tuple, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # params = p, + # rng = rng, + # ) + # end + + # @testset "Type Inference smesolve" begin + # # To avoid type instability, we must have a Tuple instead of a Vector + # c_ops_sme_tuple = Tuple(c_ops_sme) + # sc_ops_sme_tuple = Tuple(sc_ops_sme) + # c_ops_sme2_tuple = Tuple(c_ops_sme2) + # sc_ops_sme2_tuple = sc_ops_sme2 # This is an `AbstractQuantumObject` + # @inferred smesolveEnsembleProblem( + # H, + # ψ0, + # tlist, + # c_ops_sme_tuple, + # sc_ops_sme_tuple, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred smesolve( + # H, + # ψ0, + # tlist, + # c_ops_sme_tuple, + # sc_ops_sme_tuple, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred smesolve( + # H, + # ψ0, + # tlist, + # c_ops_sme2_tuple, + # sc_ops_sme2_tuple, + # ntraj = 5, + # e_ops = e_ops, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred smesolve( + # H, + # ψ0, + # tlist, + # c_ops_sme_tuple, + # sc_ops_sme_tuple, + # ntraj = 5, + # progress_bar = Val(true), + # rng = rng, + # ) + # @inferred smesolve( + # H, + # ψ0, + # [0, 10], + # c_ops_sme_tuple, + # sc_ops_sme_tuple, + # ntraj = 5, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred smesolve( + # H, + # ψ0_int, + # tlist, + # c_ops_sme_tuple, + # sc_ops_sme_tuple, + # ntraj = 5, + # progress_bar = Val(false), + # rng = rng, + # ) + # @inferred smesolve( + # H, + # ψ0, + # tlist, + # c_ops_sme_tuple, + # sc_ops_sme_tuple, + # ntraj = 5, + # e_ops = (a' * a, a'), + # progress_bar = Val(false), + # rng = rng, + # ) # We test the type inference for Tuple of different types + # end @testset "mcsolve, ssesolve and smesolve reproducibility" begin rng = MersenneTwister(1234) From 1032a6df9ec0936f07be1e2f67f753344f364eab Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 17 Feb 2025 17:02:05 +0100 Subject: [PATCH 2/5] Reduce the allocations threshold in tests --- .../callback_helpers/callback_helpers.jl | 4 +- .../mcsolve_callback_helpers.jl | 6 +- test/core-test/time_evolution.jl | 451 ++++++++++-------- 3 files changed, 254 insertions(+), 207 deletions(-) diff --git a/src/time_evolution/callback_helpers/callback_helpers.jl b/src/time_evolution/callback_helpers/callback_helpers.jl index 9f628767d..e84085b47 100644 --- a/src/time_evolution/callback_helpers/callback_helpers.jl +++ b/src/time_evolution/callback_helpers/callback_helpers.jl @@ -57,7 +57,7 @@ function _generate_save_callback(e_ops, tlist, progress_bar, method) expvals = e_ops isa Nothing ? nothing : Array{ComplexF64}(undef, length(e_ops), length(tlist)) _save_func = method(e_ops_data, progr, Ref(1), expvals) - return FunctionCallingCallback(_save_func, funcat=tlist) + return FunctionCallingCallback(_save_func, funcat = tlist) end function _generate_stochastic_save_callback(e_ops, sc_ops, tlist, store_measurement, progress_bar, method) @@ -70,7 +70,7 @@ function _generate_stochastic_save_callback(e_ops, sc_ops, tlist, store_measurem m_expvals = getVal(store_measurement) ? Array{Float64}(undef, length(sc_ops), length(tlist) - 1) : nothing _save_func = method(store_measurement, e_ops_data, m_ops_data, progr, Ref(1), expvals, m_expvals) - return FunctionCallingCallback(_save_func, funcat=tlist) + return FunctionCallingCallback(_save_func, funcat = tlist) end ## diff --git a/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl b/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl index 52ae1dc45..d96b50202 100644 --- a/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/mcsolve_callback_helpers.jl @@ -115,7 +115,7 @@ function _generate_mcsolve_kwargs(ψ0, T, e_ops, tlist, c_ops, jump_callback, rn expvals = Array{ComplexF64}(undef, length(e_ops), length(tlist)) _save_func = SaveFuncMCSolve(get_data.(e_ops), Ref(1), expvals) - cb2 = FunctionCallingCallback(_save_func, funcat=tlist) + cb2 = FunctionCallingCallback(_save_func, funcat = tlist) kwargs2 = haskey(kwargs, :callback) ? merge(kwargs, (callback = CallbackSet(cb1, cb2, kwargs.callback),)) : merge(kwargs, (callback = CallbackSet(cb1, cb2),)) @@ -218,7 +218,7 @@ function _mcsolve_initialize_callbacks(cb::CallbackSet, tlist, traj_rng) e_ops = cb_discrete[idx].affect!.func.e_ops expvals = similar(cb_discrete[idx].affect!.func.expvals) _save_func = SaveFuncMCSolve(e_ops, Ref(1), expvals) - cb_save = (FunctionCallingCallback(_save_func, funcat=tlist),) + cb_save = (FunctionCallingCallback(_save_func, funcat = tlist),) else cb_save = () end @@ -233,7 +233,7 @@ function _mcsolve_initialize_callbacks(cb::CallbackSet, tlist, traj_rng) e_ops = cb_discrete[idx].affect!.func.e_ops expvals = similar(cb_discrete[idx].affect!.func.expvals) _save_func = SaveFuncMCSolve(e_ops, Ref(1), expvals) - cb_save = (FunctionCallingCallback(_save_func, funcat=tlist),) + cb_save = (FunctionCallingCallback(_save_func, funcat = tlist),) else cb_save = () end diff --git a/test/core-test/time_evolution.jl b/test/core-test/time_evolution.jl index bafc07007..48547f614 100644 --- a/test/core-test/time_evolution.jl +++ b/test/core-test/time_evolution.jl @@ -85,11 +85,11 @@ @testset "Memory Allocations" begin allocs_tot = @allocations sesolve(H, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false)) # Warm-up allocs_tot = @allocations sesolve(H, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false)) - @test allocs_tot < 150 + @test allocs_tot < 100 allocs_tot = @allocations sesolve(H, ψ0, tlist, saveat = [tlist[end]], progress_bar = Val(false)) # Warm-up allocs_tot = @allocations sesolve(H, ψ0, tlist, saveat = [tlist[end]], progress_bar = Val(false)) - @test allocs_tot < 100 + @test allocs_tot < 90 end @testset "Type Inference sesolve" begin @@ -327,21 +327,21 @@ allocs_tot = @allocations mesolve(L, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false)) # Warm-up allocs_tot = @allocations mesolve(L, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false)) - @test allocs_tot < 210 + @test allocs_tot < 180 allocs_tot = @allocations mesolve(L, ψ0, tlist, saveat = [tlist[end]], progress_bar = Val(false)) # Warm-up allocs_tot = @allocations mesolve(L, ψ0, tlist, saveat = [tlist[end]], progress_bar = Val(false)) - @test allocs_tot < 120 + @test allocs_tot < 110 allocs_tot = @allocations mesolve(L_td, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false), params = p) # Warm-up allocs_tot = @allocations mesolve(L_td, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false), params = p) - @test allocs_tot < 210 + @test allocs_tot < 180 allocs_tot = @allocations mesolve(L_td, ψ0, tlist, progress_bar = Val(false), saveat = [tlist[end]], params = p) # Warm-up allocs_tot = @allocations mesolve(L_td, ψ0, tlist, progress_bar = Val(false), saveat = [tlist[end]], params = p) - @test allocs_tot < 120 + @test allocs_tot < 110 end @testset "Memory Allocations (mcsolve)" begin @@ -350,7 +350,7 @@ @allocations mcsolve(H, ψ0, tlist, c_ops, e_ops = e_ops, ntraj = ntraj, progress_bar = Val(false)) # Warm-up allocs_tot = @allocations mcsolve(H, ψ0, tlist, c_ops, e_ops = e_ops, ntraj = ntraj, progress_bar = Val(false)) - @test allocs_tot < 160 * ntraj + 500 # 150 allocations per trajectory + 500 for initialization + @test allocs_tot < 120 * ntraj + 400 # 150 allocations per trajectory + 500 for initialization allocs_tot = @allocations mcsolve( H, @@ -370,22 +370,23 @@ saveat = [tlist[end]], progress_bar = Val(false), ) - @test allocs_tot < 160 * ntraj + 300 # 100 allocations per trajectory + 300 for initialization + @test allocs_tot < 110 * ntraj + 300 # 100 allocations per trajectory + 300 for initialization end @testset "Memory Allocations (ssesolve)" begin + ntraj = 100 allocs_tot = - @allocations ssesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, ntraj = 100, progress_bar = Val(false)) # Warm-up + @allocations ssesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, ntraj = ntraj, progress_bar = Val(false)) # Warm-up allocs_tot = - @allocations ssesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, ntraj = 100, progress_bar = Val(false)) - @test allocs_tot < 1950000 # TODO: Fix this high number of allocations + @allocations ssesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, ntraj = ntraj, progress_bar = Val(false)) + @test allocs_tot < 1100 * ntraj + 400 # TODO: Fix this high number of allocations allocs_tot = @allocations ssesolve( H, ψ0, tlist, c_ops, - ntraj = 100, + ntraj = ntraj, saveat = [tlist[end]], progress_bar = Val(false), ) # Warm-up @@ -394,14 +395,15 @@ ψ0, tlist, c_ops, - ntraj = 100, + ntraj = ntraj, saveat = [tlist[end]], progress_bar = Val(false), ) - @test allocs_tot < 570000 # TODO: Fix this high number of allocations + @test allocs_tot < 1000 * ntraj + 300 # TODO: Fix this high number of allocations end @testset "Memory Allocations (smesolve)" begin + ntraj = 100 allocs_tot = @allocations smesolve( H, ψ0, @@ -409,7 +411,7 @@ c_ops_sme, sc_ops_sme, e_ops = e_ops, - ntraj = 100, + ntraj = ntraj, progress_bar = Val(false), ) # Warm-up allocs_tot = @allocations smesolve( @@ -419,10 +421,10 @@ c_ops_sme, sc_ops_sme, e_ops = e_ops, - ntraj = 100, + ntraj = ntraj, progress_bar = Val(false), ) - @test allocs_tot < 2750000 # TODO: Fix this high number of allocations + @test allocs_tot < 1100 * ntraj + 1800 # TODO: Fix this high number of allocations allocs_tot = @allocations smesolve( H, @@ -430,7 +432,7 @@ tlist, c_ops_sme, sc_ops_sme, - ntraj = 100, + ntraj = ntraj, saveat = [tlist[end]], progress_bar = Val(false), ) # Warm-up @@ -440,195 +442,240 @@ tlist, c_ops_sme, sc_ops_sme, - ntraj = 100, + ntraj = ntraj, + saveat = [tlist[end]], + progress_bar = Val(false), + ) + @test allocs_tot < 1000 * ntraj + 1500 # TODO: Fix this high number of allocations + + # Diagonal Noise Case + allocs_tot = @allocations smesolve( + H, + ψ0, + tlist, + c_ops_sme2, + sc_ops_sme2, + e_ops = e_ops, + ntraj = ntraj, + progress_bar = Val(false), + ) # Warm-up + allocs_tot = @allocations smesolve( + H, + ψ0, + tlist, + c_ops_sme2, + sc_ops_sme2, + e_ops = e_ops, + ntraj = 1, + progress_bar = Val(false), + ) + @test allocs_tot < 600 * ntraj + 1400 # TODO: Fix this high number of allocations + + allocs_tot = @allocations smesolve( + H, + ψ0, + tlist, + c_ops_sme2, + sc_ops_sme2, + ntraj = ntraj, saveat = [tlist[end]], progress_bar = Val(false), + ) # Warm-up + allocs_tot = @allocations smesolve( + H, + ψ0, + tlist, + c_ops_sme2, + sc_ops_sme2, + ntraj = 1, + saveat = [tlist[end]], + progress_bar = Val(false), + ) + @test allocs_tot < 550 * ntraj + 1000 # TODO: Fix this high number of allocations + end + + @testset "Type Inference mesolve" begin + coef(p, t) = exp(-t) + ad_t = QobjEvo(a', coef) + @inferred mesolveProblem(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) + @inferred mesolveProblem(H, ψ0, [0, 10], c_ops, e_ops = e_ops, progress_bar = Val(false)) + @inferred mesolveProblem(H, ψ0_int, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) + @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) + @inferred mesolve(H, ψ0, tlist, c_ops, progress_bar = Val(false)) + @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, saveat = tlist, progress_bar = Val(false)) + @inferred mesolve(H, ψ0, tlist, (a, ad_t), e_ops = (a' * a, a'), progress_bar = Val(false)) # We test the type inference for Tuple + @inferred mesolve(H_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) + @inferred mesolve(H_td2, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) + @inferred mesolve(L_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) + end + + @testset "Type Inference mcsolve" begin + @inferred mcsolveEnsembleProblem( + H, + ψ0, + tlist, + c_ops, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + rng = rng, + ) + @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, e_ops = e_ops, progress_bar = Val(false), rng = rng) + @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, progress_bar = Val(true), rng = rng) + @inferred mcsolve(H, ψ0, [0, 10], c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) + @inferred mcsolve(H, ψ0_int, tlist, c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) + @inferred mcsolve( + H, + ψ0, + tlist, + (a, a'), + e_ops = (a' * a, a'), + ntraj = 5, + progress_bar = Val(false), + rng = rng, + ) # We test the type inference for Tuple of different types + @inferred mcsolve( + H_td, + ψ0, + tlist, + c_ops, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + params = p, + rng = rng, ) - @test allocs_tot < 570000 # TODO: Fix this high number of allocations end - # @testset "Type Inference mesolve" begin - # coef(p, t) = exp(-t) - # ad_t = QobjEvo(a', coef) - # @inferred mesolveProblem(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) - # @inferred mesolveProblem(H, ψ0, [0, 10], c_ops, e_ops = e_ops, progress_bar = Val(false)) - # @inferred mesolveProblem(H, ψ0_int, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) - # @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false)) - # @inferred mesolve(H, ψ0, tlist, c_ops, progress_bar = Val(false)) - # @inferred mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops, saveat = tlist, progress_bar = Val(false)) - # @inferred mesolve(H, ψ0, tlist, (a, ad_t), e_ops = (a' * a, a'), progress_bar = Val(false)) # We test the type inference for Tuple - # @inferred mesolve(H_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) - # @inferred mesolve(H_td2, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) - # @inferred mesolve(L_td, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false), params = p) - # end - - # @testset "Type Inference mcsolve" begin - # @inferred mcsolveEnsembleProblem( - # H, - # ψ0, - # tlist, - # c_ops, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, e_ops = e_ops, progress_bar = Val(false), rng = rng) - # @inferred mcsolve(H, ψ0, tlist, c_ops, ntraj = 5, progress_bar = Val(true), rng = rng) - # @inferred mcsolve(H, ψ0, [0, 10], c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) - # @inferred mcsolve(H, ψ0_int, tlist, c_ops, ntraj = 5, progress_bar = Val(false), rng = rng) - # @inferred mcsolve( - # H, - # ψ0, - # tlist, - # (a, a'), - # e_ops = (a' * a, a'), - # ntraj = 5, - # progress_bar = Val(false), - # rng = rng, - # ) # We test the type inference for Tuple of different types - # @inferred mcsolve( - # H_td, - # ψ0, - # tlist, - # c_ops, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # params = p, - # rng = rng, - # ) - # end - - # @testset "Type Inference ssesolve" begin - # c_ops_tuple = Tuple(c_ops) # To avoid type instability, we must have a Tuple instead of a Vector - # @inferred ssesolveEnsembleProblem( - # H, - # ψ0, - # tlist, - # c_ops_tuple, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred ssesolve( - # H, - # ψ0, - # tlist, - # c_ops_tuple, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred ssesolve(H, ψ0, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(true), rng = rng) - # @inferred ssesolve(H, ψ0, [0, 10], c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) - # @inferred ssesolve(H, ψ0_int, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) - # @inferred ssesolve( - # H, - # ψ0, - # tlist, - # c_ops_tuple, - # ntraj = 5, - # e_ops = (a' * a, a'), - # progress_bar = Val(false), - # rng = rng, - # ) # We test the type inference for Tuple of different types - # @inferred ssesolve( - # H_td, - # ψ0, - # tlist, - # c_ops_tuple, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # params = p, - # rng = rng, - # ) - # end - - # @testset "Type Inference smesolve" begin - # # To avoid type instability, we must have a Tuple instead of a Vector - # c_ops_sme_tuple = Tuple(c_ops_sme) - # sc_ops_sme_tuple = Tuple(sc_ops_sme) - # c_ops_sme2_tuple = Tuple(c_ops_sme2) - # sc_ops_sme2_tuple = sc_ops_sme2 # This is an `AbstractQuantumObject` - # @inferred smesolveEnsembleProblem( - # H, - # ψ0, - # tlist, - # c_ops_sme_tuple, - # sc_ops_sme_tuple, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred smesolve( - # H, - # ψ0, - # tlist, - # c_ops_sme_tuple, - # sc_ops_sme_tuple, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred smesolve( - # H, - # ψ0, - # tlist, - # c_ops_sme2_tuple, - # sc_ops_sme2_tuple, - # ntraj = 5, - # e_ops = e_ops, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred smesolve( - # H, - # ψ0, - # tlist, - # c_ops_sme_tuple, - # sc_ops_sme_tuple, - # ntraj = 5, - # progress_bar = Val(true), - # rng = rng, - # ) - # @inferred smesolve( - # H, - # ψ0, - # [0, 10], - # c_ops_sme_tuple, - # sc_ops_sme_tuple, - # ntraj = 5, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred smesolve( - # H, - # ψ0_int, - # tlist, - # c_ops_sme_tuple, - # sc_ops_sme_tuple, - # ntraj = 5, - # progress_bar = Val(false), - # rng = rng, - # ) - # @inferred smesolve( - # H, - # ψ0, - # tlist, - # c_ops_sme_tuple, - # sc_ops_sme_tuple, - # ntraj = 5, - # e_ops = (a' * a, a'), - # progress_bar = Val(false), - # rng = rng, - # ) # We test the type inference for Tuple of different types - # end + @testset "Type Inference ssesolve" begin + c_ops_tuple = Tuple(c_ops) # To avoid type instability, we must have a Tuple instead of a Vector + @inferred ssesolveEnsembleProblem( + H, + ψ0, + tlist, + c_ops_tuple, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + rng = rng, + ) + @inferred ssesolve( + H, + ψ0, + tlist, + c_ops_tuple, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + rng = rng, + ) + @inferred ssesolve(H, ψ0, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(true), rng = rng) + @inferred ssesolve(H, ψ0, [0, 10], c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) + @inferred ssesolve(H, ψ0_int, tlist, c_ops_tuple, ntraj = 5, progress_bar = Val(false), rng = rng) + @inferred ssesolve( + H, + ψ0, + tlist, + c_ops_tuple, + ntraj = 5, + e_ops = (a' * a, a'), + progress_bar = Val(false), + rng = rng, + ) # We test the type inference for Tuple of different types + @inferred ssesolve( + H_td, + ψ0, + tlist, + c_ops_tuple, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + params = p, + rng = rng, + ) + end + + @testset "Type Inference smesolve" begin + # To avoid type instability, we must have a Tuple instead of a Vector + c_ops_sme_tuple = Tuple(c_ops_sme) + sc_ops_sme_tuple = Tuple(sc_ops_sme) + c_ops_sme2_tuple = Tuple(c_ops_sme2) + sc_ops_sme2_tuple = sc_ops_sme2 # This is an `AbstractQuantumObject` + @inferred smesolveEnsembleProblem( + H, + ψ0, + tlist, + c_ops_sme_tuple, + sc_ops_sme_tuple, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + rng = rng, + ) + @inferred smesolve( + H, + ψ0, + tlist, + c_ops_sme_tuple, + sc_ops_sme_tuple, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + rng = rng, + ) + @inferred smesolve( + H, + ψ0, + tlist, + c_ops_sme2_tuple, + sc_ops_sme2_tuple, + ntraj = 5, + e_ops = e_ops, + progress_bar = Val(false), + rng = rng, + ) + @inferred smesolve( + H, + ψ0, + tlist, + c_ops_sme_tuple, + sc_ops_sme_tuple, + ntraj = 5, + progress_bar = Val(true), + rng = rng, + ) + @inferred smesolve( + H, + ψ0, + [0, 10], + c_ops_sme_tuple, + sc_ops_sme_tuple, + ntraj = 5, + progress_bar = Val(false), + rng = rng, + ) + @inferred smesolve( + H, + ψ0_int, + tlist, + c_ops_sme_tuple, + sc_ops_sme_tuple, + ntraj = 5, + progress_bar = Val(false), + rng = rng, + ) + @inferred smesolve( + H, + ψ0, + tlist, + c_ops_sme_tuple, + sc_ops_sme_tuple, + ntraj = 5, + e_ops = (a' * a, a'), + progress_bar = Val(false), + rng = rng, + ) # We test the type inference for Tuple of different types + end @testset "mcsolve, ssesolve and smesolve reproducibility" begin rng = MersenneTwister(1234) From 5bf5da3660689982f6fe038211f375c53adee904 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 17 Feb 2025 17:03:53 +0100 Subject: [PATCH 3/5] Make changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce0837a02..29e26ed6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/qutip/QuantumToolbox.jl/tree/main) - Support for single `AbstractQuantumObject` in `sc_ops` for faster specific method in `ssesolve` and `smesolve`. ([#408]) +- Change save callbacks from `PresetTimeCallback` to `FunctionCallingCallback`. ([#410]) ## [v0.27.0] Release date: 2025-02-14 @@ -143,3 +144,4 @@ Release date: 2024-11-13 [#404]: https://github.com/qutip/QuantumToolbox.jl/issues/404 [#405]: https://github.com/qutip/QuantumToolbox.jl/issues/405 [#408]: https://github.com/qutip/QuantumToolbox.jl/issues/408 +[#410]: https://github.com/qutip/QuantumToolbox.jl/issues/410 From e0026bb4f3c7f276c8c94038b91511a99e322396 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 17 Feb 2025 17:18:36 +0100 Subject: [PATCH 4/5] Relax allocations threshold in tests --- test/core-test/time_evolution.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core-test/time_evolution.jl b/test/core-test/time_evolution.jl index 48547f614..bd5be390a 100644 --- a/test/core-test/time_evolution.jl +++ b/test/core-test/time_evolution.jl @@ -85,7 +85,7 @@ @testset "Memory Allocations" begin allocs_tot = @allocations sesolve(H, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false)) # Warm-up allocs_tot = @allocations sesolve(H, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false)) - @test allocs_tot < 100 + @test allocs_tot < 110 allocs_tot = @allocations sesolve(H, ψ0, tlist, saveat = [tlist[end]], progress_bar = Val(false)) # Warm-up allocs_tot = @allocations sesolve(H, ψ0, tlist, saveat = [tlist[end]], progress_bar = Val(false)) From 25c80cef7c0d1daa03d327e49d612a8ba989b3a2 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 17 Feb 2025 18:02:46 +0100 Subject: [PATCH 5/5] Fix progress_bar error --- src/time_evolution/callback_helpers/mesolve_callback_helpers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl b/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl index b6b448211..a24229d29 100644 --- a/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl +++ b/src/time_evolution/callback_helpers/mesolve_callback_helpers.jl @@ -10,7 +10,7 @@ struct SaveFuncMESolve{TE,PT<:Union{Nothing,ProgressBar},IT,TEXPV<:Union{Nothing end (f::SaveFuncMESolve)(u, t, integrator) = _save_func_mesolve(u, integrator, f.e_ops, f.progr, f.iter, f.expvals) -(f::SaveFuncMESolve{Nothing})(integrator) = _save_func(integrator, f.progr) +(f::SaveFuncMESolve{Nothing})(u, t, integrator) = _save_func(integrator, f.progr) _get_e_ops_data(e_ops, ::Type{SaveFuncMESolve}) = [_generate_mesolve_e_op(op) for op in e_ops] # Broadcasting generates type instabilities on Julia v1.10