Skip to content

Commit 1886cca

Browse files
Add smesolve solver (#389)
Co-authored-by: Yi-Te Huang <[email protected]>
1 parent c5ee417 commit 1886cca

File tree

12 files changed

+757
-138
lines changed

12 files changed

+757
-138
lines changed

.typos.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[default.extend-words]
2-
ket = "ket"
2+
ket = "ket"
3+
sme = "sme"

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Fix CUDA `sparse_to_dense`. ([#386])
1111
- Improve pseudo inverse spectrum solver. ([#388])
12+
- Add `smesolve` function for stochastic master equation. ([#389])
1213

1314
## [v0.25.2]
1415
Release date: 2025-02-02
@@ -109,3 +110,4 @@ Release date: 2024-11-13
109110
[#383]: https://github.com/qutip/QuantumToolbox.jl/issues/383
110111
[#386]: https://github.com/qutip/QuantumToolbox.jl/issues/386
111112
[#388]: https://github.com/qutip/QuantumToolbox.jl/issues/388
113+
[#389]: https://github.com/qutip/QuantumToolbox.jl/issues/389

docs/src/resources/api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,17 +189,20 @@ cosm
189189
TimeEvolutionProblem
190190
TimeEvolutionSol
191191
TimeEvolutionMCSol
192-
TimeEvolutionSSESol
192+
TimeEvolutionStochasticSol
193193
sesolveProblem
194194
mesolveProblem
195195
mcsolveProblem
196196
mcsolveEnsembleProblem
197197
ssesolveProblem
198198
ssesolveEnsembleProblem
199+
smesolveProblem
200+
smesolveEnsembleProblem
199201
sesolve
200202
mesolve
201203
mcsolve
202204
ssesolve
205+
smesolve
203206
dfd_mesolve
204207
liouvillian
205208
liouvillian_generalized

docs/src/users_guide/time_evolution/intro.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ The following table lists the solvers provided by `QuantumToolbox` for dynamic q
3636
| Unitary evolution, Schrödinger equation | [`sesolve`](@ref) | [`sesolveProblem`](@ref) | [`TimeEvolutionSol`](@ref) |
3737
| Lindblad master eqn. or Von Neuman eqn.| [`mesolve`](@ref) | [`mesolveProblem`](@ref) | [`TimeEvolutionSol`](@ref) |
3838
| Monte Carlo evolution | [`mcsolve`](@ref) | [`mcsolveProblem`](@ref) [`mcsolveEnsembleProblem`](@ref) | [`TimeEvolutionMCSol`](@ref) |
39-
| Stochastic Schrödinger equation | [`ssesolve`](@ref) | [`ssesolveProblem`](@ref) [`ssesolveEnsembleProblem`](@ref) | [`TimeEvolutionSSESol`](@ref) |
39+
| Stochastic Schrödinger equation | [`ssesolve`](@ref) | [`ssesolveProblem`](@ref) [`ssesolveEnsembleProblem`](@ref) | [`TimeEvolutionStochasticSol`](@ref) |
40+
| Stochastic master equation | [`smesolve`](@ref) | [`smesolveProblem`](@ref) [`smesolveEnsembleProblem`](@ref) | [`TimeEvolutionStochasticSol`](@ref) |
4041

4142
!!! note "Solving dynamics with pre-defined problems"
4243
`QuantumToolbox` provides two different methods to solve the dynamics. One can use the function calls listed above by either taking all the operators (like Hamiltonian and collapse operators, etc.) as inputs directly, or generating the `prob`lems by yourself and take it as an input of the function call, e.g., `sesolve(prob)`.

src/QuantumToolbox.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ include("time_evolution/lr_mesolve.jl")
106106
include("time_evolution/sesolve.jl")
107107
include("time_evolution/mcsolve.jl")
108108
include("time_evolution/ssesolve.jl")
109+
include("time_evolution/smesolve.jl")
109110
include("time_evolution/time_evolution_dynamical.jl")
110111

111112
# Others

src/qobj/superoperators.jl

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,22 +164,34 @@ function liouvillian(
164164
) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}}
165165
L = liouvillian(H, Id_cache)
166166
if !(c_ops isa Nothing)
167-
# sum all the (time-independent) c_ops first
168-
c_ops_ti = filter(op -> isa(op, QuantumObject), c_ops)
169-
if !isempty(c_ops_ti)
170-
L += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_ti)
171-
end
172-
173-
# sum rest of the QobjEvo together
174-
c_ops_td = filter(op -> isa(op, QuantumObjectEvolution), c_ops)
175-
if !isempty(c_ops_td)
176-
L += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_td)
177-
end
167+
L += _sum_lindblad_dissipators(c_ops, Id_cache)
178168
end
179169
return L
180170
end
181171

172+
liouvillian(H::Nothing, c_ops::Union{AbstractVector,Tuple}, Id_cache::Diagonal = I(prod(c_ops[1].dims))) =
173+
_sum_lindblad_dissipators(c_ops, Id_cache)
174+
175+
liouvillian(H::Nothing, c_ops::Nothing) = 0
176+
182177
liouvillian(H::AbstractQuantumObject{OperatorQuantumObject}, Id_cache::Diagonal = I(prod(H.dimensions))) =
183178
get_typename_wrapper(H)(_liouvillian(H.data, Id_cache), SuperOperator, H.dimensions)
184179

185180
liouvillian(H::AbstractQuantumObject{SuperOperatorQuantumObject}, Id_cache::Diagonal) = H
181+
182+
function _sum_lindblad_dissipators(c_ops, Id_cache::Diagonal)
183+
D = 0
184+
# sum all the (time-independent) c_ops first
185+
c_ops_ti = filter(op -> isa(op, QuantumObject), c_ops)
186+
if !isempty(c_ops_ti)
187+
D += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_ti)
188+
end
189+
190+
# sum rest of the QobjEvo together
191+
c_ops_td = filter(op -> isa(op, QuantumObjectEvolution), c_ops)
192+
if !isempty(c_ops_td)
193+
D += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_td)
194+
end
195+
196+
return D
197+
end

src/time_evolution/mcsolve.jl

Lines changed: 4 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ function _mcsolve_prob_func(prob, i, repeat, global_rng, seeds, tlist)
1212
return remake(prob, f = f, callback = cb)
1313
end
1414

15-
function _mcsolve_dispatch_prob_func(rng, ntraj, tlist)
16-
seeds = map(i -> rand(rng, UInt64), 1:ntraj)
17-
return (prob, i, repeat) -> _mcsolve_prob_func(prob, i, repeat, rng, seeds, tlist)
18-
end
19-
2015
# Standard output function
2116
function _mcsolve_output_func(sol, i)
2217
idx = _mc_get_jump_callback(sol).affect!.jump_times_which_idx[]
@@ -25,43 +20,6 @@ function _mcsolve_output_func(sol, i)
2520
return (sol, false)
2621
end
2722

28-
# Output function with progress bar update
29-
function _mcsolve_output_func_progress(sol, i, progr)
30-
next!(progr)
31-
return _mcsolve_output_func(sol, i)
32-
end
33-
34-
# Output function with distributed channel update for progress bar
35-
function _mcsolve_output_func_distributed(sol, i, channel)
36-
put!(channel, true)
37-
return _mcsolve_output_func(sol, i)
38-
end
39-
40-
function _mcsolve_dispatch_output_func(::ET, progress_bar, ntraj) where {ET<:Union{EnsembleSerial,EnsembleThreads}}
41-
if getVal(progress_bar)
42-
progr = ProgressBar(ntraj, enable = getVal(progress_bar))
43-
f = (sol, i) -> _mcsolve_output_func_progress(sol, i, progr)
44-
return (f, progr, nothing)
45-
else
46-
return (_mcsolve_output_func, nothing, nothing)
47-
end
48-
end
49-
function _mcsolve_dispatch_output_func(
50-
::ET,
51-
progress_bar,
52-
ntraj,
53-
) where {ET<:Union{EnsembleSplitThreads,EnsembleDistributed}}
54-
if getVal(progress_bar)
55-
progr = ProgressBar(ntraj, enable = getVal(progress_bar))
56-
progr_channel::RemoteChannel{Channel{Bool}} = RemoteChannel(() -> Channel{Bool}(1))
57-
58-
f = (sol, i) -> _mcsolve_output_func_distributed(sol, i, progr_channel)
59-
return (f, progr, progr_channel)
60-
else
61-
return (_mcsolve_output_func, nothing, nothing)
62-
end
63-
end
64-
6523
function _normalize_state!(u, dims, normalize_states)
6624
getVal(normalize_states) && normalize!(u)
6725
return QuantumObject(u, type = Ket, dims = dims)
@@ -280,9 +238,10 @@ function mcsolveEnsembleProblem(
280238
output_func::Union{Tuple,Nothing} = nothing,
281239
kwargs...,
282240
) where {TJC<:LindbladJumpCallbackType}
283-
_prob_func = prob_func isa Nothing ? _mcsolve_dispatch_prob_func(rng, ntraj, tlist) : prob_func
241+
_prob_func = isnothing(prob_func) ? _ensemble_dispatch_prob_func(rng, ntraj, tlist, _mcsolve_prob_func) : prob_func
284242
_output_func =
285-
output_func isa Nothing ? _mcsolve_dispatch_output_func(ensemble_method, progress_bar, ntraj) : output_func
243+
output_func isa Nothing ?
244+
_ensemble_dispatch_output_func(ensemble_method, progress_bar, ntraj, _mcsolve_output_func) : output_func
286245

287246
prob_mc = mcsolveProblem(
288247
H,
@@ -431,46 +390,14 @@ function mcsolve(
431390
return mcsolve(ens_prob_mc, alg, ntraj, ensemble_method, normalize_states)
432391
end
433392

434-
function _mcsolve_solve_ens(
435-
ens_prob_mc::TimeEvolutionProblem,
436-
alg::OrdinaryDiffEqAlgorithm,
437-
ensemble_method::ET,
438-
ntraj::Int,
439-
) where {ET<:Union{EnsembleSplitThreads,EnsembleDistributed}}
440-
sol = nothing
441-
442-
@sync begin
443-
@async while take!(ens_prob_mc.kwargs.channel)
444-
next!(ens_prob_mc.kwargs.progr)
445-
end
446-
447-
@async begin
448-
sol = solve(ens_prob_mc.prob, alg, ensemble_method, trajectories = ntraj)
449-
put!(ens_prob_mc.kwargs.channel, false)
450-
end
451-
end
452-
453-
return sol
454-
end
455-
456-
function _mcsolve_solve_ens(
457-
ens_prob_mc::TimeEvolutionProblem,
458-
alg::OrdinaryDiffEqAlgorithm,
459-
ensemble_method,
460-
ntraj::Int,
461-
)
462-
sol = solve(ens_prob_mc.prob, alg, ensemble_method, trajectories = ntraj)
463-
return sol
464-
end
465-
466393
function mcsolve(
467394
ens_prob_mc::TimeEvolutionProblem,
468395
alg::OrdinaryDiffEqAlgorithm = Tsit5(),
469396
ntraj::Int = 1,
470397
ensemble_method = EnsembleThreads(),
471398
normalize_states = Val(true),
472399
)
473-
sol = _mcsolve_solve_ens(ens_prob_mc, alg, ensemble_method, ntraj)
400+
sol = _ensemble_dispatch_solve(ens_prob_mc, alg, ensemble_method, ntraj)
474401

475402
dims = ens_prob_mc.dimensions
476403
_sol_1 = sol[:, 1]

src/time_evolution/mesolve.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
export mesolveProblem, mesolve
22

3-
_mesolve_make_L_QobjEvo(H::QuantumObject, c_ops) = QobjEvo(liouvillian(H, c_ops); type = SuperOperator)
3+
_mesolve_make_L_QobjEvo(H::Union{QuantumObject,Nothing}, c_ops) = QobjEvo(liouvillian(H, c_ops); type = SuperOperator)
44
_mesolve_make_L_QobjEvo(H::Union{QuantumObjectEvolution,Tuple}, c_ops) = liouvillian(QobjEvo(H), c_ops)
5+
_mesolve_make_L_QobjEvo(H::Nothing, c_ops::Nothing) = throw(ArgumentError("Both H and
6+
c_ops are Nothing. You are probably running the wrong function."))
57

68
@doc raw"""
79
mesolveProblem(
@@ -31,7 +33,7 @@ where
3133
# Arguments
3234
3335
- `H`: Hamiltonian of the system ``\hat{H}``. It can be either a [`QuantumObject`](@ref), a [`QuantumObjectEvolution`](@ref), or a `Tuple` of operator-function pairs.
34-
- `ψ0`: Initial state of the system ``|\psi(0)\rangle``.
36+
- `ψ0`: Initial state of the system ``|\psi(0)\rangle``. It can be either a [`Ket`](@ref) or a [`Operator`](@ref).
3537
- `tlist`: List of times at which to save either the state or the expectation values of the system.
3638
- `c_ops`: List of collapse operators ``\{\hat{C}_n\}_n``. It can be either a `Vector` or a `Tuple`.
3739
- `e_ops`: List of operators for which to calculate expectation values. It can be either a `Vector` or a `Tuple`.
@@ -119,7 +121,7 @@ where
119121
# Arguments
120122
121123
- `H`: Hamiltonian of the system ``\hat{H}``. It can be either a [`QuantumObject`](@ref), a [`QuantumObjectEvolution`](@ref), or a `Tuple` of operator-function pairs.
122-
- `ψ0`: Initial state of the system ``|\psi(0)\rangle``.
124+
- `ψ0`: Initial state of the system ``|\psi(0)\rangle``. It can be either a [`Ket`](@ref) or a [`Operator`](@ref).
123125
- `tlist`: List of times at which to save either the state or the expectation values of the system.
124126
- `c_ops`: List of collapse operators ``\{\hat{C}_n\}_n``. It can be either a `Vector` or a `Tuple`.
125127
- `alg`: The algorithm for the ODE solver. The default value is `Tsit5()`.

0 commit comments

Comments
 (0)