In addition to the stochastic Schrödinger and master equations, an implementation for semi-classical systems that are subject to noise is also available. In general, the functions
stochastic.master_semiclassical are written to handle time-dependent semi-classical problems including stochastic processes of any kind. From the point of view of syntax, they are very similar to the semi-classical implementations (see Semi-classical systems)
To solve semi-classical problems, the functions
fquantum(t, psi, u) and
fclassical(t, psi, u, du) need to be passed to the solver. Here,
psi is the quantum part of a
u its classical part and
du the derivative of the classical part. Now, in order to solve a semi-classical equation that is subject to noise, one (or both) of two optional functions needs to be passed to
stochastic.schroedinger_semiclassical. The corresponding keyword arguments are
fstoch_classical that are of the same form as
function fstoch_q_schroedinger(t, psi, u) # Calculate time-dependent stuff Hs end function fstoch_c_schroedinger(t, psi, u, du) # Calculate classical stochastic stuff du = -u # some example du = u end # Quantum noise stochastic.schroedinger_semiclassical(tspan, ψ0, fquantum_schroedinger, fclassical_schroedinger; fstoch_quantum=fstoch_q_schroedinger, dt=dt) # Classical noise stochastic.schroedinger_semiclassical(tspan, ψ0, fquantum_schroedinger, fclassical_schroedinger; fstoch_classical=fstoch_c_schroedinger, dt=dt)
Note, that here
ψ0 needs to be a
semiclassical.State. If one of the functions is omitted, then the semi-classical problem is solved where noise is only present in the quantum or classical part, respectively. Once again, it is possible to avoid initial calculation of the function
fquantum_stoch to obtain the length of
Hs by defining
noise_processes. This number has to be equal to the length of
fstoch_classical is given then you can set this by passing the
noise_prototype_classical keyword (see below). Note, that this argument becomes necessary when working on combinations of quantum and classical noise, or in cases of non-diagonal classical noise.
Implementing a semi-classical stochastic master equation works similarly to above. The output of the functions needs to be altered in order to return the operators needed for the Lindblad and stochastic superoperator, respectively.
function fstoch_q_master(t, psi, u) # Calculate time-dependent stuff C, Cdagger end function fstoch_c_master(t, psi, u, du) # Calculate classical stochastic stuff du = -u # some example du = u end # Quantum noise stochastic.master_semiclassical(tspan, ρ0, fquantum_master, fclassical_master; fstoch_quantum=fstoch_q_master, dt=dt) # Classical noise stochastic.master_semiclassical(tspan, ρ0, fquantum_master, fclassical_master; fstoch_classical=fstoch_c_master, dt=dt)
Note, that the operators returned by
fstoch_q_master are cast in the form of a stochastic superoperator in the stochastic master equation. Again, if one of the functions is omitted, the semi-classical time evolution is calculated where noise is only present in the part for which the respective function is defined.
If this is to combined with classical noise, some extra options are necessary.
While the above discussed examples work fine for problems with quantum noise or classical noise, one needs to be careful when working with combinations of the two. For combinations of quantum and classical noise, we need to set the keyword argument
noise_prototype_classical. This is essentially the same option as they keyword
noise_rate_prototype in the StochasticDiffEq package, which is needed to treat non-diagonal noise. It is important to note, that even if the quantum noise is diagonal (i.e. there is only one noise operator) and also the classical noise is diagonal, the combined problem corresponds to non-diagonal noise. This means, that the classical increment
du in the stochastic classical function is a two-dimensional array. The
noise_prototype_classical carries the information for the shape of this array.
For example, consider a stochastic Schrödinger equation with a single noise term in the Hamiltonian and diagonal classical noise. This can be implemented by
function fstoch_q_diagonal(t, psi, u) Hs # This is a vector containing a single operator end function fstoch_c_diagonal(t, psi, u, du) # Same example as before, but du is now an array du[1,1] = -u du[2,2] = u end stochastic.schroedinger_semiclassical(tspan, ψ0, fquantum_schroedinger, fclassical_schroedinger; fstoch_quantum=fstoch_q_diagonal, fstoch_classical=fstoch_c_diagonal, noise_prototype_classical=zeros(ComplexF64, 2, 2), dt=dt)
Note, how we need to index the diagonal of the array
du in order to treat to obtain a diagonal classical noise problem.
Non-diagonal classical noise can be treated in the same way, e.g.
function fstoch_c_nondiag(t, psi, u, du) # Non-diagonal noise du[1,1] = -u du[1,2] = 0.1u du[2,2] = u du[2,1] = -0.1u du[2,3] = u end stochastic.schroedinger_semiclassical(tspan, ψ0, fquantum_schroedinger, fclassical_schroedinger; dt=dt, fstoch_classical=fstoch_c_nondiag, noise_prototype_classical=zeros(ComplexF64, 2, 3))
Note, that the above can be combined with the quantum noise function from before (without any further changes) by passing the corresponding function. The entire discussion above can be used in the same fashion for stochastic master equations.
For details on non-diagonal noise, please refer to the DifferentialEquations documentation.