Exported functions
Running trajectories
BackAction.run_trajectories_gillipsie
— Methodrun_trajectories_gillipsie(sys::System, params::SimulParameters; progbar::Bool = true,
psireset::VecOrMat{ComplexF64}=zeros(ComplexF64, 0))
Sample multiple trajectories of sys
. with the seed
, nsamples
and psi0
specified in params
using the Quantum Gillipsie Algorithm [2]. If the process is of renewal type,i.e. after a jump it always comes to the same state, that state can be specified via psireset
and it will be used to optimize the sampling of the jump times.
Arguments
sys::System
: The system for which to run the trajectorisparams::SimulParameters
: specificies the details of the trajectiories: seed, number of points in the finegrid, initial state and tolerance for the dark state detection, and the number of trajectories to run.
Optional Arguments
progbar::Bool
: if true, show a progress bar of the iteration,true
by default.psireset::VecOrMat{ComplexF64}
: if specified, it is used to optimize the jump time sampling.
Return
A Vector{Trajectory}
of length params.ntraj
with the sampled trajectories.
State Evaluation
BackAction.states_atjumps
— Methodstates_atjumps(traj::Trajectory, sys::System, psi0::Union{Vector{ComplexF64},
Matrix{ComplexF64}}; normalize::Bool=true)
Obtain the states at jumps of the trajectory given the initial state psi0
, they are (un)normalized if normalize
is true
(false
). The return is an Array
of dimensions (sys.NLEVELS, njumps)
if the initial state was pure, and (sys.NLEVELS, sys.NLEVELS, njumps)
if it was mixed; njumps
is the number of jumps in the trajectory. You would access the state at the k-th jump with something like states_atjumps(traj, sys, psi0)[:, k]
.
In case isempty(traj)=true
the returned array is also empty.
BackAction.states_att
— Methodstates_att(t_given::Vector{Float64}, traj::Trajectory, sys::System,
psi0::Union{Vector{ComplexF64}, Matrix{ComplexF64}};
normalize::Bool=true)
Provided the initial state psi0
obtain the states at the times in t_given
on the trajectory, they are (un)normalized if normalize
is true
(false
). The return is an Array
of dimensions (sys.NLEVELS, ntimes)
if the initial state was pure and (sys.NLEVELS, sys.NLEVELS, ntimes)
if it was mixed; ntimes
is the number of times in t_given
. In case isempty(t_given)=true
the returned array is also empty.
Internal functions
Utilities
BackAction.fixlastindex
— Functionfixlastindex(array::Array{ComplexF64}, k::Int64)
Return a SubArray
of array
, defined by fixing the last index to k
.
Example
using BackAction
arr = [[1+1.0im, 2] [3, 4]]
BackAction.fixlastindex(arr, 2)
# output
2-element view(::Matrix{ComplexF64}, :, 2) with eltype ComplexF64:
3.0 + 0.0im
4.0 + 0.0im
Precomputation
BackAction.setVs!
— MethodsetVs!(sys::System, nsamples::Int64, ts::Vector{Float64}, Vs::Array{ComplexF64})
`
Calculate the matrix exponentials $\mathrm{exp}(-iH_e t_s)$ for each $t_s$ in the vector ts
, where $H_e$ is the effective hamiltonian of the system sys
, and the results are written in Vs
, which is an array of dimensions (sys.NLEVELS, sys.NLEVELS, nsamples)
. To access the exponential corresponding to ts[k]
you would do Vs[:, ;, k]
.
BackAction.setQs!
— MethodsetQs!(sys::System, nsamples::Int64,ts::Vector{Float64}, Qs::Array{ComplexF64}, Vs::Array{ComplexF64})
Calculate the matrix producs $VJV^\dagger$ for each $V$ in Vs
, where $J=\sum_k L_{k}^\dagger L_k$ is sys.J
, and the results are written in Qs
which is an array of dimensions (sys.NLEVELS, sys.NLEVELS, nsamples)
. To access the product corresponding to ts[k]
you would do Qs[:, ;, k]
.
BackAction.precompute!
— Methodprecompute!(sys::System, nsamples::Int64, ts::Vector{Float64}, Qs::Array{ComplexF64}, Vs::Array{ComplexF64})
Precompute the $Q(t_s)$ and $V(t_s)$ necessary for running the Quantum Gillipsie Algorithm [2] with the time grid ts
. The result is written in Qs
and Vs
. Under the hood, this simply calls setVs!
and setQs!
.
Click Sampling
BackAction.calculatewtdweights!
— Methodcalculatewtdweights!(W::Array{Float64}, Qs::Array{ComplexF64}, psi::Vector{ComplexF64},
params::SimulParameters)
Calculate the discretized Waiting Time Distribution for a pure state $|\psi\rangle$ i.e. $\langle\psi|Q(t_s)\psi\rangle$, and writes it at W
. This is done using LinearAlgebra
's dot
, and usually is the thing in which run_singletrajectory
spends most of the time since params.nsamples
is typically in the thousands.
BackAction.calculatewtdweights!
— Methodcalculatewtdweights!(W::Array{Float64}, Qs::Array{ComplexF64}, psi::Matrix{ComplexF64},
params::SimulParameters)
Calculate the discretized Waiting Time Distribution for a mixed state $\psi$ i.e. $\mathrm{Tr}(Q(t_s)\psi)$, and writes it at W
. This is done using LinearAlgebra
's tr
, and usually is the thing in which run_singletrajectory
spends most of the time since params.nsamples
is typically in the thousands.
BackAction.calculatechannelweights!
— Methodcalculatechannelweights!(P::Vector{Float64}, psi::Vector{ComplexF64}, sys::System)
Calculate the probabilities for a pure state $|\psi\rangle$ to jump to any of the given channels i.e. $\langle\psi| L^\dagger L|\psi\rangle$ for each jump operator $L$, and writes it at P
. This is done using the square of LinearAlgebra
's norm
.
BackAction.calculatechannelweights!
— Methodcalculatechannelweights!(P::Vector{Float64}, psi::Matrix{ComplexF64}, sys::System)
Calculate the probabilities for a mixed state $\psi$ to jump to any of the given channels i.e. $\mathrm{Tr}(L^\dagger L\psi)$ for each jump operator $L$, and writes it at P
. This is done using of LinearAlgebra
's tr
.
BackAction.sampletauindex!
— Methodsamplejumptime!(W::Vector{Float64}, Qs::Array{ComplexF64}, psi::VecOrMat{ComplexF64})
Sample a jump time index from the state psi
(pure or mixed), modfying W
to write on it. The technique is inversion sampling
BackAction.sampletauindex!
— Methodsamplejumptime!(W::Vector{Float64}, Qs::Array{ComplexF64}, psi::VecOrMat{ComplexF64})
Sample a jump time index from the state psi
(pure or mixed), modfying W
to write on it. The technique is inversion sampling
State Updates
BackAction.prejumpupdate!
— Methodprejumpupdate!(V::Matrix{ComplexF64}, psi::Vector{ComplexF64}; normalize=false)
Do the pure state transformation $|\psi\rangle\to V|\psi\rangle$ modifying psi
, if normalize=true
it also normalizes the final state.
BackAction.prejumpupdate!
— Methodprejumpupdate!(psi::Vector{ComplexF64}, V::Matrix{ComplexF64},
psi0::Union{Vector{ComplexF64}, SubArray{ComplexF64}}; normalize=false)
Do the pure state transformation $|\psi_0\rangle\to V|\psi_0\rangle$ and store the result in psi
, if normalize=true
it also normalizes the final state.
BackAction.prejumpupdate!
— Methodprejumpupdate!(psi::Matrix{ComplexF64}, V::Matrix{ComplexF64},
psi0::Union{Vector{ComplexF64}, SubArray{ComplexF64}}; normalize=false)
Do the mixed state transformation $\psi_0\to V\psi_0 V^\dagger$ and store the result in psi
, if normalize=true
it also normalizes the final state.
BackAction.prejumpupdate!
— Methodprejumpupdate!(V::Matrix{ComplexF64}, psi::Vector{ComplexF64}; normalize=false)
Do the mixed state transformation $\psi\to V\psi V^\dagger$ modifying psi
, if normalize=true
it also normalizes the final state.
BackAction.postjumpupdate!
— Methodpostjumpupdate!(L::Matrix{ComplexF64}, psi::Vector{ComplexF64}; normalize=true)
Do the pure state transformation $|\psi\rangle\to L|\psi\rangle$ modifying psi
, if normalize=true
it also normalizes the final state.
BackAction.postjumpupdate!
— Methodpostjumpupdate!(L::Matrix{ComplexF64}, psi::Vector{ComplexF64}; normalize=true)
Do the pure mixed state transformation $\psi\to L\psi L^\dagger$ modifying psi
, if normalize=true
it also normalizes the final state.
Trajectory Evaluation
BackAction.run_singletrajectory_gillipsie
— Methodrun_singletrajectory_gillipsie(sys::System, params::SimulParameters,
W::Vector{Float64}, P::Vector{Float64}, ts::Vector{Float64},
Qs::Array{ComplexF64}, Vs::Array{ComplexF64}; seed::Int64 = 1)
Sample a jump trajectory for the system sys
using the Quantum Gillipsie Algorithm [2].
Positional Arguments
sys::System
: the system from which the trajectory is obtained.params::SimulParameters
: specifies the number of points in the grid, the initial state and the tolerance for the dark state test.W::Vector{Float64}
: to store the probabilities of the WTDs used at each stepP::Vector{Float64}
: to store the probabilites of jumps to each channel used at each stepts::Vector{Float64}
: the fine grid used to sample from the WTDQs::Array{ComplexF64}
: the precomputed matrices from which the WTD weights are calculatedVs::Array{ComplexF64}
: the precomputed exponentials that evolve the state from jump to jump.
Keyword Arguments
seed::Int64 = 1
: the seed of the sample. It does not need to coincide with that inparams
Returns
traj::Trajectory
: vector with the obtained detection clicks.
BackAction.run_singletrajectory_gillipsie_renewal
— Methodrun_singletrajectory_gillipsie_renewal(sys::System, params::SimulParameters,
W::Vector{Float64}, W0::Vector{Float64}, P::Vector{Float64}, ts::Vector{Float64},
Qs::Array{ComplexF64}, Vs::Array{ComplexF64}, psireset::VecOrMat{ComplexF64}; seed::Int64 = 1)
Same as run_singletrajectory_gillipsie
but uses psireset
to optimize the jump time sampling by exploiting the process is renewal. Additionally, W0
must be provided to sample the first jump from the initial state, which may not coincide with psireset
.
BackAction.gillipsiestep_returntau!
— Methodgillipsiestep_returntau!(sys::System, params::SimulParameters, W::Vector{Float64},
P::Vector{Float64}, Vs::Array{ComplexF64}, ts::Vector{Float64},
t::Float64, psi::VecOrMat{ComplexF64}, traj::Trajectory )
Do a step of the Gillipsie algorithm, updating the state and the weights, and returning the obtained jump time. In this version the time jump sampling is done by calling StatsBase
.
BackAction.gillipsiestep_returntau!
— Methodgillipsiestep_returntau!(sys::System, params::SimulParameters, W::Vector{Float64},
P::Vector{Float64}, Qs::Array{ComplexF64}, Vs::Array{ComplexF64},
ts::Vector{Float64},
t::Float64, psi::VecOrMat{ComplexF64}, traj::Trajectory )
Do a step of the Gillipsie algorithm, updating the state and the weights, and returning the obtained jump time. In this version the time is extracted using inversion sampling instead of calling StatsBase
.
BackAction.writestate!
— Methodwritestate!(states::array{complexf64}, psi::union{vector{complexf64},
matrix{complexf64}}, counter::int64)
Writes psi
in states
at the subarray with the last index fixed at counter
.