diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 1e97e324..6f692903 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.0","generation_timestamp":"2024-10-09T14:19:14","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.0","generation_timestamp":"2024-10-09T23:55:30","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/dev/api/index.html b/dev/api/index.html index b86a623a..785a99d0 100644 --- a/dev/api/index.html +++ b/dev/api/index.html @@ -1,5 +1,5 @@ -API · QuantumToolbox.jl

API

Contents

Quantum object (Qobj) and type

QuantumToolbox.QuantumObjectType
struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,N}
+API · QuantumToolbox.jl

API

Contents

Quantum object (Qobj) and type

QuantumToolbox.QuantumObjectType
struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,N}
     data::MT
     type::ObjType
     dims::SVector{N, Int}
@@ -13,10 +13,10 @@
 ⎣⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⎦
 
 julia> a isa QuantumObject
-true
source
QuantumToolbox.OperatorSumType
struct OperatorSum

A constructor to represent a sum of operators $\sum_i c_i \hat{O}_i$ with a list of coefficients $c_i$ and a list of operators $\hat{O}_i$.

This is very useful when we have to update only the coefficients, without allocating memory by performing the sum of the operators.

source
Base.sizeFunction
size(A::QuantumObject)
-size(A::QuantumObject, idx::Int)

Returns a tuple containing each dimensions of the array in the QuantumObject.

Optionally, you can specify an index (idx) to just get the corresponding dimension of the array.

source
QuantumToolbox.isunitaryFunction
isunitary(U::QuantumObject; kwargs...)

Test whether the QuantumObject $U$ is unitary operator. This function calls Base.isapprox to test whether $U U^\dagger$ is approximately equal to identity operator.

Note that all the keyword arguments will be passed to Base.isapprox.

source

Qobj arithmetic and attributes

Base.adjointFunction
A'
-adjoint(A::QuantumObject)

Lazy adjoint (conjugate transposition) of the QuantumObject

Note that A' is a synonym for adjoint(A)

source
LinearAlgebra.dotFunction
dot(A::QuantumObject, B::QuantumObject)

Compute the dot product between two QuantumObject: $\langle A | B \rangle$

Note that A and B should be Ket or OperatorKet

A ⋅ B (where can be typed by tab-completing \cdot in the REPL) is a synonym for dot(A, B)

source
dot(i::QuantumObject, A::QuantumObject j::QuantumObject)

Compute the generalized dot product dot(i, A*j) between three QuantumObject: $\langle i | \hat{A} | j \rangle$

Supports the following inputs:

source
QuantumToolbox.OperatorSumType
struct OperatorSum

A constructor to represent a sum of operators $\sum_i c_i \hat{O}_i$ with a list of coefficients $c_i$ and a list of operators $\hat{O}_i$.

This is very useful when we have to update only the coefficients, without allocating memory by performing the sum of the operators.

source
Base.sizeFunction
size(A::QuantumObject)
+size(A::QuantumObject, idx::Int)

Returns a tuple containing each dimensions of the array in the QuantumObject.

Optionally, you can specify an index (idx) to just get the corresponding dimension of the array.

source
QuantumToolbox.isunitaryFunction
isunitary(U::QuantumObject; kwargs...)

Test whether the QuantumObject $U$ is unitary operator. This function calls Base.isapprox to test whether $U U^\dagger$ is approximately equal to identity operator.

Note that all the keyword arguments will be passed to Base.isapprox.

source

Qobj arithmetic and attributes

Base.adjointFunction
A'
+adjoint(A::QuantumObject)

Lazy adjoint (conjugate transposition) of the QuantumObject

Note that A' is a synonym for adjoint(A)

source
LinearAlgebra.dotFunction
dot(A::QuantumObject, B::QuantumObject)

Compute the dot product between two QuantumObject: $\langle A | B \rangle$

Note that A and B should be Ket or OperatorKet

A ⋅ B (where can be typed by tab-completing \cdot in the REPL) is a synonym for dot(A, B)

source
dot(i::QuantumObject, A::QuantumObject j::QuantumObject)

Compute the generalized dot product dot(i, A*j) between three QuantumObject: $\langle i | \hat{A} | j \rangle$

Supports the following inputs:

source
LinearAlgebra.trFunction
tr(A::QuantumObject)

Returns the trace of QuantumObject.

Note that this function only supports for Operator and SuperOperator

Examples

julia> a = destroy(20)
 Quantum Object:   type=Operator   dims=[20]   size=(20, 20)   ishermitian=false
 20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:
 ⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀
@@ -26,7 +26,7 @@
 ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢
 
 julia> tr(a' * a)
-190.0 + 0.0im
source
LinearAlgebra.normFunction
norm(A::QuantumObject, p::Real)

Return the standard vector p-norm or Schatten p-norm of a QuantumObject depending on the type of A:

Examples

julia> ψ = fock(10, 2)
 Quantum Object:   type=Ket   dims=[10]   size=(10,)
 10-element Vector{ComplexF64}:
  0.0 + 0.0im
@@ -41,7 +41,7 @@
  0.0 + 0.0im
 
 julia> norm(ψ)
-1.0
source
QuantumToolbox.ptraceFunction
ptrace(QO::QuantumObject, sel)

Partial trace of a quantum state QO leaving only the dimensions with the indices present in the sel vector.

Note that this function will always return Operator. No matter the input QuantumObject is a Ket, Bra, or Operator.

Examples

Two qubits in the state $\ket{\psi} = \ket{e,g}$:

julia> ψ = kron(fock(2,0), fock(2,1))
+1.0
source
QuantumToolbox.ptraceFunction
ptrace(QO::QuantumObject, sel)

Partial trace of a quantum state QO leaving only the dimensions with the indices present in the sel vector.

Note that this function will always return Operator. No matter the input QuantumObject is a Ket, Bra, or Operator.

Examples

Two qubits in the state $\ket{\psi} = \ket{e,g}$:

julia> ψ = kron(fock(2,0), fock(2,1))
 Quantum Object:   type=Ket   dims=[2, 2]   size=(4,)
 4-element Vector{ComplexF64}:
  0.0 + 0.0im
@@ -65,12 +65,12 @@
 Quantum Object:   type=Operator   dims=[2]   size=(2, 2)   ishermitian=true
 2×2 Matrix{ComplexF64}:
  0.5+0.0im  0.0+0.0im
- 0.0+0.0im  0.5+0.0im
source
QuantumToolbox.permuteFunction
permute(A::QuantumObject, order::Union{AbstractVector{Int},Tuple})

Permute the tensor structure of a QuantumObject A according to the specified order list

Note that this method currently works for Ket, Bra, and Operator types of QuantumObject.

Examples

If order = [2, 1, 3], the Hilbert space structure will be re-arranged: $\mathcal{H}_1 \otimes \mathcal{H}_2 \otimes \mathcal{H}_3 \rightarrow \mathcal{H}_2 \otimes \mathcal{H}_1 \otimes \mathcal{H}_3$.

julia> ψ1 = fock(2, 0)
+ 0.0+0.0im  0.5+0.0im
source
QuantumToolbox.permuteFunction
permute(A::QuantumObject, order::Union{AbstractVector{Int},Tuple})

Permute the tensor structure of a QuantumObject A according to the specified order list

Note that this method currently works for Ket, Bra, and Operator types of QuantumObject.

Examples

If order = [2, 1, 3], the Hilbert space structure will be re-arranged: $\mathcal{H}_1 \otimes \mathcal{H}_2 \otimes \mathcal{H}_3 \rightarrow \mathcal{H}_2 \otimes \mathcal{H}_1 \otimes \mathcal{H}_3$.

julia> ψ1 = fock(2, 0)
 julia> ψ2 = fock(3, 1)
 julia> ψ3 = fock(4, 2)
 julia> ψ_123 = tensor(ψ1, ψ2, ψ3)
 julia> permute(ψ_123, [2, 1, 3]) ≈ tensor(ψ2, ψ1, ψ3)
-true
Beware of type-stability!

It is highly recommended to use permute(A, order) with order as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.tidyupFunction
tidyup(A::QuantumObject, tol::Real=1e-14)

Given a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.

source
QuantumToolbox.tidyup!Function
tidyup!(A::QuantumObject, tol::Real=1e-14)

Given a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.

Note that this function is an in-place version of tidyup.

source
QuantumToolbox.get_coherenceFunction
get_coherence(ψ::QuantumObject)

Get the coherence value $\alpha$ by measuring the expectation value of the destruction operator $\hat{a}$ on a state $\ket{\psi}$ or a density matrix $\hat{\rho}$.

It returns both $\alpha$ and the corresponding state with the coherence removed: $\ket{\delta_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \ket{\psi}$ for a pure state, and $\hat{\rho_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \hat{\rho} \exp ( -\bar{\alpha} \hat{a} + \alpha \hat{a}^\dagger )$ for a density matrix. These states correspond to the quantum fluctuations around the coherent state $\ket{\alpha}$ or $|\alpha\rangle\langle\alpha|$.

source
QuantumToolbox.partial_transposeFunction
partial_transpose(ρ::QuantumObject, mask::Vector{Bool})

Return the partial transpose of a density matrix $\rho$, where mask is an array/vector with length that equals the length of ρ.dims. The elements in mask are boolean (true or false) which indicates whether or not the corresponding subsystem should be transposed.

Arguments

  • ρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).
  • mask::Vector{Bool}: A boolean vector selects which subsystems should be transposed.

Returns

  • ρ_pt::QuantumObject: The density matrix with the selected subsystems transposed.
source

Qobj eigenvalues and eigenvectors

QuantumToolbox.EigsolveResultType
struct EigsolveResult{T1<:Vector{<:Number}, T2<:AbstractMatrix{<:Number}, ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject},N}
+true
Beware of type-stability!

It is highly recommended to use permute(A, order) with order as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.tidyupFunction
tidyup(A::QuantumObject, tol::Real=1e-14)

Given a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.

source
QuantumToolbox.tidyup!Function
tidyup!(A::QuantumObject, tol::Real=1e-14)

Given a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.

Note that this function is an in-place version of tidyup.

source
QuantumToolbox.get_coherenceFunction
get_coherence(ψ::QuantumObject)

Get the coherence value $\alpha$ by measuring the expectation value of the destruction operator $\hat{a}$ on a state $\ket{\psi}$ or a density matrix $\hat{\rho}$.

It returns both $\alpha$ and the corresponding state with the coherence removed: $\ket{\delta_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \ket{\psi}$ for a pure state, and $\hat{\rho_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \hat{\rho} \exp ( -\bar{\alpha} \hat{a} + \alpha \hat{a}^\dagger )$ for a density matrix. These states correspond to the quantum fluctuations around the coherent state $\ket{\alpha}$ or $|\alpha\rangle\langle\alpha|$.

source
QuantumToolbox.partial_transposeFunction
partial_transpose(ρ::QuantumObject, mask::Vector{Bool})

Return the partial transpose of a density matrix $\rho$, where mask is an array/vector with length that equals the length of ρ.dims. The elements in mask are boolean (true or false) which indicates whether or not the corresponding subsystem should be transposed.

Arguments

  • ρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).
  • mask::Vector{Bool}: A boolean vector selects which subsystems should be transposed.

Returns

  • ρ_pt::QuantumObject: The density matrix with the selected subsystems transposed.
source

Qobj eigenvalues and eigenvectors

QuantumToolbox.EigsolveResultType
struct EigsolveResult{T1<:Vector{<:Number}, T2<:AbstractMatrix{<:Number}, ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject},N}
     values::T1
     vectors::T2
     type::ObjType
@@ -95,7 +95,7 @@
 julia> T
 2×2 Matrix{ComplexF64}:
  -0.707107+0.0im  0.707107+0.0im
-  0.707107+0.0im  0.707107+0.0im
source
QuantumToolbox.eigenstatesFunction
eigenstates(A::QuantumObject; sparse::Bool=false, kwargs...)

Calculate the eigenvalues and corresponding eigenvectors

Arguments

Returns

  • ::EigsolveResult: containing the eigenvalues, the eigenvectors, and some information from the solver. see also EigsolveResult
source
QuantumToolbox.eigenstatesFunction
eigenstates(A::QuantumObject; sparse::Bool=false, kwargs...)

Calculate the eigenvalues and corresponding eigenvectors

Arguments

Returns

  • ::EigsolveResult: containing the eigenvalues, the eigenvectors, and some information from the solver. see also EigsolveResult
source
LinearAlgebra.eigenFunction
LinearAlgebra.eigen(A::QuantumObject; kwargs...)

Calculates the eigenvalues and eigenvectors of the QuantumObject A using the Julia LinearAlgebra package.

julia> a = destroy(5);
 
 julia> H = a + a'
 Quantum Object:   type=Operator   dims=[5]   size=(5, 5)   ishermitian=true
@@ -124,7 +124,7 @@
   0.447214+0.0im   0.447214+0.0im     -0.447214-0.0im  0.447214-0.0im
 
 julia> expect(H, ψ[1]) ≈ E[1]
-true
source
QuantumToolbox.eigsolveFunction
eigsolve(A::QuantumObject; 
     v0::Union{Nothing,AbstractVector}=nothing, 
     sigma::Union{Nothing, Real}=nothing,
     k::Int = 1,
@@ -132,7 +132,7 @@
     tol::Real = 1e-8,
     maxiter::Int = 200,
     solver::Union{Nothing, SciMLLinearSolveAlgorithm} = nothing,
-    kwargs...)

Solve for the eigenvalues and eigenvectors of a matrix A using the Arnoldi method.

Notes

  • For more details about solver and extra kwargs, please refer to LinearSolve.jl

Returns

  • EigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver
source
QuantumToolbox.eigsolve_alFunction
eigsolve_al(H::QuantumObject,
+    kwargs...)

Solve for the eigenvalues and eigenvectors of a matrix A using the Arnoldi method.

Notes

  • For more details about solver and extra kwargs, please refer to LinearSolve.jl

Returns

  • EigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver
source
QuantumToolbox.eigsolve_alFunction
eigsolve_al(H::QuantumObject,
     T::Real, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
     alg::OrdinaryDiffEqAlgorithm=Tsit5(),
     H_t::Union{Nothing,Function}=nothing,
@@ -142,7 +142,7 @@
     krylovdim::Int=min(10, size(H, 1)),
     maxiter::Int=200,
     eigstol::Real=1e-6,
-    kwargs...)

Solve the eigenvalue problem for a Liouvillian superoperator L using the Arnoldi-Lindblad method.

Arguments

  • H: The Hamiltonian (or directly the Liouvillian) of the system.
  • T: The time at which to evaluate the time evolution
  • c_ops: A vector of collapse operators. Default is nothing meaning the system is closed.
  • alg: The differential equation solver algorithm
  • H_t: A function H_t(t) that returns the additional term at time t
  • params: A dictionary of additional parameters
  • ρ0: The initial density matrix. If not specified, a random density matrix is used
  • k: The number of eigenvalues to compute
  • krylovdim: The dimension of the Krylov subspace
  • maxiter: The maximum number of iterations for the eigsolver
  • eigstol: The tolerance for the eigsolver
  • kwargs: Additional keyword arguments passed to the differential equation solver

Notes

Returns

  • EigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver

References

  • [1] Minganti, F., & Huybrechts, D. (2022). Arnoldi-Lindblad time evolution: Faster-than-the-clock algorithm for the spectrum of time-independent and Floquet open quantum systems. Quantum, 6, 649.
source

Qobj manipulation

QuantumToolbox.ket2dmFunction
ket2dm(ψ::QuantumObject)

Transform the ket state $\ket{\psi}$ into a pure density matrix $\hat{\rho} = \dyad{\psi}$.

source
QuantumToolbox.expectFunction
expect(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})

Expectation value of the Operator O with the state ψ. The state can be a Ket, Bra or Operator.

If ψ is a Ket or Bra, the function calculates $\langle\psi|\hat{O}|\psi\rangle$.

If ψ is a density matrix (Operator), the function calculates $\textrm{Tr} \left[ \hat{O} \hat{\psi} \right]$

The function returns a real number if O is of Hermitian type or Symmetric type, and returns a complex number otherwise. You can make an operator O hermitian by using Hermitian(O).

Note that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.

Examples

julia> ψ = 1 / √2 * (fock(10,2) + fock(10,4));
+    kwargs...)

Solve the eigenvalue problem for a Liouvillian superoperator L using the Arnoldi-Lindblad method.

Arguments

  • H: The Hamiltonian (or directly the Liouvillian) of the system.
  • T: The time at which to evaluate the time evolution
  • c_ops: A vector of collapse operators. Default is nothing meaning the system is closed.
  • alg: The differential equation solver algorithm
  • H_t: A function H_t(t) that returns the additional term at time t
  • params: A dictionary of additional parameters
  • ρ0: The initial density matrix. If not specified, a random density matrix is used
  • k: The number of eigenvalues to compute
  • krylovdim: The dimension of the Krylov subspace
  • maxiter: The maximum number of iterations for the eigsolver
  • eigstol: The tolerance for the eigsolver
  • kwargs: Additional keyword arguments passed to the differential equation solver

Notes

Returns

  • EigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver

References

  • [1] Minganti, F., & Huybrechts, D. (2022). Arnoldi-Lindblad time evolution: Faster-than-the-clock algorithm for the spectrum of time-independent and Floquet open quantum systems. Quantum, 6, 649.
source

Qobj manipulation

QuantumToolbox.ket2dmFunction
ket2dm(ψ::QuantumObject)

Transform the ket state $\ket{\psi}$ into a pure density matrix $\hat{\rho} = \dyad{\psi}$.

source
QuantumToolbox.expectFunction
expect(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})

Expectation value of the Operator O with the state ψ. The state can be a Ket, Bra or Operator.

If ψ is a Ket or Bra, the function calculates $\langle\psi|\hat{O}|\psi\rangle$.

If ψ is a density matrix (Operator), the function calculates $\textrm{Tr} \left[ \hat{O} \hat{\psi} \right]$

The function returns a real number if O is of Hermitian type or Symmetric type, and returns a complex number otherwise. You can make an operator O hermitian by using Hermitian(O).

Note that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.

Examples

julia> ψ = 1 / √2 * (fock(10,2) + fock(10,4));
 
 julia> a = destroy(10);
 
@@ -150,7 +150,7 @@
 3.0 + 0.0im
 
 julia> expect(Hermitian(a' * a), ψ) |> round
-3.0
source
QuantumToolbox.varianceFunction
variance(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})

Variance of the Operator O: $\langle\hat{O}^2\rangle - \langle\hat{O}\rangle^2$,

where $\langle\hat{O}\rangle$ is the expectation value of O with the state ψ (see also expect), and the state ψ can be a Ket, Bra or Operator.

The function returns a real number if O is hermitian, and returns a complex number otherwise.

Note that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.

source
Base.kronFunction
kron(A::QuantumObject, B::QuantumObject, ...)

Returns the Kronecker product $\hat{A} \otimes \hat{B} \otimes \cdots$.

Examples

julia> a = destroy(20)
+3.0
source
QuantumToolbox.varianceFunction
variance(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})

Variance of the Operator O: $\langle\hat{O}^2\rangle - \langle\hat{O}\rangle^2$,

where $\langle\hat{O}\rangle$ is the expectation value of O with the state ψ (see also expect), and the state ψ can be a Ket, Bra or Operator.

The function returns a real number if O is hermitian, and returns a complex number otherwise.

Note that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.

source
Base.kronFunction
kron(A::QuantumObject, B::QuantumObject, ...)

Returns the Kronecker product $\hat{A} \otimes \hat{B} \otimes \cdots$.

Examples

julia> a = destroy(20)
 Quantum Object:   type=Operator   dims=[20]   size=(20, 20)   ishermitian=false
 20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:
 ⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀
@@ -182,7 +182,7 @@
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀
-⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦
source

Generate states and operators

QuantumToolbox.zero_ketFunction
zero_ket(dimensions)

Returns a zero Ket vector with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int}, Tuple}: list of dimensions representing the each number of basis in the subsystems.
Beware of type-stability!

It is highly recommended to use zero_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.fockFunction
fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))

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.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fock(N, j, dims=dims, sparse=Val(sparse)) instead of fock(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.basisFunction
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)

Generates a fock state like fock.

It is also possible to specify the list of dimensions dims if different subsystems are present.

Beware of type-stability!

If you want to keep type stability, it is recommended to use basis(N, j, dims=dims) with dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.coherentFunction
coherent(N::Int, α::Number)

Generates a coherent state $|\alpha\rangle$, which is defined as an eigenvector of the bosonic annihilation operator $\hat{a} |\alpha\rangle = \alpha |\alpha\rangle$.

This state is constructed via the displacement operator displace and zero-fock state fock: $|\alpha\rangle = \hat{D}(\alpha) |0\rangle$

source
QuantumToolbox.rand_ketFunction
rand_ket(dimensions)

Generate a random normalized Ket vector with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.
Beware of type-stability!

If you want to keep type stability, it is recommended to use rand_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.fock_dmFunction
fock_dm(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))

Density matrix representation of a Fock state.

Constructed via outer product of fock.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fock_dm(N, j, dims=dims, sparse=Val(sparse)) instead of fock_dm(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.thermal_dmFunction
thermal_dm(N::Int, n::Real; sparse::Union{Bool,Val}=Val(false))

Density matrix for a thermal state (generating thermal state probabilities) with the following arguments:

  • N::Int: Number of basis states in the Hilbert space
  • n::Real: Expectation value for number of particles in the thermal state.
  • sparse::Union{Bool,Val}: If true, return a sparse matrix representation.
Beware of type-stability!

If you want to keep type stability, it is recommended to use thermal_dm(N, n, sparse=Val(sparse)) instead of thermal_dm(N, n, sparse=sparse). See this link and the related Section about type stability for more details.

source
QuantumToolbox.maximally_mixed_dmFunction
maximally_mixed_dm(dimensions)

Returns the maximally mixed density matrix with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.
Beware of type-stability!

If you want to keep type stability, it is recommended to use maximally_mixed_dm(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.rand_dmFunction
rand_dm(dimensions; rank::Int=prod(dimensions))

Generate a random density matrix from Ginibre ensemble with given argument dimensions and rank, ensuring that it is positive semi-definite and trace equals to 1.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.

The default keyword argument rank = prod(dimensions) (full rank).

Beware of type-stability!

If you want to keep type stability, it is recommended to use rand_dm(dimensions; rank=rank) with dimensions as Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

References

source
QuantumToolbox.spin_stateFunction
spin_state(j::Real, m::Real)

Generate the spin state: $|j, m\rangle$

The eigenstate of the Spin-j $\hat{S}_z$ operator with eigenvalue m, where where j is the spin quantum number and can be a non-negative integer or half-integer

See also jmat.

source
QuantumToolbox.spin_coherentFunction
spin_coherent(j::Real, θ::Real, ϕ::Real)

Generate the coherent spin state (rotation of the $|j, j\rangle$ state), namely

\[|\theta, \phi \rangle = \hat{R}(\theta, \phi) |j, j\rangle\]

where the rotation operator is defined as

\[\hat{R}(\theta, \phi) = \exp \left( \frac{\theta}{2} (\hat{S}_- e^{i\phi} - \hat{S}_+ e^{-i\phi}) \right)\]

and $\hat{S}_\pm$ are plus and minus Spin-j operators, respectively.

Arguments

  • j::Real: The spin quantum number and can be a non-negative integer or half-integer
  • θ::Real: rotation angle from z-axis
  • ϕ::Real: rotation angle from x-axis

See also jmat and spin_state.

Reference

source
QuantumToolbox.bell_stateFunction
bell_state(x::Union{Int}, z::Union{Int})

Return the Bell state depending on the arguments (x, z):

  • (0, 0): $| \Phi^+ \rangle = ( |00\rangle + |11\rangle ) / \sqrt{2}$
  • (0, 1): $| \Phi^- \rangle = ( |00\rangle - |11\rangle ) / \sqrt{2}$
  • (1, 0): $| \Psi^+ \rangle = ( |01\rangle + |10\rangle ) / \sqrt{2}$
  • (1, 1): $| \Psi^- \rangle = ( |01\rangle - |10\rangle ) / \sqrt{2}$

Here, x = 1 (z = 1) means applying Pauli-$X$ ( Pauli-$Z$) unitary transformation on $| \Phi^+ \rangle$.

Example

julia> bell_state(0, 0)
+⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦
source

Generate states and operators

QuantumToolbox.zero_ketFunction
zero_ket(dimensions)

Returns a zero Ket vector with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int}, Tuple}: list of dimensions representing the each number of basis in the subsystems.
Beware of type-stability!

It is highly recommended to use zero_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.fockFunction
fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))

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.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fock(N, j, dims=dims, sparse=Val(sparse)) instead of fock(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.basisFunction
basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)

Generates a fock state like fock.

It is also possible to specify the list of dimensions dims if different subsystems are present.

Beware of type-stability!

If you want to keep type stability, it is recommended to use basis(N, j, dims=dims) with dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.coherentFunction
coherent(N::Int, α::Number)

Generates a coherent state $|\alpha\rangle$, which is defined as an eigenvector of the bosonic annihilation operator $\hat{a} |\alpha\rangle = \alpha |\alpha\rangle$.

This state is constructed via the displacement operator displace and zero-fock state fock: $|\alpha\rangle = \hat{D}(\alpha) |0\rangle$

source
QuantumToolbox.rand_ketFunction
rand_ket(dimensions)

Generate a random normalized Ket vector with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.
Beware of type-stability!

If you want to keep type stability, it is recommended to use rand_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.fock_dmFunction
fock_dm(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))

Density matrix representation of a Fock state.

Constructed via outer product of fock.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fock_dm(N, j, dims=dims, sparse=Val(sparse)) instead of fock_dm(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.thermal_dmFunction
thermal_dm(N::Int, n::Real; sparse::Union{Bool,Val}=Val(false))

Density matrix for a thermal state (generating thermal state probabilities) with the following arguments:

  • N::Int: Number of basis states in the Hilbert space
  • n::Real: Expectation value for number of particles in the thermal state.
  • sparse::Union{Bool,Val}: If true, return a sparse matrix representation.
Beware of type-stability!

If you want to keep type stability, it is recommended to use thermal_dm(N, n, sparse=Val(sparse)) instead of thermal_dm(N, n, sparse=sparse). See this link and the related Section about type stability for more details.

source
QuantumToolbox.maximally_mixed_dmFunction
maximally_mixed_dm(dimensions)

Returns the maximally mixed density matrix with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.
Beware of type-stability!

If you want to keep type stability, it is recommended to use maximally_mixed_dm(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.rand_dmFunction
rand_dm(dimensions; rank::Int=prod(dimensions))

Generate a random density matrix from Ginibre ensemble with given argument dimensions and rank, ensuring that it is positive semi-definite and trace equals to 1.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.

The default keyword argument rank = prod(dimensions) (full rank).

Beware of type-stability!

If you want to keep type stability, it is recommended to use rand_dm(dimensions; rank=rank) with dimensions as Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.

References

source
QuantumToolbox.spin_stateFunction
spin_state(j::Real, m::Real)

Generate the spin state: $|j, m\rangle$

The eigenstate of the Spin-j $\hat{S}_z$ operator with eigenvalue m, where where j is the spin quantum number and can be a non-negative integer or half-integer

See also jmat.

source
QuantumToolbox.spin_coherentFunction
spin_coherent(j::Real, θ::Real, ϕ::Real)

Generate the coherent spin state (rotation of the $|j, j\rangle$ state), namely

\[|\theta, \phi \rangle = \hat{R}(\theta, \phi) |j, j\rangle\]

where the rotation operator is defined as

\[\hat{R}(\theta, \phi) = \exp \left( \frac{\theta}{2} (\hat{S}_- e^{i\phi} - \hat{S}_+ e^{-i\phi}) \right)\]

and $\hat{S}_\pm$ are plus and minus Spin-j operators, respectively.

Arguments

  • j::Real: The spin quantum number and can be a non-negative integer or half-integer
  • θ::Real: rotation angle from z-axis
  • ϕ::Real: rotation angle from x-axis

See also jmat and spin_state.

Reference

source
QuantumToolbox.bell_stateFunction
bell_state(x::Union{Int}, z::Union{Int})

Return the Bell state depending on the arguments (x, z):

  • (0, 0): $| \Phi^+ \rangle = ( |00\rangle + |11\rangle ) / \sqrt{2}$
  • (0, 1): $| \Phi^- \rangle = ( |00\rangle - |11\rangle ) / \sqrt{2}$
  • (1, 0): $| \Psi^+ \rangle = ( |01\rangle + |10\rangle ) / \sqrt{2}$
  • (1, 1): $| \Psi^- \rangle = ( |01\rangle - |10\rangle ) / \sqrt{2}$

Here, x = 1 (z = 1) means applying Pauli-$X$ ( Pauli-$Z$) unitary transformation on $| \Phi^+ \rangle$.

Example

julia> bell_state(0, 0)
 Quantum Object:   type=Ket   dims=[2, 2]   size=(4,)
 4-element Vector{ComplexF64}:
  0.7071067811865475 + 0.0im
@@ -196,7 +196,7 @@
                 0.0 + 0.0im
  0.7071067811865475 + 0.0im
  0.7071067811865475 + 0.0im
-                0.0 + 0.0im
Beware of type-stability!

If you want to keep type stability, it is recommended to use bell_state(Val(x), Val(z)) instead of bell_state(x, z). See this link and the related Section for more details.

source
QuantumToolbox.triplet_statesFunction
triplet_states()

Return a list of the two particle triplet states:

  • $|11\rangle$
  • $( |01\rangle + |10\rangle ) / \sqrt{2}$
  • $|00\rangle$
source
QuantumToolbox.w_stateFunction
w_state(n::Union{Int,Val})

Returns the n-qubit W-state:

\[\frac{1}{\sqrt{n}} \left( |100...0\rangle + |010...0\rangle + \cdots + |00...01\rangle \right)\]

Beware of type-stability!

If you want to keep type stability, it is recommended to use w_state(Val(n)) instead of w_state(n). See this link and the related Section for more details.

source
QuantumToolbox.ghz_stateFunction
ghz_state(n::Union{Int,Val}; d::Int=2)

Returns the generalized n-qudit Greenberger–Horne–Zeilinger (GHZ) state:

\[\frac{1}{\sqrt{d}} \sum_{i=0}^{d-1} | i \rangle \otimes \cdots \otimes | i \rangle\]

Here, d specifies the dimension of each qudit. Default to d=2 (qubit).

Beware of type-stability!

If you want to keep type stability, it is recommended to use ghz_state(Val(n)) instead of ghz_state(n). See this link and the related Section for more details.

source
QuantumToolbox.rand_unitaryFunction
rand_unitary(dimensions, distribution=Val(:haar))

Returns a random unitary QuantumObject.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.

The distribution specifies which of the method used to obtain the unitary matrix:

  • :haar: Haar random unitary matrix using the algorithm from reference 1
  • :exp: Uses $\exp(-i\hat{H})$, where $\hat{H}$ is a randomly generated Hermitian operator.

References

  1. F. Mezzadri, How to generate random matrices from the classical compact groups, arXiv:math-ph/0609050 (2007)
Beware of type-stability!

If you want to keep type stability, it is recommended to use rand_unitary(dimensions, Val(distribution)) instead of rand_unitary(dimensions, distribution). Also, put dimensions as Tuple or SVector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.jmatFunction
jmat(j::Real, which::Union{Symbol,Val})

Generate higher-order Spin-j operators, where j is the spin quantum number and can be a non-negative integer or half-integer

The parameter which specifies which of the following operator to return.

  • :x: $\hat{S}_x$
  • :y: $\hat{S}_y$
  • :z: $\hat{S}_z$
  • :+: $\hat{S}_+$
  • :-: $\hat{S}_-$

Note that if the parameter which is not specified, returns a set of Spin-j operators: $(\hat{S}_x, \hat{S}_y, \hat{S}_z)$

Examples

julia> jmat(0.5, :x)
+                0.0 + 0.0im
Beware of type-stability!

If you want to keep type stability, it is recommended to use bell_state(Val(x), Val(z)) instead of bell_state(x, z). See this link and the related Section for more details.

source
QuantumToolbox.triplet_statesFunction
triplet_states()

Return a list of the two particle triplet states:

  • $|11\rangle$
  • $( |01\rangle + |10\rangle ) / \sqrt{2}$
  • $|00\rangle$
source
QuantumToolbox.w_stateFunction
w_state(n::Union{Int,Val})

Returns the n-qubit W-state:

\[\frac{1}{\sqrt{n}} \left( |100...0\rangle + |010...0\rangle + \cdots + |00...01\rangle \right)\]

Beware of type-stability!

If you want to keep type stability, it is recommended to use w_state(Val(n)) instead of w_state(n). See this link and the related Section for more details.

source
QuantumToolbox.ghz_stateFunction
ghz_state(n::Union{Int,Val}; d::Int=2)

Returns the generalized n-qudit Greenberger–Horne–Zeilinger (GHZ) state:

\[\frac{1}{\sqrt{d}} \sum_{i=0}^{d-1} | i \rangle \otimes \cdots \otimes | i \rangle\]

Here, d specifies the dimension of each qudit. Default to d=2 (qubit).

Beware of type-stability!

If you want to keep type stability, it is recommended to use ghz_state(Val(n)) instead of ghz_state(n). See this link and the related Section for more details.

source
QuantumToolbox.rand_unitaryFunction
rand_unitary(dimensions, distribution=Val(:haar))

Returns a random unitary QuantumObject.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.

The distribution specifies which of the method used to obtain the unitary matrix:

  • :haar: Haar random unitary matrix using the algorithm from reference 1
  • :exp: Uses $\exp(-i\hat{H})$, where $\hat{H}$ is a randomly generated Hermitian operator.

References

  1. F. Mezzadri, How to generate random matrices from the classical compact groups, arXiv:math-ph/0609050 (2007)
Beware of type-stability!

If you want to keep type stability, it is recommended to use rand_unitary(dimensions, Val(distribution)) instead of rand_unitary(dimensions, distribution). Also, put dimensions as Tuple or SVector. See this link and the related Section about type stability for more details.

source
QuantumToolbox.jmatFunction
jmat(j::Real, which::Union{Symbol,Val})

Generate higher-order Spin-j operators, where j is the spin quantum number and can be a non-negative integer or half-integer

The parameter which specifies which of the following operator to return.

  • :x: $\hat{S}_x$
  • :y: $\hat{S}_y$
  • :z: $\hat{S}_z$
  • :+: $\hat{S}_+$
  • :-: $\hat{S}_-$

Note that if the parameter which is not specified, returns a set of Spin-j operators: $(\hat{S}_x, \hat{S}_y, \hat{S}_z)$

Examples

julia> jmat(0.5, :x)
 Quantum Object:   type=Operator   dims=[2]   size=(2, 2)   ishermitian=true
 2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
      ⋅      0.5+0.0im
@@ -214,7 +214,7 @@
  1.5+0.0im      ⋅           ⋅           ⋅    
      ⋅      0.5+0.0im       ⋅           ⋅    
      ⋅          ⋅      -0.5+0.0im       ⋅    
-     ⋅          ⋅           ⋅      -1.5+0.0im
Beware of type-stability!

If you want to keep type stability, it is recommended to use jmat(j, Val(which)) instead of jmat(j, which). See this link and the related Section about type stability for more details.

source
QuantumToolbox.spin_JxFunction
spin_Jx(j::Real)

$\hat{S}_x$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JyFunction
spin_Jy(j::Real)

$\hat{S}_y$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JzFunction
spin_Jz(j::Real)

$\hat{S}_z$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JmFunction
spin_Jm(j::Real)

$\hat{S}_-$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JpFunction
spin_Jp(j::Real)

$\hat{S}_+$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_J_setFunction
spin_J_set(j::Real)

A set of Spin-j operators $(\hat{S}_x, \hat{S}_y, \hat{S}_z)$, where j is the spin quantum number and can be a non-negative integer or half-integer.

Note that this functions is same as jmat(j). See also jmat.

source
QuantumToolbox.destroyFunction
destroy(N::Int)

Bosonic annihilation operator with Hilbert space cutoff N.

This operator acts on a fock state as $\hat{a} \ket{n} = \sqrt{n} \ket{n-1}$.

Examples

julia> a = destroy(20)
+     ⋅          ⋅           ⋅      -1.5+0.0im
Beware of type-stability!

If you want to keep type stability, it is recommended to use jmat(j, Val(which)) instead of jmat(j, which). See this link and the related Section about type stability for more details.

source
QuantumToolbox.spin_JxFunction
spin_Jx(j::Real)

$\hat{S}_x$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JyFunction
spin_Jy(j::Real)

$\hat{S}_y$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JzFunction
spin_Jz(j::Real)

$\hat{S}_z$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JmFunction
spin_Jm(j::Real)

$\hat{S}_-$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_JpFunction
spin_Jp(j::Real)

$\hat{S}_+$ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.

See also jmat.

source
QuantumToolbox.spin_J_setFunction
spin_J_set(j::Real)

A set of Spin-j operators $(\hat{S}_x, \hat{S}_y, \hat{S}_z)$, where j is the spin quantum number and can be a non-negative integer or half-integer.

Note that this functions is same as jmat(j). See also jmat.

source
QuantumToolbox.destroyFunction
destroy(N::Int)

Bosonic annihilation operator with Hilbert space cutoff N.

This operator acts on a fock state as $\hat{a} \ket{n} = \sqrt{n} \ket{n-1}$.

Examples

julia> a = destroy(20)
 Quantum Object:   type=Operator   dims=[20]   size=(20, 20)   ishermitian=false
 20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:
 ⎡⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⎤
@@ -224,7 +224,7 @@
 ⎣⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⎦
 
 julia> fock(20, 3)' * a * fock(20, 4)
-2.0 + 0.0im
source
QuantumToolbox.createFunction
create(N::Int)

Bosonic creation operator with Hilbert space cutoff N.

This operator acts on a fock state as $\hat{a}^\dagger \ket{n} = \sqrt{n+1} \ket{n+1}$.

Examples

julia> a_d = create(20)
+2.0 + 0.0im
source
QuantumToolbox.createFunction
create(N::Int)

Bosonic creation operator with Hilbert space cutoff N.

This operator acts on a fock state as $\hat{a}^\dagger \ket{n} = \sqrt{n+1} \ket{n+1}$.

Examples

julia> a_d = create(20)
 Quantum Object:   type=Operator   dims=[20]   size=(20, 20)   ishermitian=false
 20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:
 ⎡⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⎤
@@ -234,15 +234,15 @@
 ⎣⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⎦
 
 julia> fock(20, 4)' * a_d * fock(20, 3)
-2.0 + 0.0im
source
QuantumToolbox.displaceFunction
displace(N::Int, α::Number)

Generate a displacement operator:

\[\hat{D}(\alpha)=\exp\left( \alpha \hat{a}^\dagger - \alpha^* \hat{a} \right),\]

where $\hat{a}$ is the bosonic annihilation operator, and $\alpha$ is the amount of displacement in optical phase space.

source
QuantumToolbox.squeezeFunction
squeeze(N::Int, z::Number)

Generate a single-mode squeeze operator:

\[\hat{S}(z)=\exp\left( \frac{1}{2} (z^* \hat{a}^2 - z(\hat{a}^\dagger)^2) \right),\]

where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.numFunction
num(N::Int)

Bosonic number operator with Hilbert space cutoff N.

This operator is defined as $\hat{N}=\hat{a}^\dagger \hat{a}$, where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.positionFunction
position(N::Int)

Position operator with Hilbert space cutoff N.

This operator is defined as $\hat{x}=\frac{1}{\sqrt{2}} (\hat{a}^\dagger + \hat{a})$, where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.momentumFunction
momentum(N::Int)

Momentum operator with Hilbert space cutoff N.

This operator is defined as $\hat{p}= \frac{i}{\sqrt{2}} (\hat{a}^\dagger - \hat{a})$, where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.phaseFunction
phase(N::Int, ϕ0::Real=0)

Single-mode Pegg-Barnett phase operator with Hilbert space cutoff $N$ and the reference phase $\phi_0$.

This operator is defined as

\[\hat{\phi} = \sum_{m=0}^{N-1} \phi_m |\phi_m\rangle \langle\phi_m|,\]

where

\[\phi_m = \phi_0 + \frac{2m\pi}{N},\]

and

\[|\phi_m\rangle = \frac{1}{\sqrt{N}} \sum_{n=0}^{N-1} \exp(i n \phi_m) |n\rangle.\]

Reference

source
QuantumToolbox.fdestroyFunction
fdestroy(N::Union{Int,Val}, j::Int)

Construct a fermionic destruction operator acting on the j-th site, where the fock space has totally N-sites:

Here, we use the Jordan-Wigner transformation, namely

\[\hat{d}_j = \hat{\sigma}_z^{\otimes j-1} \otimes \hat{\sigma}_{+} \otimes \hat{\mathbb{1}}^{\otimes N-j}\]

The site index j should satisfy: 1 ≤ j ≤ N.

Note that we put $\hat{\sigma}_{+} = \begin{pmatrix} 0 & 1 \\ 0 & 0 \end{pmatrix}$ here because we consider $|0\rangle = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ to be ground (vacant) state, and $|1\rangle = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$ to be excited (occupied) state.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fdestroy(Val(N), j) instead of fdestroy(N, j). See this link and the related Section about type stability for more details.

source
QuantumToolbox.fcreateFunction
fcreate(N::Union{Int,Val}, j::Int)

Construct a fermionic creation operator acting on the j-th site, where the fock space has totally N-sites:

Here, we use the Jordan-Wigner transformation, namely

\[\hat{d}^\dagger_j = \hat{\sigma}_z^{\otimes j-1} \otimes \hat{\sigma}_{-} \otimes \hat{\mathbb{1}}^{\otimes N-j}\]

The site index j should satisfy: 1 ≤ j ≤ N.

Note that we put $\hat{\sigma}_{-} = \begin{pmatrix} 0 & 0 \\ 1 & 0 \end{pmatrix}$ here because we consider $|0\rangle = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ to be ground (vacant) state, and $|1\rangle = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$ to be excited (occupied) state.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fcreate(Val(N), j) instead of fcreate(N, j). See this link and the related Section about type stability for more details.

source
QuantumToolbox.tunnelingFunction
tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))

Generate a tunneling operator defined as:

\[\sum_{n=0}^{N-m} | n \rangle\langle n+m | + | n+m \rangle\langle n |,\]

where $N$ is the number of basis states in the Hilbert space, and $m$ is the number of excitations in tunneling event.

If sparse=true, the operator is returned as a sparse matrix, otherwise a dense matrix is returned.

Beware of type-stability!

If you want to keep type stability, it is recommended to use tunneling(N, m, Val(sparse)) instead of tunneling(N, m, sparse). See this link and the related Section about type stability for more details.

source
QuantumToolbox.qftFunction
qft(dimensions)

Generates a discrete Fourier transform matrix $\hat{F}_N$ for Quantum Fourier Transform (QFT) with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.

$N$ represents the total dimension, and therefore the matrix is defined as

\[\hat{F}_N = \frac{1}{\sqrt{N}}\begin{bmatrix} +2.0 + 0.0im

source
QuantumToolbox.displaceFunction
displace(N::Int, α::Number)

Generate a displacement operator:

\[\hat{D}(\alpha)=\exp\left( \alpha \hat{a}^\dagger - \alpha^* \hat{a} \right),\]

where $\hat{a}$ is the bosonic annihilation operator, and $\alpha$ is the amount of displacement in optical phase space.

source
QuantumToolbox.squeezeFunction
squeeze(N::Int, z::Number)

Generate a single-mode squeeze operator:

\[\hat{S}(z)=\exp\left( \frac{1}{2} (z^* \hat{a}^2 - z(\hat{a}^\dagger)^2) \right),\]

where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.numFunction
num(N::Int)

Bosonic number operator with Hilbert space cutoff N.

This operator is defined as $\hat{N}=\hat{a}^\dagger \hat{a}$, where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.positionFunction
position(N::Int)

Position operator with Hilbert space cutoff N.

This operator is defined as $\hat{x}=\frac{1}{\sqrt{2}} (\hat{a}^\dagger + \hat{a})$, where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.momentumFunction
momentum(N::Int)

Momentum operator with Hilbert space cutoff N.

This operator is defined as $\hat{p}= \frac{i}{\sqrt{2}} (\hat{a}^\dagger - \hat{a})$, where $\hat{a}$ is the bosonic annihilation operator.

source
QuantumToolbox.phaseFunction
phase(N::Int, ϕ0::Real=0)

Single-mode Pegg-Barnett phase operator with Hilbert space cutoff $N$ and the reference phase $\phi_0$.

This operator is defined as

\[\hat{\phi} = \sum_{m=0}^{N-1} \phi_m |\phi_m\rangle \langle\phi_m|,\]

where

\[\phi_m = \phi_0 + \frac{2m\pi}{N},\]

and

\[|\phi_m\rangle = \frac{1}{\sqrt{N}} \sum_{n=0}^{N-1} \exp(i n \phi_m) |n\rangle.\]

Reference

source
QuantumToolbox.fdestroyFunction
fdestroy(N::Union{Int,Val}, j::Int)

Construct a fermionic destruction operator acting on the j-th site, where the fock space has totally N-sites:

Here, we use the Jordan-Wigner transformation, namely

\[\hat{d}_j = \hat{\sigma}_z^{\otimes j-1} \otimes \hat{\sigma}_{+} \otimes \hat{\mathbb{1}}^{\otimes N-j}\]

The site index j should satisfy: 1 ≤ j ≤ N.

Note that we put $\hat{\sigma}_{+} = \begin{pmatrix} 0 & 1 \\ 0 & 0 \end{pmatrix}$ here because we consider $|0\rangle = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ to be ground (vacant) state, and $|1\rangle = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$ to be excited (occupied) state.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fdestroy(Val(N), j) instead of fdestroy(N, j). See this link and the related Section about type stability for more details.

source
QuantumToolbox.fcreateFunction
fcreate(N::Union{Int,Val}, j::Int)

Construct a fermionic creation operator acting on the j-th site, where the fock space has totally N-sites:

Here, we use the Jordan-Wigner transformation, namely

\[\hat{d}^\dagger_j = \hat{\sigma}_z^{\otimes j-1} \otimes \hat{\sigma}_{-} \otimes \hat{\mathbb{1}}^{\otimes N-j}\]

The site index j should satisfy: 1 ≤ j ≤ N.

Note that we put $\hat{\sigma}_{-} = \begin{pmatrix} 0 & 0 \\ 1 & 0 \end{pmatrix}$ here because we consider $|0\rangle = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ to be ground (vacant) state, and $|1\rangle = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$ to be excited (occupied) state.

Beware of type-stability!

If you want to keep type stability, it is recommended to use fcreate(Val(N), j) instead of fcreate(N, j). See this link and the related Section about type stability for more details.

source
QuantumToolbox.tunnelingFunction
tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))

Generate a tunneling operator defined as:

\[\sum_{n=0}^{N-m} | n \rangle\langle n+m | + | n+m \rangle\langle n |,\]

where $N$ is the number of basis states in the Hilbert space, and $m$ is the number of excitations in tunneling event.

If sparse=true, the operator is returned as a sparse matrix, otherwise a dense matrix is returned.

Beware of type-stability!

If you want to keep type stability, it is recommended to use tunneling(N, m, Val(sparse)) instead of tunneling(N, m, sparse). See this link and the related Section about type stability for more details.

source
QuantumToolbox.qftFunction
qft(dimensions)

Generates a discrete Fourier transform matrix $\hat{F}_N$ for Quantum Fourier Transform (QFT) with given argument dimensions.

The dimensions can be either the following types:

  • dimensions::Int: Number of basis states in the Hilbert space.
  • dimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.

$N$ represents the total dimension, and therefore the matrix is defined as

\[\hat{F}_N = \frac{1}{\sqrt{N}}\begin{bmatrix} 1 & 1 & 1 & 1 & \cdots & 1\\ 1 & \omega & \omega^2 & \omega^3 & \cdots & \omega^{N-1}\\ 1 & \omega^2 & \omega^4 & \omega^6 & \cdots & \omega^{2(N-1)}\\ 1 & \omega^3 & \omega^6 & \omega^9 & \cdots & \omega^{3(N-1)}\\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ 1 & \omega^{N-1} & \omega^{2(N-1)} & \omega^{3(N-1)} & \cdots & \omega^{(N-1)(N-1)} -\end{bmatrix},\]

where $\omega = \exp(\frac{2 \pi i}{N})$.

Beware of type-stability!

It is highly recommended to use qft(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.eyeFunction
eye(N::Int; type=Operator, dims=nothing)

Identity operator $\hat{\mathbb{1}}$ with size N.

It is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.

Note that type can only be either Operator or SuperOperator

source
QuantumToolbox.projectionFunction
projection(N::Int, i::Int, j::Int)

Generates the projection operator $\hat{O} = \dyad{i}{j}$ with Hilbert space dimension N.

source
QuantumToolbox.commutatorFunction
commutator(A::QuantumObject, B::QuantumObject; anti::Bool=false)

Return the commutator (or anti-commutator) of the two QuantumObject:

  • commutator (anti=false): $\hat{A}\hat{B}-\hat{B}\hat{A}$
  • anticommutator (anti=true): $\hat{A}\hat{B}+\hat{B}\hat{A}$

Note that A and B must be Operator

source
QuantumToolbox.spreFunction
spre(A::QuantumObject, Id_cache=I(size(A,1)))

Returns the SuperOperator form of A acting on the left of the density matrix operator: $\mathcal{O} \left(\hat{A}\right) \left[ \hat{\rho} \right] = \hat{A} \hat{\rho}$.

Since the density matrix is vectorized in OperatorKet form: $|\hat{\rho}\rangle\rangle$, this SuperOperator is always a matrix $\hat{\mathbb{1}} \otimes \hat{A}$, namely

\[\mathcal{O} \left(\hat{A}\right) \left[ \hat{\rho} \right] = \hat{\mathbb{1}} \otimes \hat{A} ~ |\hat{\rho}\rangle\rangle\]

(see the section in documentation: Superoperators and Vectorized Operators for more details)

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.

source
QuantumToolbox.spostFunction
spost(B::QuantumObject, Id_cache=I(size(B,1)))

Returns the SuperOperator form of B acting on the right of the density matrix operator: $\mathcal{O} \left(\hat{B}\right) \left[ \hat{\rho} \right] = \hat{\rho} \hat{B}$.

Since the density matrix is vectorized in OperatorKet form: $|\hat{\rho}\rangle\rangle$, this SuperOperator is always a matrix $\hat{B}^T \otimes \hat{\mathbb{1}}$, namely

\[\mathcal{O} \left(\hat{B}\right) \left[ \hat{\rho} \right] = \hat{B}^T \otimes \hat{\mathbb{1}} ~ |\hat{\rho}\rangle\rangle\]

(see the section in documentation: Superoperators and Vectorized Operators for more details)

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.

source
QuantumToolbox.sprepostFunction
sprepost(A::QuantumObject, B::QuantumObject)

Returns the SuperOperator form of A and B acting on the left and right of the density matrix operator, respectively: $\mathcal{O} \left( \hat{A}, \hat{B} \right) \left[ \hat{\rho} \right] = \hat{A} \hat{\rho} \hat{B}$.

Since the density matrix is vectorized in OperatorKet form: $|\hat{\rho}\rangle\rangle$, this SuperOperator is always a matrix $\hat{B}^T \otimes \hat{A}$, namely

\[\mathcal{O} \left(\hat{A}, \hat{B}\right) \left[ \hat{\rho} \right] = \hat{B}^T \otimes \hat{A} ~ |\hat{\rho}\rangle\rangle = \textrm{spre}(\hat{A}) * \textrm{spost}(\hat{B}) ~ |\hat{\rho}\rangle\rangle\]

(see the section in documentation: Superoperators and Vectorized Operators for more details)

See also spre and spost.

source
QuantumToolbox.lindblad_dissipatorFunction
lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1))

Returns the Lindblad SuperOperator defined as

\[\mathcal{D} \left( \hat{O} \right) \left[ \hat{\rho} \right] = \frac{1}{2} \left( 2 \hat{O} \hat{\rho} \hat{O}^\dagger - -\hat{O}^\dagger \hat{O} \hat{\rho} - \hat{\rho} \hat{O}^\dagger \hat{O} \right)\]

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.

See also spre and spost.

source

Synonyms of functions for Qobj

QuantumToolbox.QobjFunction
Qobj(A::AbstractArray; type::QuantumObjectType, dims::Vector{Int})

Generate QuantumObject

Note that this functions is same as QuantumObject(A; type=type, dims=dims)

source
QuantumToolbox.matrix_elementFunction
matrix_element(i::QuantumObject, A::QuantumObject j::QuantumObject)

Compute the generalized dot product dot(i, A*j) between three QuantumObject: $\langle i | \hat{A} | j \rangle$

Note that this function is same as dot(i, A, j)

Supports the following inputs:

source
QuantumToolbox.tensorFunction
tensor(A::QuantumObject, B::QuantumObject, ...)

Returns the Kronecker product $\hat{A} \otimes \hat{B} \otimes \cdots$.

Note that this function is same as kron(A, B, ...)

Examples

julia> x = sigmax()
+\end{bmatrix},\]

where $\omega = \exp(\frac{2 \pi i}{N})$.

Beware of type-stability!

It is highly recommended to use qft(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.

source
QuantumToolbox.eyeFunction
eye(N::Int; type=Operator, dims=nothing)

Identity operator $\hat{\mathbb{1}}$ with size N.

It is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.

Note that type can only be either Operator or SuperOperator

source
QuantumToolbox.projectionFunction
projection(N::Int, i::Int, j::Int)

Generates the projection operator $\hat{O} = \dyad{i}{j}$ with Hilbert space dimension N.

source
QuantumToolbox.commutatorFunction
commutator(A::QuantumObject, B::QuantumObject; anti::Bool=false)

Return the commutator (or anti-commutator) of the two QuantumObject:

  • commutator (anti=false): $\hat{A}\hat{B}-\hat{B}\hat{A}$
  • anticommutator (anti=true): $\hat{A}\hat{B}+\hat{B}\hat{A}$

Note that A and B must be Operator

source
QuantumToolbox.spreFunction
spre(A::QuantumObject, Id_cache=I(size(A,1)))

Returns the SuperOperator form of A acting on the left of the density matrix operator: $\mathcal{O} \left(\hat{A}\right) \left[ \hat{\rho} \right] = \hat{A} \hat{\rho}$.

Since the density matrix is vectorized in OperatorKet form: $|\hat{\rho}\rangle\rangle$, this SuperOperator is always a matrix $\hat{\mathbb{1}} \otimes \hat{A}$, namely

\[\mathcal{O} \left(\hat{A}\right) \left[ \hat{\rho} \right] = \hat{\mathbb{1}} \otimes \hat{A} ~ |\hat{\rho}\rangle\rangle\]

(see the section in documentation: Superoperators and Vectorized Operators for more details)

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.

source
QuantumToolbox.spostFunction
spost(B::QuantumObject, Id_cache=I(size(B,1)))

Returns the SuperOperator form of B acting on the right of the density matrix operator: $\mathcal{O} \left(\hat{B}\right) \left[ \hat{\rho} \right] = \hat{\rho} \hat{B}$.

Since the density matrix is vectorized in OperatorKet form: $|\hat{\rho}\rangle\rangle$, this SuperOperator is always a matrix $\hat{B}^T \otimes \hat{\mathbb{1}}$, namely

\[\mathcal{O} \left(\hat{B}\right) \left[ \hat{\rho} \right] = \hat{B}^T \otimes \hat{\mathbb{1}} ~ |\hat{\rho}\rangle\rangle\]

(see the section in documentation: Superoperators and Vectorized Operators for more details)

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.

source
QuantumToolbox.sprepostFunction
sprepost(A::QuantumObject, B::QuantumObject)

Returns the SuperOperator form of A and B acting on the left and right of the density matrix operator, respectively: $\mathcal{O} \left( \hat{A}, \hat{B} \right) \left[ \hat{\rho} \right] = \hat{A} \hat{\rho} \hat{B}$.

Since the density matrix is vectorized in OperatorKet form: $|\hat{\rho}\rangle\rangle$, this SuperOperator is always a matrix $\hat{B}^T \otimes \hat{A}$, namely

\[\mathcal{O} \left(\hat{A}, \hat{B}\right) \left[ \hat{\rho} \right] = \hat{B}^T \otimes \hat{A} ~ |\hat{\rho}\rangle\rangle = \textrm{spre}(\hat{A}) * \textrm{spost}(\hat{B}) ~ |\hat{\rho}\rangle\rangle\]

(see the section in documentation: Superoperators and Vectorized Operators for more details)

See also spre and spost.

source
QuantumToolbox.lindblad_dissipatorFunction
lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1))

Returns the Lindblad SuperOperator defined as

\[\mathcal{D} \left( \hat{O} \right) \left[ \hat{\rho} \right] = \frac{1}{2} \left( 2 \hat{O} \hat{\rho} \hat{O}^\dagger - +\hat{O}^\dagger \hat{O} \hat{\rho} - \hat{\rho} \hat{O}^\dagger \hat{O} \right)\]

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.

See also spre and spost.

source

Synonyms of functions for Qobj

QuantumToolbox.QobjFunction
Qobj(A::AbstractArray; type::QuantumObjectType, dims::Vector{Int})

Generate QuantumObject

Note that this functions is same as QuantumObject(A; type=type, dims=dims)

source
QuantumToolbox.matrix_elementFunction
matrix_element(i::QuantumObject, A::QuantumObject j::QuantumObject)

Compute the generalized dot product dot(i, A*j) between three QuantumObject: $\langle i | \hat{A} | j \rangle$

Note that this function is same as dot(i, A, j)

Supports the following inputs:

source
QuantumToolbox.tensorFunction
tensor(A::QuantumObject, B::QuantumObject, ...)

Returns the Kronecker product $\hat{A} \otimes \hat{B} \otimes \cdots$.

Note that this function is same as kron(A, B, ...)

Examples

julia> x = sigmax()
 Quantum Object:   type=Operator   dims=[2]   size=(2, 2)   ishermitian=true
 2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:
      ⋅      1.0+0.0im
@@ -260,7 +260,7 @@
      ⋅          ⋅          ⋅             ⋅          ⋅          ⋅
      ⋅          ⋅      1.0+0.0im  …      ⋅          ⋅          ⋅
      ⋅      1.0+0.0im      ⋅             ⋅          ⋅          ⋅
- 1.0+0.0im      ⋅          ⋅             ⋅          ⋅          ⋅
source
QuantumToolbox.:⊗Function
⊗(A::QuantumObject, B::QuantumObject)

Returns the Kronecker product $\hat{A} \otimes \hat{B}$.

Note that this function is same as kron(A, B)

Examples

julia> a = destroy(20)
+ 1.0+0.0im      ⋅          ⋅             ⋅          ⋅          ⋅
source
QuantumToolbox.:⊗Function
⊗(A::QuantumObject, B::QuantumObject)

Returns the Kronecker product $\hat{A} \otimes \hat{B}$.

Note that this function is same as kron(A, B)

Examples

julia> a = destroy(20)
 Quantum Object:   type=Operator   dims=[20]   size=(20, 20)   ishermitian=false
 20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:
 ⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀
@@ -292,7 +292,7 @@
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀
-⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦
source
QuantumToolbox.qeyeFunction
qeye(N::Int; type=Operator, dims=nothing)

Identity operator $\hat{\mathbb{1}}$ with size N.

It is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.

Note that this function is same as eye(N, type=type, dims=dims), and type can only be either Operator or SuperOperator

source

Time evolution

QuantumToolbox.TimeEvolutionSolType
struct TimeEvolutionSol

A structure storing the results and some information from solving time evolution.

Fields (Attributes)

  • times::AbstractVector: The time list of the evolution.
  • states::Vector{QuantumObject}: The list of result states.
  • expect::Matrix: The expectation values corresponding to each time point in times.
  • retcode: The return code from the solver.
  • alg: The algorithm which is used during the solving process.
  • abstol::Real: The absolute tolerance which is used during the solving process.
  • reltol::Real: The relative tolerance which is used during the solving process.
source
QuantumToolbox.TimeEvolutionMCSolType
struct TimeEvolutionMCSol

A structure storing the results and some information from solving quantum trajectories of the Monte Carlo wave function time evolution.

Fields (Attributes)

  • ntraj::Int: Number of trajectories
  • times::AbstractVector: The time list of the evolution.
  • states::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.
  • expect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.
  • expect_all::Array: The expectation values corresponding to each trajectory and each time point in times
  • jump_times::Vector{Vector{Real}}: The time records of every quantum jump occurred in each trajectory.
  • jump_which::Vector{Vector{Int}}: The indices of the jump operators in c_ops that describe the corresponding quantum jumps occurred in each trajectory.
  • converged::Bool: Whether the solution is converged or not.
  • alg: The algorithm which is used during the solving process.
  • abstol::Real: The absolute tolerance which is used during the solving process.
  • reltol::Real: The relative tolerance which is used during the solving process.
source
QuantumToolbox.TimeEvolutionSSESolType
struct TimeEvolutionSSESol

A structure storing the results and some information from solving trajectories of the Stochastic Shrodinger equation time evolution.

Fields (Attributes)

  • ntraj::Int: Number of trajectories
  • times::AbstractVector: The time list of the evolution.
  • states::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.
  • expect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.
  • expect_all::Array: The expectation values corresponding to each trajectory and each time point in times
  • converged::Bool: Whether the solution is converged or not.
  • alg: The algorithm which is used during the solving process.
  • abstol::Real: The absolute tolerance which is used during the solving process.
  • reltol::Real: The relative tolerance which is used during the solving process.
source
QuantumToolbox.sesolveProblemFunction
sesolveProblem(H::QuantumObject,
+⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦
source
QuantumToolbox.qeyeFunction
qeye(N::Int; type=Operator, dims=nothing)

Identity operator $\hat{\mathbb{1}}$ with size N.

It is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.

Note that this function is same as eye(N, type=type, dims=dims), and type can only be either Operator or SuperOperator

source

Time evolution

QuantumToolbox.TimeEvolutionSolType
struct TimeEvolutionSol

A structure storing the results and some information from solving time evolution.

Fields (Attributes)

  • times::AbstractVector: The time list of the evolution.
  • states::Vector{QuantumObject}: The list of result states.
  • expect::Matrix: The expectation values corresponding to each time point in times.
  • retcode: The return code from the solver.
  • alg: The algorithm which is used during the solving process.
  • abstol::Real: The absolute tolerance which is used during the solving process.
  • reltol::Real: The relative tolerance which is used during the solving process.
source
QuantumToolbox.TimeEvolutionMCSolType
struct TimeEvolutionMCSol

A structure storing the results and some information from solving quantum trajectories of the Monte Carlo wave function time evolution.

Fields (Attributes)

  • ntraj::Int: Number of trajectories
  • times::AbstractVector: The time list of the evolution.
  • states::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.
  • expect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.
  • expect_all::Array: The expectation values corresponding to each trajectory and each time point in times
  • jump_times::Vector{Vector{Real}}: The time records of every quantum jump occurred in each trajectory.
  • jump_which::Vector{Vector{Int}}: The indices of the jump operators in c_ops that describe the corresponding quantum jumps occurred in each trajectory.
  • converged::Bool: Whether the solution is converged or not.
  • alg: The algorithm which is used during the solving process.
  • abstol::Real: The absolute tolerance which is used during the solving process.
  • reltol::Real: The relative tolerance which is used during the solving process.
source
QuantumToolbox.TimeEvolutionSSESolType
struct TimeEvolutionSSESol

A structure storing the results and some information from solving trajectories of the Stochastic Shrodinger equation time evolution.

Fields (Attributes)

  • ntraj::Int: Number of trajectories
  • times::AbstractVector: The time list of the evolution.
  • states::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.
  • expect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.
  • expect_all::Array: The expectation values corresponding to each trajectory and each time point in times
  • converged::Bool: Whether the solution is converged or not.
  • alg: The algorithm which is used during the solving process.
  • abstol::Real: The absolute tolerance which is used during the solving process.
  • reltol::Real: The relative tolerance which is used during the solving process.
source
QuantumToolbox.sesolveProblemFunction
sesolveProblem(H::QuantumObject,
     ψ0::QuantumObject,
     tlist::AbstractVector;
     alg::OrdinaryDiffEqAlgorithm=Tsit5()
@@ -300,7 +300,7 @@
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
     progress_bar::Union{Val,Bool}=Val(true),
-    kwargs...)

Generates the ODEProblem for the Schrödinger time evolution of a quantum system:

\[\frac{\partial}{\partial t} |\psi(t)\rangle = -i \hat{H} |\psi(t)\rangle\]

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: The time list of the evolution.
  • alg::OrdinaryDiffEqAlgorithm: The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: The keyword arguments passed to the ODEProblem constructor.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob: The ODEProblem for the Schrödinger time evolution of the system.
source
QuantumToolbox.mesolveProblemFunction
mesolveProblem(H::QuantumObject,
+    kwargs...)

Generates the ODEProblem for the Schrödinger time evolution of a quantum system:

\[\frac{\partial}{\partial t} |\psi(t)\rangle = -i \hat{H} |\psi(t)\rangle\]

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: The time list of the evolution.
  • alg::OrdinaryDiffEqAlgorithm: The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: The keyword arguments passed to the ODEProblem constructor.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob: The ODEProblem for the Schrödinger time evolution of the system.
source
QuantumToolbox.mesolveProblemFunction
mesolveProblem(H::QuantumObject,
     ψ0::QuantumObject,
     tlist::AbstractVector, 
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
@@ -309,7 +309,7 @@
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
     progress_bar::Union{Val,Bool}=Val(true),
-    kwargs...)

Generates the ODEProblem for the master equation time evolution of an open quantum system:

\[\frac{\partial \hat{\rho}(t)}{\partial t} = -i[\hat{H}, \hat{\rho}(t)] + \sum_n \mathcal{D}(\hat{C}_n) [\hat{\rho}(t)]\]

where

\[\mathcal{D}(\hat{C}_n) [\hat{\rho}(t)] = \hat{C}_n \hat{\rho}(t) \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n \hat{\rho}(t) - \frac{1}{2} \hat{\rho}(t) \hat{C}_n^\dagger \hat{C}_n\]

Arguments

  • H::QuantumObject: The Hamiltonian $\hat{H}$ or the Liouvillian of the system.
  • ψ0::QuantumObject: The initial state of the system.
  • tlist::AbstractVector: The time list of the evolution.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm=Tsit5(): The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}=nothing: 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::Union{Val,Bool}=Val(true): Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: The keyword arguments for the ODEProblem.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::ODEProblem: The ODEProblem for the master equation time evolution.
source
QuantumToolbox.mcsolveProblemFunction
mcsolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
+    kwargs...)

Generates the ODEProblem for the master equation time evolution of an open quantum system:

\[\frac{\partial \hat{\rho}(t)}{\partial t} = -i[\hat{H}, \hat{\rho}(t)] + \sum_n \mathcal{D}(\hat{C}_n) [\hat{\rho}(t)]\]

where

\[\mathcal{D}(\hat{C}_n) [\hat{\rho}(t)] = \hat{C}_n \hat{\rho}(t) \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n \hat{\rho}(t) - \frac{1}{2} \hat{\rho}(t) \hat{C}_n^\dagger \hat{C}_n\]

Arguments

  • H::QuantumObject: The Hamiltonian $\hat{H}$ or the Liouvillian of the system.
  • ψ0::QuantumObject: The initial state of the system.
  • tlist::AbstractVector: The time list of the evolution.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm=Tsit5(): The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}=nothing: 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::Union{Val,Bool}=Val(true): Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: The keyword arguments for the ODEProblem.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::ODEProblem: The ODEProblem for the master equation time evolution.
source
QuantumToolbox.mcsolveProblemFunction
mcsolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
     ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},
     tlist::AbstractVector,
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
@@ -317,8 +317,9 @@
     e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
+    rng::AbstractRNG=default_rng(),
     jump_callback::TJC=ContinuousLindbladJumpCallback(),
-    kwargs...)

Generates the ODEProblem for a single trajectory of the Monte Carlo wave function time evolution of an open quantum system.

Given a system Hamiltonian $\hat{H}$ and a list of collapse (jump) operators $\{\hat{C}_n\}_n$, the evolution of the state $|\psi(t)\rangle$ is governed by the Schrodinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle= -i \hat{H}_{\textrm{eff}} |\psi(t)\rangle\]

with a non-Hermitian effective Hamiltonian:

\[\hat{H}_{\textrm{eff}} = \hat{H} - \frac{i}{2} \sum_n \hat{C}_n^\dagger \hat{C}_n.\]

To the first-order of the wave function in a small time $\delta t$, the strictly negative non-Hermitian portion in $\hat{H}_{\textrm{eff}}$ gives rise to a reduction in the norm of the wave function, namely

\[\langle \psi(t+\delta t) | \psi(t+\delta t) \rangle = 1 - \delta p,\]

where

\[\delta p = \delta t \sum_n \langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle\]

is the corresponding quantum jump probability.

If the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting $|\psi(t)\rangle$ using the collapse operator $\hat{C}_n$ corresponding to the measurement, namely

\[| \psi(t+\delta t) \rangle = \frac{\hat{C}_n |\psi(t)\rangle}{ \sqrt{\langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle} }\]

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::ODEProblem: The ODEProblem for the Monte Carlo wave function time evolution.
source
QuantumToolbox.mcsolveEnsembleProblemFunction
mcsolveEnsembleProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
+    kwargs...)

Generates the ODEProblem for a single trajectory of the Monte Carlo wave function time evolution of an open quantum system.

Given a system Hamiltonian $\hat{H}$ and a list of collapse (jump) operators $\{\hat{C}_n\}_n$, the evolution of the state $|\psi(t)\rangle$ is governed by the Schrodinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle= -i \hat{H}_{\textrm{eff}} |\psi(t)\rangle\]

with a non-Hermitian effective Hamiltonian:

\[\hat{H}_{\textrm{eff}} = \hat{H} - \frac{i}{2} \sum_n \hat{C}_n^\dagger \hat{C}_n.\]

To the first-order of the wave function in a small time $\delta t$, the strictly negative non-Hermitian portion in $\hat{H}_{\textrm{eff}}$ gives rise to a reduction in the norm of the wave function, namely

\[\langle \psi(t+\delta t) | \psi(t+\delta t) \rangle = 1 - \delta p,\]

where

\[\delta p = \delta t \sum_n \langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle\]

is the corresponding quantum jump probability.

If the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting $|\psi(t)\rangle$ using the collapse operator $\hat{C}_n$ corresponding to the measurement, namely

\[| \psi(t+\delta t) \rangle = \frac{\hat{C}_n |\psi(t)\rangle}{ \sqrt{\langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle} }\]

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • rng::AbstractRNG: Random number generator for reproducibility.
  • jump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::ODEProblem: The ODEProblem for the Monte Carlo wave function time evolution.
source
QuantumToolbox.mcsolveEnsembleProblemFunction
mcsolveEnsembleProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
     ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},
     tlist::AbstractVector,
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
@@ -332,7 +333,7 @@
     prob_func::Function=_mcsolve_prob_func,
     output_func::Function=_mcsolve_output_func,
     progress_bar::Union{Val,Bool}=Val(true),
-    kwargs...)

Generates the EnsembleProblem of ODEProblems for the ensemble of trajectories of the Monte Carlo wave function time evolution of an open quantum system.

Given a system Hamiltonian $\hat{H}$ and a list of collapse (jump) operators $\{\hat{C}_n\}_n$, the evolution of the state $|\psi(t)\rangle$ is governed by the Schrodinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle= -i \hat{H}_{\textrm{eff}} |\psi(t)\rangle\]

with a non-Hermitian effective Hamiltonian:

\[\hat{H}_{\textrm{eff}} = \hat{H} - \frac{i}{2} \sum_n \hat{C}_n^\dagger \hat{C}_n.\]

To the first-order of the wave function in a small time $\delta t$, the strictly negative non-Hermitian portion in $\hat{H}_{\textrm{eff}}$ gives rise to a reduction in the norm of the wave function, namely

\[\langle \psi(t+\delta t) | \psi(t+\delta t) \rangle = 1 - \delta p,\]

where

\[\delta p = \delta t \sum_n \langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle\]

is the corresponding quantum jump probability.

If the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting $|\psi(t)\rangle$ using the collapse operator $\hat{C}_n$ corresponding to the measurement, namely

\[| \psi(t+\delta t) \rangle = \frac{\hat{C}_n |\psi(t)\rangle}{ \sqrt{\langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle} }\]

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • ntraj::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.
  • progress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::EnsembleProblem with ODEProblem: The Ensemble ODEProblem for the Monte Carlo wave function time evolution.
source
QuantumToolbox.ssesolveProblemFunction
ssesolveProblem(H::QuantumObject,
+    kwargs...)

Generates the EnsembleProblem of ODEProblems for the ensemble of trajectories of the Monte Carlo wave function time evolution of an open quantum system.

Given a system Hamiltonian $\hat{H}$ and a list of collapse (jump) operators $\{\hat{C}_n\}_n$, the evolution of the state $|\psi(t)\rangle$ is governed by the Schrodinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle= -i \hat{H}_{\textrm{eff}} |\psi(t)\rangle\]

with a non-Hermitian effective Hamiltonian:

\[\hat{H}_{\textrm{eff}} = \hat{H} - \frac{i}{2} \sum_n \hat{C}_n^\dagger \hat{C}_n.\]

To the first-order of the wave function in a small time $\delta t$, the strictly negative non-Hermitian portion in $\hat{H}_{\textrm{eff}}$ gives rise to a reduction in the norm of the wave function, namely

\[\langle \psi(t+\delta t) | \psi(t+\delta t) \rangle = 1 - \delta p,\]

where

\[\delta p = \delta t \sum_n \langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle\]

is the corresponding quantum jump probability.

If the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting $|\psi(t)\rangle$ using the collapse operator $\hat{C}_n$ corresponding to the measurement, namely

\[| \psi(t+\delta t) \rangle = \frac{\hat{C}_n |\psi(t)\rangle}{ \sqrt{\langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle} }\]

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • rng::AbstractRNG: Random number generator for reproducibility.
  • ntraj::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.
  • progress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::EnsembleProblem with ODEProblem: The Ensemble ODEProblem for the Monte Carlo wave function time evolution.
source
QuantumToolbox.ssesolveProblemFunction
ssesolveProblem(H::QuantumObject,
     ψ0::QuantumObject,
     tlist::AbstractVector;
     sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
@@ -340,11 +341,12 @@
     e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
+    rng::AbstractRNG=default_rng(),
     kwargs...)

Generates the SDEProblem for the Stochastic Schrödinger time evolution of a quantum system. This is defined by the following stochastic differential equation:

\[ d|\psi(t)\rangle = -i K |\psi(t)\rangle dt + \sum_n M_n |\psi(t)\rangle dW_n(t) ``` where - \]

math K = \hat{H} + i \sumn \left(\frac{ej} Cn - \frac{1}{2} \sum{j} Cn^\dagger Cn - \frac{ej^2}{8}\right), math Mn = Cn - \frac{en}{2}, andmath en = \langle Cn + C_n^\dagger \rangle. ```

Above, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: The time list of the evolution.
  • sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators $\{\hat{C}_n\}_n$.
  • alg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}=nothing: 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.
  • kwargs...: The keyword arguments passed to the SDEProblem constructor.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.
  • For more details about alg please refer to DifferentialEquations.jl (SDE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob: The SDEProblem for the Stochastic Schrödinger time evolution of the system.
source
QuantumToolbox.ssesolveEnsembleProblemFunction
ssesolveEnsembleProblem(H::QuantumObject,
+    \]

math K = \hat{H} + i \sumn \left(\frac{ej} Cn - \frac{1}{2} \sum{j} Cn^\dagger Cn - \frac{ej^2}{8}\right), math Mn = Cn - \frac{en}{2}, andmath en = \langle Cn + C_n^\dagger \rangle. ```

Above, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: The time list of the evolution.
  • sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators $\{\hat{C}_n\}_n$.
  • alg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}=nothing: 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.
  • rng::AbstractRNG: The random number generator for reproducibility.
  • kwargs...: The keyword arguments passed to the SDEProblem constructor.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.
  • For more details about alg please refer to DifferentialEquations.jl (SDE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob: The SDEProblem for the Stochastic Schrödinger time evolution of the system.
source
QuantumToolbox.ssesolveEnsembleProblemFunction
ssesolveEnsembleProblem(H::QuantumObject,
     ψ0::QuantumObject,
     tlist::AbstractVector;
     sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing;
@@ -352,6 +354,7 @@
     e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
+    rng::AbstractRNG=default_rng(),
     ntraj::Int=1,
     ensemble_method=EnsembleThreads(),
     prob_func::Function=_mcsolve_prob_func,
@@ -361,7 +364,7 @@
     ```
 
 where 
-    \]

math K = \hat{H} + i \sumn \left(\frac{ej} Cn - \frac{1}{2} \sum{j} Cn^\dagger Cn - \frac{ej^2}{8}\right), math Mn = Cn - \frac{en}{2}, andmath en = \langle Cn + C_n^\dagger \rangle. ```

Above, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: The time list of the evolution.
  • sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators $\{\hat{C}_n\}_n$.
  • alg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}=nothing: 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.
  • ntraj::Int: Number of trajectories to use.
  • ensemble_method: Ensemble method to use.
  • prob_func::Function: Function to use for generating the SDEProblem.
  • output_func::Function: Function to use for generating the output of a single trajectory.
  • progress_bar::Union{Val,Bool}: Whether to show a progress bar.
  • kwargs...: The keyword arguments passed to the SDEProblem constructor.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.
  • For more details about alg please refer to DifferentialEquations.jl (SDE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::EnsembleProblem with SDEProblem: The Ensemble SDEProblem for the Stochastic Shrödinger time evolution.
source
QuantumToolbox.lr_mesolveProblemFunction
lr_mesolveProblem(H, z, B, tlist, c_ops; e_ops=(), f_ops=(), opt=LRMesolveOptions(), kwargs...) where T
+    \]

math K = \hat{H} + i \sumn \left(\frac{ej} Cn - \frac{1}{2} \sum{j} Cn^\dagger Cn - \frac{ej^2}{8}\right), math Mn = Cn - \frac{en}{2}, andmath en = \langle Cn + C_n^\dagger \rangle. ```

Above, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: The time list of the evolution.
  • sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators $\{\hat{C}_n\}_n$.
  • alg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}=nothing: 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.
  • rng::AbstractRNG: The random number generator for reproducibility.
  • ntraj::Int: Number of trajectories to use.
  • ensemble_method: Ensemble method to use.
  • prob_func::Function: Function to use for generating the SDEProblem.
  • output_func::Function: Function to use for generating the output of a single trajectory.
  • progress_bar::Union{Val,Bool}: Whether to show a progress bar.
  • kwargs...: The keyword arguments passed to the SDEProblem constructor.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.
  • For more details about alg please refer to DifferentialEquations.jl (SDE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • prob::EnsembleProblem with SDEProblem: The Ensemble SDEProblem for the Stochastic Shrödinger time evolution.
source
QuantumToolbox.lr_mesolveProblemFunction
lr_mesolveProblem(H, z, B, tlist, c_ops; e_ops=(), f_ops=(), opt=LRMesolveOptions(), kwargs...) where T
 Formulates the ODEproblem for the low-rank time evolution of the system. The function is called by lr_mesolve.
 
 Parameters
@@ -383,7 +386,7 @@
 opt : LRMesolveOptions
     The options of the problem.
 kwargs : NamedTuple
-    Additional keyword arguments for the ODEProblem.
source
QuantumToolbox.sesolveFunction
sesolve(H::QuantumObject,
     ψ0::QuantumObject,
     tlist::AbstractVector;
     alg::OrdinaryDiffEqAlgorithm=Tsit5(),
@@ -391,7 +394,7 @@
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
     progress_bar::Union{Val,Bool}=Val(true),
-    kwargs...)

Time evolution of a closed quantum system using the Schrödinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle = -i \hat{H} |\psi(t)\rangle\]

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • sol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol
source
QuantumToolbox.mesolveFunction
mesolve(H::QuantumObject,
+    kwargs...)

Time evolution of a closed quantum system using the Schrödinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle = -i \hat{H} |\psi(t)\rangle\]

Arguments

  • H::QuantumObject: The Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: The initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • sol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol
source
QuantumToolbox.mesolveFunction
mesolve(H::QuantumObject,
     ψ0::QuantumObject,
     tlist::AbstractVector, 
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
@@ -400,7 +403,7 @@
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
     progress_bar::Union{Val,Bool}=Val(true),
-    kwargs...)

Time evolution of an open quantum system using Lindblad master equation:

\[\frac{\partial \hat{\rho}(t)}{\partial t} = -i[\hat{H}, \hat{\rho}(t)] + \sum_n \mathcal{D}(\hat{C}_n) [\hat{\rho}(t)]\]

where

\[\mathcal{D}(\hat{C}_n) [\hat{\rho}(t)] = \hat{C}_n \hat{\rho}(t) \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n \hat{\rho}(t) - \frac{1}{2} \hat{\rho}(t) \hat{C}_n^\dagger \hat{C}_n\]

Arguments

  • H::QuantumObject: The Hamiltonian $\hat{H}$ or the Liouvillian of the system.
  • ψ0::QuantumObject: The initial state of the system.
  • tlist::AbstractVector: The time list of the evolution.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • sol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol
source
QuantumToolbox.mcsolveFunction
mcsolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
+    kwargs...)

Time evolution of an open quantum system using Lindblad master equation:

\[\frac{\partial \hat{\rho}(t)}{\partial t} = -i[\hat{H}, \hat{\rho}(t)] + \sum_n \mathcal{D}(\hat{C}_n) [\hat{\rho}(t)]\]

where

\[\mathcal{D}(\hat{C}_n) [\hat{\rho}(t)] = \hat{C}_n \hat{\rho}(t) \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n \hat{\rho}(t) - \frac{1}{2} \hat{\rho}(t) \hat{C}_n^\dagger \hat{C}_n\]

Arguments

  • H::QuantumObject: The Hamiltonian $\hat{H}$ or the Liouvillian of the system.
  • ψ0::QuantumObject: The initial state of the system.
  • tlist::AbstractVector: The time list of the evolution.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

  • sol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol
source
QuantumToolbox.mcsolveFunction
mcsolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},
     ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},
     tlist::AbstractVector,
     c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;
@@ -408,7 +411,7 @@
     e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,
     H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing,
     params::NamedTuple = NamedTuple(),
-    seeds::Union{Nothing,Vector{Int}} = nothing,
+    rng::AbstractRNG = default_rng(),
     ntraj::Int = 1,
     ensemble_method = EnsembleThreads(),
     jump_callback::TJC = ContinuousLindbladJumpCallback(),
@@ -416,7 +419,7 @@
     output_func::Function = _mcsolve_dispatch_output_func(ensemble_method),
     progress_bar::Union{Val,Bool} = Val(true),
     kwargs...,
-)

Time evolution of an open quantum system using quantum trajectories.

Given a system Hamiltonian $\hat{H}$ and a list of collapse (jump) operators $\{\hat{C}_n\}_n$, the evolution of the state $|\psi(t)\rangle$ is governed by the Schrodinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle= -i \hat{H}_{\textrm{eff}} |\psi(t)\rangle\]

with a non-Hermitian effective Hamiltonian:

\[\hat{H}_{\textrm{eff}} = \hat{H} - \frac{i}{2} \sum_n \hat{C}_n^\dagger \hat{C}_n.\]

To the first-order of the wave function in a small time $\delta t$, the strictly negative non-Hermitian portion in $\hat{H}_{\textrm{eff}}$ gives rise to a reduction in the norm of the wave function, namely

\[\langle \psi(t+\delta t) | \psi(t+\delta t) \rangle = 1 - \delta p,\]

where

\[\delta p = \delta t \sum_n \langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle\]

is the corresponding quantum jump probability.

If the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting $|\psi(t)\rangle$ using the collapse operator $\hat{C}_n$ corresponding to the measurement, namely

\[| \psi(t+\delta t) \rangle = \frac{\hat{C}_n |\psi(t)\rangle}{ \sqrt{\langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle} }\]

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • ntraj::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.
  • progress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.

Notes

  • ensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()
  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

source
QuantumToolbox.ssesolveFunction
ssesolve(H::QuantumObject,
+)

Time evolution of an open quantum system using quantum trajectories.

Given a system Hamiltonian $\hat{H}$ and a list of collapse (jump) operators $\{\hat{C}_n\}_n$, the evolution of the state $|\psi(t)\rangle$ is governed by the Schrodinger equation:

\[\frac{\partial}{\partial t} |\psi(t)\rangle= -i \hat{H}_{\textrm{eff}} |\psi(t)\rangle\]

with a non-Hermitian effective Hamiltonian:

\[\hat{H}_{\textrm{eff}} = \hat{H} - \frac{i}{2} \sum_n \hat{C}_n^\dagger \hat{C}_n.\]

To the first-order of the wave function in a small time $\delta t$, the strictly negative non-Hermitian portion in $\hat{H}_{\textrm{eff}}$ gives rise to a reduction in the norm of the wave function, namely

\[\langle \psi(t+\delta t) | \psi(t+\delta t) \rangle = 1 - \delta p,\]

where

\[\delta p = \delta t \sum_n \langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle\]

is the corresponding quantum jump probability.

If the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting $|\psi(t)\rangle$ using the collapse operator $\hat{C}_n$ corresponding to the measurement, namely

\[| \psi(t+\delta t) \rangle = \frac{\hat{C}_n |\psi(t)\rangle}{ \sqrt{\langle \psi(t) | \hat{C}_n^\dagger \hat{C}_n | \psi(t) \rangle} }\]

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators $\{\hat{C}_n\}_n$.
  • alg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • rng::AbstractRNG: Random number generator for reproducibility.
  • ntraj::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.
  • progress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.

Notes

  • ensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()
  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.
  • For more details about alg please refer to DifferentialEquations.jl (ODE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

source
QuantumToolbox.ssesolveFunction
ssesolve(H::QuantumObject,
     ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},
     tlist::AbstractVector,
     sc_ops::Union{Nothing, AbstractVector}=nothing;
@@ -424,6 +427,7 @@
     e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
+    rng::AbstractRNG=default_rng(),
     ntraj::Int=1,
     ensemble_method=EnsembleThreads(),
     prob_func::Function=_ssesolve_prob_func,
@@ -433,7 +437,7 @@
     ```
 
 where 
-    \]

math K = \hat{H} + i \sumn \left(\frac{ej} Cn - \frac{1}{2} \sum{j} Cn^\dagger Cn - \frac{ej^2}{8}\right), math Mn = Cn - \frac{en}{2}, andmath en = \langle Cn + C_n^\dagger \rangle. ```

Above, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators $\{\hat{C}_n\}_n$.
  • alg::StochasticDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • ntraj::Int: Number of trajectories to use.
  • ensemble_method: Ensemble method to use.
  • prob_func::Function: Function to use for generating the SDEProblem.
  • output_func::Function: Function to use for generating the output of a single trajectory.
  • progress_bar::Union{Val,Bool}: Whether to show a progress bar.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • ensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()
  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.
  • For more details about alg please refer to DifferentialEquations.jl (SDE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

source
QuantumToolbox.dfd_mesolveFunction
dfd_mesolve(H::Function, ψ0::QuantumObject,
+    \]

math K = \hat{H} + i \sumn \left(\frac{ej} Cn - \frac{1}{2} \sum{j} Cn^\dagger Cn - \frac{ej^2}{8}\right), math Mn = Cn - \frac{en}{2}, andmath en = \langle Cn + C_n^\dagger \rangle. ```

Above, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.

Arguments

  • H::QuantumObject: Hamiltonian of the system $\hat{H}$.
  • ψ0::QuantumObject: Initial state of the system $|\psi(0)\rangle$.
  • tlist::AbstractVector: List of times at which to save the state of the system.
  • sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators $\{\hat{C}_n\}_n$.
  • alg::StochasticDiffEqAlgorithm: Algorithm to use for the time evolution.
  • e_ops::Union{Nothing,AbstractVector,Tuple}: 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.
  • rng::AbstractRNG: Random number generator for reproducibility.
  • ntraj::Int: Number of trajectories to use.
  • ensemble_method: Ensemble method to use.
  • prob_func::Function: Function to use for generating the SDEProblem.
  • output_func::Function: Function to use for generating the output of a single trajectory.
  • progress_bar::Union{Val,Bool}: Whether to show a progress bar.
  • kwargs...: Additional keyword arguments to pass to the solver.

Notes

  • ensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()
  • The states will be saved depend on the keyword argument saveat in kwargs.
  • If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.
  • The default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.
  • For more details about alg please refer to DifferentialEquations.jl (SDE Solvers)
  • For more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)

Returns

source
QuantumToolbox.dfd_mesolveFunction
dfd_mesolve(H::Function, ψ0::QuantumObject,
     t_l::AbstractVector, c_ops::Function, maxdims::AbstractVector,
     dfd_params::NamedTuple=NamedTuple();
     alg::OrdinaryDiffEqAlgorithm=Tsit5(),
@@ -441,7 +445,7 @@
     H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,
     params::NamedTuple=NamedTuple(),
     tol_list::Vector{<:Number}=fill(1e-8, length(maxdims)),
-    kwargs...)

Time evolution of an open quantum system using master equation, dynamically changing the dimension of the Hilbert subspaces.

Notes

source
QuantumToolbox.dsf_mesolveFunction
dsf_mesolve(H::Function,
     ψ0::QuantumObject,
     t_l::AbstractVector, c_ops::Function,
     op_list::Vector{TOl},
@@ -453,7 +457,7 @@
     params::NamedTuple=NamedTuple(),
     δα_list::Vector{<:Number}=fill(0.2, length(op_list)),
     krylov_dim::Int=max(6, min(10, cld(length(ket2dm(ψ0).data), 4))),
-    kwargs...)

Time evolution of an open quantum system using master equation and the Dynamical Shifted Fock algorithm.

Notes

source
QuantumToolbox.dsf_mcsolveFunction
dsf_mcsolve(H::Function,
     ψ0::QuantumObject,
     t_l::AbstractVector, c_ops::Function,
     op_list::Vector{TOl},
@@ -469,7 +473,7 @@
     jump_callback::LindbladJumpCallbackType=ContinuousLindbladJumpCallback(),
     krylov_dim::Int=max(6, min(10, cld(length(ket2dm(ψ0).data), 4))),
     progress_bar::Union{Bool,Val} = Val(true)
-    kwargs...)

Time evolution of a quantum system using the Monte Carlo wave function method and the Dynamical Shifted Fock algorithm.

Notes

source
QuantumToolbox.lr_mesolveFunction
lr_mesolve(prob::ODEProblem; kwargs...)
 Solves the ODEProblem formulated by lr_mesolveProblem. The function is called by lr_mesolve.
 
 Parameters
@@ -477,13 +481,13 @@
 prob : ODEProblem
     The ODEProblem formulated by lr_mesolveProblem.
 kwargs : NamedTuple
-    Additional keyword arguments for the ODEProblem.
source
QuantumToolbox.liouvillianFunction
liouvillian(H::QuantumObject, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing, Id_cache=I(prod(H.dims)))

Construct the Liouvillian SuperOperator for a system Hamiltonian $\hat{H}$ and a set of collapse operators $\{\hat{C}_n\}_n$:

\[\mathcal{L} [\cdot] = -i[\hat{H}, \cdot] + \sum_n \mathcal{D}(\hat{C}_n) [\cdot]\]

where

\[\mathcal{D}(\hat{C}_n) [\cdot] = \hat{C}_n [\cdot] \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n [\cdot] - \frac{1}{2} [\cdot] \hat{C}_n^\dagger \hat{C}_n\]

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.

See also spre, spost, and lindblad_dissipator.

source
QuantumToolbox.liouvillian_generalizedFunction
liouvillian_generalized(H::QuantumObject, fields::Vector, 
-T_list::Vector; N_trunc::Int=size(H,1), tol::Float64=0.0, σ_filter::Union{Nothing, Real}=nothing)

Constructs the generalized Liouvillian for a system coupled to a bath of harmonic oscillators.

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.

source
QuantumToolbox.liouvillianFunction
liouvillian(H::QuantumObject, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing, Id_cache=I(prod(H.dims)))

Construct the Liouvillian SuperOperator for a system Hamiltonian $\hat{H}$ and a set of collapse operators $\{\hat{C}_n\}_n$:

\[\mathcal{L} [\cdot] = -i[\hat{H}, \cdot] + \sum_n \mathcal{D}(\hat{C}_n) [\cdot]\]

where

\[\mathcal{D}(\hat{C}_n) [\cdot] = \hat{C}_n [\cdot] \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n [\cdot] - \frac{1}{2} [\cdot] \hat{C}_n^\dagger \hat{C}_n\]

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.

See also spre, spost, and lindblad_dissipator.

source
QuantumToolbox.liouvillian_generalizedFunction
liouvillian_generalized(H::QuantumObject, fields::Vector, 
+T_list::Vector; N_trunc::Int=size(H,1), tol::Float64=0.0, σ_filter::Union{Nothing, Real}=nothing)

Constructs the generalized Liouvillian for a system coupled to a bath of harmonic oscillators.

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.

source
QuantumToolbox.steadystateFunction
steadystate(
     H::QuantumObject,
     c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;
     solver::SteadyStateSolver = SteadyStateDirectSolver(),
     kwargs...
-)

Solve the stationary state based on different solvers.

Parameters

  • H::QuantumObject: The Hamiltonian or the Liouvillian of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.
  • solver::SteadyStateSolver=SteadyStateDirectSolver(): see documentation Solving for Steady-State Solutions for different solvers.
  • kwargs...: The keyword arguments for the solver.
source
steadystate(
+)

Solve the stationary state based on different solvers.

Parameters

  • H::QuantumObject: The Hamiltonian or the Liouvillian of the system.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.
  • solver::SteadyStateSolver=SteadyStateDirectSolver(): see documentation Solving for Steady-State Solutions for different solvers.
  • kwargs...: The keyword arguments for the solver.
source
steadystate(
     H::QuantumObject,
     ψ0::QuantumObject,
     tspan::Real = Inf,
@@ -492,7 +496,7 @@
     reltol::Real = 1.0e-8,
     abstol::Real = 1.0e-10,
     kwargs...
-)

Solve the stationary state based on time evolution (ordinary differential equations; OrdinaryDiffEq.jl) with a given initial state.

The termination condition of the stationary state $|\rho\rangle\rangle$ is that either the following condition is true:

\[\lVert\frac{\partial |\hat{\rho}\rangle\rangle}{\partial t}\rVert \leq \textrm{reltol} \times\lVert\frac{\partial |\hat{\rho}\rangle\rangle}{\partial t}+|\hat{\rho}\rangle\rangle\rVert\]

or

\[\lVert\frac{\partial |\hat{\rho}\rangle\rangle}{\partial t}\rVert \leq \textrm{abstol}\]

Parameters

  • H::QuantumObject: The Hamiltonian or the Liouvillian of the system.
  • ψ0::QuantumObject: The initial state of the system.
  • tspan::Real=Inf: The final time step for the steady state problem.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.
  • solver::SteadyStateODESolver=SteadyStateODESolver(): see SteadyStateODESolver for more details.
  • reltol::Real=1.0e-8: Relative tolerance in steady state terminate condition and solver adaptive timestepping.
  • abstol::Real=1.0e-10: Absolute tolerance in steady state terminate condition and solver adaptive timestepping.
  • kwargs...: The keyword arguments for the ODEProblem.
source
QuantumToolbox.steadystate_floquetFunction
steadystate_floquet(
+)

Solve the stationary state based on time evolution (ordinary differential equations; OrdinaryDiffEq.jl) with a given initial state.

The termination condition of the stationary state $|\rho\rangle\rangle$ is that either the following condition is true:

\[\lVert\frac{\partial |\hat{\rho}\rangle\rangle}{\partial t}\rVert \leq \textrm{reltol} \times\lVert\frac{\partial |\hat{\rho}\rangle\rangle}{\partial t}+|\hat{\rho}\rangle\rangle\rVert\]

or

\[\lVert\frac{\partial |\hat{\rho}\rangle\rangle}{\partial t}\rVert \leq \textrm{abstol}\]

Parameters

  • H::QuantumObject: The Hamiltonian or the Liouvillian of the system.
  • ψ0::QuantumObject: The initial state of the system.
  • tspan::Real=Inf: The final time step for the steady state problem.
  • c_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.
  • solver::SteadyStateODESolver=SteadyStateODESolver(): see SteadyStateODESolver for more details.
  • reltol::Real=1.0e-8: Relative tolerance in steady state terminate condition and solver adaptive timestepping.
  • abstol::Real=1.0e-10: Absolute tolerance in steady state terminate condition and solver adaptive timestepping.
  • kwargs...: The keyword arguments for the ODEProblem.
source
QuantumToolbox.steadystate_floquetFunction
steadystate_floquet(
     H_0::QuantumObject{MT,OpType1},
     H_p::QuantumObject{<:AbstractArray,OpType2},
     H_m::QuantumObject{<:AbstractArray,OpType3},
@@ -516,7 +520,7 @@
 \vdots \\
 \hat{\rho}_{n_{\textrm{max}}-1} \\
 \hat{\rho}_{n_{\textrm{max}}}
-\end{pmatrix}\]

This will allow to simultaneously obtain all the $\hat{\rho}_n$.

In the case of SSFloquetEffectiveLiouvillian, instead, the effective Liouvillian is calculated using the matrix continued fraction method.

different return

The two solvers returns different objects. The SSFloquetLinearSystem returns a list of QuantumObject, containing the density matrices for each Fourier component ($\hat{\rho}_{-n}$, with $n$ from $0$ to $n_\textrm{max}$), while the SSFloquetEffectiveLiouvillian returns only $\hat{\rho}_0$.

Arguments

  • H_0::QuantumObject: The Hamiltonian or the Liouvillian of the undriven system.
  • H_p::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as $e^{i \omega t}$.
  • H_m::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as $e^{-i \omega t}$.
  • ωd::Number: The frequency of the drive.
  • c_ops::Union{Nothing,AbstractVector} = nothing: The optional collapse operators.
  • n_max::Integer = 2: The number of Fourier components to consider.
  • tol::R = 1e-8: The tolerance for the solver.
  • solver::FSolver = SSFloquetLinearSystem: The solver to use.
  • kwargs...: Additional keyword arguments to be passed to the solver.
source
QuantumToolbox.SteadyStateLinearSolverType
SteadyStateLinearSolver(alg = KrylovJL_GMRES(), Pl = nothing, Pr = nothing)

A solver which solves steadystate by finding the inverse of Liouvillian SuperOperator using the algorithms given in LinearSolve.jl.

Parameters

source

Correlations and Spectrum

QuantumToolbox.correlation_3op_2tFunction
correlation_3op_2t(H::QuantumObject,
+\end{pmatrix}\]

This will allow to simultaneously obtain all the $\hat{\rho}_n$.

In the case of SSFloquetEffectiveLiouvillian, instead, the effective Liouvillian is calculated using the matrix continued fraction method.

different return

The two solvers returns different objects. The SSFloquetLinearSystem returns a list of QuantumObject, containing the density matrices for each Fourier component ($\hat{\rho}_{-n}$, with $n$ from $0$ to $n_\textrm{max}$), while the SSFloquetEffectiveLiouvillian returns only $\hat{\rho}_0$.

Arguments

  • H_0::QuantumObject: The Hamiltonian or the Liouvillian of the undriven system.
  • H_p::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as $e^{i \omega t}$.
  • H_m::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as $e^{-i \omega t}$.
  • ωd::Number: The frequency of the drive.
  • c_ops::Union{Nothing,AbstractVector} = nothing: The optional collapse operators.
  • n_max::Integer = 2: The number of Fourier components to consider.
  • tol::R = 1e-8: The tolerance for the solver.
  • solver::FSolver = SSFloquetLinearSystem: The solver to use.
  • kwargs...: Additional keyword arguments to be passed to the solver.
source
QuantumToolbox.SteadyStateLinearSolverType
SteadyStateLinearSolver(alg = KrylovJL_GMRES(), Pl = nothing, Pr = nothing)

A solver which solves steadystate by finding the inverse of Liouvillian SuperOperator using the algorithms given in LinearSolve.jl.

Parameters

source

Correlations and Spectrum

QuantumToolbox.correlation_3op_2tFunction
correlation_3op_2t(H::QuantumObject,
     ψ0::QuantumObject,
     t_l::AbstractVector,
     τ_l::AbstractVector,
@@ -524,7 +528,7 @@
     B::QuantumObject,
     C::QuantumObject,
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
-    kwargs...)

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}$.

source
QuantumToolbox.correlation_2op_2tFunction
correlation_2op_2t(H::QuantumObject,
+    kwargs...)

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}$.

source
QuantumToolbox.correlation_2op_2tFunction
correlation_2op_2t(H::QuantumObject,
     ψ0::QuantumObject,
     t_l::AbstractVector,
     τ_l::AbstractVector,
@@ -532,20 +536,20 @@
     B::QuantumObject,
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
     reverse::Bool=false,
-    kwargs...)

Returns the two-times correlation function of two operators $\hat{A}$ and $\hat{B}$ 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)}$.

source
QuantumToolbox.correlation_2op_1tFunction
correlation_2op_1t(H::QuantumObject,
+    kwargs...)

Returns the two-times correlation function of two operators $\hat{A}$ and $\hat{B}$ 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)}$.

source
QuantumToolbox.correlation_2op_1tFunction
correlation_2op_1t(H::QuantumObject,
     ψ0::QuantumObject,
     τ_l::AbstractVector,
     A::QuantumObject,
     B::QuantumObject,
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
     reverse::Bool=false,
-    kwargs...)

Returns the one-time correlation function of two operators $\hat{A}$ and $\hat{B}$ 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)}$.

source
QuantumToolbox.spectrumFunction
spectrum(H::QuantumObject,
+    kwargs...)

Returns the one-time correlation function of two operators $\hat{A}$ and $\hat{B}$ 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)}$.

source
QuantumToolbox.spectrumFunction
spectrum(H::QuantumObject,
     ω_list::AbstractVector,
     A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject},
     B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject},
     c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
     solver::MySolver=ExponentialSeries(),
-    kwargs...)

Returns the emission spectrum

\[S(\omega) = \int_{-\infty}^\infty \expval{\hat{A}(\tau) \hat{B}(0)} e^{-i \omega \tau} d \tau\]

source

Metrics

QuantumToolbox.entropy_vnFunction
entropy_vn(ρ::QuantumObject; base::Int=0, tol::Real=1e-15)

Calculates the Von Neumann entropy $S = - \Tr \left[ \hat{\rho} \log \left( \hat{\rho} \right) \right]$ where $\hat{\rho}$ is the density matrix of the system.

The base parameter specifies the base of the logarithm to use, and when using the default value 0, the natural logarithm is used. The tol parameter describes the absolute tolerance for detecting the zero-valued eigenvalues of the density matrix $\hat{\rho}$.

Examples

Pure state:

julia> ψ = fock(2,0)
+    kwargs...)

Returns the emission spectrum

\[S(\omega) = \int_{-\infty}^\infty \expval{\hat{A}(\tau) \hat{B}(0)} e^{-i \omega \tau} d \tau\]

source

Metrics

QuantumToolbox.entropy_vnFunction
entropy_vn(ρ::QuantumObject; base::Int=0, tol::Real=1e-15)

Calculates the Von Neumann entropy $S = - \Tr \left[ \hat{\rho} \log \left( \hat{\rho} \right) \right]$ where $\hat{\rho}$ is the density matrix of the system.

The base parameter specifies the base of the logarithm to use, and when using the default value 0, the natural logarithm is used. The tol parameter describes the absolute tolerance for detecting the zero-valued eigenvalues of the density matrix $\hat{\rho}$.

Examples

Pure state:

julia> ψ = fock(2,0)
 Quantum Object:   type=Ket   dims=[2]   size=(2,)
 2-element Vector{ComplexF64}:
  1.0 + 0.0im
@@ -565,8 +569,8 @@
      ⋅      0.5-0.0im
 
 julia> entropy_vn(ρ, base=2)
-1.0
source
QuantumToolbox.entanglementFunction
entanglement(QO::QuantumObject, sel::Union{Int,AbstractVector{Int},Tuple})

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.

source
QuantumToolbox.fidelityFunction
fidelity(ρ::QuantumObject, σ::QuantumObject)

Calculate the fidelity of two QuantumObject: $F(\hat{\rho}, \hat{\sigma}) = \textrm{Tr} \sqrt{\sqrt{\hat{\rho}} \hat{\sigma} \sqrt{\hat{\rho}}}$

Here, the definition is from Nielsen & Chuang, "Quantum Computation and Quantum Information". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994).

Note that ρ and σ must be either Ket or Operator.

source

Miscellaneous

QuantumToolbox.wignerFunction
wigner(state::QuantumObject, xvec::AbstractVector, yvec::AbstractVector; g::Real=√2,
-    solver::WignerSolver=WignerLaguerre())

Generates the Wigner quasipropability distribution of state at points xvec + 1im * yvec. The g parameter is a scaling factor related to the value of $\hbar$ in the commutation relation $[x, y] = i \hbar$ via $\hbar=2/g^2$ giving the default value $\hbar=1$.

The solver parameter can be either WignerLaguerre() or WignerClenshaw(). The former uses the Laguerre polynomial expansion of the Wigner function, while the latter uses the Clenshaw algorithm. The Laguerre expansion is faster for 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.

source
QuantumToolbox.negativityFunction
negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool=false)

Compute the negativity $N(\hat{\rho}) = \frac{\Vert \hat{\rho}^{\Gamma}\Vert_1 - 1}{2}$ where $\hat{\rho}^{\Gamma}$ is the partial transpose of $\hat{\rho}$ with respect to the subsystem, and $\Vert \hat{X} \Vert_1=\textrm{Tr}\sqrt{\hat{X}^\dagger \hat{X}}$ is the trace norm.

Arguments

  • ρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).
  • subsys::Int: an index that indicates which subsystem to compute the negativity for.
  • logarithmic::Bool: choose whether to calculate logarithmic negativity or not. Default as false

Returns

  • N::Real: The value of negativity.

Examples

julia> Ψ = bell_state(0, 0)
+1.0
source
QuantumToolbox.entanglementFunction
entanglement(QO::QuantumObject, sel::Union{Int,AbstractVector{Int},Tuple})

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.

source
QuantumToolbox.fidelityFunction
fidelity(ρ::QuantumObject, σ::QuantumObject)

Calculate the fidelity of two QuantumObject: $F(\hat{\rho}, \hat{\sigma}) = \textrm{Tr} \sqrt{\sqrt{\hat{\rho}} \hat{\sigma} \sqrt{\hat{\rho}}}$

Here, the definition is from Nielsen & Chuang, "Quantum Computation and Quantum Information". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994).

Note that ρ and σ must be either Ket or Operator.

source

Miscellaneous

QuantumToolbox.wignerFunction
wigner(state::QuantumObject, xvec::AbstractVector, yvec::AbstractVector; g::Real=√2,
+    solver::WignerSolver=WignerLaguerre())

Generates the Wigner quasipropability distribution of state at points xvec + 1im * yvec. The g parameter is a scaling factor related to the value of $\hbar$ in the commutation relation $[x, y] = i \hbar$ via $\hbar=2/g^2$ giving the default value $\hbar=1$.

The solver parameter can be either WignerLaguerre() or WignerClenshaw(). The former uses the Laguerre polynomial expansion of the Wigner function, while the latter uses the Clenshaw algorithm. The Laguerre expansion is faster for 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.

source
QuantumToolbox.negativityFunction
negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool=false)

Compute the negativity $N(\hat{\rho}) = \frac{\Vert \hat{\rho}^{\Gamma}\Vert_1 - 1}{2}$ where $\hat{\rho}^{\Gamma}$ is the partial transpose of $\hat{\rho}$ with respect to the subsystem, and $\Vert \hat{X} \Vert_1=\textrm{Tr}\sqrt{\hat{X}^\dagger \hat{X}}$ is the trace norm.

Arguments

  • ρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).
  • subsys::Int: an index that indicates which subsystem to compute the negativity for.
  • logarithmic::Bool: choose whether to calculate logarithmic negativity or not. Default as false

Returns

  • N::Real: The value of negativity.

Examples

julia> Ψ = bell_state(0, 0)
 Quantum Object:   type=Ket   dims=[2, 2]   size=(4,)
 4-element Vector{ComplexF64}:
  0.7071067811865475 + 0.0im
@@ -583,7 +587,7 @@
  0.5+0.0im  0.0+0.0im  0.0+0.0im  0.5+0.0im
 
 julia> negativity(ρ, 2)
-0.4999999999999998
source

Linear Maps

QuantumToolbox.AbstractLinearMapType
AbstractLinearMap{T, TS}

Represents a general linear map with element type T and size TS.

Overview

A linear map is a transformation L that satisfies:

  • Additivity: math L(u + v) = L(u) + L(v)
  • Homogeneity: math L(cu) = cL(u)

It is typically represented as a matrix with dimensions given by size, and this abtract type helps to define this map when the matrix is not explicitly available.

Methods

  • Base.eltype(A): Returns the element type T.
  • Base.size(A): Returns the size A.size.
  • Base.size(A, i): Returns the i-th dimension.

Example

As an example, we now define the linear map used in the eigsolve_al function for Arnoldi-Lindblad eigenvalue solver:

struct ArnoldiLindbladIntegratorMap{T,TS,TI} <: AbstractLinearMap{T,TS}
+0.4999999999999998
source

Linear Maps

QuantumToolbox.AbstractLinearMapType
AbstractLinearMap{T, TS}

Represents a general linear map with element type T and size TS.

Overview

A linear map is a transformation L that satisfies:

  • Additivity: math L(u + v) = L(u) + L(v)
  • Homogeneity: math L(cu) = cL(u)

It is typically represented as a matrix with dimensions given by size, and this abtract type helps to define this map when the matrix is not explicitly available.

Methods

  • Base.eltype(A): Returns the element type T.
  • Base.size(A): Returns the size A.size.
  • Base.size(A, i): Returns the i-th dimension.

Example

As an example, we now define the linear map used in the eigsolve_al function for Arnoldi-Lindblad eigenvalue solver:

struct ArnoldiLindbladIntegratorMap{T,TS,TI} <: AbstractLinearMap{T,TS}
     elty::Type{T}
     size::TS
     integrator::TI
@@ -593,15 +597,15 @@
     reinit!(A.integrator, x)
     solve!(A.integrator)
     return copyto!(y, A.integrator.u)
-end

where integrator is the ODE integrator for the time-evolution. In this way, we can diagonalize this linear map using the eigsolve function.

source

Utility functions

QuantumToolbox.gaussianFunction
gaussian(x::Number, μ::Number, σ::Number)

Returns the gaussian function $\exp \left[- \frac{(x - \mu)^2}{2 \sigma^2} \right]$, where $\mu$ and $\sigma^2$ are the mean and the variance respectively.

source
QuantumToolbox.n_thermalFunction
n_thermal(ω::Real, ω_th::Real)

Return the number of photons in thermal equilibrium for an harmonic oscillator mode with frequency $\omega$, at the temperature described by $\omega_{\textrm{th}} \equiv k_B T / \hbar$:

\[n(\omega, \omega_{\textrm{th}}) = \frac{1}{e^{\omega/\omega_{\textrm{th}}} - 1},\]

where $\hbar$ is the reduced Planck constant, and $k_B$ is the Boltzmann constant.

source
QuantumToolbox.PhysicalConstantsConstant
const PhysicalConstants

A NamedTuple which stores some constant values listed in CODATA recommended values of the fundamental physical constants: 2022

The current stored constants are:

  • c : (exact) speed of light in vacuum with unit $[\textrm{m}\cdot\textrm{s}^{-1}]$
  • G : Newtonian constant of gravitation with unit $[\textrm{m}^3\cdot\textrm{kg}^{−1}\cdot\textrm{s}^{−2}]$
  • h : (exact) Planck constant with unit $[\textrm{J}\cdot\textrm{s}]$
  • ħ : reduced Planck constant with unit $[\textrm{J}\cdot\textrm{s}]$
  • e : (exact) elementary charge with unit $[\textrm{C}]$
  • μ0 : vacuum magnetic permeability with unit $[\textrm{N}\cdot\textrm{A}^{-2}]$
  • ϵ0 : vacuum electric permittivity with unit $[\textrm{F}\cdot\textrm{m}^{-1}]$
  • k : (exact) Boltzmann constant with unit $[\textrm{J}\cdot\textrm{K}^{-1}]$
  • NA : (exact) Avogadro constant with unit $[\textrm{mol}^{-1}]$

Examples

julia> PhysicalConstants.ħ
-1.0545718176461565e-34
source
QuantumToolbox.convert_unitFunction
convert_unit(value::Real, unit1::Symbol, unit2::Symbol)

Convert the energy value from unit1 to unit2. The unit1 and unit2 can be either the following Symbol:

  • :J : Joule
  • :eV : electron volt
  • :meV : milli-electron volt
  • :MHz : Mega-Hertz multiplied by Planck constant $h$
  • :GHz : Giga-Hertz multiplied by Planck constant $h$
  • :K : Kelvin multiplied by Boltzmann constant $k$
  • :mK : milli-Kelvin multiplied by Boltzmann constant $k$

Note that we use the values stored in PhysicalConstants to do the conversion.

Examples

julia> convert_unit(1, :eV, :J)
+end

where integrator is the ODE integrator for the time-evolution. In this way, we can diagonalize this linear map using the eigsolve function.

source

Utility functions

QuantumToolbox.gaussianFunction
gaussian(x::Number, μ::Number, σ::Number)

Returns the gaussian function $\exp \left[- \frac{(x - \mu)^2}{2 \sigma^2} \right]$, where $\mu$ and $\sigma^2$ are the mean and the variance respectively.

source
QuantumToolbox.n_thermalFunction
n_thermal(ω::Real, ω_th::Real)

Return the number of photons in thermal equilibrium for an harmonic oscillator mode with frequency $\omega$, at the temperature described by $\omega_{\textrm{th}} \equiv k_B T / \hbar$:

\[n(\omega, \omega_{\textrm{th}}) = \frac{1}{e^{\omega/\omega_{\textrm{th}}} - 1},\]

where $\hbar$ is the reduced Planck constant, and $k_B$ is the Boltzmann constant.

source
QuantumToolbox.PhysicalConstantsConstant
const PhysicalConstants

A NamedTuple which stores some constant values listed in CODATA recommended values of the fundamental physical constants: 2022

The current stored constants are:

  • c : (exact) speed of light in vacuum with unit $[\textrm{m}\cdot\textrm{s}^{-1}]$
  • G : Newtonian constant of gravitation with unit $[\textrm{m}^3\cdot\textrm{kg}^{−1}\cdot\textrm{s}^{−2}]$
  • h : (exact) Planck constant with unit $[\textrm{J}\cdot\textrm{s}]$
  • ħ : reduced Planck constant with unit $[\textrm{J}\cdot\textrm{s}]$
  • e : (exact) elementary charge with unit $[\textrm{C}]$
  • μ0 : vacuum magnetic permeability with unit $[\textrm{N}\cdot\textrm{A}^{-2}]$
  • ϵ0 : vacuum electric permittivity with unit $[\textrm{F}\cdot\textrm{m}^{-1}]$
  • k : (exact) Boltzmann constant with unit $[\textrm{J}\cdot\textrm{K}^{-1}]$
  • NA : (exact) Avogadro constant with unit $[\textrm{mol}^{-1}]$

Examples

julia> PhysicalConstants.ħ
+1.0545718176461565e-34
source
QuantumToolbox.convert_unitFunction
convert_unit(value::Real, unit1::Symbol, unit2::Symbol)

Convert the energy value from unit1 to unit2. The unit1 and unit2 can be either the following Symbol:

  • :J : Joule
  • :eV : electron volt
  • :meV : milli-electron volt
  • :MHz : Mega-Hertz multiplied by Planck constant $h$
  • :GHz : Giga-Hertz multiplied by Planck constant $h$
  • :K : Kelvin multiplied by Boltzmann constant $k$
  • :mK : milli-Kelvin multiplied by Boltzmann constant $k$

Note that we use the values stored in PhysicalConstants to do the conversion.

Examples

julia> convert_unit(1, :eV, :J)
 1.602176634e-19
 
 julia> convert_unit(1, :GHz, :J)
 6.62607015e-25
 
 julia> convert_unit(1, :meV, :mK)
-11604.518121550082
source
QuantumToolbox._calculate_expectation!Function
_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.
 The function is called by the callback _save_affect_lr_mesolve!.
 
@@ -614,7 +618,7 @@
 B : AbstractMatrix{T}
     The B matrix.
 idx : Integer
-    The index of the current time step.
source
QuantumToolbox._adjM_condition_variationalFunction
_adjM_condition_variational(u, t, integrator) where T
 Condition for the dynamical rank adjustment based on the leakage out of the low-rank manifold.
 
 Parameters
@@ -624,14 +628,14 @@
 t : Real
     The current time.
 integrator : ODEIntegrator
-    The integrator of the problem.
source
QuantumToolbox._adjM_affect!Function
_adjM_affect!(integrator)
 Affect function for the dynamical rank adjustment. It increases the rank of the low-rank manifold by one, and updates the matrices accordingly.
 If Δt>0, it rewinds the integrator to the previous time step.
 
 Parameters
 ----------
 integrator : ODEIntegrator
-    The integrator of the problem.
source
QuantumToolbox._adjM_condition_ratioFunction
_adjM_condition_ratio(u, t, integrator) where T
 Condition for the dynamical rank adjustment based on the ratio between the smallest and largest eigenvalues of the density matrix.
 The spectrum of the density matrix is calculated efficiently using the properties of the SVD decomposition of the matrix.
 
@@ -642,7 +646,7 @@
 t : Real
     The current time.
 integrator : ODEIntegrator
-    The integrator of the problem.
source
QuantumToolbox._pinv!Function
_pinv!(A, T1, T2; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T
+    The integrator of the problem.
source
QuantumToolbox._pinv!Function
_pinv!(A, T1, T2; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T
 Computes the pseudo-inverse of a matrix A, and stores it in T1. If T2 is provided, it is used as a temporary matrix. 
 The algorithm is based on the SVD decomposition of A, and is taken from the Julia package LinearAlgebra.
 The difference with respect to the original function is that the cutoff is done with a smooth function instead of a step function.
@@ -657,7 +661,7 @@
 atol : Real
     Absolute tolerance for the calculation of the pseudo-inverse.   
 rtol : Real
-    Relative tolerance for the calculation of the pseudo-inverse.
source
QuantumToolbox.dBdz!Function
dBdz!(du, u, p, t) where T
 Dynamical evolution equations for the low-rank manifold. The function is called by the ODEProblem.
 
 Parameters
@@ -669,4 +673,4 @@
 p : NamedTuple
     The parameters of the problem.
 t : Real
-    The current time.
source
+ The current time.source diff --git a/dev/index.html b/dev/index.html index 7352738c..2e8998a7 100644 --- a/dev/index.html +++ b/dev/index.html @@ -31,4 +31,4 @@ c_ops = [sqrt(γ) * a_gpu] e_ops = [a_gpu' * a_gpu] -sol = mesolve(H_gpu, ψ0_gpu, tlist, c_ops, e_ops = e_ops) +sol = mesolve(H_gpu, ψ0_gpu, tlist, c_ops, e_ops = e_ops) diff --git a/dev/qutip_differences/index.html b/dev/qutip_differences/index.html index b77ead0b..485ee877 100644 --- a/dev/qutip_differences/index.html +++ b/dev/qutip_differences/index.html @@ -1,2 +1,2 @@ -Key differences from QuTiP · QuantumToolbox.jl
+Key differences from QuTiP · QuantumToolbox.jl
diff --git a/dev/search_index.js b/dev/search_index.js index e6acf668..c5dbdc92 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"type_stability/#doc:Type-Stability","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"You are here because you have probably heard about the excellent performance of Julia compared to other common programming languages like Python. One of the reasons is the Just-In-Time (JIT) compiler of Julia, which is able to generate highly optimized machine code. However, the JIT compiler can only do its job if the code type can be inferred. You can also read the Performance Tips section in Julia's documentation for more details. Here, we try to explain it briefly, with a focus on the QuantumToolbox.jl package.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"note: Note\nThis page is not a tutorial on QuantumToolbox.jl, but rather a general guide to writing Julia code for simulating quantum systems efficiently. If you don't care about the performance of your code, you can skip this page.","category":"page"},{"location":"type_stability/#Basics-of-type-stability","page":"The Importance of Type-Stability","title":"Basics of type stability","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Let's have a look at the following example:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"using InteractiveUtils\nusing QuantumToolbox","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function foo(x)\n if x > 0\n return 1\n else\n return -1.0\n end\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The function foo apparently seems to be innocent. It takes an argument x and returns either 1 or -1.0 depending on the sign of x. However, the return type of foo is not clear. If x is positive, the return type is Int, otherwise it is Float64. This is a problem for the JIT compiler, because it has to determine the return type of foo at runtime. This is called type instability (even though it is a weak form) and may lead to a significant performance penalty. To avoid this, always aim for type-stable code. This means that the return type of a function should be clear from the types of its arguments. We can check the inferred return type of foo using the @code_warntype macro:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype foo(1)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The key point is to ensure the return type of a function is clear from the types of its arguments. There are several ways to achieve this, and the best approach depends on the specific problem. For example, one can use the same return type:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function foo(x)\n if x > 0\n return 1.0\n else\n return -1.0\n end\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Or you can ensure the return type matches the type of the argument:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function foo(x::T) where T\n if x > 0\n return T(1)\n else\n return -T(1)\n end\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The latter example is very important because it takes advantage of Julia's multiple dispatch, which is one of the most powerful features of the language. Depending on the type T of the argument x, the Julia compiler generates a specialized version of foo that is optimized for this type. If the input type is an Int64, the return type is Int64, if x is a Float64, the return type is Float64, and so on.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@show foo(1)\n@show foo(-4.4)\n@show foo(1//2)\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"note: Note\nIf you didn't know how to make this function type-stable, it is probably a good idea to read the official Julia documentation, and in particular its Performance Tips section.","category":"page"},{"location":"type_stability/#Global-variables","page":"The Importance of Type-Stability","title":"Global variables","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Another source of type instability is the use of global variables. In general, it is a good idea to declare global variables as const to ensure their type is fixed for the entire program. For example, consider the following function that internally takes a global variable y:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"y = 2.4\n\nfunction bar(x)\n res = zero(x) # this returns the zero of the same type of x\n for i in 1:1000\n res += y * x\n end\n return res\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The Julia compiler cannot infer the type of res because it depends on the type of y, which is a global variable that can change at any time of the program. We can check it using the @code_warntype macro:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype bar(3.2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"While in the last example of the foo function we got a weak form of type instability, returning a Union{Int, Float64}, in this case the return type of bar is Any, meaning that the compiler doesn't know anything about the return type. Thus, this function has nothing different from a dynamically typed language like Python. We can benchmark the performance of bar using the BenchmarkTools.jl package:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"using BenchmarkTools\n\n@benchmark bar(3.2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Here we see a lot of memory allocations and low performances in general. To fix this, we can declare a const (constant) variable instead:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"const z = 2.4\n\nfunction bar(x)\n res = zero(x) # this returns the zero of the same type of x\n for i in 1:1000\n res += z * x\n end\n return res\nend\n\n@benchmark bar(3.2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"And we can see that the performance has improved significantly. Hence, we highly recommend using global variables as const, but only when truly necessary. This choice is problem-dependent, but in the case of QuantumToolbox.jl, this can be applied for example in the case of defining the Hilbert space dimensions, static parameters, or the system operators.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Although it is always a good practice to avoid such kind of type instabilities, in the actual implementation of QuantumToolbox.jl (where we mainly deal with linear algebra operations), the compiler may perform only a few runtime dispatches, and the performance penalty may be negligible compared to the heavy linear algebra operations.","category":"page"},{"location":"type_stability/#Vectors-vs-Tuples-vs-StaticArrays","page":"The Importance of Type-Stability","title":"Vectors vs Tuples vs StaticArrays","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Julia has many ways to represent arrays or lists of general objects. The most common are Vectors and Tuples. The former is a dynamic array that can change its size at runtime, while the latter is a fixed-size array that is immutable, and where the type of each element is already known at compile time. For example:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"v1 = [1, 2, 3] # Vector of Int64\nv2 = [1.0 + 2.0im, 3.0 + 4.0im] # Vector of ComplexF64\nv3 = [1, \"ciao\", 3.0] # Vector of Any\n\nt1 = (1, 2, 3) # Tuple of {Int64, Int64, Int64}\nt2 = (1.0 + 2.0im, 3.0 + 4.0im) # Tuple of {ComplexF64, ComplexF64}\nt3 = (1, \"ciao\", 3.0) # Tuple of {Int64, String, Float64}\n\n@show typeof(v1)\n@show typeof(v2)\n@show typeof(v3)\n@show typeof(t1)\n@show typeof(t2)\n@show typeof(t3)\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Thus, we highly recommend using Vector only when we are sure that it contains elements of the same type, and only when we don't need to know its size at compile time. On the other hand, Tuples are less flexible but more efficient in terms of performance. A third option is to use the SVector type from the StaticArrays.jl package. This is similar to Vector, where the elements should have the same type, but it is fixed-size and immutable. One may ask when it is necessary to know the array size at compile time. A practical example is the case of ptrace, where it internally reshapes the quantum state into a tensor whose dimensions depend on the number of subsystems. We will see this in more detail in the next section.","category":"page"},{"location":"type_stability/#The-[QuantumObject](@ref)-internal-structure","page":"The Importance of Type-Stability","title":"The QuantumObject internal structure","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Before making a practical example, let's see the internal structure of the QuantumObject type. As an example, we consider the case of three qubits, and we study the internal structure of the hatsigma_x^(2) operator:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2 = tensor(qeye(2), sigmax(), qeye(2))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"and its type is","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"obj_type = typeof(σx_2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"This is exactly what the Julia compiler sees: it is a QuantumObject, composed by a field of type SparseMatrixCSC{ComplexF64, Int64} (i.e., the 8x8 matrix containing the Pauli matrix, tensored with the identity matrices of the other two qubits). Then, we can also see that it is a OperatorQuantumObject, with 3 subsystems in total. Hence, just looking at the type of the object, the compiler has all the information it needs to generate a specialized version of the functions.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Let's see more in the details all the internal fields of the QuantumObject type:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"fieldnames(obj_type)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2.data","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2.type","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Operator is a synonym for OperatorQuantumObject.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2.dims","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The dims field contains the dimensions of the subsystems (in this case, three subsystems with dimension 2 each). We can see that the type of dims is SVector instead of Vector. As we mentioned before, this is very useful in functions like ptrace. Let's do a simple example of reshaping an operator internally generated from some dims input:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function reshape_operator_data(dims)\n op = Qobj(randn(prod(dims), prod(dims)), type=Operator, dims=dims)\n op_dims = op.dims\n op_data = op.data\n return reshape(op_data, vcat(op_dims, op_dims)...)\nend\n\ntypeof(reshape_operator_data([2, 2, 2]))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Which returns a tensor of size 2x2x2x2x2x2. Let's check the @code_warntype:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype reshape_operator_data([2, 2, 2])","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"We got a Any type, because the compiler doesn't know the size of the dims vector. We can fix this by using a Tuple (or SVector):","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"typeof(reshape_operator_data((2, 2, 2)))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype reshape_operator_data((2, 2, 2))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Finally, let's look at the benchmarks","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@benchmark reshape_operator_data($[2, 2, 2])","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@benchmark reshape_operator_data($((2, 2, 2)))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Which is an innocuous but huge difference in terms of performance. Hence, we highly recommend using Tuple or SVector when defining the dimensions of a user-defined QuantumObject.","category":"page"},{"location":"type_stability/#The-use-of-Val-in-some-QuantumToolbox.jl-functions","page":"The Importance of Type-Stability","title":"The use of Val in some QuantumToolbox.jl functions","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"In some functions of QuantumToolbox.jl, you may find the use of the Val type in the arguments. This is a trick to pass a value at compile time, and it is very useful to avoid type instabilities. Let's make a very simple example, where we want to create a Fock state jrangle of a given dimension N, and we give the possibility to create it as a sparse or dense vector. At first, we can write the function without using Val:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function my_fock(N::Int, j::Int = 0; sparse::Bool = false)\n if sparse\n array = sparsevec([j + 1], [1.0 + 0im], N)\n else\n array = zeros(ComplexF64, N)\n array[j+1] = 1\n end\n return QuantumObject(array; type = Ket)\nend\n@show my_fock(2, 1)\n@show my_fock(2, 1; sparse = true)\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"But it is immediately clear that the return type of this function is not clear, because it depends on the value of the sparse argument. We can check it using the @code_warntype macro:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock(2, 1)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock(2, 1; sparse = true)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"We can fix this by using the Val type, where we enable the multiple dispatch of the function:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"getVal(::Val{N}) where N = N\nfunction my_fock_good(N::Int, j::Int = 0; sparse::Val = Val(false))\n if getVal(sparse)\n array = zeros(ComplexF64, N)\n array[j+1] = 1\n else\n array = sparsevec([j + 1], [1.0 + 0im], N)\n end\n return QuantumObject(array; type = Ket)\nend\n@show my_fock_good(2, 1)\n@show my_fock_good(2, 1; sparse = Val(true))\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"And now the return type of the function is clear:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock_good(2, 1)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock_good(2, 1; sparse = Val(true))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"This is exactly how the current fock function is implemented in QuantumToolbox.jl. There are many other functions that support this feature, and we highly recommend using it when necessary.","category":"page"},{"location":"type_stability/#Conclusions","page":"The Importance of Type-Stability","title":"Conclusions","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"In this page, we have seen the importance of type stability in Julia, and how to write efficient code in the context of QuantumToolbox.jl. We have seen that the internal structure of the QuantumObject type is already optimized for the compiler, and we have seen some practical examples of how to write efficient code. We have seen that the use of Vector should be avoided when the elements don't have the same type, and that the use of Tuple or SVector is highly recommended when the size of the array is known at compile time. Finally, we have seen the use of Val to pass values at compile time, to avoid type instabilities in some functions. ```","category":"page"},{"location":"users_guide/states_and_operators/#doc:Manipulating-States-and-Operators","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"","category":"section"},{"location":"users_guide/states_and_operators/#Introduction","page":"Manipulating States and Operators","title":"Introduction","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"In the previous guide section Basic Operations on Quantum Objects, we saw how to create states and operators, using the functions built into QuantumToolbox. In this portion of the guide, we will look at performing basic operations with states and operators. For more detailed demonstrations on how to use and manipulate these objects, see the examples given in the tutorial section.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/states_and_operators/#doc:State-vectors","page":"Manipulating States and Operators","title":"State Vectors (kets or bras)","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Here we begin by creating a Fock basis (or fock) vacuum state vector 0rangle with in a Hilbert space with 5 number states, from 0 to 4:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(5, 0)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"and then create a lowering operator hata corresponding to 5 number states using the destroy function:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"a = destroy(5)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Now lets apply the lowering operator \\hat{a} to our vacuum state vac:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"a * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"We see that, as expected, the vacuum is transformed to the zero vector. A more interesting example comes from using the adjoint of the lowering operator hata, the raising operator hata^dagger:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"a' * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The raising operator has in indeed raised the state vac from the vacuum to the 1rangle state. Instead of using the adjoint method to raise the state, we could have also used the built-in create function to make a raising operator:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad = create(5)\nad * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"which does the same thing. We can raise the vacuum state more than once by successively apply the raising operator:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * ad * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"or just taking the square of the raising operator left(hata^daggerright)^2:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad^2 * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Applying the raising operator twice gives the expected sqrtn+1 dependence. We can use the product of hata^dagger hata to also apply the number operator to the state vector vac:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"or on the 1rangle state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * (ad * vac)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"or on the 2rangle state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * (ad^2 * vac)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Notice how in this last example, application of the number operator does not give the expected value n=2, but rather 2sqrt2. This is because this last state is not normalized to unity as hata^daggernrangle=sqrtn+1n+1rangle. Therefore, we should normalize (or use unit) our vector first:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * normalize(ad^2 * vac)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Since we are giving a demonstration of using states and operators, we have done a lot more work than we should have. For example, we do not need to operate on the vacuum state to generate a higher number Fock state. Instead we can use the basis (or fock) function to directly obtain the required state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket = basis(5, 2)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Notice how it is automatically normalized. We can also use the built in number operator num:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"n = num(5)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Therefore, instead of ad * a * normalize(ad^2 * vac), we have:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"n * ket","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"We can also create superpositions of states:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket = normalize(basis(5, 0) + basis(5, 1))","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"where we have used the normalize function again to normalize the state. Apply the number opeartor again:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"n * ket","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"We can also create coherent states and squeezed states by applying the displace and squeeze functions to the vacuum state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(5, 0)\n\nd = displace(5, 1im)\n\ns = squeeze(5, 0.25 + 0.25im)\n\nd * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"d * s * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Of course, displacing the vacuum gives a coherent state, which can also be generated using the built in coherent function.","category":"page"},{"location":"users_guide/states_and_operators/#doc:Density-matrices","page":"Manipulating States and Operators","title":"Density matrices","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"One of the main purpose of QuantumToolbox is to explore the dynamics of open quantum systems, where the most general state of a system is no longer a state vector, but rather a density matrix. Since operations on density matrices operate identically to those of vectors, we will just briefly highlight creating and using these structures.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The simplest density matrix is created by forming the outer-product psiranglelanglepsi of a ket vector:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket = basis(5, 2)\nket * ket'","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"A similar task can also be accomplished via the fock_dm or ket2dm functions:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"fock_dm(5, 2)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket2dm(ket)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"If we want to create a density matrix with equal classical probability of being found in the 2rangle or 4rangle number states, we can do the following:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"0.5 * fock_dm(5, 2) + 0.5 * fock_dm(5, 4) # with fock_dm\n0.5 * ket2dm(basis(5, 2)) + 0.5 * ket2dm(basis(5, 4)) # with ket2dm","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"There are also several other built-in functions for creating predefined density matrices, for example coherent_dm and thermal_dm which create coherent state and thermal state density matrices, respectively.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"coherent_dm(5, 1.25)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"thermal_dm(5, 1.25)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"QuantumToolbox also provides a set of distance metrics for determining how close two density matrix distributions are to each other. Included are the fidelity, and trace distance (tracedist).","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"x = coherent_dm(5, 1.25)\n\ny = coherent_dm(5, 1.25im)\n\nz = thermal_dm(5, 0.125)\n\nfidelity(x, y)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Note that the definition of fidelity here is from Nielsen & Chuang, \"Quantum Computation and Quantum Information\". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994). We also know that for two pure states, the trace distance (T) and the fidelity (F) are related by T = sqrt1-F^2:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"tracedist(x, y) ≈ sqrt(1 - (fidelity(x, y))^2)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"For a pure state and a mixed state, 1 - F leq T which can also be verified:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"1 - fidelity(x, z) < tracedist(x, z)","category":"page"},{"location":"users_guide/states_and_operators/#doc:Two-level-systems","page":"Manipulating States and Operators","title":"Two-level systems (Qubits)","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Having spent a fair amount of time on basis states that represent harmonic oscillator states, we now move on to qubit, or two-level quantum systems (for example a spin-12). To create a state vector corresponding to a qubit system, we use the same basis, or fock, function with only two levels:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"spin = basis(2, 0)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Now at this point one may ask how this state is different than that of a harmonic oscillator in the vacuum state truncated to two energy levels?","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(2, 0)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"At this stage, there is no difference. This should not be surprising as we called the exact same function twice. The difference between the two comes from the action of the spin operators sigmax, sigmay, sigmaz, sigmap, and sigmam on these two-level states. For example, if vac corresponds to the vacuum state of a harmonic oscillator, then, as we have already seen, we can use the raising operator (create) to get the 1rangle state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"create(2) * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"For a spin system, the operator analogous to the raising operator is the hatsigma_+ operator sigmap. Applying on the spin state gives:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmap() * spin","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Now we see the difference! The sigmap operator acting on the spin state returns the zero vector. Why is this? To see what happened, let us use the hatsigma_z (sigmaz) operator:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmaz()","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmaz() * spin","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"spin2 = basis(2, 1)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmaz() * spin2","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The answer is now apparent. Since the QuantumToolbox sigmaz function uses the standard Z-basis representation of the hatsigma_z spin operator, the spin state corresponds to the uparrowrangle state of a two-level spin system while spin2 gives the downarrowrangle state. Therefore, in our previous example sigmap() * spin, we raised the qubit state out of the truncated two-level Hilbert space resulting in the zero state.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"While at first glance this convention might seem somewhat odd, it is in fact quite handy. For one, the spin operators remain in the conventional form. Second, this corresponds nicely with the quantum information definitions of qubit states, where the excited uparrowrangle state is label as 0rangle, and the downarrowrangle state by 1rangle.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"If one wants to create spin operators for higher spin systems, then the jmat function comes in handy.","category":"page"},{"location":"users_guide/states_and_operators/#doc:Expectation-values","page":"Manipulating States and Operators","title":"Expectation values","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Some of the most important information about quantum systems comes from calculating the expectation value of operators, both Hermitian and non-Hermitian, as the state or density matrix of the system varies in time. Therefore, in this section we demonstrate the use of the expect function. To begin:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(5, 0)\n\none = basis(5, 1)\n\nc = create(5)\n\nN = num(5)\n\ncoh = coherent_dm(5, 1.0im)\n\ncat = normalize(basis(5, 4) + 1.0im * basis(5, 3))\n\nprintln(expect(N, vac) ≈ 0)\nprintln(expect(N, one) ≈ 1)\nprintln(expect(N, coh) ≈ 0.9970555745806597)\nprintln(expect(c, cat) ≈ 1im)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The expect function also accepts lists or arrays of state vectors or density matrices for the second input:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"states = [normalize(c^k * vac) for k in 0:4]\n\nexpect(N, states)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"cat_list = [normalize(basis(5, 4) + x * basis(5, 3)) for x in [0, 1.0im, -1.0, -1.0im]]\n\nexpect(c, cat_list)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Notice how in this last example, all of the return values are complex numbers. This is because the expect function looks to see whether the operator is Hermitian or not. If the operator is Hermitian, then the output will always be real. In the case of non-Hermitian operators, the return values may be complex. Therefore, the expect function will return an array of complex values for non-Hermitian operators when the input is a list/array of states or density matrices.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Of course, the expect function works for spin states and operators:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"up = basis(2, 0)\n\ndn = basis(2, 1)\n\nprintln(expect(sigmaz(), up) ≈ 1)\nprintln(expect(sigmaz(), dn) ≈ -1)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"as well as the composite objects discussed in the next section Tensor Products and Partial Traces:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"spin1 = basis(2, 0)\n\nspin2 = basis(2, 1)\n\ntwo_spins = tensor(spin1, spin2)\n\nsz1 = tensor(sigmaz(), qeye(2))\n\nsz2 = tensor(qeye(2), sigmaz())\n\nprintln(expect(sz1, two_spins) ≈ 1)\nprintln(expect(sz2, two_spins) ≈ -1)","category":"page"},{"location":"users_guide/states_and_operators/#doc:Superoperators-and-Vectorized-Operators","page":"Manipulating States and Operators","title":"Superoperators and Vectorized Operators","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"In addition to state vectors and density operators, QuantumToolbox allows for representing maps that act linearly on density operators using the Liouville supermatrix formalisms.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"This support is based on the correspondence between linear operators acting on a Hilbert space, and vectors in two copies of that Hilbert space (which is also called the Fock-Liouville space), ","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"textrmvec mathcalL(mathcalH) rightarrow mathcalHotimesmathcalH","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Therefore, a given density matrix hatrho can then be vectorized, denoted as ","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"hatrhoranglerangle = textrmvec(hatrho)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"QuantumToolbox uses the column-stacking convention for the isomorphism between mathcalL(mathcalH) and mathcalHotimesmathcalH. This isomorphism is implemented by the functions mat2vec and vec2mat:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"rho = Qobj([1 2; 3 4])","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vec_rho = mat2vec(rho)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"rho2 = vec2mat(vec_rho)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The QuantumObject.type attribute indicates whether a quantum object is a vector corresponding to an OperatorKet, or its Hermitian conjugate OperatorBra. One can also use isoper, isoperket, and isoperbra to check the type:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"println(isoper(vec_rho))\nprintln(isoperket(vec_rho))\nprintln(isoperbra(vec_rho))\nprintln(isoper(vec_rho'))\nprintln(isoperket(vec_rho'))\nprintln(isoperbra(vec_rho'))","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Because Julia is a column-oriented languages (like Fortran and MATLAB), in QuantumToolbox, we define the spre (left), spost (right), and sprepost (left-and-right) multiplication superoperators as follows:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"beginalign\nhatAhatrho rightarrow textrmspre(hatA) * textrmvec(hatrho) = hatmathbb1otimes hatA hatrhorangleranglenotag\nhatrho hatB rightarrow textrmspost(hatB) * textrmvec(hatrho) = hatB^Totimes hatmathbb1 hatrhorangleranglenotag\nhatA hatrho hatB rightarrow textrmsprepost(hatAhatB) * textrmvec(hatrho) = hatB^Totimes hatA hatrhorangleranglenotag\nendalign","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"where hatmathbb1 represents the identity operator with Hilbert space dimension equal to hatrho.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"A = Qobj([1 2; 3 4])\nS_A = spre(A)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"B = Qobj([5 6; 7 8])\nS_B = spost(B)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"S_AB = sprepost(A, B)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"S_AB ≈ S_A * S_B ≈ S_B * S_A","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"One can also use issuper to check the type:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"println(isoper(S_AB))\nprintln(issuper(S_AB))","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"With the above definitions, the following equalities hold in Julia:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"textrmvec(hatA hatrho hatB) = textrmspre(hatA) * textrmspre(hatB) * textrmvec(hatrho) = textrmsprepost(hatAhatB) * textrmvec(hatrho) forallhatA hatB hatrho","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"N = 10\nA = Qobj(rand(ComplexF64, N, N))\nB = Qobj(rand(ComplexF64, N, N))\nρ = rand_dm(N) # random density matrix\nmat2vec(A * ρ * B) ≈ spre(A) * spost(B) * mat2vec(ρ) ≈ sprepost(A, B) * mat2vec(ρ)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"In addition, dynamical generators on this extended space, often called Liouvillian superoperators, can be created using the liouvillian function. Each of these takes a Hamiltonian along with a list of collapse operators, and returns a type=SuperOperator object that can be exponentiated to find the superoperator for that evolution.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"H = 10 * sigmaz()\n\nc = destroy(2)\n\nL = liouvillian(H, [c])","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"t = 0.8\nexp(L * t)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"See the section Lindblad Master Equation Solver for more details.","category":"page"},{"location":"users_guide/tensor/#doc:Tensor-products-and-Partial-Traces","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/tensor/#doc:Tensor-products","page":"Tensor Products and Partial Traces","title":"Tensor products","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"To describe the states of multipartite quantum systems (such as two coupled qubits, a qubit coupled to an oscillator, etc.) we need to expand the Hilbert space by taking the tensor product of the state vectors for each of the system components. Similarly, the operators acting on the state vectors in the combined Hilbert space (describing the coupled system) are formed by taking the tensor product of the individual operators.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"In QuantumToolbox, the function tensor (or kron) is used to accomplish this task. This function takes a collection of Ket or Operator as argument and returns a composite QuantumObject for the combined Hilbert space. The function accepts an arbitrary number of QuantumObject as argument. The type of returned QuantumObject is the same as that of the input(s).","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"A collection of QuantumObject:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(sigmax(), sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"or a Vector{QuantumObject}:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"op_list = fill(sigmax(), 3)\ntensor(op_list)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"warning: Beware of type-stability!\nPlease note that tensor(op_list) or kron(op_list) with op_list is a Vector is type-instable and can hurt performance. It is recommended to use tensor(op_list...) or kron(op_list...) instead. See the Section The Importance of Type-Stability for more details.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"For example, the state vector describing two qubits in their ground states is formed by taking the tensor product of the two single-qubit ground state vectors:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(basis(2, 0), basis(2, 0))","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"One can generalize to more qubits by adding more component state vectors in the argument list to the tensor (or kron) function, as illustrated in the following example:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"states = QuantumObject[\n normalize(basis(2, 0) + basis(2, 1)),\n normalize(basis(2, 0) + basis(2, 1)),\n basis(2, 0)\n]\ntensor(states...)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"This state is slightly more complicated, describing two qubits in a superposition between the up and down states, while the third qubit is in its ground state.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"To construct operators that act on an extended Hilbert space of a combined system, we similarly pass a list of operators for each component system to the tensor (or kron) function. For example, to form the operator that represents the simultaneous action of the hatsigma_x operator on two qubits:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"To create operators in a combined Hilbert space that only act on a single component, we take the tensor product of the operator acting on the subspace of interest, with the identity operators corresponding to the components that are to be unchanged. For example, the operator that represents hatsigma_z on the first qubit in a two-qubit system, while leaving the second qubit unaffected:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(sigmaz(), qeye(2))","category":"page"},{"location":"users_guide/tensor/#Example:-Constructing-composite-Hamiltonians","page":"Tensor Products and Partial Traces","title":"Example: Constructing composite Hamiltonians","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The tensor (or kron) function is extensively used when constructing Hamiltonians for composite systems. Here we’ll look at some simple examples.","category":"page"},{"location":"users_guide/tensor/#Two-coupled-qubits","page":"Tensor Products and Partial Traces","title":"Two coupled qubits","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"First, let’s consider a system of two coupled qubits. Assume that both the qubits have equal energy splitting, and that the qubits are coupled through a hatsigma_x otimes hatsigma_x interaction with strength g = 005 (in units where the bare qubit energy splitting is unity). The Hamiltonian describing this system is:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"H = tensor(sigmaz(), qeye(2)) + \n tensor(qeye(2), sigmaz()) + \n 0.05 * tensor(sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/#Three-coupled-qubits","page":"Tensor Products and Partial Traces","title":"Three coupled qubits","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The two-qubit example is easily generalized to three coupled qubits:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"H = tensor(sigmaz(), qeye(2), qeye(2)) + \n tensor(qeye(2), sigmaz(), qeye(2)) + \n tensor(qeye(2), qeye(2), sigmaz()) + \n 0.5 * tensor(sigmax(), sigmax(), qeye(2)) + \n 0.25 * tensor(qeye(2), sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/#A-two-level-system-coupled-to-a-cavity:-The-Jaynes-Cummings-model","page":"Tensor Products and Partial Traces","title":"A two-level system coupled to a cavity: The Jaynes-Cummings model","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The simplest possible quantum mechanical description for light-matter interaction is encapsulated in the Jaynes-Cummings model, which describes the coupling between a two-level atom and a single-mode electromagnetic field (a cavity mode). Denoting the energy splitting of the atom and cavity omega_a and omega_c, respectively, and the atom-cavity interaction strength g, the Jaynes-Cummings Hamiltonian can be constructed as:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"H = fracomega_a2hatsigma_z + omega_c hata^dagger hata + g (hata^dagger hatsigma_- + hata hatsigma_+)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"N = 6 # cavity fock space truncation\nωc = 1.25 # frequency of cavity\nωa = 1.0 # frequency of two-level atom\ng = 0.75 # interaction strength\n\na = tensor(qeye(2), destroy(N)) # cavity annihilation operator\n\n# two-level atom operators\nσm = tensor(destroy(2), qeye(N))\nσz = tensor(sigmaz(), qeye(N))\n\nH = 0.5 * ωa * σz + ωc * a' * a + g * (a' * σm + a * σm')","category":"page"},{"location":"users_guide/tensor/#doc:Partial-trace","page":"Tensor Products and Partial Traces","title":"Partial trace","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The partial trace is an operation that reduces the dimension of a Hilbert space by eliminating some degrees of freedom by averaging (tracing). In this sense it is therefore the converse of the tensor product. It is useful when one is interested in only a part of a coupled quantum system. For open quantum systems, this typically involves tracing over the environment leaving only the system of interest. In QuantumToolbox the function ptrace is used to take partial traces. ptrace takes one QuantumObject as an input, and also one argument sel, which marks the component systems that should be kept, and all the other components are traced out. ","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"Remember that the index of Julia starts from 1, and all the elements in sel should be positive Integer. Therefore, the type of sel can be either Integer, Tuple, SVector, or Vector.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"warning: Beware of type-stability!\nAlthough it supports also Vector type, it is recommended to use Tuple or SVector from StaticArrays.jl to improve performance. For a brief explanation on the impact of the type of sel, see the section The Importance of Type-Stability.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"For example, the density matrix describing a single qubit obtained from a coupled two-qubit system is obtained via:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ψ = tensor(\n basis(2, 0), \n basis(2, 1), \n normalize(basis(2, 0) + basis(2, 1))\n)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ψ, 1) # trace out 2nd and 3rd systems","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ψ, (1, 3)) # trace out 2nd system","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"Note that the partial trace always results in a Operator (density matrix), regardless of whether the composite system is a pure state (described by a Ket) or a mixed state (described by a Operator):","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ψ1 = normalize(basis(2, 0) + basis(2, 1))\nψ2 = basis(2, 0)\nψT = tensor(ψ1, ψ2)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ψT, 1)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ρT = tensor(ket2dm(ψ1), ket2dm(ψ1))","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ρT, 1)","category":"page"},{"location":"users_guide/steadystate/#doc:Solving-for-Steady-State-Solutions","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"","category":"section"},{"location":"users_guide/steadystate/#Introduction","page":"Solving for Steady-State Solutions","title":"Introduction","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"For time-independent open quantum systems with decay rates larger than the corresponding excitation rates, the system will tend toward a steady state as trightarrowinfty that satisfies the equation","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"fracdhatrho_textrmssdt = mathcalLhatrho_textrmss=0","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Although the requirement for time-independence seems quite restrictive, one can often employ a transformation to the interaction picture that yields a time-independent Hamiltonian. For many these systems, solving for the asymptotic density matrix hatrho_textrmss can be achieved using direct or iterative solution methods faster than using master equation or Monte-Carlo simulations. Although the steady state equation has a simple mathematical form, the properties of the Liouvillian operator are such that the solutions to this equation are anything but straightforward to find.","category":"page"},{"location":"users_guide/steadystate/#Steady-State-solvers-in-QuantumToolbox.jl","page":"Solving for Steady-State Solutions","title":"Steady State solvers in QuantumToolbox.jl","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"In QuantumToolbox.jl, the steady-state solution for a system Hamiltonian or Liouvillian is given by steadystate. This function implements a number of different methods for finding the steady state, each with their own pros and cons, where the method used can be chosen using the solver keyword argument.","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Solver Description\nSteadyStateDirectSolver() Directly solve Ax=b using the standard method given in Julia LinearAlgebra\nSteadyStateLinearSolver() Directly solve Ax=b using the algorithms given in LinearSolve.jl\nSteadyStateEigenSolver() Find the zero (or lowest) eigenvalue of mathcalL using eigsolve\nSteadyStateODESolver() Solving time evolution with algorithms given in DifferentialEquations.jl (ODE Solvers)","category":"page"},{"location":"users_guide/steadystate/#Using-Steady-State-solvers","page":"Solving for Steady-State Solutions","title":"Using Steady State solvers","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"The function steadystate can take either a Hamiltonian and a list of collapse operators c_ops as input, generating internally the corresponding Liouvillian mathcalL in Lindblad form, or alternatively, a Liouvillian mathcalL passed by the user.","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"ρ_ss = steadystate(H) # Hamiltonian\nρ_ss = steadystate(H, c_ops) # Hamiltonian and collapse operators\nρ_ss = steadystate(L) # Liouvillian","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"where H is a quantum object representing the system Hamiltonian (Operator) or Liouvillian (SuperOperator), and c_ops (defaults to nothing) can be a list of QuantumObject for the system collapse operators. The output, labelled as ρ_ss, is the steady-state solution for the systems. If no other keywords are passed to the function, the default solver SteadyStateDirectSolver() is used.","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"To change a solver, use the keyword argument solver, for example:","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"ρ_ss = steadystate(H, c_ops; solver = SteadyStateLinearSolver())","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"note: Initial state for `SteadyStateODESolver()`\nIt is necessary to provide the initial state ψ0 for ODE solving method, namely steadystate(H, ψ0, tspan, c_ops, solver = SteadyStateODESolver()), where tspan::Real represents the final time step, defaults to Inf (infinity).","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Although it is not obvious, the SteadyStateDirectSolver() and SteadyStateEigenSolver() methods all use an LU decomposition internally and thus can have a large memory overhead. In contrast, for SteadyStateLinearSolver(), iterative algorithms provided by LinearSolve.jl, such as KrylovJL_GMRES() and KrylovJL_BICGSTAB(), do not factor the matrix and thus take less memory than the LU methods and allow, in principle, for extremely large system sizes. The downside is that these methods can take much longer than the direct method as the condition number of the Liouvillian matrix is large, indicating that these iterative methods require a large number of iterations for convergence. ","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"To overcome this, one can provide preconditioner that solves for an approximate inverse for the (modified) Liouvillian, thus better conditioning the problem, leading to faster convergence. The left and right preconditioner can be specified as the keyword argument Pl and Pr, respectively:","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"solver = SteadyStateLinearSolver(alg = KrylovJL_GMRES(), Pl = Pl, Pr = Pr)","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"The use of a preconditioner can actually make these iterative methods faster than the other solution methods. The problem with precondioning is that it is only well defined for Hermitian matrices. Since the Liouvillian is non-Hermitian, the ability to find a good preconditioner is not guaranteed. Moreover, if a preconditioner is found, it is not guaranteed to have a good condition number. ","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Furthermore, QuantiumToolbox can take advantage of the Intel (Pardiso) LU solver in the Intel Math Kernel library (Intel-MKL) by using LinearSolve.jl and either Pardiso.jl or MKL_jll.jl:","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"using QuantumToolbox\nusing LinearSolve # must be loaded\n\nusing Pardiso\nsolver = SteadyStateLinearSolver(alg = MKLPardisoFactorize())\n\nusing MKL_jll\nsolver = SteadyStateLinearSolver(alg = MKLLUFactorization())","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"See LinearSolve.jl Solvers for more details.","category":"page"},{"location":"users_guide/steadystate/#Example:-Harmonic-oscillator-in-thermal-bath","page":"Solving for Steady-State Solutions","title":"Example: Harmonic oscillator in thermal bath","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Here, we demonstrate steadystate by using the example with the harmonic oscillator in thermal bath from the previous section (Lindblad Master Equation Solver).","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"using QuantumToolbox\nusing CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\n# Define parameters\nN = 20 # number of basis states to consider\na = destroy(N)\nH = a' * a\nψ0 = basis(N, 10) # initial state\nκ = 0.1 # coupling to oscillator\nn_th = 2 # temperature with average of 2 excitations\n\n# collapse operators \nc_ops = [\n sqrt(κ * (n_th + 1)) * a, # emission\n sqrt(κ * n_th ) * a' # absorption\n]\n\n# find steady-state solution\nρ_ss = steadystate(H, c_ops)\n\n# find expectation value for particle number in steady state\ne_ops = [a' * a]\nexp_ss = real(expect(e_ops[1], ρ_ss))\n\ntlist = LinRange(0, 50, 100)\n\n# monte-carlo\nsol_mc = mcsolve(H, ψ0, tlist, c_ops, e_ops=e_ops, ntraj=100, progress_bar=false)\nexp_mc = real(sol_mc.expect[1, :])\n\n# master eq.\nsol_me = mesolve(H, ψ0, tlist, c_ops, e_ops=e_ops, progress_bar=false)\nexp_me = real(sol_me.expect[1, :])\n\n# plot the results\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], \n title = L\"Decay of Fock state $|10\\rangle$ in a thermal environment with $\\langle n\\rangle=2$\",\n xlabel = \"Time\", \n ylabel = \"Number of excitations\",\n)\nlines!(ax, tlist, exp_mc, label = \"Monte-Carlo\", linewidth = 2, color = :blue)\nlines!(ax, tlist, exp_me, label = \"Master Equation\", linewidth = 2, color = :orange, linestyle = :dash)\nlines!(ax, tlist, exp_ss .* ones(length(tlist)), label = \"Steady State\", linewidth = 2, color = :red)\naxislegend(ax, position = :rt)\n\nfig","category":"page"},{"location":"users_guide/steadystate/#Calculate-steady-state-for-periodically-driven-systems","page":"Solving for Steady-State Solutions","title":"Calculate steady state for periodically driven systems","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"See the docstring of steadystate_floquet for more details.","category":"page"},{"location":"users_guide/time_evolution/solution/#doc-TE:Time-Evolution-Solutions","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/time_evolution/solution/#Solution","page":"Time Evolution Solutions","title":"Solution","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"QuantumToolbox utilizes the powerful DifferentialEquation.jl to simulate different kinds of quantum system dynamics. Thus, we will first look at the data structure used for returning the solution (sol) from DifferentialEquation.jl. The solution stores all the crucial data needed for analyzing and plotting the results of a simulation. A generic structure TimeEvolutionSol contains the following properties for storing simulation data:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Fields (Attributes) Description\nsol.times The time list of the evolution.\nsol.states The list of result states.\nsol.expect The expectation values corresponding to each time point in sol.times.\nsol.alg The algorithm which is used during the solving process.\nsol.abstol The absolute tolerance which is used during the solving process.\nsol.reltol The relative tolerance which is used during the solving process.\nsol.retcode (or sol.converged) The returned status from the solver.","category":"page"},{"location":"users_guide/time_evolution/solution/#Accessing-data-in-solutions","page":"Time Evolution Solutions","title":"Accessing data in solutions","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"To understand how to access the data in solution, we will use an example as a guide, although we do not worry about the simulation details at this stage. The Schrödinger equation solver (sesolve) used in this example returns TimeEvolutionSol:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"H = 0.5 * sigmay()\nψ0 = basis(2, 0)\ne_ops = [\n proj(basis(2, 0)),\n proj(basis(2, 1)),\n basis(2, 0) * basis(2, 1)'\n]\ntlist = LinRange(0, 10, 100)\nsol = sesolve(H, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false))\nnothing # hide","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"To see what is contained inside the solution, we can use the print function:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"print(sol)","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"It tells us the number of expectation values are computed and the number of states are stored. Now we have all the information needed to analyze the simulation results. To access the data for the three expectation values, one can do:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"expt1 = real(sol.expect[1,:])\nexpt2 = real(sol.expect[2,:])\nexpt3 = real(sol.expect[3,:])\nnothing # hide","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Recall that Julia uses Fortran-style indexing that begins with one (i.e., [1,:] represents the 1-st observable, where : represents all values corresponding to tlist).","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Together with the array of times at which these expectation values are calculated:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"times = sol.times\nnothing # hide","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"we can plot the resulting expectation values:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"using CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = L\"t\")\nlines!(ax, times, expt1, label = L\"\\langle 0 | \\rho(t) | 0 \\rangle\")\nlines!(ax, times, expt2, label = L\"\\langle 1 | \\rho(t) | 1 \\rangle\")\nlines!(ax, times, expt3, label = L\"\\langle 0 | \\rho(t) | 1 \\rangle\")\n\nylims!(ax, (-0.5, 1.0))\naxislegend(ax, position = :lb)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"State vectors, or density matrices, are accessed in a similar manner:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"sol.states","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Here, the solution contains only one (final) state. Because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). One can also specify e_ops and saveat separately.","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Some other solvers can have other output.","category":"page"},{"location":"users_guide/time_evolution/solution/#Multiple-trajectories-solution","page":"Time Evolution Solutions","title":"Multiple trajectories solution","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"This part is still under construction, please visit API first.","category":"page"},{"location":"users_guide/time_evolution/intro/#doc:Time-Evolution-and-Quantum-System-Dynamics","page":"Introduction","title":"Time Evolution and Quantum System Dynamics","text":"","category":"section"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Table of contents","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Pages = [\n \"intro.md\",\n \"solution.md\",\n \"sesolve.md\",\n \"mesolve.md\",\n \"mcsolve.md\",\n \"stochastic.md\",\n \"time_dependent.md\",\n]\nDepth = 1:2","category":"page"},{"location":"users_guide/time_evolution/intro/#doc-TE:Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Although in some cases, we want to find the stationary states of a quantum system, often we are interested in the dynamics: how the state of a system or an ensemble of systems evolves with time. QuantumToolbox provides many ways to model dynamics.","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"There are two kinds of quantum systems: open systems that interact with a larger environment and closed systems that do not. In a closed system, the state can be described by a state vector. When we are modeling an open system, or an ensemble of systems, the use of the density matrix is mandatory.","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"The following table lists the solvers provided by QuantumToolbox for dynamic quantum systems and the corresponding type of solution returned by the solver:","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Equation Function Call Problem Returned Solution\nUnitary evolution, Schrödinger equation sesolve sesolveProblem TimeEvolutionSol\nLindblad master eqn. or Von Neuman eqn. mesolve mesolveProblem TimeEvolutionSol\nMonte Carlo evolution mcsolve mcsolveProblem mcsolveEnsembleProblem TimeEvolutionMCSol\nStochastic Schrödinger equation ssesolve ssesolveProblem ssesolveEnsembleProblem TimeEvolutionSSESol","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"note: Solving dynamics with pre-defined problems\nQuantumToolbox 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 problems by yourself and take it as an input of the function call, e.g., sesolve(prob).","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#doc:Functions-operating-on-Qobj","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"QuantumToolbox also provide functions (methods) that operates on QuantumObject.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"You can click the function links and see the corresponding docstring for more information.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#Linear-algebra-and-attributes","page":"Functions operating on Qobj","title":"Linear algebra and attributes","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"Here is a table that summarizes all the supported linear algebra functions and attribute functions operating on a given QuantumObject Q:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"Description Function call Synonyms\nconjugate conj(Q) -\ntranspose transpose(Q) trans(Q)\nconjugate transposition adjoint(Q) Q', dag(Q)\npartial transpose partial_transpose(Q, mask) -\ndot product dot(Q1, Q2) -\ngeneralized dot product dot(Q1, Q2, Q3) matrix_element(Q1, Q2, Q3)\ntrace tr(Q) -\npartial trace ptrace(Q, sel) -\nsingular values svdvals(Q) -\nstandard vector p-norm or Schatten p-norm norm(Q, p) -\nnormalization normalize(Q, p) unit(Q, p)\nnormalization (in-place) normalize!(Q, p) -\nmatrix inverse inv(Q) -\nmatrix square root sqrt(Q) √(Q), sqrtm(Q)\nmatrix logarithm log(Q) logm(Q)\nmatrix exponential exp(Q) expm(Q)\nmatrix sine sin(Q) sinm(Q)\nmatrix cosine cos(Q) cosm(Q)\ndiagonal elements diag(Q) -\nprojector proj(Q) -\npurity purity(Q) -\npermute permute(Q, order) -\nremove small elements tidyup(Q, tol) -\nremove small elements (in-place) tidyup!(Q, tol) -\nget data get_data(Q) -\nget coherence get_coherence(Q) -","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#Eigenvalue-decomposition","page":"Functions operating on Qobj","title":"Eigenvalue decomposition","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"eigenenergies: return eigenenergies (eigenvalues)\neigenstates: return EigsolveResult (contains eigenvalues and eigenvectors)\neigvals: return eigenvalues\neigen: using dense eigen solver and return EigsolveResult (contains eigenvalues and eigenvectors)\neigsolve: using sparse eigen solver and return EigsolveResult (contains eigenvalues and eigenvectors)\neigsolve_al: using the Arnoldi-Lindblad eigen solver and return EigsolveResult (contains eigenvalues and eigenvectors)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#Examples","page":"Functions operating on Qobj","title":"Examples","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ψ = normalize(basis(4, 1) + basis(4, 2))","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ψ'","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ρ = coherent_dm(5, 1)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"diag(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"get_data(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"norm(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"sqrtm(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"tr(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"eigenenergies(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"result = eigenstates(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"λ, ψ = result\nλ # eigenvalues","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ψ # eigenvectors","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"λ, ψ, T = result\nT # transformation matrix","category":"page"},{"location":"users_guide/time_evolution/mesolve/#doc-TE:Lindblad-Master-Equation-Solver","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Von-Neumann-equation","page":"Lindblad Master Equation Solver","title":"Von Neumann equation","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"While the evolution of the state vector in a closed quantum system is deterministic (as we discussed in the previous section: Schrödinger Equation Solver), open quantum systems are stochastic in nature. The effect of an environment on the system of interest is to induce stochastic transitions between energy levels, and to introduce uncertainty in the phase difference between states of the system. The state of an open quantum system is therefore described in terms of ensemble averaged states using the density matrix formalism. A density matrix hatrho describes a probability distribution of quantum states psi_nrangle in a matrix representation, namely","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"hatrho = sum_n p_n psi_nranglelanglepsi_n","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"where p_n is the classical probability that the system is in the quantum state psi_nrangle. The time evolution of a density matrix hatrho is the topic of the remaining portions of this section.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"The time evolution of the density matrix hatrho(t) under closed system dynamics is governed by the von Neumann equation: ","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"beginequation\nlabelvon-Neumann-Eq\nfracddthatrho(t) = -fracihbarlefthatH hatrho(t)right\nendequation","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"where cdot cdot represents the commutator. The above equation is equivalent to the Schrödinger equation described in the previous section under the density matrix formalism.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"In QuantumToolbox, given a Hamiltonian, we can calculate the unitary (non-dissipative) time-evolution of an arbitrary initial state using the QuantumToolbox time evolution problem mesolveProblem or directly call the function mesolve. It evolves the density matrix hatrho(t) and evaluates the expectation values for a set of operators e_ops at each given time points, using an ordinary differential equation solver provided by the powerful julia package DifferentialEquation.jl.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"H = 0.5 * sigmax()\nstate0 = basis(2, 0) # state vector\nstate0 = ket2dm(basis(2, 0)) # density matrix\ntlist = LinRange(0.0, 10.0, 20)\n\nsol = mesolve(H, state0, tlist, e_ops = [sigmaz()])","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"note: Type of initial state\nThe initial state state0 here can be given as a state vector psi(0)rangle (in the type of Ket) or a density matrix hatrho(0) (in the type of Operator). If it is given as a Ket, it will be transformed to density matrix hatrho(0) = psi(0)ranglelanglepsi(0) internally in mesolve.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"The function returns TimeEvolutionSol, as described in the previous section Time Evolution Solutions. The stored states will always be in the type of Operator (density matrix).","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"sol.states","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Here, only the final state is stored because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). ","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"One can also specify e_ops and saveat separately:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"tlist = [0, 5, 10]\nsol = mesolve(H, state0, tlist, e_ops = [sigmay()], saveat = tlist)","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"sol.expect","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"sol.states","category":"page"},{"location":"users_guide/time_evolution/mesolve/#The-Lindblad-master-equation","page":"Lindblad Master Equation Solver","title":"The Lindblad master equation","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"The standard approach for deriving the equations of motion for a system interacting with its environment is to expand the scope of the system to include the environment. The combined quantum system is then closed, and its evolution is governed by the von Neumann equation given in Eq. \\eqref{von-Neumann-Eq}","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"beginequation\nlabeltot-von-Neumann-Eq\nfracddthatrho_textrmtot(t) = -fracihbarlefthatH_textrmtot hatrho_textrmtot(t)right\nendequation","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Here, the total Hamiltonian","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"hatH_textrmtot = hatH_textrmsys + hatH_textrmenv + hatH_textrmint","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"includes the original system Hamiltonian hatH_textrmsys, the Hamiltonian for the environment hatH_textrmenv, and a term representing the interaction between the system and its environment hatH_textrmint. Since we are only interested in the dynamics of the system, we can, perform a partial trace over the environmental degrees of freedom in Eq. \\eqref{tot-von-Neumann-Eq}, and thereby obtain a master equation for the motion of the original system density matrix hatrho_textrmsys(t)=textrmTr_textrmenvhatrho_textrmtot(t). The most general trace-preserving and completely positive form of this evolution is the Lindblad master equation for the reduced density matrix, namely","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"beginequation\nlabelLindblad-master-Eq\nfracddthatrho_textrmsys(t) = -fracihbarlefthatH_textrmsys hatrho_textrmsys(t)right + sum_n hatC_n hatrho_textrmsys(t) hatC_n^dagger - frac12 hatC_n^dagger hatC_n hatrho_textrmsys(t) - frac12 hatrho_textrmsys(t) hatC_n^dagger hatC_n\nendequation","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"where hatC_n equiv sqrtgamma_nhatA_n are the collapse operators, hatA_n are the operators acting on the system in hatH_textrmint which describes the system-environment interaction, and gamma_n are the corresponding rates. The derivation of Eq. \\eqref{Lindblad-master-Eq} may be found in several sources, and will not be reproduced here. Instead, we emphasize the approximations that are required to arrive at the master equation in the form of Eq. \\eqref{Lindblad-master-Eq} from physical arguments, and hence perform a calculation in QuantumToolbox:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Separability: At t = 0, there are no correlations between the system and environment, such that the total density matrix can be written as a tensor product, namely hatrho_textrmtot(0)=hatrho_textrmsys(0)otimeshatrho_textrmenv(0).\nBorn approximation: Requires: (i) the state of the environment does not significantly change as a result of the interaction with the system; (ii) the system and the environment remain separable throughout the evolution. These assumptions are justified if the interaction is weak, and if the environment is much larger than the system. In summary, hatrho_textrmtot(t)approxhatrho_textrmsys(t)otimeshatrho_textrmenv(0).\nMarkov approximation: The time-scale of decay for the environment tau_textrmenv is much shorter than the smallest time-scale of the system dynamics, i.e., tau_textrmsysggtau_textrmenv. This approximation is often deemed a “short-memory environment” as it requires the environmental correlation functions decay in a fast time-scale compared to those of the system.\nSecular approximation: Stipulates that elements in the master equation corresponding to transition frequencies satisfy omega_ab-omega_cd ll 1tau_textrmsys, i.e., all fast rotating terms in the interaction picture can be neglected. It also ignores terms that lead to a small renormalization of the system energy levels. This approximation is not strictly necessary for all master-equation formalisms (e.g., the Block-Redfield master equation), but it is required for arriving at the Lindblad form in Eq. \\eqref{Lindblad-master-Eq} which is used in mesolve.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"For systems with environments satisfying the conditions outlined above, the Lindblad master equation in Eq. \\eqref{Lindblad-master-Eq} governs the time-evolution of the system density matrix, giving an ensemble average of the system dynamics. In order to ensure that these approximations are not violated, it is important that the decay rates gamma_n be smaller than the minimum energy splitting in the system Hamiltonian. Situations that demand special attention therefore include, for example, systems strongly coupled to their environment, and systems with degenerate or nearly degenerate energy levels.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"What is new in the master equation compared to the Schrödinger equation (or von Neumann equation) are processes that describe dissipation in the quantum system due to its interaction with an environment. For example, evolution that includes incoherent processes such as relaxation and dephasing. These environmental interactions are defined by the operators hatA_n through which the system couples to the environment, and rates gamma_n that describe the strength of the processes.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"In QuantumToolbox, the function mesolve can also be used for solving the master equation. This is done by passing a list of collapse operators (c_ops) as the fourth argument of the mesolve function in order to define the dissipation processes of the master equation in Eq. \\eqref{Lindblad-master-Eq}. As we mentioned above, each collapse operator hatC_n is the product of sqrtgamma_n (the square root of the rate) and hatA_n (operator which describes the dissipation process). ","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Furthermore, QuantumToolbox solves the master equation in the SuperOperator formalism. That is, a Liouvillian SuperOperator will be generated internally in mesolve by the input system Hamiltonian hatH_textrmsys and the collapse operators hatC_n. One can also generate the Liouvillian SuperOperator manually for special purposes, and pass it as the first argument of the mesolve function. To do so, it is useful to read the section Superoperators and Vectorized Operators, and also the docstrings of the following functions:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"spre\nspost\nsprepost\nliouvillian\nlindblad_dissipator","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Example:-Spin-dynamics","page":"Lindblad Master Equation Solver","title":"Example: Spin dynamics","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Using the example with the dynamics of spin-frac12 from the previous section (Schrödinger Equation Solver), we can easily add a relaxation process (describing the dissipation of energy from the spin to the environment), by adding [sqrt(γ) * sigmax()] in the fourth parameter of the mesolve function.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"H = 2 * π * 0.1 * sigmax()\nψ0 = basis(2, 0) # spin-up\ntlist = LinRange(0.0, 10.0, 100)\n\nγ = 0.05\nc_ops = [sqrt(γ) * sigmax()]\n\nsol = mesolve(H, ψ0, tlist, c_ops, e_ops = [sigmaz(), sigmay()])","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"We can therefore plot the expectation values:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"using CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\ntimes = sol.times\nexpt_z = real(sol.expect[1,:])\nexpt_y = real(sol.expect[2,:])\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = \"Time\", ylabel = \"Expectation values\")\nlines!(ax, times, expt_z, label = L\"\\langle\\hat{\\sigma}_z\\rangle\", linestyle = :solid)\nlines!(ax, times, expt_y, label = L\"\\langle\\hat{\\sigma}_y\\rangle\", linestyle = :dash)\n\naxislegend(ax, position = :rt)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Example:-Harmonic-oscillator-in-thermal-bath","page":"Lindblad Master Equation Solver","title":"Example: Harmonic oscillator in thermal bath","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Consider a harmonic oscillator (single-mode cavity) couples to a thermal bath. If the single-mode cavity initially is in a 10-photon fock state, the dynamics is calculated with the following code:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"# Define parameters\nN = 20 # number of basis states to consider\na = destroy(N)\nH = a' * a\nψ0 = fock(N, 10) # initial state\nκ = 0.1 # coupling to oscillator\nn_th = 2 # temperature with average of 2 excitations\ntlist = LinRange(0, 50, 100)\n\n# collapse operators \nc_ops = [\n sqrt(κ * (n_th + 1)) * a, # emission\n sqrt(κ * n_th ) * a' # absorption\n]\n\n# find expectation value for particle number\ne_ops = [a' * a]\n\nsol = mesolve(H, ψ0, tlist, c_ops, e_ops=e_ops)\nNum = real(sol.expect[1, :])\n\n# plot the results\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], \n title = L\"Decay of Fock state $|10\\rangle$ in a thermal environment with $\\langle n\\rangle=2$\",\n xlabel = \"Time\", \n ylabel = \"Number of excitations\",\n)\nlines!(ax, tlist, Num)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Example:-Two-level-atom-coupled-to-dissipative-single-mode-cavity","page":"Lindblad Master Equation Solver","title":"Example: Two-level atom coupled to dissipative single-mode cavity","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Consider a two-level atom coupled to a dissipative single-mode cavity through a dipole-type interaction, which supports a coherent exchange of quanta between the two systems. If the atom initially is in its ground state and the cavity in a 5-photon fock state, the dynamics is calculated with the following code:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"note: Generate Liouviilian superoperator manually\nIn this example, we demonstrate how to generate the Liouvillian SuperOperator manually and pass it as the first argument of the mesolve function.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"# two-level atom\nσm = tensor(destroy(2), qeye(10))\nH_a = 2 * π * σm' * σm\n\n# dissipative single-mode cavity\nγ = 0.1 # dissipation rate\na = tensor(qeye(2), destroy(10))\nH_c = 2 * π * a' * a\nc_ops = [sqrt(γ) * a]\n\n# coupling between two-level atom and single-mode cavity\ng = 0.25 # coupling strength\nH_I = 2 * π * g * (σm * a' + σm' * a)\n\nψ0 = tensor(basis(2,0), fock(10, 5)) # initial state\ntlist = LinRange(0.0, 10.0, 200)\n\n# generate Liouvillian superoperator manually\nL = liouvillian(H_a + H_c + H_I, c_ops)\nsol = mesolve(L, ψ0, tlist, e_ops=[σm' * σm, a' * a])\n\ntimes = sol.times\n\n# expectation value of Number operator\nN_atom = real(sol.expect[1,:])\nN_cavity = real(sol.expect[2,:])\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = \"Time\", ylabel = \"Expectation values\")\nlines!(ax, times, N_atom, label = \"atom excitation probability\", linestyle = :solid)\nlines!(ax, times, N_cavity, label = \"cavity photon number\", linestyle = :dash)\n\naxislegend(ax, position = :rt)\n\nfig","category":"page"},{"location":"api/","page":"API","title":"API","text":"CurrentModule = QuantumToolbox","category":"page"},{"location":"api/#doc-API","page":"API","title":"API","text":"","category":"section"},{"location":"api/#Contents","page":"API","title":"Contents","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Pages = [\"api.md\"]","category":"page"},{"location":"api/#doc-API:Quantum-object-and-type","page":"API","title":"Quantum object (Qobj) and type","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"BraQuantumObject\nBra\nKetQuantumObject\nKet\nOperatorQuantumObject\nOperator\nOperatorBraQuantumObject\nOperatorBra\nOperatorKetQuantumObject\nOperatorKet\nSuperOperatorQuantumObject\nSuperOperator\nQuantumObject\nOperatorSum\nsize\neltype\nlength\nisbra\nisket\nisoper\nisoperbra\nisoperket\nissuper\nLinearAlgebra.ishermitian\nLinearAlgebra.issymmetric\nLinearAlgebra.isposdef\nisunitary","category":"page"},{"location":"api/#QuantumToolbox.BraQuantumObject","page":"API","title":"QuantumToolbox.BraQuantumObject","text":"BraQuantumObject <: QuantumObjectType\n\nConstructor representing a bra state langlepsi.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.Bra","page":"API","title":"QuantumToolbox.Bra","text":"const Bra = BraQuantumObject()\n\nA constant representing the type of BraQuantumObject: a bra state langlepsi\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.KetQuantumObject","page":"API","title":"QuantumToolbox.KetQuantumObject","text":"KetQuantumObject <: QuantumObjectType\n\nConstructor representing a ket state psirangle.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.Ket","page":"API","title":"QuantumToolbox.Ket","text":"const Ket = KetQuantumObject()\n\nA constant representing the type of KetQuantumObject: a ket state psirangle\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.OperatorQuantumObject","page":"API","title":"QuantumToolbox.OperatorQuantumObject","text":"OperatorQuantumObject <: QuantumObjectType\n\nConstructor representing an operator hatO.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.Operator","page":"API","title":"QuantumToolbox.Operator","text":"const Operator = OperatorQuantumObject()\n\nA constant representing the type of OperatorQuantumObject: an operator hatO\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.OperatorBraQuantumObject","page":"API","title":"QuantumToolbox.OperatorBraQuantumObject","text":"OperatorBraQuantumObject <: QuantumObjectType\n\nConstructor representing a bra state in the SuperOperator formalism langlelanglerho.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.OperatorBra","page":"API","title":"QuantumToolbox.OperatorBra","text":"const OperatorBra = OperatorBraQuantumObject()\n\nA constant representing the type of OperatorBraQuantumObject: a bra state in the SuperOperator formalism langlelanglerho.\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.OperatorKetQuantumObject","page":"API","title":"QuantumToolbox.OperatorKetQuantumObject","text":"OperatorKetQuantumObject <: QuantumObjectType\n\nConstructor representing a ket state in the SuperOperator formalism rhoranglerangle.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.OperatorKet","page":"API","title":"QuantumToolbox.OperatorKet","text":"const OperatorKet = OperatorKetQuantumObject()\n\nA constant representing the type of OperatorKetQuantumObject: a ket state in the SuperOperator formalism rhoranglerangle\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.SuperOperatorQuantumObject","page":"API","title":"QuantumToolbox.SuperOperatorQuantumObject","text":"SuperOperatorQuantumObject <: QuantumObjectType\n\nConstructor representing a super-operator hatmathcalO acting on vectorized density operator matrices.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SuperOperator","page":"API","title":"QuantumToolbox.SuperOperator","text":"const SuperOperator = SuperOperatorQuantumObject()\n\nA constant representing the type of SuperOperatorQuantumObject: a super-operator hatmathcalO acting on vectorized density operator matrices\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.QuantumObject","page":"API","title":"QuantumToolbox.QuantumObject","text":"struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,N}\n data::MT\n type::ObjType\n dims::SVector{N, Int}\nend\n\nJulia struct representing any quantum objects.\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⎡⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⎤\n⎢⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⎥\n⎣⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⎦\n\njulia> a isa QuantumObject\ntrue\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.OperatorSum","page":"API","title":"QuantumToolbox.OperatorSum","text":"struct OperatorSum\n\nA constructor to represent a sum of operators sum_i c_i hatO_i with a list of coefficients c_i and a list of operators hatO_i.\n\nThis is very useful when we have to update only the coefficients, without allocating memory by performing the sum of the operators.\n\n\n\n\n\n","category":"type"},{"location":"api/#Base.size","page":"API","title":"Base.size","text":"size(A::QuantumObject)\nsize(A::QuantumObject, idx::Int)\n\nReturns a tuple containing each dimensions of the array in the QuantumObject.\n\nOptionally, you can specify an index (idx) to just get the corresponding dimension of the array.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.eltype","page":"API","title":"Base.eltype","text":"eltype(A::QuantumObject)\n\nReturns the elements type of the matrix or vector corresponding to the QuantumObject A.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.length","page":"API","title":"Base.length","text":"length(A::QuantumObject)\n\nReturns the length of the matrix or vector corresponding to the QuantumObject A.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isbra","page":"API","title":"QuantumToolbox.isbra","text":"isbra(A::QuantumObject)\n\nChecks if the QuantumObject A is a BraQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isket","page":"API","title":"QuantumToolbox.isket","text":"isket(A::QuantumObject)\n\nChecks if the QuantumObject A is a KetQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isoper","page":"API","title":"QuantumToolbox.isoper","text":"isoper(A::QuantumObject)\n\nChecks if the QuantumObject A is a OperatorQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isoperbra","page":"API","title":"QuantumToolbox.isoperbra","text":"isoperbra(A::QuantumObject)\n\nChecks if the QuantumObject A is a OperatorBraQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isoperket","page":"API","title":"QuantumToolbox.isoperket","text":"isoperket(A::QuantumObject)\n\nChecks if the QuantumObject A is a OperatorKetQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.issuper","page":"API","title":"QuantumToolbox.issuper","text":"issuper(A::QuantumObject)\n\nChecks if the QuantumObject A is a SuperOperatorQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.ishermitian","page":"API","title":"LinearAlgebra.ishermitian","text":"ishermitian(A::QuantumObject)\n\nTest whether the QuantumObject is Hermitian.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.issymmetric","page":"API","title":"LinearAlgebra.issymmetric","text":"issymmetric(A::QuantumObject)\n\nTest whether the QuantumObject is symmetric.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.isposdef","page":"API","title":"LinearAlgebra.isposdef","text":"isposdef(A::QuantumObject)\n\nTest whether the QuantumObject is positive definite (and Hermitian) by trying to perform a Cholesky factorization of A.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isunitary","page":"API","title":"QuantumToolbox.isunitary","text":"isunitary(U::QuantumObject; kwargs...)\n\nTest whether the QuantumObject U is unitary operator. This function calls Base.isapprox to test whether U U^dagger is approximately equal to identity operator.\n\nNote that all the keyword arguments will be passed to Base.isapprox.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Qobj-arithmetic-and-attributes","page":"API","title":"Qobj arithmetic and attributes","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Base.conj\nLinearAlgebra.transpose\nLinearAlgebra.adjoint\nLinearAlgebra.dot\nLinearAlgebra.sqrt\nLinearAlgebra.log\nLinearAlgebra.exp\nLinearAlgebra.sin\nLinearAlgebra.cos\nLinearAlgebra.tr\nLinearAlgebra.svdvals\nLinearAlgebra.norm\nLinearAlgebra.normalize\nLinearAlgebra.normalize!\nLinearAlgebra.inv\nLinearAlgebra.diag\nproj\nptrace\npurity\npermute\ntidyup\ntidyup!\nget_data\nget_coherence\npartial_transpose","category":"page"},{"location":"api/#Base.conj","page":"API","title":"Base.conj","text":"conj(A::QuantumObject)\n\nReturn the element-wise complex conjugation of the QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.transpose","page":"API","title":"Base.transpose","text":"transpose(A::QuantumObject)\n\nLazy matrix transpose of the QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.adjoint","page":"API","title":"Base.adjoint","text":"A'\nadjoint(A::QuantumObject)\n\nLazy adjoint (conjugate transposition) of the QuantumObject\n\nNote that A' is a synonym for adjoint(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.dot","page":"API","title":"LinearAlgebra.dot","text":"dot(A::QuantumObject, B::QuantumObject)\n\nCompute the dot product between two QuantumObject: langle A B rangle\n\nNote that A and B should be Ket or OperatorKet\n\nA ⋅ B (where ⋅ can be typed by tab-completing \\cdot in the REPL) is a synonym for dot(A, B)\n\n\n\n\n\ndot(i::QuantumObject, A::QuantumObject j::QuantumObject)\n\nCompute the generalized dot product dot(i, A*j) between three QuantumObject: langle i hatA j rangle\n\nSupports the following inputs:\n\nA is in the type of Operator, with i and j are both Ket.\nA is in the type of SuperOperator, with i and j are both OperatorKet\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.sqrt","page":"API","title":"Base.sqrt","text":"√(A)\nsqrt(A::QuantumObject)\n\nMatrix square root of QuantumObject\n\nNote that √(A) is a synonym for sqrt(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.log","page":"API","title":"Base.log","text":"log(A::QuantumObject)\n\nMatrix logarithm of QuantumObject\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.exp","page":"API","title":"Base.exp","text":"exp(A::QuantumObject)\n\nMatrix exponential of QuantumObject\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.sin","page":"API","title":"Base.sin","text":"sin(A::QuantumObject)\n\nMatrix sine of QuantumObject, defined as\n\nsin left( hatA right) = frace^i hatA - e^-i hatA2 i\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.cos","page":"API","title":"Base.cos","text":"cos(A::QuantumObject)\n\nMatrix cosine of QuantumObject, defined as\n\ncos left( hatA right) = frace^i hatA + e^-i hatA2\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.tr","page":"API","title":"LinearAlgebra.tr","text":"tr(A::QuantumObject)\n\nReturns the trace of QuantumObject.\n\nNote that this function only supports for Operator and SuperOperator\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢\n\njulia> tr(a' * a)\n190.0 + 0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.svdvals","page":"API","title":"LinearAlgebra.svdvals","text":"svdvals(A::QuantumObject)\n\nReturn the singular values of a QuantumObject in descending order\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.norm","page":"API","title":"LinearAlgebra.norm","text":"norm(A::QuantumObject, p::Real)\n\nReturn the standard vector p-norm or Schatten p-norm of a QuantumObject depending on the type of A:\n\nIf A is either Ket, Bra, OperatorKet, or OperatorBra, returns the standard vector p-norm (default p=2) of A.\nIf A is either Operator or SuperOperator, returns Schatten p-norm (default p=1) of A.\n\nExamples\n\njulia> ψ = fock(10, 2)\nQuantum Object: type=Ket dims=[10] size=(10,)\n10-element Vector{ComplexF64}:\n 0.0 + 0.0im\n 0.0 + 0.0im\n 1.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n\njulia> norm(ψ)\n1.0\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.normalize","page":"API","title":"LinearAlgebra.normalize","text":"normalize(A::QuantumObject, p::Real)\n\nReturn normalized QuantumObject so that its p-norm equals to unity, i.e. norm(A, p) == 1.\n\nSupport for the following types of QuantumObject:\n\nIf A is Ket or Bra, default p = 2\nIf A is Operator, default p = 1\n\nAlso, see norm about its definition for different types of QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.normalize!","page":"API","title":"LinearAlgebra.normalize!","text":"normalize!(A::QuantumObject, p::Real)\n\nNormalize QuantumObject in-place so that its p-norm equals to unity, i.e. norm(A, p) == 1.\n\nSupport for the following types of QuantumObject:\n\nIf A is Ket or Bra, default p = 2\nIf A is Operator, default p = 1\n\nAlso, see norm about its definition for different types of QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.inv","page":"API","title":"Base.inv","text":"inv(A::QuantumObject)\n\nMatrix inverse of the QuantumObject\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.diag","page":"API","title":"LinearAlgebra.diag","text":"diag(A::QuantumObject, k::Int=0)\n\nReturn the k-th diagonal elements of a matrix-type QuantumObject\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.proj","page":"API","title":"QuantumToolbox.proj","text":"proj(ψ::QuantumObject)\n\nReturn the projector for a Ket or Bra type of QuantumObject\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ptrace","page":"API","title":"QuantumToolbox.ptrace","text":"ptrace(QO::QuantumObject, sel)\n\nPartial trace of a quantum state QO leaving only the dimensions with the indices present in the sel vector.\n\nNote that this function will always return Operator. No matter the input QuantumObject is a Ket, Bra, or Operator.\n\nExamples\n\nTwo qubits in the state ketpsi = keteg:\n\njulia> ψ = kron(fock(2,0), fock(2,1))\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.0 + 0.0im\n 1.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n\njulia> ptrace(ψ, 2)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Matrix{ComplexF64}:\n 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 1.0+0.0im\n\nor in an entangled state ketpsi = frac1sqrt2 left( ketee + ketgg right):\n\njulia> ψ = 1 / √2 * (kron(fock(2,0), fock(2,0)) + kron(fock(2,1), fock(2,1)))\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n\njulia> ptrace(ψ, 1)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Matrix{ComplexF64}:\n 0.5+0.0im 0.0+0.0im\n 0.0+0.0im 0.5+0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.purity","page":"API","title":"QuantumToolbox.purity","text":"purity(ρ::QuantumObject)\n\nCalculate the purity of a QuantumObject: textrmTr(rho^2)\n\nNote that this function only supports for Ket, Bra, and Operator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.permute","page":"API","title":"QuantumToolbox.permute","text":"permute(A::QuantumObject, order::Union{AbstractVector{Int},Tuple})\n\nPermute the tensor structure of a QuantumObject A according to the specified order list\n\nNote that this method currently works for Ket, Bra, and Operator types of QuantumObject.\n\nExamples\n\nIf order = [2, 1, 3], the Hilbert space structure will be re-arranged: mathcalH_1 otimes mathcalH_2 otimes mathcalH_3 rightarrow mathcalH_2 otimes mathcalH_1 otimes mathcalH_3.\n\njulia> ψ1 = fock(2, 0)\njulia> ψ2 = fock(3, 1)\njulia> ψ3 = fock(4, 2)\njulia> ψ_123 = tensor(ψ1, ψ2, ψ3)\njulia> permute(ψ_123, [2, 1, 3]) ≈ tensor(ψ2, ψ1, ψ3)\ntrue\n\nwarning: Beware of type-stability!\nIt is highly recommended to use permute(A, order) with order as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tidyup","page":"API","title":"QuantumToolbox.tidyup","text":"tidyup(A::QuantumObject, tol::Real=1e-14)\n\nGiven a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tidyup!","page":"API","title":"QuantumToolbox.tidyup!","text":"tidyup!(A::QuantumObject, tol::Real=1e-14)\n\nGiven a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.\n\nNote that this function is an in-place version of tidyup.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.get_data","page":"API","title":"QuantumToolbox.get_data","text":"get_data(A::QuantumObject)\n\nReturns the data of a QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.get_coherence","page":"API","title":"QuantumToolbox.get_coherence","text":"get_coherence(ψ::QuantumObject)\n\nGet the coherence value alpha by measuring the expectation value of the destruction operator hata on a state ketpsi or a density matrix hatrho.\n\nIt returns both alpha and the corresponding state with the coherence removed: ketdelta_alpha = exp ( alpha^* hata - alpha hata^dagger ) ketpsi for a pure state, and hatrho_alpha = exp ( alpha^* hata - alpha hata^dagger ) hatrho exp ( -baralpha hata + alpha hata^dagger ) for a density matrix. These states correspond to the quantum fluctuations around the coherent state ketalpha or alpharanglelanglealpha.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.partial_transpose","page":"API","title":"QuantumToolbox.partial_transpose","text":"partial_transpose(ρ::QuantumObject, mask::Vector{Bool})\n\nReturn the partial transpose of a density matrix rho, where mask is an array/vector with length that equals the length of ρ.dims. The elements in mask are boolean (true or false) which indicates whether or not the corresponding subsystem should be transposed.\n\nArguments\n\nρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).\nmask::Vector{Bool}: A boolean vector selects which subsystems should be transposed.\n\nReturns\n\nρ_pt::QuantumObject: The density matrix with the selected subsystems transposed.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Qobj-eigenvalues-and-eigenvectors","page":"API","title":"Qobj eigenvalues and eigenvectors","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"EigsolveResult\neigenenergies\neigenstates\nLinearAlgebra.eigen\nLinearAlgebra.eigvals\neigsolve\neigsolve_al","category":"page"},{"location":"api/#QuantumToolbox.EigsolveResult","page":"API","title":"QuantumToolbox.EigsolveResult","text":"struct EigsolveResult{T1<:Vector{<:Number}, T2<:AbstractMatrix{<:Number}, ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject},N}\n values::T1\n vectors::T2\n type::ObjType\n dims::SVector{N,Int}\n iter::Int\n numops::Int\n converged::Bool\nend\n\nA struct containing the eigenvalues, the eigenvectors, and some information from the solver\n\nFields\n\nvalues::AbstractVector: the eigenvalues\nvectors::AbstractMatrix: the transformation matrix (eigenvectors)\ntype::Union{Nothing,QuantumObjectType}: the type of QuantumObject, or nothing means solving eigen equation for general matrix\ndims::SVector: the dims of QuantumObject\niter::Int: the number of iteration during the solving process\nnumops::Int : number of times the linear map was applied in krylov methods\nconverged::Bool: Whether the result is converged\n\nExamples\n\nOne can obtain the eigenvalues and the corresponding QuantumObject-type eigenvectors by:\n\njulia> result = eigenstates(sigmax());\n\njulia> λ, ψ, T = result;\n\njulia> λ\n2-element Vector{ComplexF64}:\n -1.0 + 0.0im\n 1.0 + 0.0im\n\njulia> ψ\n2-element Vector{QuantumObject{Vector{ComplexF64}, KetQuantumObject}}:\n QuantumObject{Vector{ComplexF64}, KetQuantumObject}(ComplexF64[-0.7071067811865475 + 0.0im, 0.7071067811865475 + 0.0im], KetQuantumObject(), [2])\n QuantumObject{Vector{ComplexF64}, KetQuantumObject}(ComplexF64[0.7071067811865475 + 0.0im, 0.7071067811865475 + 0.0im], KetQuantumObject(), [2])\n\njulia> T\n2×2 Matrix{ComplexF64}:\n -0.707107+0.0im 0.707107+0.0im\n 0.707107+0.0im 0.707107+0.0im\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.eigenenergies","page":"API","title":"QuantumToolbox.eigenenergies","text":"eigenenergies(A::QuantumObject; sparse::Bool=false, kwargs...)\n\nCalculate the eigenenergies\n\nArguments\n\nA::QuantumObject: the QuantumObject to solve eigenvalues\nsparse::Bool: if false call eigvals(A::QuantumObject; kwargs...), otherwise call eigsolve. Default to false.\nkwargs: Additional keyword arguments passed to the solver\n\nReturns\n\n::Vector{<:Number}: a list of eigenvalues\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eigenstates","page":"API","title":"QuantumToolbox.eigenstates","text":"eigenstates(A::QuantumObject; sparse::Bool=false, kwargs...)\n\nCalculate the eigenvalues and corresponding eigenvectors\n\nArguments\n\nA::QuantumObject: the QuantumObject to solve eigenvalues and eigenvectors\nsparse::Bool: if false call eigen(A::QuantumObject; kwargs...), otherwise call eigsolve. Default to false.\nkwargs: Additional keyword arguments passed to the solver\n\nReturns\n\n::EigsolveResult: containing the eigenvalues, the eigenvectors, and some information from the solver. see also EigsolveResult\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.eigen","page":"API","title":"LinearAlgebra.eigen","text":"LinearAlgebra.eigen(A::QuantumObject; kwargs...)\n\nCalculates the eigenvalues and eigenvectors of the QuantumObject A using the Julia LinearAlgebra package.\n\njulia> a = destroy(5);\n\njulia> H = a + a'\nQuantum Object: type=Operator dims=[5] size=(5, 5) ishermitian=true\n5×5 SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ 1.0+0.0im ⋅ ⋅ ⋅\n 1.0+0.0im ⋅ 1.41421+0.0im ⋅ ⋅\n ⋅ 1.41421+0.0im ⋅ 1.73205+0.0im ⋅\n ⋅ ⋅ 1.73205+0.0im ⋅ 2.0+0.0im\n ⋅ ⋅ ⋅ 2.0+0.0im ⋅\n\njulia> E, ψ, U = eigen(H)\nEigsolveResult: type=Operator dims=[5]\nvalues:\n5-element Vector{Float64}:\n -2.8569700138728\n -1.3556261799742608\n 1.3322676295501878e-15\n 1.3556261799742677\n 2.8569700138728056\nvectors:\n5×5 Matrix{ComplexF64}:\n 0.106101+0.0im -0.471249-0.0im … 0.471249-0.0im 0.106101-0.0im\n -0.303127-0.0im 0.638838+0.0im 0.638838+0.0im 0.303127-0.0im\n 0.537348+0.0im -0.279149-0.0im 0.279149-0.0im 0.537348-0.0im\n -0.638838-0.0im -0.303127-0.0im -0.303127-0.0im 0.638838+0.0im\n 0.447214+0.0im 0.447214+0.0im -0.447214-0.0im 0.447214-0.0im\n\njulia> expect(H, ψ[1]) ≈ E[1]\ntrue\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.eigvals","page":"API","title":"LinearAlgebra.eigvals","text":"LinearAlgebra.eigvals(A::QuantumObject; kwargs...)\n\nSame as eigen(A::QuantumObject; kwargs...) but for only the eigenvalues.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eigsolve","page":"API","title":"QuantumToolbox.eigsolve","text":"eigsolve(A::QuantumObject; \n v0::Union{Nothing,AbstractVector}=nothing, \n sigma::Union{Nothing, Real}=nothing,\n k::Int = 1,\n krylovdim::Int = max(20, 2*k+1),\n tol::Real = 1e-8,\n maxiter::Int = 200,\n solver::Union{Nothing, SciMLLinearSolveAlgorithm} = nothing,\n kwargs...)\n\nSolve for the eigenvalues and eigenvectors of a matrix A using the Arnoldi method.\n\nNotes\n\nFor more details about solver and extra kwargs, please refer to LinearSolve.jl\n\nReturns\n\nEigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eigsolve_al","page":"API","title":"QuantumToolbox.eigsolve_al","text":"eigsolve_al(H::QuantumObject,\n T::Real, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n H_t::Union{Nothing,Function}=nothing,\n params::NamedTuple=NamedTuple(),\n ρ0::Union{Nothing, AbstractMatrix} = nothing,\n k::Int=1,\n krylovdim::Int=min(10, size(H, 1)),\n maxiter::Int=200,\n eigstol::Real=1e-6,\n kwargs...)\n\nSolve the eigenvalue problem for a Liouvillian superoperator L using the Arnoldi-Lindblad method.\n\nArguments\n\nH: The Hamiltonian (or directly the Liouvillian) of the system.\nT: The time at which to evaluate the time evolution\nc_ops: A vector of collapse operators. Default is nothing meaning the system is closed.\nalg: The differential equation solver algorithm\nH_t: A function H_t(t) that returns the additional term at time t\nparams: A dictionary of additional parameters\nρ0: The initial density matrix. If not specified, a random density matrix is used\nk: The number of eigenvalues to compute\nkrylovdim: The dimension of the Krylov subspace\nmaxiter: The maximum number of iterations for the eigsolver\neigstol: The tolerance for the eigsolver\nkwargs: Additional keyword arguments passed to the differential equation solver\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nEigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver\n\nReferences\n\n[1] Minganti, F., & Huybrechts, D. (2022). Arnoldi-Lindblad time evolution: Faster-than-the-clock algorithm for the spectrum of time-independent and Floquet open quantum systems. Quantum, 6, 649.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Qobj-manipulation","page":"API","title":"Qobj manipulation","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"ket2dm\nexpect\nvariance\nLinearAlgebra.kron\nsparse_to_dense\ndense_to_sparse\nvec2mat\nmat2vec","category":"page"},{"location":"api/#QuantumToolbox.ket2dm","page":"API","title":"QuantumToolbox.ket2dm","text":"ket2dm(ψ::QuantumObject)\n\nTransform the ket state ketpsi into a pure density matrix hatrho = dyadpsi.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.expect","page":"API","title":"QuantumToolbox.expect","text":"expect(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})\n\nExpectation value of the Operator O with the state ψ. The state can be a Ket, Bra or Operator.\n\nIf ψ is a Ket or Bra, the function calculates langlepsihatOpsirangle.\n\nIf ψ is a density matrix (Operator), the function calculates textrmTr left hatO hatpsi right\n\nThe function returns a real number if O is of Hermitian type or Symmetric type, and returns a complex number otherwise. You can make an operator O hermitian by using Hermitian(O).\n\nNote that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.\n\nExamples\n\njulia> ψ = 1 / √2 * (fock(10,2) + fock(10,4));\n\njulia> a = destroy(10);\n\njulia> expect(a' * a, ψ) |> round\n3.0 + 0.0im\n\njulia> expect(Hermitian(a' * a), ψ) |> round\n3.0\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.variance","page":"API","title":"QuantumToolbox.variance","text":"variance(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})\n\nVariance of the Operator O: langlehatO^2rangle - langlehatOrangle^2,\n\nwhere langlehatOrangle is the expectation value of O with the state ψ (see also expect), and the state ψ can be a Ket, Bra or Operator.\n\nThe function returns a real number if O is hermitian, and returns a complex number otherwise.\n\nNote that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.kron","page":"API","title":"Base.kron","text":"kron(A::QuantumObject, B::QuantumObject, ...)\n\nReturns the Kronecker product hatA otimes hatB otimes cdots.\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢\n\njulia> kron(a, a)\nQuantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian=false\n400×400 SparseMatrixCSC{ComplexF64, Int64} with 361 stored entries:\n⠀⠀⠘⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sparse_to_dense","page":"API","title":"QuantumToolbox.sparse_to_dense","text":"sparse_to_dense(A::QuantumObject)\n\nConverts a sparse QuantumObject to a dense QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dense_to_sparse","page":"API","title":"QuantumToolbox.dense_to_sparse","text":"dense_to_sparse(A::QuantumObject)\n\nConverts a dense QuantumObject to a sparse QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.vec2mat","page":"API","title":"QuantumToolbox.vec2mat","text":"vec2mat(A::AbstractVector)\n\nConverts a vector to a matrix.\n\n\n\n\n\nvec2mat(A::QuantumObject)\n\nConvert a quantum object from vector (OperatorKetQuantumObject-type) to matrix (OperatorQuantumObject-type)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mat2vec","page":"API","title":"QuantumToolbox.mat2vec","text":"mat2vec(A::QuantumObject)\n\nConvert a quantum object from matrix (OperatorQuantumObject-type) to vector (OperatorKetQuantumObject-type)\n\n\n\n\n\nmat2vec(A::AbstractMatrix)\n\nConverts a matrix to a vector.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Generate-states-and-operators","page":"API","title":"Generate states and operators","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"zero_ket\nfock\nbasis\ncoherent\nrand_ket\nfock_dm\ncoherent_dm\nthermal_dm\nmaximally_mixed_dm\nrand_dm\nspin_state\nspin_coherent\nbell_state\nsinglet_state\ntriplet_states\nw_state\nghz_state\nrand_unitary\nsigmap\nsigmam\nsigmax\nsigmay\nsigmaz\njmat\nspin_Jx\nspin_Jy\nspin_Jz\nspin_Jm\nspin_Jp\nspin_J_set\ndestroy\ncreate\ndisplace\nsqueeze\nnum\nQuantumToolbox.position\nQuantumToolbox.momentum\nphase\nfdestroy\nfcreate\ntunneling\nqft\neye\nprojection\ncommutator\nspre\nspost\nsprepost\nlindblad_dissipator","category":"page"},{"location":"api/#QuantumToolbox.zero_ket","page":"API","title":"QuantumToolbox.zero_ket","text":"zero_ket(dimensions)\n\nReturns a zero Ket vector with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int}, Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nwarning: Beware of type-stability!\nIt is highly recommended to use zero_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fock","page":"API","title":"QuantumToolbox.fock","text":"fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))\n\nGenerates a fock state ketpsi of dimension N. \n\nIt is also possible to specify the list of dimensions dims if different subsystems are present.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fock(N, j, dims=dims, sparse=Val(sparse)) instead of fock(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.basis","page":"API","title":"QuantumToolbox.basis","text":"basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)\n\nGenerates a fock state like fock.\n\nIt is also possible to specify the list of dimensions dims if different subsystems are present.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use basis(N, j, dims=dims) with dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.coherent","page":"API","title":"QuantumToolbox.coherent","text":"coherent(N::Int, α::Number)\n\nGenerates a coherent state alpharangle, which is defined as an eigenvector of the bosonic annihilation operator hata alpharangle = alpha alpharangle.\n\nThis state is constructed via the displacement operator displace and zero-fock state fock: alpharangle = hatD(alpha) 0rangle\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.rand_ket","page":"API","title":"QuantumToolbox.rand_ket","text":"rand_ket(dimensions)\n\nGenerate a random normalized Ket vector with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use rand_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fock_dm","page":"API","title":"QuantumToolbox.fock_dm","text":"fock_dm(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))\n\nDensity matrix representation of a Fock state.\n\nConstructed via outer product of fock.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fock_dm(N, j, dims=dims, sparse=Val(sparse)) instead of fock_dm(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.coherent_dm","page":"API","title":"QuantumToolbox.coherent_dm","text":"coherent_dm(N::Int, α::Number)\n\nDensity matrix representation of a coherent state.\n\nConstructed via outer product of coherent.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.thermal_dm","page":"API","title":"QuantumToolbox.thermal_dm","text":"thermal_dm(N::Int, n::Real; sparse::Union{Bool,Val}=Val(false))\n\nDensity matrix for a thermal state (generating thermal state probabilities) with the following arguments:\n\nN::Int: Number of basis states in the Hilbert space\nn::Real: Expectation value for number of particles in the thermal state.\nsparse::Union{Bool,Val}: If true, return a sparse matrix representation.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use thermal_dm(N, n, sparse=Val(sparse)) instead of thermal_dm(N, n, sparse=sparse). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.maximally_mixed_dm","page":"API","title":"QuantumToolbox.maximally_mixed_dm","text":"maximally_mixed_dm(dimensions)\n\nReturns the maximally mixed density matrix with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use maximally_mixed_dm(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.rand_dm","page":"API","title":"QuantumToolbox.rand_dm","text":"rand_dm(dimensions; rank::Int=prod(dimensions))\n\nGenerate a random density matrix from Ginibre ensemble with given argument dimensions and rank, ensuring that it is positive semi-definite and trace equals to 1.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nThe default keyword argument rank = prod(dimensions) (full rank).\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use rand_dm(dimensions; rank=rank) with dimensions as Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\nReferences\n\nJ. Ginibre, Statistical ensembles of complex, quaternion, and real matrices, Journal of Mathematical Physics 6.3 (1965): 440-449\nK. Życzkowski, et al., Generating random density matrices, Journal of Mathematical Physics 52, 062201 (2011)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_state","page":"API","title":"QuantumToolbox.spin_state","text":"spin_state(j::Real, m::Real)\n\nGenerate the spin state: j mrangle\n\nThe eigenstate of the Spin-j hatS_z operator with eigenvalue m, where where j is the spin quantum number and can be a non-negative integer or half-integer\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_coherent","page":"API","title":"QuantumToolbox.spin_coherent","text":"spin_coherent(j::Real, θ::Real, ϕ::Real)\n\nGenerate the coherent spin state (rotation of the j jrangle state), namely\n\ntheta phi rangle = hatR(theta phi) j jrangle\n\nwhere the rotation operator is defined as\n\nhatR(theta phi) = exp left( fractheta2 (hatS_- e^iphi - hatS_+ e^-iphi) right)\n\nand hatS_pm are plus and minus Spin-j operators, respectively.\n\nArguments\n\nj::Real: The spin quantum number and can be a non-negative integer or half-integer\nθ::Real: rotation angle from z-axis\nϕ::Real: rotation angle from x-axis\n\nSee also jmat and spin_state.\n\nReference\n\nRobert Jones, Spin Coherent States and Statistical Physics\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.bell_state","page":"API","title":"QuantumToolbox.bell_state","text":"bell_state(x::Union{Int}, z::Union{Int})\n\nReturn the Bell state depending on the arguments (x, z):\n\n(0, 0): Phi^+ rangle = ( 00rangle + 11rangle ) sqrt2\n(0, 1): Phi^- rangle = ( 00rangle - 11rangle ) sqrt2\n(1, 0): Psi^+ rangle = ( 01rangle + 10rangle ) sqrt2\n(1, 1): Psi^- rangle = ( 01rangle - 10rangle ) sqrt2\n\nHere, x = 1 (z = 1) means applying Pauli-X ( Pauli-Z) unitary transformation on Phi^+ rangle.\n\nExample\n\njulia> bell_state(0, 0)\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n\njulia> bell_state(Val(1), Val(0))\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use bell_state(Val(x), Val(z)) instead of bell_state(x, z). See this link and the related Section for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.singlet_state","page":"API","title":"QuantumToolbox.singlet_state","text":"singlet_state()\n\nReturn the two particle singlet state: frac1sqrt2 ( 01rangle - 10rangle )\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.triplet_states","page":"API","title":"QuantumToolbox.triplet_states","text":"triplet_states()\n\nReturn a list of the two particle triplet states: \n\n11rangle\n( 01rangle + 10rangle ) sqrt2\n00rangle\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.w_state","page":"API","title":"QuantumToolbox.w_state","text":"w_state(n::Union{Int,Val})\n\nReturns the n-qubit W-state:\n\nfrac1sqrtn left( 1000rangle + 0100rangle + cdots + 0001rangle right)\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use w_state(Val(n)) instead of w_state(n). See this link and the related Section for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ghz_state","page":"API","title":"QuantumToolbox.ghz_state","text":"ghz_state(n::Union{Int,Val}; d::Int=2)\n\nReturns the generalized n-qudit Greenberger–Horne–Zeilinger (GHZ) state:\n\nfrac1sqrtd sum_i=0^d-1 i rangle otimes cdots otimes i rangle\n\nHere, d specifies the dimension of each qudit. Default to d=2 (qubit).\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use ghz_state(Val(n)) instead of ghz_state(n). See this link and the related Section for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.rand_unitary","page":"API","title":"QuantumToolbox.rand_unitary","text":"rand_unitary(dimensions, distribution=Val(:haar))\n\nReturns a random unitary QuantumObject.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nThe distribution specifies which of the method used to obtain the unitary matrix:\n\n:haar: Haar random unitary matrix using the algorithm from reference 1\n:exp: Uses exp(-ihatH), where hatH is a randomly generated Hermitian operator.\n\nReferences\n\nF. Mezzadri, How to generate random matrices from the classical compact groups, arXiv:math-ph/0609050 (2007)\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use rand_unitary(dimensions, Val(distribution)) instead of rand_unitary(dimensions, distribution). Also, put dimensions as Tuple or SVector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmap","page":"API","title":"QuantumToolbox.sigmap","text":"sigmap()\n\nPauli ladder operator hatsigma_+ = (hatsigma_x + i hatsigma_y) 2.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmam","page":"API","title":"QuantumToolbox.sigmam","text":"sigmam()\n\nPauli ladder operator hatsigma_- = (hatsigma_x - i hatsigma_y) 2.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmax","page":"API","title":"QuantumToolbox.sigmax","text":"sigmax()\n\nPauli operator hatsigma_x = hatsigma_- + hatsigma_+.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmay","page":"API","title":"QuantumToolbox.sigmay","text":"sigmay()\n\nPauli operator hatsigma_y = i left( hatsigma_- - hatsigma_+ right).\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmaz","page":"API","title":"QuantumToolbox.sigmaz","text":"sigmaz()\n\nPauli operator hatsigma_z = commhatsigma_+hatsigma_-.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.jmat","page":"API","title":"QuantumToolbox.jmat","text":"jmat(j::Real, which::Union{Symbol,Val})\n\nGenerate higher-order Spin-j operators, where j is the spin quantum number and can be a non-negative integer or half-integer\n\nThe parameter which specifies which of the following operator to return.\n\n:x: hatS_x\n:y: hatS_y\n:z: hatS_z\n:+: hatS_+\n:-: hatS_-\n\nNote that if the parameter which is not specified, returns a set of Spin-j operators: (hatS_x hatS_y hatS_z)\n\nExamples\n\njulia> jmat(0.5, :x)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 0.5+0.0im\n 0.5+0.0im ⋅\n\njulia> jmat(0.5, :-)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 1 stored entry:\n ⋅ ⋅ \n 1.0+0.0im ⋅\n\njulia> jmat(1.5, Val(:z))\nQuantum Object: type=Operator dims=[4] size=(4, 4) ishermitian=true\n4×4 SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 1.5+0.0im ⋅ ⋅ ⋅ \n ⋅ 0.5+0.0im ⋅ ⋅ \n ⋅ ⋅ -0.5+0.0im ⋅ \n ⋅ ⋅ ⋅ -1.5+0.0im\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use jmat(j, Val(which)) instead of jmat(j, which). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jx","page":"API","title":"QuantumToolbox.spin_Jx","text":"spin_Jx(j::Real)\n\nhatS_x operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jy","page":"API","title":"QuantumToolbox.spin_Jy","text":"spin_Jy(j::Real)\n\nhatS_y operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jz","page":"API","title":"QuantumToolbox.spin_Jz","text":"spin_Jz(j::Real)\n\nhatS_z operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jm","page":"API","title":"QuantumToolbox.spin_Jm","text":"spin_Jm(j::Real)\n\nhatS_- operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jp","page":"API","title":"QuantumToolbox.spin_Jp","text":"spin_Jp(j::Real)\n\nhatS_+ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_J_set","page":"API","title":"QuantumToolbox.spin_J_set","text":"spin_J_set(j::Real)\n\nA set of Spin-j operators (hatS_x hatS_y hatS_z), where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nNote that this functions is same as jmat(j). See also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.destroy","page":"API","title":"QuantumToolbox.destroy","text":"destroy(N::Int)\n\nBosonic annihilation operator with Hilbert space cutoff N. \n\nThis operator acts on a fock state as hata ketn = sqrtn ketn-1.\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⎡⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⎤\n⎢⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⎥\n⎣⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⎦\n\njulia> fock(20, 3)' * a * fock(20, 4)\n2.0 + 0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.create","page":"API","title":"QuantumToolbox.create","text":"create(N::Int)\n\nBosonic creation operator with Hilbert space cutoff N.\n\nThis operator acts on a fock state as hata^dagger ketn = sqrtn+1 ketn+1.\n\nExamples\n\njulia> a_d = create(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⎡⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⎤\n⎢⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⎥\n⎣⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⎦\n\njulia> fock(20, 4)' * a_d * fock(20, 3)\n2.0 + 0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.displace","page":"API","title":"QuantumToolbox.displace","text":"displace(N::Int, α::Number)\n\nGenerate a displacement operator:\n\nhatD(alpha)=expleft( alpha hata^dagger - alpha^* hata right)\n\nwhere hata is the bosonic annihilation operator, and alpha is the amount of displacement in optical phase space.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.squeeze","page":"API","title":"QuantumToolbox.squeeze","text":"squeeze(N::Int, z::Number)\n\nGenerate a single-mode squeeze operator:\n\nhatS(z)=expleft( frac12 (z^* hata^2 - z(hata^dagger)^2) right)\n\nwhere hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.num","page":"API","title":"QuantumToolbox.num","text":"num(N::Int)\n\nBosonic number operator with Hilbert space cutoff N. \n\nThis operator is defined as hatN=hata^dagger hata, where hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.position","page":"API","title":"QuantumToolbox.position","text":"position(N::Int)\n\nPosition operator with Hilbert space cutoff N. \n\nThis operator is defined as hatx=frac1sqrt2 (hata^dagger + hata), where hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.momentum","page":"API","title":"QuantumToolbox.momentum","text":"momentum(N::Int)\n\nMomentum operator with Hilbert space cutoff N. \n\nThis operator is defined as hatp= fracisqrt2 (hata^dagger - hata), where hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.phase","page":"API","title":"QuantumToolbox.phase","text":"phase(N::Int, ϕ0::Real=0)\n\nSingle-mode Pegg-Barnett phase operator with Hilbert space cutoff N and the reference phase phi_0.\n\nThis operator is defined as\n\nhatphi = sum_m=0^N-1 phi_m phi_mrangle langlephi_m\n\nwhere\n\nphi_m = phi_0 + frac2mpiN\n\nand\n\nphi_mrangle = frac1sqrtN sum_n=0^N-1 exp(i n phi_m) nrangle\n\nReference\n\nMichael Martin Nieto, QUANTUM PHASE AND QUANTUM PHASE OPERATORS: Some Physics and Some History, arXiv:hep-th/9304036, Equation (30-32).\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fdestroy","page":"API","title":"QuantumToolbox.fdestroy","text":"fdestroy(N::Union{Int,Val}, j::Int)\n\nConstruct a fermionic destruction operator acting on the j-th site, where the fock space has totally N-sites:\n\nHere, we use the Jordan-Wigner transformation, namely\n\nhatd_j = hatsigma_z^otimes j-1 otimes hatsigma_+ otimes hatmathbb1^otimes N-j\n\nThe site index j should satisfy: 1 ≤ j ≤ N.\n\nNote that we put hatsigma_+ = beginpmatrix 0 1 0 0 endpmatrix here because we consider 0rangle = beginpmatrix 1 0 endpmatrix to be ground (vacant) state, and 1rangle = beginpmatrix 0 1 endpmatrix to be excited (occupied) state.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fdestroy(Val(N), j) instead of fdestroy(N, j). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fcreate","page":"API","title":"QuantumToolbox.fcreate","text":"fcreate(N::Union{Int,Val}, j::Int)\n\nConstruct a fermionic creation operator acting on the j-th site, where the fock space has totally N-sites:\n\nHere, we use the Jordan-Wigner transformation, namely\n\nhatd^dagger_j = hatsigma_z^otimes j-1 otimes hatsigma_- otimes hatmathbb1^otimes N-j\n\nThe site index j should satisfy: 1 ≤ j ≤ N.\n\nNote that we put hatsigma_- = beginpmatrix 0 0 1 0 endpmatrix here because we consider 0rangle = beginpmatrix 1 0 endpmatrix to be ground (vacant) state, and 1rangle = beginpmatrix 0 1 endpmatrix to be excited (occupied) state.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fcreate(Val(N), j) instead of fcreate(N, j). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tunneling","page":"API","title":"QuantumToolbox.tunneling","text":"tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))\n\nGenerate a tunneling operator defined as:\n\nsum_n=0^N-m n ranglelangle n+m + n+m ranglelangle n \n\nwhere N is the number of basis states in the Hilbert space, and m is the number of excitations in tunneling event.\n\nIf sparse=true, the operator is returned as a sparse matrix, otherwise a dense matrix is returned.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use tunneling(N, m, Val(sparse)) instead of tunneling(N, m, sparse). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.qft","page":"API","title":"QuantumToolbox.qft","text":"qft(dimensions)\n\nGenerates a discrete Fourier transform matrix hatF_N for Quantum Fourier Transform (QFT) with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nN represents the total dimension, and therefore the matrix is defined as\n\nhatF_N = frac1sqrtNbeginbmatrix\n1 1 1 1 cdots 1\n1 omega omega^2 omega^3 cdots omega^N-1\n1 omega^2 omega^4 omega^6 cdots omega^2(N-1)\n1 omega^3 omega^6 omega^9 cdots omega^3(N-1)\nvdots vdots vdots vdots ddots vdots\n1 omega^N-1 omega^2(N-1) omega^3(N-1) cdots omega^(N-1)(N-1)\nendbmatrix\n\nwhere omega = exp(frac2 pi iN).\n\nwarning: Beware of type-stability!\nIt is highly recommended to use qft(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eye","page":"API","title":"QuantumToolbox.eye","text":"eye(N::Int; type=Operator, dims=nothing)\n\nIdentity operator hatmathbb1 with size N.\n\nIt is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.\n\nNote that type can only be either Operator or SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.projection","page":"API","title":"QuantumToolbox.projection","text":"projection(N::Int, i::Int, j::Int)\n\nGenerates the projection operator hatO = dyadij with Hilbert space dimension N.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.commutator","page":"API","title":"QuantumToolbox.commutator","text":"commutator(A::QuantumObject, B::QuantumObject; anti::Bool=false)\n\nReturn the commutator (or anti-commutator) of the two QuantumObject:\n\ncommutator (anti=false): hatAhatB-hatBhatA\nanticommutator (anti=true): hatAhatB+hatBhatA\n\nNote that A and B must be Operator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spre","page":"API","title":"QuantumToolbox.spre","text":"spre(A::QuantumObject, Id_cache=I(size(A,1)))\n\nReturns the SuperOperator form of A acting on the left of the density matrix operator: mathcalO left(hatAright) left hatrho right = hatA hatrho.\n\nSince the density matrix is vectorized in OperatorKet form: hatrhoranglerangle, this SuperOperator is always a matrix hatmathbb1 otimes hatA, namely \n\nmathcalO left(hatAright) left hatrho right = hatmathbb1 otimes hatA hatrhoranglerangle\n\n(see the section in documentation: Superoperators and Vectorized Operators for more details)\n\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spost","page":"API","title":"QuantumToolbox.spost","text":"spost(B::QuantumObject, Id_cache=I(size(B,1)))\n\nReturns the SuperOperator form of B acting on the right of the density matrix operator: mathcalO left(hatBright) left hatrho right = hatrho hatB.\n\nSince the density matrix is vectorized in OperatorKet form: hatrhoranglerangle, this SuperOperator is always a matrix hatB^T otimes hatmathbb1, namely\n\nmathcalO left(hatBright) left hatrho right = hatB^T otimes hatmathbb1 hatrhoranglerangle\n\n(see the section in documentation: Superoperators and Vectorized Operators for more details)\n\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sprepost","page":"API","title":"QuantumToolbox.sprepost","text":"sprepost(A::QuantumObject, B::QuantumObject)\n\nReturns the SuperOperator form of A and B acting on the left and right of the density matrix operator, respectively: mathcalO left( hatA hatB right) left hatrho right = hatA hatrho hatB.\n\nSince the density matrix is vectorized in OperatorKet form: hatrhoranglerangle, this SuperOperator is always a matrix hatB^T otimes hatA, namely\n\nmathcalO left(hatA hatBright) left hatrho right = hatB^T otimes hatA hatrhoranglerangle = textrmspre(hatA) * textrmspost(hatB) hatrhoranglerangle\n\n(see the section in documentation: Superoperators and Vectorized Operators for more details)\n\nSee also spre and spost.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.lindblad_dissipator","page":"API","title":"QuantumToolbox.lindblad_dissipator","text":"lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1))\n\nReturns the Lindblad SuperOperator defined as\n\nmathcalD left( hatO right) left hatrho right = frac12 left( 2 hatO hatrho hatO^dagger - \nhatO^dagger hatO hatrho - hatrho hatO^dagger hatO right)\n\nThe 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.\n\nSee also spre and spost.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Synonyms-of-functions-for-Qobj","page":"API","title":"Synonyms of functions for Qobj","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Qobj\nshape\nisherm\ntrans\ndag\nmatrix_element\nunit\nsqrtm\nlogm\nexpm\nsinm\ncosm\ntensor\n⊗\nqeye","category":"page"},{"location":"api/#QuantumToolbox.Qobj","page":"API","title":"QuantumToolbox.Qobj","text":"Qobj(A::AbstractArray; type::QuantumObjectType, dims::Vector{Int})\n\nGenerate QuantumObject\n\nNote that this functions is same as QuantumObject(A; type=type, dims=dims)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.shape","page":"API","title":"QuantumToolbox.shape","text":"shape(A::QuantumObject)\n\nReturns a tuple containing each dimensions of the array in the QuantumObject.\n\nNote that this function is same as size(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isherm","page":"API","title":"QuantumToolbox.isherm","text":"isherm(A::QuantumObject)\n\nTest whether the QuantumObject is Hermitian.\n\nNote that this functions is same as ishermitian(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.trans","page":"API","title":"QuantumToolbox.trans","text":"trans(A::QuantumObject)\n\nLazy matrix transpose of the QuantumObject.\n\nNote that this function is same as transpose(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dag","page":"API","title":"QuantumToolbox.dag","text":"dag(A::QuantumObject)\n\nLazy adjoint (conjugate transposition) of the QuantumObject\n\nNote that this function is same as adjoint(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.matrix_element","page":"API","title":"QuantumToolbox.matrix_element","text":"matrix_element(i::QuantumObject, A::QuantumObject j::QuantumObject)\n\nCompute the generalized dot product dot(i, A*j) between three QuantumObject: langle i hatA j rangle\n\nNote that this function is same as dot(i, A, j)\n\nSupports the following inputs:\n\nA is in the type of Operator, with i and j are both Ket.\nA is in the type of SuperOperator, with i and j are both OperatorKet\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.unit","page":"API","title":"QuantumToolbox.unit","text":"unit(A::QuantumObject, p::Real)\n\nReturn normalized QuantumObject so that its p-norm equals to unity, i.e. norm(A, p) == 1.\n\nSupport for the following types of QuantumObject:\n\nIf A is Ket or Bra, default p = 2\nIf A is Operator, default p = 1\n\nNote that this function is same as normalize(A, p)\n\nAlso, see norm about its definition for different types of QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sqrtm","page":"API","title":"QuantumToolbox.sqrtm","text":"sqrtm(A::QuantumObject)\n\nMatrix square root of Operator type of QuantumObject\n\nNote that for other types of QuantumObject use sprt(A) instead.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.logm","page":"API","title":"QuantumToolbox.logm","text":"logm(A::QuantumObject)\n\nMatrix logarithm of QuantumObject\n\nNote that this function is same as log(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.expm","page":"API","title":"QuantumToolbox.expm","text":"expm(A::QuantumObject)\n\nMatrix exponential of QuantumObject\n\nNote that this function is same as exp(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sinm","page":"API","title":"QuantumToolbox.sinm","text":"sinm(A::QuantumObject)\n\nMatrix sine of QuantumObject, defined as\n\nsin left( hatA right) = frace^i hatA - e^-i hatA2 i\n\nNote that this function is same as sin(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.cosm","page":"API","title":"QuantumToolbox.cosm","text":"cosm(A::QuantumObject)\n\nMatrix cosine of QuantumObject, defined as\n\ncos left( hatA right) = frace^i hatA + e^-i hatA2\n\nNote that this function is same as cos(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tensor","page":"API","title":"QuantumToolbox.tensor","text":"tensor(A::QuantumObject, B::QuantumObject, ...)\n\nReturns the Kronecker product hatA otimes hatB otimes cdots.\n\nNote that this function is same as kron(A, B, ...)\n\nExamples\n\njulia> x = sigmax()\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅\n\njulia> x_list = fill(x, 3);\n\njulia> tensor(x_list...)\nQuantum Object: type=Operator dims=[2, 2, 2] size=(8, 8) ishermitian=true\n8×8 SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ ⋅ … ⋅ ⋅ 1.0+0.0im\n ⋅ ⋅ ⋅ ⋅ 1.0+0.0im ⋅\n ⋅ ⋅ ⋅ 1.0+0.0im ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅\n ⋅ ⋅ 1.0+0.0im … ⋅ ⋅ ⋅\n ⋅ 1.0+0.0im ⋅ ⋅ ⋅ ⋅\n 1.0+0.0im ⋅ ⋅ ⋅ ⋅ ⋅\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.:⊗","page":"API","title":"QuantumToolbox.:⊗","text":"⊗(A::QuantumObject, B::QuantumObject)\n\nReturns the Kronecker product hatA otimes hatB.\n\nNote that this function is same as kron(A, B)\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢\n\njulia> a ⊗ a\nQuantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian=false\n400×400 SparseMatrixCSC{ComplexF64, Int64} with 361 stored entries:\n⠀⠀⠘⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.qeye","page":"API","title":"QuantumToolbox.qeye","text":"qeye(N::Int; type=Operator, dims=nothing)\n\nIdentity operator hatmathbb1 with size N.\n\nIt is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.\n\nNote that this function is same as eye(N, type=type, dims=dims), and type can only be either Operator or SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Time-evolution","page":"API","title":"Time evolution","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"TimeEvolutionSol\nTimeEvolutionMCSol\nTimeEvolutionSSESol\nsesolveProblem\nmesolveProblem\nmcsolveProblem\nmcsolveEnsembleProblem\nssesolveProblem\nssesolveEnsembleProblem\nlr_mesolveProblem\nsesolve\nmesolve\nmcsolve\nssesolve\ndfd_mesolve\ndsf_mesolve\ndsf_mcsolve\nlr_mesolve\nliouvillian\nliouvillian_generalized\nsteadystate\nsteadystate_floquet\nSteadyStateDirectSolver\nSteadyStateEigenSolver\nSteadyStateLinearSolver\nSteadyStateODESolver","category":"page"},{"location":"api/#QuantumToolbox.TimeEvolutionSol","page":"API","title":"QuantumToolbox.TimeEvolutionSol","text":"struct TimeEvolutionSol\n\nA structure storing the results and some information from solving time evolution.\n\nFields (Attributes)\n\ntimes::AbstractVector: The time list of the evolution.\nstates::Vector{QuantumObject}: The list of result states.\nexpect::Matrix: The expectation values corresponding to each time point in times.\nretcode: The return code from the solver.\nalg: The algorithm which is used during the solving process.\nabstol::Real: The absolute tolerance which is used during the solving process.\nreltol::Real: The relative tolerance which is used during the solving process.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.TimeEvolutionMCSol","page":"API","title":"QuantumToolbox.TimeEvolutionMCSol","text":"struct TimeEvolutionMCSol\n\nA structure storing the results and some information from solving quantum trajectories of the Monte Carlo wave function time evolution.\n\nFields (Attributes)\n\nntraj::Int: Number of trajectories\ntimes::AbstractVector: The time list of the evolution.\nstates::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.\nexpect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.\nexpect_all::Array: The expectation values corresponding to each trajectory and each time point in times\njump_times::Vector{Vector{Real}}: The time records of every quantum jump occurred in each trajectory.\njump_which::Vector{Vector{Int}}: The indices of the jump operators in c_ops that describe the corresponding quantum jumps occurred in each trajectory.\nconverged::Bool: Whether the solution is converged or not.\nalg: The algorithm which is used during the solving process.\nabstol::Real: The absolute tolerance which is used during the solving process.\nreltol::Real: The relative tolerance which is used during the solving process.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.TimeEvolutionSSESol","page":"API","title":"QuantumToolbox.TimeEvolutionSSESol","text":"struct TimeEvolutionSSESol\n\nA structure storing the results and some information from solving trajectories of the Stochastic Shrodinger equation time evolution.\n\nFields (Attributes)\n\nntraj::Int: Number of trajectories\ntimes::AbstractVector: The time list of the evolution.\nstates::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.\nexpect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.\nexpect_all::Array: The expectation values corresponding to each trajectory and each time point in times\nconverged::Bool: Whether the solution is converged or not.\nalg: The algorithm which is used during the solving process.\nabstol::Real: The absolute tolerance which is used during the solving process.\nreltol::Real: The relative tolerance which is used during the solving process.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.sesolveProblem","page":"API","title":"QuantumToolbox.sesolveProblem","text":"sesolveProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n alg::OrdinaryDiffEqAlgorithm=Tsit5()\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the ODEProblem for the Schrödinger time evolution of a quantum system:\n\nfracpartialpartial t psi(t)rangle = -i hatH psi(t)rangle\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: The time list of the evolution.\nalg::OrdinaryDiffEqAlgorithm: The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: The list of operators to be evaluated during the evolution.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: The time-dependent Hamiltonian of the system. If nothing, the Hamiltonian is time-independent.\nparams::NamedTuple: The parameters of the system.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: The keyword arguments passed to the ODEProblem constructor.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob: The ODEProblem for the Schrödinger time evolution of the system.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mesolveProblem","page":"API","title":"QuantumToolbox.mesolveProblem","text":"mesolveProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector, \n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the ODEProblem for the master equation time evolution of an open quantum system:\n\nfracpartial hatrho(t)partial t = -ihatH hatrho(t) + sum_n mathcalD(hatC_n) hatrho(t)\n\nwhere \n\nmathcalD(hatC_n) hatrho(t) = hatC_n hatrho(t) hatC_n^dagger - frac12 hatC_n^dagger hatC_n hatrho(t) - frac12 hatrho(t) hatC_n^dagger hatC_n\n\nArguments\n\nH::QuantumObject: The Hamiltonian hatH or the Liouvillian of the system.\nψ0::QuantumObject: The initial state of the system.\ntlist::AbstractVector: The time list of the evolution.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm=Tsit5(): The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the operators for which the expectation values are calculated.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing: The time-dependent Hamiltonian or Liouvillian.\nparams::NamedTuple=NamedTuple(): The parameters of the time evolution.\nprogress_bar::Union{Val,Bool}=Val(true): Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: The keyword arguments for the ODEProblem.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::ODEProblem: The ODEProblem for the master equation time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mcsolveProblem","page":"API","title":"QuantumToolbox.mcsolveProblem","text":"mcsolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n jump_callback::TJC=ContinuousLindbladJumpCallback(),\n kwargs...)\n\nGenerates the ODEProblem for a single trajectory of the Monte Carlo wave function time evolution of an open quantum system.\n\nGiven a system Hamiltonian hatH and a list of collapse (jump) operators hatC_n_n, the evolution of the state psi(t)rangle is governed by the Schrodinger equation:\n\nfracpartialpartial t psi(t)rangle= -i hatH_textrmeff psi(t)rangle\n\nwith a non-Hermitian effective Hamiltonian:\n\nhatH_textrmeff = hatH - fraci2 sum_n hatC_n^dagger hatC_n\n\nTo the first-order of the wave function in a small time delta t, the strictly negative non-Hermitian portion in hatH_textrmeff gives rise to a reduction in the norm of the wave function, namely\n\nlangle psi(t+delta t) psi(t+delta t) rangle = 1 - delta p\n\nwhere \n\ndelta p = delta t sum_n langle psi(t) hatC_n^dagger hatC_n psi(t) rangle\n\nis the corresponding quantum jump probability.\n\nIf the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting psi(t)rangle using the collapse operator hatC_n corresponding to the measurement, namely\n\n psi(t+delta t) rangle = frachatC_n psi(t)rangle sqrtlangle psi(t) hatC_n^dagger hatC_n psi(t) rangle \n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nseeds::Union{Nothing, Vector{Int}}: List of seeds for the random number generator. Length must be equal to the number of trajectories provided.\njump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::ODEProblem: The ODEProblem for the Monte Carlo wave function time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mcsolveEnsembleProblem","page":"API","title":"QuantumToolbox.mcsolveEnsembleProblem","text":"mcsolveEnsembleProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n jump_callback::TJC=ContinuousLindbladJumpCallback(),\n prob_func::Function=_mcsolve_prob_func,\n output_func::Function=_mcsolve_output_func,\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the EnsembleProblem of ODEProblems for the ensemble of trajectories of the Monte Carlo wave function time evolution of an open quantum system.\n\nGiven a system Hamiltonian hatH and a list of collapse (jump) operators hatC_n_n, the evolution of the state psi(t)rangle is governed by the Schrodinger equation:\n\nfracpartialpartial t psi(t)rangle= -i hatH_textrmeff psi(t)rangle\n\nwith a non-Hermitian effective Hamiltonian:\n\nhatH_textrmeff = hatH - fraci2 sum_n hatC_n^dagger hatC_n\n\nTo the first-order of the wave function in a small time delta t, the strictly negative non-Hermitian portion in hatH_textrmeff gives rise to a reduction in the norm of the wave function, namely\n\nlangle psi(t+delta t) psi(t+delta t) rangle = 1 - delta p\n\nwhere \n\ndelta p = delta t sum_n langle psi(t) hatC_n^dagger hatC_n psi(t) rangle\n\nis the corresponding quantum jump probability.\n\nIf the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting psi(t)rangle using the collapse operator hatC_n corresponding to the measurement, namely\n\n psi(t+delta t) rangle = frachatC_n psi(t)rangle sqrtlangle psi(t) hatC_n^dagger hatC_n psi(t) rangle \n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nseeds::Union{Nothing, Vector{Int}}: List of seeds for the random number generator. Length must be equal to the number of trajectories provided.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\njump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.\nprob_func::Function: Function to use for generating the ODEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::EnsembleProblem with ODEProblem: The Ensemble ODEProblem for the Monte Carlo wave function time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ssesolveProblem","page":"API","title":"QuantumToolbox.ssesolveProblem","text":"ssesolveProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::StochasticDiffEqAlgorithm=SRA1()\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n kwargs...)\n\nGenerates the SDEProblem for the Stochastic Schrödinger time evolution of a quantum system. This is defined by the following stochastic differential equation:\n\n dpsi(t)rangle = -i K psi(t)rangle dt + sum_n M_n psi(t)rangle dW_n(t)\n \n\nwhere \n \n\nmath K = \\hat{H} + i \\sumn \\left(\\frac{ej} Cn - \\frac{1}{2} \\sum{j} Cn^\\dagger Cn - \\frac{ej^2}{8}\\right), math Mn = Cn - \\frac{en}{2}, andmath en = \\langle Cn + C_n^\\dagger \\rangle. ```\n\nAbove, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: The time list of the evolution.\nsc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators hatC_n_n.\nalg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of operators to be evaluated during the evolution.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: The time-dependent Hamiltonian of the system. If nothing, the Hamiltonian is time-independent.\nparams::NamedTuple: The parameters of the system.\nkwargs...: The keyword arguments passed to the SDEProblem constructor.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.\nFor more details about alg please refer to DifferentialEquations.jl (SDE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob: The SDEProblem for the Stochastic Schrödinger time evolution of the system.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ssesolveEnsembleProblem","page":"API","title":"QuantumToolbox.ssesolveEnsembleProblem","text":"ssesolveEnsembleProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n alg::StochasticDiffEqAlgorithm=SRA1()\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n prob_func::Function=_mcsolve_prob_func,\n output_func::Function=_ssesolve_dispatch_output_func(ensemble_method),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the SDE EnsembleProblem for the Stochastic Schrödinger time evolution of a quantum system. This is defined by the following stochastic differential equation:\n\n dpsi(t)rangle = -i K psi(t)rangle dt + sum_n M_n psi(t)rangle dW_n(t)\n \n\nwhere \n \n\nmath K = \\hat{H} + i \\sumn \\left(\\frac{ej} Cn - \\frac{1}{2} \\sum{j} Cn^\\dagger Cn - \\frac{ej^2}{8}\\right), math Mn = Cn - \\frac{en}{2}, andmath en = \\langle Cn + C_n^\\dagger \\rangle. ```\n\nAbove, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: The time list of the evolution.\nsc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators hatC_n_n.\nalg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of operators to be evaluated during the evolution.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: The time-dependent Hamiltonian of the system. If nothing, the Hamiltonian is time-independent.\nparams::NamedTuple: The parameters of the system.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\nprob_func::Function: Function to use for generating the SDEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nprogress_bar::Union{Val,Bool}: Whether to show a progress bar.\nkwargs...: The keyword arguments passed to the SDEProblem constructor.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.\nFor more details about alg please refer to DifferentialEquations.jl (SDE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::EnsembleProblem with SDEProblem: The Ensemble SDEProblem for the Stochastic Shrödinger time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.lr_mesolveProblem","page":"API","title":"QuantumToolbox.lr_mesolveProblem","text":"lr_mesolveProblem(H, z, B, tlist, c_ops; e_ops=(), f_ops=(), opt=LRMesolveOptions(), kwargs...) where T\nFormulates the ODEproblem for the low-rank time evolution of the system. The function is called by lr_mesolve.\n\nParameters\n----------\nH : QuantumObject\n The Hamiltonian of the system.\nz : AbstractMatrix{T}\n The initial z matrix.\nB : AbstractMatrix{T}\n The initial B matrix.\ntlist : AbstractVector{T}\n The time steps at which the expectation values and function values are calculated.\nc_ops : AbstractVector{QuantumObject}\n The jump operators of the system.\ne_ops : Tuple{QuantumObject}\n The operators whose expectation values are calculated.\nf_ops : Tuple{Function}\n The functions whose values are calculated.\nopt : LRMesolveOptions\n The options of the problem.\nkwargs : NamedTuple\n Additional keyword arguments for the ODEProblem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sesolve","page":"API","title":"QuantumToolbox.sesolve","text":"sesolve(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nTime evolution of a closed quantum system using the Schrödinger equation:\n\nfracpartialpartial t psi(t)rangle = -i hatH psi(t)rangle\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mesolve","page":"API","title":"QuantumToolbox.mesolve","text":"mesolve(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector, \n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nTime evolution of an open quantum system using Lindblad master equation:\n\nfracpartial hatrho(t)partial t = -ihatH hatrho(t) + sum_n mathcalD(hatC_n) hatrho(t)\n\nwhere \n\nmathcalD(hatC_n) hatrho(t) = hatC_n hatrho(t) hatC_n^dagger - frac12 hatC_n^dagger hatC_n hatrho(t) - frac12 hatrho(t) hatC_n^dagger hatC_n\n\nArguments\n\nH::QuantumObject: The Hamiltonian hatH or the Liouvillian of the system.\nψ0::QuantumObject: The initial state of the system.\ntlist::AbstractVector: The time list of the evolution.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Named Tuple of parameters to pass to the solver.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mcsolve","page":"API","title":"QuantumToolbox.mcsolve","text":"mcsolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n alg::OrdinaryDiffEqAlgorithm = Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing,\n params::NamedTuple = NamedTuple(),\n seeds::Union{Nothing,Vector{Int}} = nothing,\n ntraj::Int = 1,\n ensemble_method = EnsembleThreads(),\n jump_callback::TJC = ContinuousLindbladJumpCallback(),\n prob_func::Function = _mcsolve_prob_func,\n output_func::Function = _mcsolve_dispatch_output_func(ensemble_method),\n progress_bar::Union{Val,Bool} = Val(true),\n kwargs...,\n)\n\nTime evolution of an open quantum system using quantum trajectories.\n\nGiven a system Hamiltonian hatH and a list of collapse (jump) operators hatC_n_n, the evolution of the state psi(t)rangle is governed by the Schrodinger equation:\n\nfracpartialpartial t psi(t)rangle= -i hatH_textrmeff psi(t)rangle\n\nwith a non-Hermitian effective Hamiltonian:\n\nhatH_textrmeff = hatH - fraci2 sum_n hatC_n^dagger hatC_n\n\nTo the first-order of the wave function in a small time delta t, the strictly negative non-Hermitian portion in hatH_textrmeff gives rise to a reduction in the norm of the wave function, namely\n\nlangle psi(t+delta t) psi(t+delta t) rangle = 1 - delta p\n\nwhere \n\ndelta p = delta t sum_n langle psi(t) hatC_n^dagger hatC_n psi(t) rangle\n\nis the corresponding quantum jump probability.\n\nIf the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting psi(t)rangle using the collapse operator hatC_n corresponding to the measurement, namely\n\n psi(t+delta t) rangle = frachatC_n psi(t)rangle sqrtlangle psi(t) hatC_n^dagger hatC_n psi(t) rangle \n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nseeds::Union{Nothing, Vector{Int}}: List of seeds for the random number generator. Length must be equal to the number of trajectories provided.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\njump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.\nprob_func::Function: Function to use for generating the ODEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nkwargs...: Additional keyword arguments to pass to the solver.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\n\nNotes\n\nensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionMCSol: The solution of the time evolution. See also TimeEvolutionMCSol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ssesolve","page":"API","title":"QuantumToolbox.ssesolve","text":"ssesolve(H::QuantumObject,\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n sc_ops::Union{Nothing, AbstractVector}=nothing;\n alg::StochasticDiffEqAlgorithm=SRA1(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n prob_func::Function=_ssesolve_prob_func,\n output_func::Function=_ssesolve_dispatch_output_func(ensemble_method),\n progress_bar::Union{Val,Bool} = Val(true),\n kwargs...)\n\nStochastic Schrödinger equation evolution of a quantum system given the system Hamiltonian hatH and a list of stochadtic collapse (jump) operators hatC_n_n. The stochastic evolution of the state psi(t)rangle is defined by:\n\n dpsi(t)rangle = -i K psi(t)rangle dt + sum_n M_n psi(t)rangle dW_n(t)\n \n\nwhere \n \n\nmath K = \\hat{H} + i \\sumn \\left(\\frac{ej} Cn - \\frac{1}{2} \\sum{j} Cn^\\dagger Cn - \\frac{ej^2}{8}\\right), math Mn = Cn - \\frac{en}{2}, andmath en = \\langle Cn + C_n^\\dagger \\rangle. ```\n\nAbove, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.\n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nsc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators hatC_n_n.\nalg::StochasticDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nseeds::Union{Nothing, Vector{Int}}: List of seeds for the random number generator. Length must be equal to the number of trajectories provided.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\nprob_func::Function: Function to use for generating the SDEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nprogress_bar::Union{Val,Bool}: Whether to show a progress bar.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.\nFor more details about alg please refer to DifferentialEquations.jl (SDE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionSSESol: The solution of the time evolution. See also TimeEvolutionSSESol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dfd_mesolve","page":"API","title":"QuantumToolbox.dfd_mesolve","text":"dfd_mesolve(H::Function, ψ0::QuantumObject,\n t_l::AbstractVector, c_ops::Function, maxdims::AbstractVector,\n dfd_params::NamedTuple=NamedTuple();\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Function=(dim_list) -> Vector{Vector{T1}}([]),\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n tol_list::Vector{<:Number}=fill(1e-8, length(maxdims)),\n kwargs...)\n\nTime evolution of an open quantum system using master equation, dynamically changing the dimension of the Hilbert subspaces.\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dsf_mesolve","page":"API","title":"QuantumToolbox.dsf_mesolve","text":"dsf_mesolve(H::Function,\n ψ0::QuantumObject,\n t_l::AbstractVector, c_ops::Function,\n op_list::Vector{TOl},\n α0_l::Vector{<:Number}=zeros(length(op_list)),\n dsf_params::NamedTuple=NamedTuple();\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Function=(op_list,p) -> Vector{TOl}([]),\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n δα_list::Vector{<:Number}=fill(0.2, length(op_list)),\n krylov_dim::Int=max(6, min(10, cld(length(ket2dm(ψ0).data), 4))),\n kwargs...)\n\nTime evolution of an open quantum system using master equation and the Dynamical Shifted Fock algorithm.\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dsf_mcsolve","page":"API","title":"QuantumToolbox.dsf_mcsolve","text":"dsf_mcsolve(H::Function,\n ψ0::QuantumObject,\n t_l::AbstractVector, c_ops::Function,\n op_list::Vector{TOl},\n α0_l::Vector{<:Number}=zeros(length(op_list)),\n dsf_params::NamedTuple=NamedTuple();\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Function=(op_list,p) -> Vector{TOl}([]),\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n δα_list::Vector{<:Real}=fill(0.2, length(op_list)),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n jump_callback::LindbladJumpCallbackType=ContinuousLindbladJumpCallback(),\n krylov_dim::Int=max(6, min(10, cld(length(ket2dm(ψ0).data), 4))),\n progress_bar::Union{Bool,Val} = Val(true)\n kwargs...)\n\nTime evolution of a quantum system using the Monte Carlo wave function method and the Dynamical Shifted Fock algorithm.\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.lr_mesolve","page":"API","title":"QuantumToolbox.lr_mesolve","text":"lr_mesolve(prob::ODEProblem; kwargs...)\nSolves the ODEProblem formulated by lr_mesolveProblem. The function is called by lr_mesolve.\n\nParameters\n----------\nprob : ODEProblem\n The ODEProblem formulated by lr_mesolveProblem.\nkwargs : NamedTuple\n Additional keyword arguments for the ODEProblem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.liouvillian","page":"API","title":"QuantumToolbox.liouvillian","text":"liouvillian(H::QuantumObject, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing, Id_cache=I(prod(H.dims)))\n\nConstruct the Liouvillian SuperOperator for a system Hamiltonian hatH and a set of collapse operators hatC_n_n:\n\nmathcalL cdot = -ihatH cdot + sum_n mathcalD(hatC_n) cdot\n\nwhere \n\nmathcalD(hatC_n) cdot = hatC_n cdot hatC_n^dagger - frac12 hatC_n^dagger hatC_n cdot - frac12 cdot hatC_n^dagger hatC_n\n\nThe 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.\n\nSee also spre, spost, and lindblad_dissipator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.liouvillian_generalized","page":"API","title":"QuantumToolbox.liouvillian_generalized","text":"liouvillian_generalized(H::QuantumObject, fields::Vector, \nT_list::Vector; N_trunc::Int=size(H,1), tol::Float64=0.0, σ_filter::Union{Nothing, Real}=nothing)\n\nConstructs the generalized Liouvillian for a system coupled to a bath of harmonic oscillators.\n\nSee, 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.steadystate","page":"API","title":"QuantumToolbox.steadystate","text":"steadystate(\n H::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n solver::SteadyStateSolver = SteadyStateDirectSolver(),\n kwargs...\n)\n\nSolve the stationary state based on different solvers.\n\nParameters\n\nH::QuantumObject: The Hamiltonian or the Liouvillian of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.\nsolver::SteadyStateSolver=SteadyStateDirectSolver(): see documentation Solving for Steady-State Solutions for different solvers.\nkwargs...: The keyword arguments for the solver.\n\n\n\n\n\nsteadystate(\n H::QuantumObject,\n ψ0::QuantumObject,\n tspan::Real = Inf,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n solver::SteadyStateODESolver = SteadyStateODESolver(),\n reltol::Real = 1.0e-8,\n abstol::Real = 1.0e-10,\n kwargs...\n)\n\nSolve the stationary state based on time evolution (ordinary differential equations; OrdinaryDiffEq.jl) with a given initial state.\n\nThe termination condition of the stationary state rhoranglerangle is that either the following condition is true:\n\nlVertfracpartial hatrhorangleranglepartial trVert leq textrmreltol timeslVertfracpartial hatrhorangleranglepartial t+hatrhorangleranglerVert\n\nor\n\nlVertfracpartial hatrhorangleranglepartial trVert leq textrmabstol\n\nParameters\n\nH::QuantumObject: The Hamiltonian or the Liouvillian of the system.\nψ0::QuantumObject: The initial state of the system.\ntspan::Real=Inf: The final time step for the steady state problem.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.\nsolver::SteadyStateODESolver=SteadyStateODESolver(): see SteadyStateODESolver for more details.\nreltol::Real=1.0e-8: Relative tolerance in steady state terminate condition and solver adaptive timestepping.\nabstol::Real=1.0e-10: Absolute tolerance in steady state terminate condition and solver adaptive timestepping.\nkwargs...: The keyword arguments for the ODEProblem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.steadystate_floquet","page":"API","title":"QuantumToolbox.steadystate_floquet","text":"steadystate_floquet(\n H_0::QuantumObject{MT,OpType1},\n H_p::QuantumObject{<:AbstractArray,OpType2},\n H_m::QuantumObject{<:AbstractArray,OpType3},\n ωd::Number,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n n_max::Integer = 2,\n tol::R = 1e-8,\n solver::FSolver = SSFloquetLinearSystem,\n kwargs...,\n)\n\nCalculates the steady state of a periodically driven system. Here H_0 is the Hamiltonian or the Liouvillian of the undriven system. Considering a monochromatic drive at frequency omega_d, we divide it into two parts, H_p and H_m, where H_p oscillates as e^i omega t and H_m oscillates as e^-i omega t. There are two solvers available for this function:\n\nSSFloquetLinearSystem: Solves the linear system of equations.\nSSFloquetEffectiveLiouvillian: Solves the effective Liouvillian.\n\nFor both cases, n_max is the number of Fourier components to consider, and tol is the tolerance for the solver.\n\nIn the case of SSFloquetLinearSystem, the full linear system is solved at once:\n\n( mathcalL_0 - i n omega_d ) hatrho_n + mathcalL_1 hatrho_n-1 + mathcalL_-1 hatrho_n+1 = 0\n\nThis is a tridiagonal linear system of the form\n\nmathbfA cdot mathbfb = 0\n\nwhere\n\nmathbfA = beginpmatrix\nmathcalL_0 - i (-n_textrmmax) omega_textrmd mathcalL_-1 0 cdots 0 \nmathcalL_1 mathcalL_0 - i (-n_textrmmax+1) omega_textrmd mathcalL_-1 cdots 0 \n0 mathcalL_1 mathcalL_0 - i (-n_textrmmax+2) omega_textrmd cdots 0 \nvdots vdots vdots ddots vdots \n0 0 0 cdots mathcalL_0 - i n_textrmmax omega_textrmd\nendpmatrix\n\nand\n\nmathbfb = beginpmatrix\nhatrho_-n_textrmmax \nhatrho_-n_textrmmax+1 \nvdots \nhatrho_0 \nvdots \nhatrho_n_textrmmax-1 \nhatrho_n_textrmmax\nendpmatrix\n\nThis will allow to simultaneously obtain all the hatrho_n.\n\nIn the case of SSFloquetEffectiveLiouvillian, instead, the effective Liouvillian is calculated using the matrix continued fraction method.\n\nnote: different return\nThe two solvers returns different objects. The SSFloquetLinearSystem returns a list of QuantumObject, containing the density matrices for each Fourier component (hatrho_-n, with n from 0 to n_textrmmax), while the SSFloquetEffectiveLiouvillian returns only hatrho_0. \n\nArguments\n\nH_0::QuantumObject: The Hamiltonian or the Liouvillian of the undriven system.\nH_p::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as e^i omega t.\nH_m::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as e^-i omega t.\nωd::Number: The frequency of the drive.\nc_ops::Union{Nothing,AbstractVector} = nothing: The optional collapse operators.\nn_max::Integer = 2: The number of Fourier components to consider.\ntol::R = 1e-8: The tolerance for the solver.\nsolver::FSolver = SSFloquetLinearSystem: The solver to use.\nkwargs...: Additional keyword arguments to be passed to the solver.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.SteadyStateDirectSolver","page":"API","title":"QuantumToolbox.SteadyStateDirectSolver","text":"SteadyStateDirectSolver()\n\nA solver which solves steadystate by finding the inverse of Liouvillian SuperOperator using the standard method given in LinearAlgebra.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SteadyStateEigenSolver","page":"API","title":"QuantumToolbox.SteadyStateEigenSolver","text":"SteadyStateEigenSolver()\n\nA solver which solves steadystate by finding the zero (or lowest) eigenvalue of Liouvillian SuperOperator using eigsolve.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SteadyStateLinearSolver","page":"API","title":"QuantumToolbox.SteadyStateLinearSolver","text":"SteadyStateLinearSolver(alg = KrylovJL_GMRES(), Pl = nothing, Pr = nothing)\n\nA solver which solves steadystate by finding the inverse of Liouvillian SuperOperator using the algorithms given in LinearSolve.jl.\n\nParameters\n\nalg::SciMLLinearSolveAlgorithm=KrylovJL_GMRES(): algorithms given in LinearSolve.jl\nPl::Union{Function,Nothing}=nothing: left preconditioner, see documentation Solving for Steady-State Solutions for more details.\nPr::Union{Function,Nothing}=nothing: right preconditioner, see documentation Solving for Steady-State Solutions for more details.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SteadyStateODESolver","page":"API","title":"QuantumToolbox.SteadyStateODESolver","text":"SteadyStateODESolver(alg = Tsit5())\n\nAn ordinary differential equation (ODE) solver for solving steadystate.\n\nIt includes a field (attribute) SteadyStateODESolver.alg that specifies the solving algorithm. Default to Tsit5().\n\nFor more details about the solvers, please refer to OrdinaryDiffEq.jl\n\n\n\n\n\n","category":"type"},{"location":"api/#doc-API:Correlations-and-Spectrum","page":"API","title":"Correlations and Spectrum","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"correlation_3op_2t\ncorrelation_2op_2t\ncorrelation_2op_1t\nspectrum","category":"page"},{"location":"api/#QuantumToolbox.correlation_3op_2t","page":"API","title":"QuantumToolbox.correlation_3op_2t","text":"correlation_3op_2t(H::QuantumObject,\n ψ0::QuantumObject,\n t_l::AbstractVector,\n τ_l::AbstractVector,\n A::QuantumObject,\n B::QuantumObject,\n C::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n kwargs...)\n\nReturns the two-times correlation function of three operators hatA, hatB and hatC: expvalhatA(t) hatB(t + tau) hatC(t)\n\nfor a given initial state ketpsi_0.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.correlation_2op_2t","page":"API","title":"QuantumToolbox.correlation_2op_2t","text":"correlation_2op_2t(H::QuantumObject,\n ψ0::QuantumObject,\n t_l::AbstractVector,\n τ_l::AbstractVector,\n A::QuantumObject,\n B::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n reverse::Bool=false,\n kwargs...)\n\nReturns the two-times correlation function of two operators hatA and hatB at different times: expvalhatA(t + tau) hatB(t).\n\nWhen reverse=true, the correlation function is calculated as expvalhatA(t) hatB(t + tau).\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.correlation_2op_1t","page":"API","title":"QuantumToolbox.correlation_2op_1t","text":"correlation_2op_1t(H::QuantumObject,\n ψ0::QuantumObject,\n τ_l::AbstractVector,\n A::QuantumObject,\n B::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n reverse::Bool=false,\n kwargs...)\n\nReturns the one-time correlation function of two operators hatA and hatB at different times expvalhatA(tau) hatB(0).\n\nWhen reverse=true, the correlation function is calculated as expvalhatA(0) hatB(tau).\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spectrum","page":"API","title":"QuantumToolbox.spectrum","text":"spectrum(H::QuantumObject,\n ω_list::AbstractVector,\n A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject},\n B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject},\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n solver::MySolver=ExponentialSeries(),\n kwargs...)\n\nReturns the emission spectrum \n\nS(omega) = int_-infty^infty expvalhatA(tau) hatB(0) e^-i omega tau d tau\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Metrics","page":"API","title":"Metrics","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"entropy_vn\nentanglement\ntracedist\nfidelity","category":"page"},{"location":"api/#QuantumToolbox.entropy_vn","page":"API","title":"QuantumToolbox.entropy_vn","text":"entropy_vn(ρ::QuantumObject; base::Int=0, tol::Real=1e-15)\n\nCalculates the Von Neumann entropy S = - Tr left hatrho log left( hatrho right) right where hatrho is the density matrix of the system.\n\nThe base parameter specifies the base of the logarithm to use, and when using the default value 0, the natural logarithm is used. The tol parameter describes the absolute tolerance for detecting the zero-valued eigenvalues of the density matrix hatrho.\n\nExamples\n\nPure state:\n\njulia> ψ = fock(2,0)\nQuantum Object: type=Ket dims=[2] size=(2,)\n2-element Vector{ComplexF64}:\n 1.0 + 0.0im\n 0.0 + 0.0im\n\njulia> ρ = ket2dm(ψ)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Matrix{ComplexF64}:\n 1.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im\n\njulia> entropy_vn(ρ, base=2)\n-0.0\n\nMixed state:\n\njulia> ρ = maximally_mixed_dm(2)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Diagonal{ComplexF64, Vector{ComplexF64}}:\n 0.5-0.0im ⋅ \n ⋅ 0.5-0.0im\n\njulia> entropy_vn(ρ, base=2)\n1.0\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.entanglement","page":"API","title":"QuantumToolbox.entanglement","text":"entanglement(QO::QuantumObject, sel::Union{Int,AbstractVector{Int},Tuple})\n\nCalculates 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tracedist","page":"API","title":"QuantumToolbox.tracedist","text":"tracedist(ρ::QuantumObject, σ::QuantumObject)\n\nCalculates the trace distance between two QuantumObject: T(hatrho hatsigma) = frac12 lVert hatrho - hatsigma rVert_1\n\nNote that ρ and σ must be either Ket or Operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fidelity","page":"API","title":"QuantumToolbox.fidelity","text":"fidelity(ρ::QuantumObject, σ::QuantumObject)\n\nCalculate the fidelity of two QuantumObject: F(hatrho hatsigma) = textrmTr sqrtsqrthatrho hatsigma sqrthatrho\n\nHere, the definition is from Nielsen & Chuang, \"Quantum Computation and Quantum Information\". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994).\n\nNote that ρ and σ must be either Ket or Operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Miscellaneous","page":"API","title":"Miscellaneous","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"wigner\nnegativity","category":"page"},{"location":"api/#QuantumToolbox.wigner","page":"API","title":"QuantumToolbox.wigner","text":"wigner(state::QuantumObject, xvec::AbstractVector, yvec::AbstractVector; g::Real=√2,\n solver::WignerSolver=WignerLaguerre())\n\nGenerates the Wigner quasipropability distribution of state at points xvec + 1im * yvec. The g parameter is a scaling factor related to the value of hbar in the commutation relation x y = i hbar via hbar=2g^2 giving the default value hbar=1.\n\nThe solver parameter can be either WignerLaguerre() or WignerClenshaw(). The former uses the Laguerre polynomial expansion of the Wigner function, while the latter uses the Clenshaw algorithm. The Laguerre expansion is faster for 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.negativity","page":"API","title":"QuantumToolbox.negativity","text":"negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool=false)\n\nCompute the negativity N(hatrho) = fracVert hatrho^GammaVert_1 - 12 where hatrho^Gamma is the partial transpose of hatrho with respect to the subsystem, and Vert hatX Vert_1=textrmTrsqrthatX^dagger hatX is the trace norm.\n\nArguments\n\nρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).\nsubsys::Int: an index that indicates which subsystem to compute the negativity for.\nlogarithmic::Bool: choose whether to calculate logarithmic negativity or not. Default as false\n\nReturns\n\nN::Real: The value of negativity.\n\nExamples\n\njulia> Ψ = bell_state(0, 0)\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n\njulia> ρ = ket2dm(Ψ)\nQuantum Object: type=Operator dims=[2, 2] size=(4, 4) ishermitian=true\n4×4 Matrix{ComplexF64}:\n 0.5+0.0im 0.0+0.0im 0.0+0.0im 0.5+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.5+0.0im 0.0+0.0im 0.0+0.0im 0.5+0.0im\n\njulia> negativity(ρ, 2)\n0.4999999999999998\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Linear-Maps","page":"API","title":"Linear Maps","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractLinearMap","category":"page"},{"location":"api/#QuantumToolbox.AbstractLinearMap","page":"API","title":"QuantumToolbox.AbstractLinearMap","text":"AbstractLinearMap{T, TS}\n\nRepresents a general linear map with element type T and size TS.\n\nOverview\n\nA linear map is a transformation L that satisfies:\n\nAdditivity: math L(u + v) = L(u) + L(v)\nHomogeneity: math L(cu) = cL(u)\n\nIt is typically represented as a matrix with dimensions given by size, and this abtract type helps to define this map when the matrix is not explicitly available.\n\nMethods\n\nBase.eltype(A): Returns the element type T.\nBase.size(A): Returns the size A.size.\nBase.size(A, i): Returns the i-th dimension.\n\nExample\n\nAs an example, we now define the linear map used in the eigsolve_al function for Arnoldi-Lindblad eigenvalue solver:\n\nstruct ArnoldiLindbladIntegratorMap{T,TS,TI} <: AbstractLinearMap{T,TS}\n elty::Type{T}\n size::TS\n integrator::TI\nend\n\nfunction LinearAlgebra.mul!(y::AbstractVector, A::ArnoldiLindbladIntegratorMap, x::AbstractVector)\n reinit!(A.integrator, x)\n solve!(A.integrator)\n return copyto!(y, A.integrator.u)\nend\n\nwhere integrator is the ODE integrator for the time-evolution. In this way, we can diagonalize this linear map using the eigsolve function.\n\n\n\n\n\n","category":"type"},{"location":"api/#doc-API:Utility-functions","page":"API","title":"Utility functions","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"QuantumToolbox.versioninfo\nQuantumToolbox.about\ngaussian\nn_thermal\nPhysicalConstants\nconvert_unit\nrow_major_reshape\nmeshgrid\n_calculate_expectation!\n_adjM_condition_variational\n_adjM_affect!\n_adjM_condition_ratio\n_pinv!\ndBdz!","category":"page"},{"location":"api/#QuantumToolbox.versioninfo","page":"API","title":"QuantumToolbox.versioninfo","text":"QuantumToolbox.versioninfo(io::IO=stdout)\n\nCommand line output of information on QuantumToolbox, dependencies, and system information, same as QuantumToolbox.about.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.about","page":"API","title":"QuantumToolbox.about","text":"QuantumToolbox.about(io::IO=stdout)\n\nCommand line output of information on QuantumToolbox, dependencies, and system information, same as QuantumToolbox.versioninfo.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.gaussian","page":"API","title":"QuantumToolbox.gaussian","text":"gaussian(x::Number, μ::Number, σ::Number)\n\nReturns the gaussian function exp left- frac(x - mu)^22 sigma^2 right, where mu and sigma^2 are the mean and the variance respectively.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.n_thermal","page":"API","title":"QuantumToolbox.n_thermal","text":"n_thermal(ω::Real, ω_th::Real)\n\nReturn the number of photons in thermal equilibrium for an harmonic oscillator mode with frequency omega, at the temperature described by omega_textrmth equiv k_B T hbar:\n\nn(omega omega_textrmth) = frac1e^omegaomega_textrmth - 1\n\nwhere hbar is the reduced Planck constant, and k_B is the Boltzmann constant.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.PhysicalConstants","page":"API","title":"QuantumToolbox.PhysicalConstants","text":"const PhysicalConstants\n\nA NamedTuple which stores some constant values listed in CODATA recommended values of the fundamental physical constants: 2022\n\nThe current stored constants are:\n\nc : (exact) speed of light in vacuum with unit textrmmcdottextrms^-1\nG : Newtonian constant of gravitation with unit textrmm^3cdottextrmkg^1cdottextrms^2\nh : (exact) Planck constant with unit textrmJcdottextrms\nħ : reduced Planck constant with unit textrmJcdottextrms\ne : (exact) elementary charge with unit textrmC\nμ0 : vacuum magnetic permeability with unit textrmNcdottextrmA^-2\nϵ0 : vacuum electric permittivity with unit textrmFcdottextrmm^-1\nk : (exact) Boltzmann constant with unit textrmJcdottextrmK^-1\nNA : (exact) Avogadro constant with unit textrmmol^-1\n\nExamples\n\njulia> PhysicalConstants.ħ\n1.0545718176461565e-34\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.convert_unit","page":"API","title":"QuantumToolbox.convert_unit","text":"convert_unit(value::Real, unit1::Symbol, unit2::Symbol)\n\nConvert the energy value from unit1 to unit2. The unit1 and unit2 can be either the following Symbol:\n\n:J : Joule\n:eV : electron volt\n:meV : milli-electron volt\n:MHz : Mega-Hertz multiplied by Planck constant h\n:GHz : Giga-Hertz multiplied by Planck constant h\n:K : Kelvin multiplied by Boltzmann constant k\n:mK : milli-Kelvin multiplied by Boltzmann constant k\n\nNote that we use the values stored in PhysicalConstants to do the conversion.\n\nExamples\n\njulia> convert_unit(1, :eV, :J)\n1.602176634e-19\n\njulia> convert_unit(1, :GHz, :J)\n6.62607015e-25\n\njulia> convert_unit(1, :meV, :mK)\n11604.518121550082\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.row_major_reshape","page":"API","title":"QuantumToolbox.row_major_reshape","text":"row_major_reshape(Q::AbstractArray, shapes...)\n\nReshapes Q in the row-major order, as numpy.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.meshgrid","page":"API","title":"QuantumToolbox.meshgrid","text":"meshgrid(x::AbstractVector, y::AbstractVector)\n\nEquivalent to numpy meshgrid.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._calculate_expectation!","page":"API","title":"QuantumToolbox._calculate_expectation!","text":"_calculate_expectation!(p,z,B,idx) where T\nCalculates 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.\nThe function is called by the callback _save_affect_lr_mesolve!.\n\nParameters\n----------\np : NamedTuple\n The parameters of the problem.\nz : AbstractMatrix{T}\n The z matrix.\nB : AbstractMatrix{T}\n The B matrix.\nidx : Integer\n The index of the current time step.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._adjM_condition_variational","page":"API","title":"QuantumToolbox._adjM_condition_variational","text":"_adjM_condition_variational(u, t, integrator) where T\nCondition for the dynamical rank adjustment based on the leakage out of the low-rank manifold.\n\nParameters\n----------\nu : AbstractVector{T}\n The current state of the system.\nt : Real\n The current time.\nintegrator : ODEIntegrator\n The integrator of the problem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._adjM_affect!","page":"API","title":"QuantumToolbox._adjM_affect!","text":"_adjM_affect!(integrator)\nAffect function for the dynamical rank adjustment. It increases the rank of the low-rank manifold by one, and updates the matrices accordingly.\nIf Δt>0, it rewinds the integrator to the previous time step.\n\nParameters\n----------\nintegrator : ODEIntegrator\n The integrator of the problem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._adjM_condition_ratio","page":"API","title":"QuantumToolbox._adjM_condition_ratio","text":"_adjM_condition_ratio(u, t, integrator) where T\nCondition for the dynamical rank adjustment based on the ratio between the smallest and largest eigenvalues of the density matrix.\nThe spectrum of the density matrix is calculated efficiently using the properties of the SVD decomposition of the matrix.\n\nParameters\n----------\nu : AbstractVector{T}\n The current state of the system.\nt : Real\n The current time.\nintegrator : ODEIntegrator\n The integrator of the problem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._pinv!","page":"API","title":"QuantumToolbox._pinv!","text":"_pinv!(A, T1, T2; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T\nComputes the pseudo-inverse of a matrix A, and stores it in T1. If T2 is provided, it is used as a temporary matrix. \nThe algorithm is based on the SVD decomposition of A, and is taken from the Julia package LinearAlgebra.\nThe difference with respect to the original function is that the cutoff is done with a smooth function instead of a step function.\n\nParameters\n----------\nA : AbstractMatrix{T}\n The matrix to be inverted.\nT1 : AbstractMatrix{T}\nT2 : AbstractMatrix{T}\n Temporary matrices used in the calculation.\natol : Real\n Absolute tolerance for the calculation of the pseudo-inverse. \nrtol : Real\n Relative tolerance for the calculation of the pseudo-inverse.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dBdz!","page":"API","title":"QuantumToolbox.dBdz!","text":"dBdz!(du, u, p, t) where T\nDynamical evolution equations for the low-rank manifold. The function is called by the ODEProblem.\n\nParameters\n----------\ndu : AbstractVector{T}\n The derivative of the state of the system.\nu : AbstractVector{T}\n The current state of the system.\np : NamedTuple\n The parameters of the problem.\nt : Real\n The current time.\n\n\n\n\n\n","category":"function"},{"location":"users_guide/time_evolution/time_dependent/#doc-TE:Solving-Problems-with-Time-dependent-Hamiltonians","page":"Solving Problems with Time-dependent Hamiltonians","title":"Solving Problems with Time-dependent Hamiltonians","text":"","category":"section"},{"location":"users_guide/time_evolution/time_dependent/","page":"Solving Problems with Time-dependent Hamiltonians","title":"Solving Problems with Time-dependent Hamiltonians","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"users_guide/time_evolution/stochastic/#doc-TE:Stochastic-Solver","page":"Stochastic Solver","title":"Stochastic Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/stochastic/","page":"Stochastic Solver","title":"Stochastic Solver","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"users_guide/time_evolution/stochastic/#Stochastic-Schrodinger-equation","page":"Stochastic Solver","title":"Stochastic Schrodinger equation","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/#doc-TE:Schrödinger-Equation-Solver","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/#Unitary-evolution","page":"Schrödinger Equation Solver","title":"Unitary evolution","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"The dynamics of a closed (pure) quantum system is governed by the Schrödinger equation","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"ihbarfracpartialpartial tPsi(vecx t) = hatHPsi(vecx t)","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"where Psi(vecx t) is the wave function, hatH is the Hamiltonian, and hbar is reduced Planck constant. In general, the Schrödinger equation is a partial differential equation (PDE) where both Psi and hatH are functions of space vecx and time t. For computational purposes it is useful to expand the PDE in a set of basis functions that span the Hilbert space of the Hamiltonian, and to write the equation in matrix and vector form, namely","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"ihbarfracddtpsi(t)rangle = hatHpsi(t)rangle","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"where psi(t)rangle is the state vector, and the Hamiltonian hatH is now under matrix representation. This matrix equation can, in principle, be solved by diagonalizing the Hamiltonian matrix hatH. In practice, however, it is difficult to perform this diagonalization unless the size of the Hilbert space (dimension of the matrix hatH) is small. Analytically, it is a formidable task to calculate the dynamics for systems with more than two states. If, in addition, we consider dissipation due to the inevitable interaction with a surrounding environment, the computational complexity grows even larger, and we have to resort to numerical calculations in all realistic situations. This illustrates the importance of numerical calculations in describing the dynamics of open quantum systems, and the need for efficient and accessible tools for this task.","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"The Schrödinger equation, which governs the time-evolution of closed quantum systems, is defined by its Hamiltonian and state vector. In the previous sections, Manipulating States and Operators and Tensor Products and Partial Traces, we showed how Hamiltonians and state vectors are constructed in QuantumToolbox.jl. Given a Hamiltonian, we can calculate the unitary (non-dissipative) time-evolution of an arbitrary initial state vector psi(0)rangle using the QuantumToolbox time evolution problem sesolveProblem or directly call the function sesolve. It evolves the state vector psi(t)rangle and evaluates the expectation values for a set of operators e_ops at each given time points, using an ordinary differential equation solver provided by the powerful julia package DifferentialEquation.jl.","category":"page"},{"location":"users_guide/time_evolution/sesolve/#Example:-Spin-dynamics","page":"Schrödinger Equation Solver","title":"Example: Spin dynamics","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"For example, the time evolution of a quantum spin-frac12 system (initialized in spin-uparrow) with tunneling rate 01 is calculated, and the expectation values of the Pauli-Z operator hatsigma_z is also evaluated, with the following code","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"H = 2 * π * 0.1 * sigmax()\nψ0 = basis(2, 0) # spin-up\ntlist = LinRange(0.0, 10.0, 20)\n\nprob = sesolveProblem(H, ψ0, tlist, e_ops = [sigmaz()])\nsol = sesolve(prob)","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"note: Note\nHere, we generate the time evolution problem by sesolveProblem first and then put it into the function sesolve. One can also directly call sesolve, which we also demonstrates in below.","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"The function returns TimeEvolutionSol, as described in the previous section Time Evolution Solutions. The attribute expect in solution is a list of expectation values for the operator(s) that are passed to the e_ops keyword argument. ","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"sol.expect","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"Passing multiple operators to e_ops as a Vector results in the expectation values for each operators at each time points.","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"tlist = LinRange(0.0, 10.0, 100)\nsol = sesolve(H, ψ0, tlist, e_ops = [sigmaz(), sigmay()])","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"note: Note\nHere, we call sesolve directly instead of pre-defining sesolveProblem first (as shown previously).","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"times = sol.times\nprint(size(times))","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"expt = sol.expect\nprint(size(expt))","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"We can therefore plot the expectation values:","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"using CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\nexpt_z = real(expt[1,:])\nexpt_y = real(expt[2,:])\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = \"Time\", ylabel = \"Expectation values\")\nlines!(ax, times, expt_z, label = L\"\\langle\\hat{\\sigma}_z\\rangle\", linestyle = :solid)\nlines!(ax, times, expt_y, label = L\"\\langle\\hat{\\sigma}_y\\rangle\", linestyle = :dash)\n\naxislegend(ax, position = :rb)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"If the keyword argument e_ops is not specified (or given as an empty Vector), the sesolve and functions return a TimeEvolutionSol that contains a list of state vectors which corresponds to the time points specified in tlist:","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"tlist = [0, 10]\nsol = sesolve(H, ψ0, tlist) # or specify: e_ops = []\n\nsol.states","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"This is because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). ","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"One can also specify e_ops and saveat separately:","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"tlist = [0, 5, 10]\nsol = sesolve(H, ψ0, tlist, e_ops = [sigmay()], saveat = tlist)","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"sol.expect","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"sol.states","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#doc:Qobj","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/#Introduction","page":"Quantum Objects (Qobj)","title":"Introduction","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"The key difference between classical and quantum mechanics is the use of operators instead of numbers as variables. Moreover, we need to specify state vectors and their properties. Therefore, in computing the dynamics of quantum systems, we need a data structure that encapsulates the properties of a quantum operator and ket/bra vectors. The quantum object structure, QuantumObject, accomplishes this using array representation.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"QuantumObject supports general Julia arrays (Base.AbstractArray). For example, it can be:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Base.Vector (dense vector)\nBase.Matrix (dense matrix)\nSparseArrays.SparseVector (sparse vector)\nSparseArrays.SparseMatrixCSC (sparse matrix)\nCUDA.CuArray (dense GPU vector / matrix)\nCUDA.CUSPARSE.CuSparseVector (sparse GPU vector)\nCUDA.CUSPARSE.CuSparseMatrixCSC (sparse GPU matrix)\nCUDA.CUSPARSE.CuSparseMatrixCSR (sparse GPU matrix)\nand even more ...","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"note: Support for GPU arrays\nSee CUDA extension for more details.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"We can create a QuantumObject with a user defined data set by passing an array of data into the QuantumObject:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"QuantumObject([1, 2, 3, 4, 5])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"We can also use the same function Qobj in QuTiP (Python):","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj([1, 2, 3, 4, 5])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj([1 2 3 4 5])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj(rand(4, 4))","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"M = rand(ComplexF64, 4, 4)\nQobj(M, dims = [2, 2]) # dims as Vector\nQobj(M, dims = (2, 2)) # dims as Tuple (recommended)\nQobj(M, dims = SVector(2, 2)) # dims as StaticArrays.SVector (recommended)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"warning: Beware of type-stability!\nPlease note that here we put the dims as a tuple (2, 2). Although it supports also Vector type (dims = [2, 2]), it is recommended to use Tuple or SVector from StaticArrays.jl to improve performance. For a brief explanation on the impact of the type of dims, see the Section The Importance of Type-Stability.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj(rand(4, 4), type = SuperOperator)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"note: Difference between `dims` and `size`\nNotice that type, dims, and size will change according to the input data. Although dims and size appear to be the same, dims keep tracking the dimension of individual Hilbert spaces of a multipartite system, while size does not. We refer the reader to the section Tensor Products and Partial Traces for more information.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#States-and-operators","page":"Quantum Objects (Qobj)","title":"States and operators","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Manually specifying the data for each quantum object is inefficient. Even more so when most objects correspond to commonly used types such as the ladder operators of a harmonic oscillator, the Pauli spin operators for a two-level system, or state vectors such as Fock states. Therefore, QuantumToolbox includes predefined functions to construct variety of states and operators (you can click the function links and see the corresponding docstring):","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#States","page":"Quantum Objects (Qobj)","title":"States","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"zero_ket: zero ket vector\nfock or basis: fock state ket vector\nfock_dm: density matrix of a fock state\ncoherent: coherent state ket vector \nrand_ket: random ket vector\ncoherent_dm: density matrix of a coherent state\nthermal_dm: density matrix of a thermal state\nmaximally_mixed_dm: density matrix of a maximally mixed state\nrand_dm: random density matrix\nspin_state: spin state\nspin_coherent: coherent spin state\nbell_state: Bell state\nsinglet_state: two particle singlet state\ntriplet_states: list of the two particle triplet states\nw_state: n-qubit W-state\nghz_state: n-qudit GHZ state","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#Operators","page":"Quantum Objects (Qobj)","title":"Operators","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"eye or qeye: identity operator\ndestroy: lowering (destruction) operator\ncreate: raising (creation) operator\nprojection: projection operator\ndisplace: displacement operator\nsqueeze: single-mode squeeze operator\nnum: bosonic number operator\nphase: single-mode Pegg-Barnett phase operator\nQuantumToolbox.position: position operator\nQuantumToolbox.momentum: momentum operator\nrand_unitary: random unitary operator\nsigmax: Pauli-X operator\nsigmay: Pauli-Y operator\nsigmaz: Pauli-Z operator\nsigmap: Pauli ladder (sigma_+) operator\nsigmam: Pauli ladder (sigma_-) operator\njmat: high-order Spin-j operator\nspin_Jx: S_x operator for Spin-j\nspin_Jy: S_y operator for Spin-j\nspin_Jz: S_z operator for Spin-j\nspin_Jm: S_- operator for Spin-j\nspin_Jp: S_+ operator for Spin-j\nspin_J_set: a set of Spin-j operators (S_x S_y S_z)\nfdestroy: fermion destruction operator\nfcreate: fermion creation operator\ncommutator: commutator or anti-commutator\ntunneling: tunneling operator\nqft: discrete quantum Fourier transform matrix","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"As an example, we give the output for a few of these functions:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"basis(5, 3)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"coherent(5, 0.5 - 0.5im)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"destroy(4)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"sigmaz()","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#Qobj-fields-(attributes)","page":"Quantum Objects (Qobj)","title":"Qobj fields (attributes)","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"We have seen that a structure QuantumObject has several fields (attributes), such as data, type and dims. These can be accessed in the following way:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a = destroy(4)\na.data","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a[2, 3] # the indexing in Julia starts from `1`","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a.type","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a.dims","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"In general, the properties of a QuantumObject can be retrieved using several functions with inputting QuantumObject:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"size(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"shape(a) # synonym of size(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"length(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"eltype(a) # element type","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"println(isket(a)) # ket\nprintln(isbra(a)) # bra\nprintln(isoper(a)) # operator\nprintln(isoperket(a)) # operator-ket\nprintln(isoperbra(a)) # operator-bra\nprintln(issuper(a)) # super operator\nprintln(ishermitian(a)) # Hermitian\nprintln(isherm(a)) # synonym of ishermitian(a)\nprintln(issymmetric(a)) # symmetric\nprintln(isposdef(a)) # positive definite (and Hermitian)\nprintln(isunitary(a)) # unitary","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#data-conversions","page":"Quantum Objects (Qobj)","title":"data conversions","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"As we mentioned above, QuantumObject.data supports general Julia arrays. The conversion between different type of QuantumObject.data is done using the standard type-conversion for arrays in Julia:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v_d = basis(2, 0)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Vector{Int64}(v_d)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v_s = SparseVector(v_d)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"SparseVector{Float64}(v_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x_s = sigmax()","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"SparseMatrixCSC{Int64}(x_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Matrix{Float64}(x_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"To convert between dense and sparse arrays, one can also use dense_to_sparse and sparse_to_dense:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x_d = sparse_to_dense(x_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"dense_to_sparse(x_d)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"note: Convert to GPU arrays\nSee CUDA extension for more details.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"QuantumToolbox will do conversion when needed to keep everything working in any format. However these conversions could slow down computation and it is recommended to keep to one format family where possible.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#Qobj-math","page":"Quantum Objects (Qobj)","title":"Qobj math","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"The rules for mathematical operations on QuantumObject are similar to the standard scalar, vector, and matrix arithmetic:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a = destroy(4)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a' # synonym of adjoint(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a + 5","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a' * a","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a ^ 3","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x = sigmax()","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x / sqrt(2)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x ^ 3 == x","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"# type \\approx + to get symbol ≈\nx ^ 3 ≈ x ","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Of course, like matrices, multiplying two objects of incompatible dims or size throws an error:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a * x","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Note that there is a special case for multiplying Ket and Bra, which results in outer product urangle otimes langle v:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"u = Qobj([1, 2, 3])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v = Qobj([4, 5, 6])\nv'","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"u * v'","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Of course, if you switch the order of multiplication, it becomes inner product langle v u rangle:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v' * u","category":"page"},{"location":"tutorials/logo/#doc-tutor:Create-QuantumToolbox.jl-logo","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"","category":"section"},{"location":"tutorials/logo/#Introduction","page":"Create QuantumToolbox.jl logo","title":"Introduction","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"In this tutorial, we will demonstrate how to create the logo for the QuantumToolbox.jl package. The logo represents the Wigner function of the triangular cat state, which is a linear superposition of three coherent states. The resulting Wigner function has a triangular shape that resembles the Julia logo. We will also define a custom colormap that varies based on the value of the Wigner function and the spatial coordinates, such that the three blobs corresponding to the coherent states have different colors (matching the colors of the Julia logo).","category":"page"},{"location":"tutorials/logo/#Triangular-Cat-State","page":"Create QuantumToolbox.jl logo","title":"Triangular Cat State","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"A cat state, often referred to as a Schrödinger cat state, is a quantum state that is a superposition of two coherent states with opposite phases:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":" psi_textcat rangle = frac1sqrt2 left( alpha rangle + -alpha rangle right)","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where alpha rangle is a coherent state with amplitude alpha.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The triangular cat state is a generalization of the standard cat state. It is a superposition of three coherent states with phases theta_0 theta_1 theta_2 separated by 120^circ(or 2pi3radians):","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":" psi_texttri-cat rangle = frac1sqrt3 left( alpha_0 rangle + alpha_1 rangle + alpha_2 rangle right)","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where alpha_j = rho e^itheta_jwith theta_j = fracpi2 + frac2pi j3and j = 0 1 2.","category":"page"},{"location":"tutorials/logo/#Wigner-Function","page":"Create QuantumToolbox.jl logo","title":"Wigner Function","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The Wigner function W(x p)is a quasi-probability distribution used in quantum mechanics to represent quantum states in phase space. It is defined as:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"W(x p) = frac1pi hbar int_-infty^infty psi^*(x + y) psi(x - y) e^2ipy hbar dy","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where psi(x)is the wave function of the quantum state, xis the position, pis the momentum, and hbaris the reduced Planck constant. Unlike classical probability distributions, the Wigner function can take negative values, which indicates non-classical behavior.","category":"page"},{"location":"tutorials/logo/#Generating-the-Logo","page":"Create QuantumToolbox.jl logo","title":"Generating the Logo","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"First, let's load the required packages:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"using QuantumToolbox\nusing CairoMakie\nCairoMakie.activate!(type = \"svg\", pt_per_unit = 1)\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())","category":"page"},{"location":"tutorials/logo/#Parameters","page":"Create QuantumToolbox.jl logo","title":"Parameters","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Here we define the parameters for the triangular cat state:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"N = 30 # Cutoff of the Hilbert space for the harmonic oscillator\nρ = 2.5 # Amplitude of the coherent state\nθ1 = π / 2\nθ2 = π / 2 + 2π / 3\nθ3 = π / 2 + 4π / 3\nα1 = ρ * exp(im * θ1)\nα2 = ρ * exp(im * θ2)\nα3 = ρ * exp(im * θ3)","category":"page"},{"location":"tutorials/logo/#Constructing-the-State","page":"Create QuantumToolbox.jl logo","title":"Constructing the State","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Next, we construct the triangular cat state as a normalized superposition of three coherent states:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"ψ = coherent(N, α1) + coherent(N, α2) + coherent(N, α3)\nnormalize!(ψ)","category":"page"},{"location":"tutorials/logo/#Defining-the-Grid-and-calculating-the-Wigner-function","page":"Create QuantumToolbox.jl logo","title":"Defining the Grid and calculating the Wigner function","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"We define the grid for the Wigner function and calculate it using the wigner function. We shift the grid in the imaginary direction to ensure that the Wigner function is centered around the origin of the figure. The wigner function also supports the g scaling factor, which we put here equal to 2.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"xvec = range(-ρ, ρ, 500) .* 1.5\nyvec = xvec .+ (abs(imag(α1)) - abs(imag(α2))) / 2\n\nwig = wigner(ψ, xvec, yvec, g = 2)","category":"page"},{"location":"tutorials/logo/#Plotting-the-Wigner-function","page":"Create QuantumToolbox.jl logo","title":"Plotting the Wigner function","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Finally, we plot the Wigner function using the heatmap function from the CairoMakie package.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"fig = Figure(size = (250, 250), figure_padding = 0)\nax = Axis(fig[1, 1])\nheatmap!(ax, xvec, yvec, wig', colormap = :RdBu, interpolate = true, rasterize = 1)\nhidespines!(ax)\nhidexdecorations!(ax)\nhideydecorations!(ax)\nfig","category":"page"},{"location":"tutorials/logo/#Introducing-some-decoherence","page":"Create QuantumToolbox.jl logo","title":"Introducing some decoherence","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The figure obtained above coulb be already a potential logo for the package. However, we see that the fringe patterns are more intense than the three coherent gaussian amplitudes. We can introduce some decoherence to reduce this effect. Thus, we evolve the system under the evolution of a damped quantum harmonic oscillator, which is described by the Lindblad master equation:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"fracd hatrhodt = -i hatH hatrho + gamma left( 2 hata hatrho hata^dagger - hata^dagger hata hatrho - hatrho hata^dagger hata right)","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where hatrho is the density matrix, hatH = omega hata^dagger hatais the Hamiltonian of the harmonic oscillator (hbar = 1), hataand hata^daggerare the annihilation and creation operators, and gammais the damping rate. Thus, we initialize the system in the triangular cat state and evolve it under the Lindblad master equation, using the mesolve function.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"γ = 0.012\n\na = destroy(N)\nH = a' * a\nc_ops = [sqrt(γ) * a]\n\ntlist = range(0, 2π, 100)\n\nsol = mesolve(H, ψ, tlist, c_ops, progress_bar = Val(false))\nnothing # hide","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"And the Wigner function becomes more uniform:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"wig = wigner(sol.states[end], xvec, yvec, g = 2)\n\nfig = Figure(size = (250, 250), figure_padding = 0)\nax = Axis(fig[1, 1])\n\nimg_wig = heatmap!(ax, xvec, yvec, wig', colormap = :RdBu, interpolate = true, rasterize = 1)\nhidespines!(ax)\nhidexdecorations!(ax)\nhideydecorations!(ax)\n\nfig","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"At this stage, we have finished to use the QuantumToolbox package. From now on, we will use the CairoMakie package to define custom colormaps and plot the Wigner function in a Julia logo style.","category":"page"},{"location":"tutorials/logo/#Custom-Colormap","page":"Create QuantumToolbox.jl logo","title":"Custom Colormap","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"We define a custom colormap that changes depending on the Wigner function and spatial coordinates. Indeed, we want the three different colormaps, in the regions corresponding to the three coherent states, to match the colors of the Julia logo. We also want the colormap change to be smooth, so we use a Gaussian function to blend the colors. We introduce also a Wigner function dependent transparency to make the logo more appealing.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"function set_color_julia(x, y, wig::T, α1, α2, α3, cmap1, cmap2, cmap3, δ) where {T}\n amp1 = gaussian(x, real(α1), δ) * gaussian(y, imag(α1), δ)\n amp2 = gaussian(x, real(α2), δ) * gaussian(y, imag(α2), δ)\n amp3 = gaussian(x, real(α3), δ) * gaussian(y, imag(α3), δ)\n\n c1 = get(cmap1, wig)\n c2 = get(cmap2, wig)\n c3 = get(cmap3, wig)\n\n c_tot = (amp1 * c1 + amp2 * c2 + amp3 * c3) / (amp1 + amp2 + amp3)\n\n wig_abs = abs(2 * (wig - 1 / 2))\n # We introduce some non-linearity to increase the contrast\n alpha = 2 * (1 / (1 + exp(-5 * wig_abs)) - 1 / 2)\n\n return RGBAf(c_tot.r, c_tot.g, c_tot.b, alpha)\nend\n\nX, Y = meshgrid(xvec, yvec)\nδ = 1.25 # Smoothing parameter for the Gaussian functions","category":"page"},{"location":"tutorials/logo/#Colormaps-from-the-Julia-colors","page":"Create QuantumToolbox.jl logo","title":"Colormaps from the Julia colors","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"We define the colormaps for the three coherent states using the colors of the Julia logo. We use the cgrad function from the CairoMakie package to create the colormaps.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"julia_red = RGBAf(0.796, 0.235, 0.2, 1.0)\njulia_green = RGBAf(0.22, 0.596, 0.149, 1.0)\njulia_blue = RGBAf(0.251, 0.388, 0.847, 1.0)\njulia_purple = RGBAf(0.584, 0.345, 0.698, 1.0)\nn_repeats = 2\n\ncmap1 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_green, n_repeats)))\ncmap2 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_red, n_repeats)))\ncmap3 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_purple, n_repeats)))","category":"page"},{"location":"tutorials/logo/#Normalizing-the-Wigner-function-and-applying-the-custom-colormap","page":"Create QuantumToolbox.jl logo","title":"Normalizing the Wigner function and applying the custom colormap","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The colormaps require the input to be in the range 0 1. We normalize the Wigner function such that the maximum value is 1and the zeros are set to 05.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"vmax = maximum(wig)\nwig_normalized = wig ./ (vmax * 2) .+ 1 / 2\nnothing # hide","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"And we now apply this custom colormap to make an image (a Matrix{RGBAf}).","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"img = set_color_julia.(X, Y, wig_normalized, α1, α2, α3, Ref(cmap1), Ref(cmap2), Ref(cmap3), δ)","category":"page"},{"location":"tutorials/logo/#Final-Plot","page":"Create QuantumToolbox.jl logo","title":"Final Plot","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Finally, we plot the Wigner function with the custom colormap.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"fig = Figure(size = (250, 250), figure_padding = 0, backgroundcolor = :transparent)\nax = Axis(fig[1, 1], backgroundcolor = :transparent)\nimage!(ax, img', rasterize = 1)\nhidespines!(ax)\nhidexdecorations!(ax)\nhideydecorations!(ax)\nfig","category":"page"},{"location":"tutorials/logo/#Conclusion","page":"Create QuantumToolbox.jl logo","title":"Conclusion","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"This tutorial demonstrates how to generate the QuantumToolbox.jl logo using the package itself and Makie.jl for visualization. The logo is a visualization of the Wigner function of a triangular cat state, with a custom colormap that highlights the different coherent states with colors matching the Julia logo.","category":"page"},{"location":"users_guide/extensions/cuda/#doc:CUDA","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"","category":"section"},{"location":"users_guide/extensions/cuda/#Introduction","page":"Extension for CUDA.jl","title":"Introduction","text":"","category":"section"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"This is an extension to support QuantumObject.data conversion from standard dense and sparse CPU arrays to GPU (CUDA.jl) arrays.","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"This extension will be automatically loaded if user imports both QuantumToolbox and CUDA.jl:","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"using QuantumToolbox\nusing CUDA\nusing CUDA.CUSPARSE\nCUDA.allowscalar(false) # Avoid unexpected scalar indexing","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"We wrapped several functions in CUDA and CUDA.CUSPARSE in order to not only converting QuantumObject.data into GPU arrays, but also changing the element type and word size (32 and 64) since some of the GPUs perform better in 32-bit. The functions are listed as follows (where input A is a QuantumObject):","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(A; word_size=64): return a new QuantumObject with CUDA arrays and specified word_size.\nCuArray(A): If A.data is a dense array, return a new QuantumObject with CUDA.CuArray.\nCuArray{T}(A): If A.data is a dense array, return a new QuantumObject with CUDA.CuArray under element type T.\nCuSparseVector(A): If A.data is a sparse vector, return a new QuantumObject with CUDA.CUSPARSE.CuSparseVector.\nCuSparseVector{T}(A): If A.data is a sparse vector, return a new QuantumObject with CUDA.CUSPARSE.CuSparseVector under element type T.\nCuSparseMatrixCSC(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSC.\nCuSparseMatrixCSC{T}(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSC under element type T.\nCuSparseMatrixCSR(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSR.\nCuSparseMatrixCSR{T}(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSR under element type T.","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"We suggest to convert the arrays from CPU to GPU memory by using the function cu because it allows different data-types of input QuantumObject.","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Here are some examples:","category":"page"},{"location":"users_guide/extensions/cuda/#Converting-dense-arrays","page":"Extension for CUDA.jl","title":"Converting dense arrays","text":"","category":"section"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"V = fock(2, 0) # CPU dense vector","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element Vector{ComplexF64}:\n 1.0 + 0.0im\n 0.0 + 0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuArray{ComplexF64, 1, CUDA.DeviceMemory}:\n 1.0 + 0.0im\n 0.0 + 0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuArray{ComplexF32, 1, CUDA.DeviceMemory}:\n 1.0 + 0.0im\n 0.0 + 0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"M = Qobj([1 2; 3 4]) # CPU dense matrix","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 Matrix{Int64}:\n 1 2\n 3 4","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 CuArray{Int64, 2, CUDA.DeviceMemory}:\n 1 2\n 3 4","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 CuArray{Int32, 2, CUDA.DeviceMemory}:\n 1 2\n 3 4","category":"page"},{"location":"users_guide/extensions/cuda/#Converting-sparse-arrays","page":"Extension for CUDA.jl","title":"Converting sparse arrays","text":"","category":"section"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"V = fock(2, 0; sparse=true) # CPU sparse vector","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element SparseVector{ComplexF64, Int64} with 1 stored entry:\n [1] = 1.0+0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuSparseVector{ComplexF64, Int32} with 1 stored entry:\n [1] = 1.0+0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuSparseVector{ComplexF32, Int32} with 1 stored entry:\n [1] = 1.0+0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"M = sigmax() # CPU sparse matrix","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅ ","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 CuSparseMatrixCSC{ComplexF64, Int32} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅ ","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 CuSparseMatrixCSC{ComplexF32, Int32} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅ ","category":"page"},{"location":"users_guide/time_evolution/mcsolve/#doc-TE:Monte-Carlo-Solver","page":"Monte-Carlo Solver","title":"Monte-Carlo Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/mcsolve/","page":"Monte-Carlo Solver","title":"Monte-Carlo Solver","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"qutip_differences/","page":"Key differences from QuTiP","title":"Key differences from QuTiP","text":"CurrentModule = QuantumToolbox","category":"page"},{"location":"qutip_differences/#doc:Key-differences-from-QuTiP","page":"Key differences from QuTiP","title":"Key differences from QuTiP","text":"","category":"section"},{"location":"qutip_differences/","page":"Key differences from QuTiP","title":"Key differences from QuTiP","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"CurrentModule = QuantumToolbox","category":"page"},{"location":"#QuantumToolbox.jl-Documentation","page":"Introduction","title":"QuantumToolbox.jl Documentation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"QuantumToolbox.jl is a cutting-edge Julia package designed for quantum physics simulations, closely emulating the popular Python QuTiP package. It uniquely combines the simplicity and power of Julia with advanced features like GPU acceleration and distributed computing, making simulation of quantum systems more accessible and efficient.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"With this package, moving from Python to Julia for quantum physics simulations has never been easier, due to the similar syntax and functionalities.","category":"page"},{"location":"#Features","page":"Introduction","title":"Features","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"QuantumToolbox.jl is equipped with a robust set of features:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Quantum State and Operator Manipulation: Easily handle quantum states and operators with a rich set of tools, with the same functionalities as QuTiP.\nDynamical Evolution: Advanced solvers for time evolution of quantum systems, thanks to the powerful DifferentialEquations.jl package.\nGPU Computing: Leverage GPU resources for high-performance computing. For example, you run the master equation direclty on the GPU with the same syntax as the CPU case.\nDistributed Computing: Distribute the computation over multiple nodes (e.g., a cluster). For example, you can run undreds of quantum trajectories in parallel on a cluster, with, again, the same syntax as the simple case.\nEasy Extension: Easily extend the package, taking advantage of the Julia language features, like multiple dispatch and metaprogramming.","category":"page"},{"location":"#doc:Installation","page":"Introduction","title":"Installation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"note: Requirements\nQuantumToolbox.jl requires Julia 1.10+.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"To install QuantumToolbox.jl, run the following commands inside Julia's interactive session (also known as REPL):","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using Pkg\nPkg.add(\"QuantumToolbox\")","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Alternatively, this can also be done in Julia's Pkg REPL by pressing the key ] in the REPL to use the package mode, and then type the following command:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"(1.10) pkg> add QuantumToolbox","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"More information about Julia's package manager can be found at Pkg.jl.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"To load the package and check the version information, use either QuantumToolbox.versioninfo() or QuantumToolbox.about(), namely","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using QuantumToolbox\nQuantumToolbox.versioninfo()\nQuantumToolbox.about()","category":"page"},{"location":"#Brief-Example","page":"Introduction","title":"Brief Example","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"We now provide a brief example to demonstrate the similarity between QuantumToolbox.jl and QuTiP.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Let's consider a quantum harmonic oscillator with a Hamiltonian given by:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"hatH = omega hata^dagger hata","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"where hata and hata^dagger are the annihilation and creation operators, respectively. We can define the Hamiltonian as follows:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using QuantumToolbox\n\nN = 20 # cutoff of the Hilbert space dimension\nω = 1.0 # frequency of the harmonic oscillator\n\na = destroy(N) # annihilation operator\n\nH = ω * a' * a","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"We now introduce some losses in a thermal environment, described by the Lindblad master equation:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"fracd hatrhodt = -i hatH hatrho + gamma mathcalDhata hatrho","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"where hatrho is the density matrix, gamma is the damping rate, and mathcalDhata is the Lindblad dissipator, defined as:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"mathcalDhatahatrho = hatahatrhohata^dagger - frac12hata^daggerhatahatrho - frac12hatrhohata^daggerhata","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"We now compute the time evolution of the system using the mesolve function, starting from the initial state ketpsi (0) = ket3:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"γ = 0.1 # damping rate\n\nψ0 = fock(N, 3) # initial state\n\ntlist = range(0, 10, 100) # time list\n\nc_ops = [sqrt(γ) * a]\ne_ops = [a' * a]\n\nsol = mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops)","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"We can extract the expectation value of the number operator hata^dagger hata with the command sol.expect, and the states with the command sol.states.","category":"page"},{"location":"#Support-for-GPU-calculation","page":"Introduction","title":"Support for GPU calculation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"We can easily pass the computation to the GPU, by simply passing all the Qobjs to the GPU:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using QuantumToolbox\nusing CUDA\nCUDA.allowscalar(false) # Avoid unexpected scalar indexing\n\na_gpu = cu(destroy(N)) # The only difference in the code is the cu() function\n\nH_gpu = ω * a_gpu' * a_gpu\n\nψ0_gpu = cu(fock(N, 3))\n\nc_ops = [sqrt(γ) * a_gpu]\ne_ops = [a_gpu' * a_gpu]\n\nsol = mesolve(H_gpu, ψ0_gpu, tlist, c_ops, e_ops = e_ops)","category":"page"},{"location":"tutorials/lowrank/#doc-tutor:Low-rank-master-equation","page":"Low Rank Master Equation","title":"Low rank master equation","text":"","category":"section"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"We start by importing the packages","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"using QuantumToolbox\nusing CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define lattice","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Nx, Ny = 2, 3\nlatt = Lattice(Nx = Nx, Ny = Ny)","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define lr-space dimensions","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"N_cut = 2 # Number of states of each mode\nN_modes = latt.N # Number of modes\nN = N_cut^N_modes # Total number of states\nM = Nx * Ny + 1 # Number of states in the LR basis","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define lr states. Take as initial state all spins up. All other N states are taken as those with miniman Hamming distance to the initial state.","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"ϕ = Vector{QuantumObject{Vector{ComplexF64},KetQuantumObject}}(undef, M)\nϕ[1] = kron(repeat([basis(2, 0)], N_modes)...)\n\nglobal i = 1\nfor j in 1:N_modes\n global i += 1\n i <= M && (ϕ[i] = mb(sp, j, latt) * ϕ[1])\nend\nfor k in 1:N_modes-1\n for l in k+1:N_modes\n global i += 1\n i <= M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1])\n end\nend\nfor i in i+1:M\n ϕ[i] = QuantumObject(rand(ComplexF64, size(ϕ[1])[1]), dims = ϕ[1].dims)\n normalize!(ϕ[i])\nend","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define the initial state","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"z = hcat(broadcast(x -> x.data, ϕ)...)\np0 = 0.0 # Population of the lr states other than the initial state\nB = Matrix(Diagonal([1 + 0im; p0 * ones(M - 1)]))\nS = z' * z # Overlap matrix\nB = B / tr(S * B) # Normalize B\n\nρ = QuantumObject(z * B * z', dims = ones(Int, N_modes) * N_cut); # Full density matrix","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define the Hamiltonian and collapse operators","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"# Define Hamiltonian and collapse operators\nJx = 0.9\nJy = 1.04\nJz = 1.0\nhx = 0.0\nγ = 1\n\nSx = sum([mb(sx, i, latt) for i in 1:latt.N])\nSy = sum([mb(sy, i, latt) for i in 1:latt.N])\nSz = sum([mb(sz, i, latt) for i in 1:latt.N])\nSFxx = sum([mb(sx, i, latt) * mb(sx, j, latt) for i in 1:latt.N for j in 1:latt.N])\n\nH, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc = pbc, order = 1)\ne_ops = (Sx, Sy, Sz, SFxx)\n\ntl = LinRange(0, 10, 100);","category":"page"},{"location":"tutorials/lowrank/#Full-evolution","page":"Low Rank Master Equation","title":"Full evolution","text":"","category":"section"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"@time mesol = mesolve(H, ρ, tl, c_ops; e_ops = [e_ops...]);\nA = Matrix(mesol.states[end].data)\nλ = eigvals(Hermitian(A))\nStrue = -sum(λ .* log2.(λ)) / latt.N;","category":"page"},{"location":"tutorials/lowrank/#Low-Rank-evolution","page":"Low Rank Master Equation","title":"Low Rank evolution","text":"","category":"section"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define functions to be evaluated during the low-rank evolution","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"function f_purity(p, z, B)\n N = p.N\n M = p.M\n S = p.S\n T = p.temp_MM\n\n mul!(T, S, B)\n return tr(T^2)\nend\n\nfunction f_trace(p, z, B)\n N = p.N\n M = p.M\n S = p.S\n T = p.temp_MM\n\n mul!(T, S, B)\n return tr(T)\nend\n\nfunction f_entropy(p, z, B)\n C = p.A0\n σ = p.Bi\n\n mul!(C, z, sqrt(B))\n mul!(σ, C', C)\n λ = eigvals(Hermitian(σ))\n λ = λ[λ.>1e-10]\n return -sum(λ .* log2.(λ))\nend;","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define the options for the low-rank evolution","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"opt =\n LRMesolveOptions(err_max = 1e-3, p0 = 0.0, atol_inv = 1e-6, adj_condition = \"variational\", Δt = 0.0);\n\n@time lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops = e_ops, f_ops = (f_purity, f_entropy, f_trace), opt = opt);","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Plot the results","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"m_me = real(mesol.expect[3, :]) / Nx / Ny\nm_lr = real(lrsol.expvals[3, :]) / Nx / Ny\n\nfig = Figure(size = (500, 350), fontsize = 15)\nax = Axis(fig[1, 1], xlabel = L\"\\gamma t\", ylabel = L\"M_{z}\", xlabelsize = 20, ylabelsize = 20)\nlines!(ax, tl, m_lr, label = L\"LR $[M=M(t)]$\", linewidth = 2)\nlines!(ax, tl, m_me, label = \"Fock\", linewidth = 2, linestyle = :dash)\naxislegend(ax, position = :rb)\n\nax2 = Axis(fig[1, 2], xlabel = L\"\\gamma t\", ylabel = \"Value\", xlabelsize = 20, ylabelsize = 20)\nlines!(ax2, tl, 1 .- real(lrsol.funvals[1, :]), label = L\"$1-P$\", linewidth = 2)\nlines!(\n ax2,\n tl,\n 1 .- real(lrsol.funvals[3, :]),\n label = L\"$1-\\mathrm{Tr}(\\rho)$\",\n linewidth = 2,\n linestyle = :dash,\n color = :orange,\n)\nlines!(ax2, tl, real(lrsol.funvals[2, :]) / Nx / Ny, color = :blue, label = L\"S\", linewidth = 2)\nhlines!(ax2, [Strue], color = :blue, linestyle = :dash, linewidth = 2, label = L\"S^{\\,\\mathrm{true}}_{\\mathrm{ss}}\")\naxislegend(ax2, position = :rb)\n\nfig","category":"page"}] +[{"location":"type_stability/#doc:Type-Stability","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"You are here because you have probably heard about the excellent performance of Julia compared to other common programming languages like Python. One of the reasons is the Just-In-Time (JIT) compiler of Julia, which is able to generate highly optimized machine code. However, the JIT compiler can only do its job if the code type can be inferred. You can also read the Performance Tips section in Julia's documentation for more details. Here, we try to explain it briefly, with a focus on the QuantumToolbox.jl package.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"note: Note\nThis page is not a tutorial on QuantumToolbox.jl, but rather a general guide to writing Julia code for simulating quantum systems efficiently. If you don't care about the performance of your code, you can skip this page.","category":"page"},{"location":"type_stability/#Basics-of-type-stability","page":"The Importance of Type-Stability","title":"Basics of type stability","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Let's have a look at the following example:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"using InteractiveUtils\nusing QuantumToolbox","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function foo(x)\n if x > 0\n return 1\n else\n return -1.0\n end\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The function foo apparently seems to be innocent. It takes an argument x and returns either 1 or -1.0 depending on the sign of x. However, the return type of foo is not clear. If x is positive, the return type is Int, otherwise it is Float64. This is a problem for the JIT compiler, because it has to determine the return type of foo at runtime. This is called type instability (even though it is a weak form) and may lead to a significant performance penalty. To avoid this, always aim for type-stable code. This means that the return type of a function should be clear from the types of its arguments. We can check the inferred return type of foo using the @code_warntype macro:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype foo(1)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The key point is to ensure the return type of a function is clear from the types of its arguments. There are several ways to achieve this, and the best approach depends on the specific problem. For example, one can use the same return type:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function foo(x)\n if x > 0\n return 1.0\n else\n return -1.0\n end\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Or you can ensure the return type matches the type of the argument:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function foo(x::T) where T\n if x > 0\n return T(1)\n else\n return -T(1)\n end\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The latter example is very important because it takes advantage of Julia's multiple dispatch, which is one of the most powerful features of the language. Depending on the type T of the argument x, the Julia compiler generates a specialized version of foo that is optimized for this type. If the input type is an Int64, the return type is Int64, if x is a Float64, the return type is Float64, and so on.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@show foo(1)\n@show foo(-4.4)\n@show foo(1//2)\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"note: Note\nIf you didn't know how to make this function type-stable, it is probably a good idea to read the official Julia documentation, and in particular its Performance Tips section.","category":"page"},{"location":"type_stability/#Global-variables","page":"The Importance of Type-Stability","title":"Global variables","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Another source of type instability is the use of global variables. In general, it is a good idea to declare global variables as const to ensure their type is fixed for the entire program. For example, consider the following function that internally takes a global variable y:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"y = 2.4\n\nfunction bar(x)\n res = zero(x) # this returns the zero of the same type of x\n for i in 1:1000\n res += y * x\n end\n return res\nend\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The Julia compiler cannot infer the type of res because it depends on the type of y, which is a global variable that can change at any time of the program. We can check it using the @code_warntype macro:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype bar(3.2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"While in the last example of the foo function we got a weak form of type instability, returning a Union{Int, Float64}, in this case the return type of bar is Any, meaning that the compiler doesn't know anything about the return type. Thus, this function has nothing different from a dynamically typed language like Python. We can benchmark the performance of bar using the BenchmarkTools.jl package:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"using BenchmarkTools\n\n@benchmark bar(3.2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Here we see a lot of memory allocations and low performances in general. To fix this, we can declare a const (constant) variable instead:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"const z = 2.4\n\nfunction bar(x)\n res = zero(x) # this returns the zero of the same type of x\n for i in 1:1000\n res += z * x\n end\n return res\nend\n\n@benchmark bar(3.2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"And we can see that the performance has improved significantly. Hence, we highly recommend using global variables as const, but only when truly necessary. This choice is problem-dependent, but in the case of QuantumToolbox.jl, this can be applied for example in the case of defining the Hilbert space dimensions, static parameters, or the system operators.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Although it is always a good practice to avoid such kind of type instabilities, in the actual implementation of QuantumToolbox.jl (where we mainly deal with linear algebra operations), the compiler may perform only a few runtime dispatches, and the performance penalty may be negligible compared to the heavy linear algebra operations.","category":"page"},{"location":"type_stability/#Vectors-vs-Tuples-vs-StaticArrays","page":"The Importance of Type-Stability","title":"Vectors vs Tuples vs StaticArrays","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Julia has many ways to represent arrays or lists of general objects. The most common are Vectors and Tuples. The former is a dynamic array that can change its size at runtime, while the latter is a fixed-size array that is immutable, and where the type of each element is already known at compile time. For example:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"v1 = [1, 2, 3] # Vector of Int64\nv2 = [1.0 + 2.0im, 3.0 + 4.0im] # Vector of ComplexF64\nv3 = [1, \"ciao\", 3.0] # Vector of Any\n\nt1 = (1, 2, 3) # Tuple of {Int64, Int64, Int64}\nt2 = (1.0 + 2.0im, 3.0 + 4.0im) # Tuple of {ComplexF64, ComplexF64}\nt3 = (1, \"ciao\", 3.0) # Tuple of {Int64, String, Float64}\n\n@show typeof(v1)\n@show typeof(v2)\n@show typeof(v3)\n@show typeof(t1)\n@show typeof(t2)\n@show typeof(t3)\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Thus, we highly recommend using Vector only when we are sure that it contains elements of the same type, and only when we don't need to know its size at compile time. On the other hand, Tuples are less flexible but more efficient in terms of performance. A third option is to use the SVector type from the StaticArrays.jl package. This is similar to Vector, where the elements should have the same type, but it is fixed-size and immutable. One may ask when it is necessary to know the array size at compile time. A practical example is the case of ptrace, where it internally reshapes the quantum state into a tensor whose dimensions depend on the number of subsystems. We will see this in more detail in the next section.","category":"page"},{"location":"type_stability/#The-[QuantumObject](@ref)-internal-structure","page":"The Importance of Type-Stability","title":"The QuantumObject internal structure","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Before making a practical example, let's see the internal structure of the QuantumObject type. As an example, we consider the case of three qubits, and we study the internal structure of the hatsigma_x^(2) operator:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2 = tensor(qeye(2), sigmax(), qeye(2))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"and its type is","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"obj_type = typeof(σx_2)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"This is exactly what the Julia compiler sees: it is a QuantumObject, composed by a field of type SparseMatrixCSC{ComplexF64, Int64} (i.e., the 8x8 matrix containing the Pauli matrix, tensored with the identity matrices of the other two qubits). Then, we can also see that it is a OperatorQuantumObject, with 3 subsystems in total. Hence, just looking at the type of the object, the compiler has all the information it needs to generate a specialized version of the functions.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Let's see more in the details all the internal fields of the QuantumObject type:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"fieldnames(obj_type)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2.data","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2.type","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Operator is a synonym for OperatorQuantumObject.","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"σx_2.dims","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"The dims field contains the dimensions of the subsystems (in this case, three subsystems with dimension 2 each). We can see that the type of dims is SVector instead of Vector. As we mentioned before, this is very useful in functions like ptrace. Let's do a simple example of reshaping an operator internally generated from some dims input:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function reshape_operator_data(dims)\n op = Qobj(randn(prod(dims), prod(dims)), type=Operator, dims=dims)\n op_dims = op.dims\n op_data = op.data\n return reshape(op_data, vcat(op_dims, op_dims)...)\nend\n\ntypeof(reshape_operator_data([2, 2, 2]))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Which returns a tensor of size 2x2x2x2x2x2. Let's check the @code_warntype:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype reshape_operator_data([2, 2, 2])","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"We got a Any type, because the compiler doesn't know the size of the dims vector. We can fix this by using a Tuple (or SVector):","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"typeof(reshape_operator_data((2, 2, 2)))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype reshape_operator_data((2, 2, 2))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Finally, let's look at the benchmarks","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@benchmark reshape_operator_data($[2, 2, 2])","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@benchmark reshape_operator_data($((2, 2, 2)))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"Which is an innocuous but huge difference in terms of performance. Hence, we highly recommend using Tuple or SVector when defining the dimensions of a user-defined QuantumObject.","category":"page"},{"location":"type_stability/#The-use-of-Val-in-some-QuantumToolbox.jl-functions","page":"The Importance of Type-Stability","title":"The use of Val in some QuantumToolbox.jl functions","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"In some functions of QuantumToolbox.jl, you may find the use of the Val type in the arguments. This is a trick to pass a value at compile time, and it is very useful to avoid type instabilities. Let's make a very simple example, where we want to create a Fock state jrangle of a given dimension N, and we give the possibility to create it as a sparse or dense vector. At first, we can write the function without using Val:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"function my_fock(N::Int, j::Int = 0; sparse::Bool = false)\n if sparse\n array = sparsevec([j + 1], [1.0 + 0im], N)\n else\n array = zeros(ComplexF64, N)\n array[j+1] = 1\n end\n return QuantumObject(array; type = Ket)\nend\n@show my_fock(2, 1)\n@show my_fock(2, 1; sparse = true)\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"But it is immediately clear that the return type of this function is not clear, because it depends on the value of the sparse argument. We can check it using the @code_warntype macro:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock(2, 1)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock(2, 1; sparse = true)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"We can fix this by using the Val type, where we enable the multiple dispatch of the function:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"getVal(::Val{N}) where N = N\nfunction my_fock_good(N::Int, j::Int = 0; sparse::Val = Val(false))\n if getVal(sparse)\n array = zeros(ComplexF64, N)\n array[j+1] = 1\n else\n array = sparsevec([j + 1], [1.0 + 0im], N)\n end\n return QuantumObject(array; type = Ket)\nend\n@show my_fock_good(2, 1)\n@show my_fock_good(2, 1; sparse = Val(true))\nnothing # hide","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"And now the return type of the function is clear:","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock_good(2, 1)","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"@code_warntype my_fock_good(2, 1; sparse = Val(true))","category":"page"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"This is exactly how the current fock function is implemented in QuantumToolbox.jl. There are many other functions that support this feature, and we highly recommend using it when necessary.","category":"page"},{"location":"type_stability/#Conclusions","page":"The Importance of Type-Stability","title":"Conclusions","text":"","category":"section"},{"location":"type_stability/","page":"The Importance of Type-Stability","title":"The Importance of Type-Stability","text":"In this page, we have seen the importance of type stability in Julia, and how to write efficient code in the context of QuantumToolbox.jl. We have seen that the internal structure of the QuantumObject type is already optimized for the compiler, and we have seen some practical examples of how to write efficient code. We have seen that the use of Vector should be avoided when the elements don't have the same type, and that the use of Tuple or SVector is highly recommended when the size of the array is known at compile time. Finally, we have seen the use of Val to pass values at compile time, to avoid type instabilities in some functions. ```","category":"page"},{"location":"users_guide/states_and_operators/#doc:Manipulating-States-and-Operators","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"","category":"section"},{"location":"users_guide/states_and_operators/#Introduction","page":"Manipulating States and Operators","title":"Introduction","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"In the previous guide section Basic Operations on Quantum Objects, we saw how to create states and operators, using the functions built into QuantumToolbox. In this portion of the guide, we will look at performing basic operations with states and operators. For more detailed demonstrations on how to use and manipulate these objects, see the examples given in the tutorial section.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/states_and_operators/#doc:State-vectors","page":"Manipulating States and Operators","title":"State Vectors (kets or bras)","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Here we begin by creating a Fock basis (or fock) vacuum state vector 0rangle with in a Hilbert space with 5 number states, from 0 to 4:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(5, 0)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"and then create a lowering operator hata corresponding to 5 number states using the destroy function:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"a = destroy(5)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Now lets apply the lowering operator \\hat{a} to our vacuum state vac:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"a * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"We see that, as expected, the vacuum is transformed to the zero vector. A more interesting example comes from using the adjoint of the lowering operator hata, the raising operator hata^dagger:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"a' * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The raising operator has in indeed raised the state vac from the vacuum to the 1rangle state. Instead of using the adjoint method to raise the state, we could have also used the built-in create function to make a raising operator:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad = create(5)\nad * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"which does the same thing. We can raise the vacuum state more than once by successively apply the raising operator:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * ad * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"or just taking the square of the raising operator left(hata^daggerright)^2:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad^2 * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Applying the raising operator twice gives the expected sqrtn+1 dependence. We can use the product of hata^dagger hata to also apply the number operator to the state vector vac:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"or on the 1rangle state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * (ad * vac)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"or on the 2rangle state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * (ad^2 * vac)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Notice how in this last example, application of the number operator does not give the expected value n=2, but rather 2sqrt2. This is because this last state is not normalized to unity as hata^daggernrangle=sqrtn+1n+1rangle. Therefore, we should normalize (or use unit) our vector first:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ad * a * normalize(ad^2 * vac)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Since we are giving a demonstration of using states and operators, we have done a lot more work than we should have. For example, we do not need to operate on the vacuum state to generate a higher number Fock state. Instead we can use the basis (or fock) function to directly obtain the required state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket = basis(5, 2)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Notice how it is automatically normalized. We can also use the built in number operator num:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"n = num(5)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Therefore, instead of ad * a * normalize(ad^2 * vac), we have:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"n * ket","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"We can also create superpositions of states:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket = normalize(basis(5, 0) + basis(5, 1))","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"where we have used the normalize function again to normalize the state. Apply the number opeartor again:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"n * ket","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"We can also create coherent states and squeezed states by applying the displace and squeeze functions to the vacuum state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(5, 0)\n\nd = displace(5, 1im)\n\ns = squeeze(5, 0.25 + 0.25im)\n\nd * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"d * s * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Of course, displacing the vacuum gives a coherent state, which can also be generated using the built in coherent function.","category":"page"},{"location":"users_guide/states_and_operators/#doc:Density-matrices","page":"Manipulating States and Operators","title":"Density matrices","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"One of the main purpose of QuantumToolbox is to explore the dynamics of open quantum systems, where the most general state of a system is no longer a state vector, but rather a density matrix. Since operations on density matrices operate identically to those of vectors, we will just briefly highlight creating and using these structures.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The simplest density matrix is created by forming the outer-product psiranglelanglepsi of a ket vector:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket = basis(5, 2)\nket * ket'","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"A similar task can also be accomplished via the fock_dm or ket2dm functions:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"fock_dm(5, 2)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"ket2dm(ket)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"If we want to create a density matrix with equal classical probability of being found in the 2rangle or 4rangle number states, we can do the following:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"0.5 * fock_dm(5, 2) + 0.5 * fock_dm(5, 4) # with fock_dm\n0.5 * ket2dm(basis(5, 2)) + 0.5 * ket2dm(basis(5, 4)) # with ket2dm","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"There are also several other built-in functions for creating predefined density matrices, for example coherent_dm and thermal_dm which create coherent state and thermal state density matrices, respectively.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"coherent_dm(5, 1.25)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"thermal_dm(5, 1.25)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"QuantumToolbox also provides a set of distance metrics for determining how close two density matrix distributions are to each other. Included are the fidelity, and trace distance (tracedist).","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"x = coherent_dm(5, 1.25)\n\ny = coherent_dm(5, 1.25im)\n\nz = thermal_dm(5, 0.125)\n\nfidelity(x, y)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Note that the definition of fidelity here is from Nielsen & Chuang, \"Quantum Computation and Quantum Information\". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994). We also know that for two pure states, the trace distance (T) and the fidelity (F) are related by T = sqrt1-F^2:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"tracedist(x, y) ≈ sqrt(1 - (fidelity(x, y))^2)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"For a pure state and a mixed state, 1 - F leq T which can also be verified:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"1 - fidelity(x, z) < tracedist(x, z)","category":"page"},{"location":"users_guide/states_and_operators/#doc:Two-level-systems","page":"Manipulating States and Operators","title":"Two-level systems (Qubits)","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Having spent a fair amount of time on basis states that represent harmonic oscillator states, we now move on to qubit, or two-level quantum systems (for example a spin-12). To create a state vector corresponding to a qubit system, we use the same basis, or fock, function with only two levels:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"spin = basis(2, 0)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Now at this point one may ask how this state is different than that of a harmonic oscillator in the vacuum state truncated to two energy levels?","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(2, 0)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"At this stage, there is no difference. This should not be surprising as we called the exact same function twice. The difference between the two comes from the action of the spin operators sigmax, sigmay, sigmaz, sigmap, and sigmam on these two-level states. For example, if vac corresponds to the vacuum state of a harmonic oscillator, then, as we have already seen, we can use the raising operator (create) to get the 1rangle state:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"create(2) * vac","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"For a spin system, the operator analogous to the raising operator is the hatsigma_+ operator sigmap. Applying on the spin state gives:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmap() * spin","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Now we see the difference! The sigmap operator acting on the spin state returns the zero vector. Why is this? To see what happened, let us use the hatsigma_z (sigmaz) operator:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmaz()","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmaz() * spin","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"spin2 = basis(2, 1)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"sigmaz() * spin2","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The answer is now apparent. Since the QuantumToolbox sigmaz function uses the standard Z-basis representation of the hatsigma_z spin operator, the spin state corresponds to the uparrowrangle state of a two-level spin system while spin2 gives the downarrowrangle state. Therefore, in our previous example sigmap() * spin, we raised the qubit state out of the truncated two-level Hilbert space resulting in the zero state.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"While at first glance this convention might seem somewhat odd, it is in fact quite handy. For one, the spin operators remain in the conventional form. Second, this corresponds nicely with the quantum information definitions of qubit states, where the excited uparrowrangle state is label as 0rangle, and the downarrowrangle state by 1rangle.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"If one wants to create spin operators for higher spin systems, then the jmat function comes in handy.","category":"page"},{"location":"users_guide/states_and_operators/#doc:Expectation-values","page":"Manipulating States and Operators","title":"Expectation values","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Some of the most important information about quantum systems comes from calculating the expectation value of operators, both Hermitian and non-Hermitian, as the state or density matrix of the system varies in time. Therefore, in this section we demonstrate the use of the expect function. To begin:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vac = basis(5, 0)\n\none = basis(5, 1)\n\nc = create(5)\n\nN = num(5)\n\ncoh = coherent_dm(5, 1.0im)\n\ncat = normalize(basis(5, 4) + 1.0im * basis(5, 3))\n\nprintln(expect(N, vac) ≈ 0)\nprintln(expect(N, one) ≈ 1)\nprintln(expect(N, coh) ≈ 0.9970555745806597)\nprintln(expect(c, cat) ≈ 1im)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The expect function also accepts lists or arrays of state vectors or density matrices for the second input:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"states = [normalize(c^k * vac) for k in 0:4]\n\nexpect(N, states)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"cat_list = [normalize(basis(5, 4) + x * basis(5, 3)) for x in [0, 1.0im, -1.0, -1.0im]]\n\nexpect(c, cat_list)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Notice how in this last example, all of the return values are complex numbers. This is because the expect function looks to see whether the operator is Hermitian or not. If the operator is Hermitian, then the output will always be real. In the case of non-Hermitian operators, the return values may be complex. Therefore, the expect function will return an array of complex values for non-Hermitian operators when the input is a list/array of states or density matrices.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Of course, the expect function works for spin states and operators:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"up = basis(2, 0)\n\ndn = basis(2, 1)\n\nprintln(expect(sigmaz(), up) ≈ 1)\nprintln(expect(sigmaz(), dn) ≈ -1)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"as well as the composite objects discussed in the next section Tensor Products and Partial Traces:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"spin1 = basis(2, 0)\n\nspin2 = basis(2, 1)\n\ntwo_spins = tensor(spin1, spin2)\n\nsz1 = tensor(sigmaz(), qeye(2))\n\nsz2 = tensor(qeye(2), sigmaz())\n\nprintln(expect(sz1, two_spins) ≈ 1)\nprintln(expect(sz2, two_spins) ≈ -1)","category":"page"},{"location":"users_guide/states_and_operators/#doc:Superoperators-and-Vectorized-Operators","page":"Manipulating States and Operators","title":"Superoperators and Vectorized Operators","text":"","category":"section"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"In addition to state vectors and density operators, QuantumToolbox allows for representing maps that act linearly on density operators using the Liouville supermatrix formalisms.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"This support is based on the correspondence between linear operators acting on a Hilbert space, and vectors in two copies of that Hilbert space (which is also called the Fock-Liouville space), ","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"textrmvec mathcalL(mathcalH) rightarrow mathcalHotimesmathcalH","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Therefore, a given density matrix hatrho can then be vectorized, denoted as ","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"hatrhoranglerangle = textrmvec(hatrho)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"QuantumToolbox uses the column-stacking convention for the isomorphism between mathcalL(mathcalH) and mathcalHotimesmathcalH. This isomorphism is implemented by the functions mat2vec and vec2mat:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"rho = Qobj([1 2; 3 4])","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"vec_rho = mat2vec(rho)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"rho2 = vec2mat(vec_rho)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"The QuantumObject.type attribute indicates whether a quantum object is a vector corresponding to an OperatorKet, or its Hermitian conjugate OperatorBra. One can also use isoper, isoperket, and isoperbra to check the type:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"println(isoper(vec_rho))\nprintln(isoperket(vec_rho))\nprintln(isoperbra(vec_rho))\nprintln(isoper(vec_rho'))\nprintln(isoperket(vec_rho'))\nprintln(isoperbra(vec_rho'))","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"Because Julia is a column-oriented languages (like Fortran and MATLAB), in QuantumToolbox, we define the spre (left), spost (right), and sprepost (left-and-right) multiplication superoperators as follows:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"beginalign\nhatAhatrho rightarrow textrmspre(hatA) * textrmvec(hatrho) = hatmathbb1otimes hatA hatrhorangleranglenotag\nhatrho hatB rightarrow textrmspost(hatB) * textrmvec(hatrho) = hatB^Totimes hatmathbb1 hatrhorangleranglenotag\nhatA hatrho hatB rightarrow textrmsprepost(hatAhatB) * textrmvec(hatrho) = hatB^Totimes hatA hatrhorangleranglenotag\nendalign","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"where hatmathbb1 represents the identity operator with Hilbert space dimension equal to hatrho.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"A = Qobj([1 2; 3 4])\nS_A = spre(A)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"B = Qobj([5 6; 7 8])\nS_B = spost(B)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"S_AB = sprepost(A, B)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"S_AB ≈ S_A * S_B ≈ S_B * S_A","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"One can also use issuper to check the type:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"println(isoper(S_AB))\nprintln(issuper(S_AB))","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"With the above definitions, the following equalities hold in Julia:","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"textrmvec(hatA hatrho hatB) = textrmspre(hatA) * textrmspre(hatB) * textrmvec(hatrho) = textrmsprepost(hatAhatB) * textrmvec(hatrho) forallhatA hatB hatrho","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"N = 10\nA = Qobj(rand(ComplexF64, N, N))\nB = Qobj(rand(ComplexF64, N, N))\nρ = rand_dm(N) # random density matrix\nmat2vec(A * ρ * B) ≈ spre(A) * spost(B) * mat2vec(ρ) ≈ sprepost(A, B) * mat2vec(ρ)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"In addition, dynamical generators on this extended space, often called Liouvillian superoperators, can be created using the liouvillian function. Each of these takes a Hamiltonian along with a list of collapse operators, and returns a type=SuperOperator object that can be exponentiated to find the superoperator for that evolution.","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"H = 10 * sigmaz()\n\nc = destroy(2)\n\nL = liouvillian(H, [c])","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"t = 0.8\nexp(L * t)","category":"page"},{"location":"users_guide/states_and_operators/","page":"Manipulating States and Operators","title":"Manipulating States and Operators","text":"See the section Lindblad Master Equation Solver for more details.","category":"page"},{"location":"users_guide/tensor/#doc:Tensor-products-and-Partial-Traces","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/tensor/#doc:Tensor-products","page":"Tensor Products and Partial Traces","title":"Tensor products","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"To describe the states of multipartite quantum systems (such as two coupled qubits, a qubit coupled to an oscillator, etc.) we need to expand the Hilbert space by taking the tensor product of the state vectors for each of the system components. Similarly, the operators acting on the state vectors in the combined Hilbert space (describing the coupled system) are formed by taking the tensor product of the individual operators.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"In QuantumToolbox, the function tensor (or kron) is used to accomplish this task. This function takes a collection of Ket or Operator as argument and returns a composite QuantumObject for the combined Hilbert space. The function accepts an arbitrary number of QuantumObject as argument. The type of returned QuantumObject is the same as that of the input(s).","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"A collection of QuantumObject:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(sigmax(), sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"or a Vector{QuantumObject}:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"op_list = fill(sigmax(), 3)\ntensor(op_list)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"warning: Beware of type-stability!\nPlease note that tensor(op_list) or kron(op_list) with op_list is a Vector is type-instable and can hurt performance. It is recommended to use tensor(op_list...) or kron(op_list...) instead. See the Section The Importance of Type-Stability for more details.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"For example, the state vector describing two qubits in their ground states is formed by taking the tensor product of the two single-qubit ground state vectors:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(basis(2, 0), basis(2, 0))","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"One can generalize to more qubits by adding more component state vectors in the argument list to the tensor (or kron) function, as illustrated in the following example:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"states = QuantumObject[\n normalize(basis(2, 0) + basis(2, 1)),\n normalize(basis(2, 0) + basis(2, 1)),\n basis(2, 0)\n]\ntensor(states...)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"This state is slightly more complicated, describing two qubits in a superposition between the up and down states, while the third qubit is in its ground state.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"To construct operators that act on an extended Hilbert space of a combined system, we similarly pass a list of operators for each component system to the tensor (or kron) function. For example, to form the operator that represents the simultaneous action of the hatsigma_x operator on two qubits:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"To create operators in a combined Hilbert space that only act on a single component, we take the tensor product of the operator acting on the subspace of interest, with the identity operators corresponding to the components that are to be unchanged. For example, the operator that represents hatsigma_z on the first qubit in a two-qubit system, while leaving the second qubit unaffected:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"tensor(sigmaz(), qeye(2))","category":"page"},{"location":"users_guide/tensor/#Example:-Constructing-composite-Hamiltonians","page":"Tensor Products and Partial Traces","title":"Example: Constructing composite Hamiltonians","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The tensor (or kron) function is extensively used when constructing Hamiltonians for composite systems. Here we’ll look at some simple examples.","category":"page"},{"location":"users_guide/tensor/#Two-coupled-qubits","page":"Tensor Products and Partial Traces","title":"Two coupled qubits","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"First, let’s consider a system of two coupled qubits. Assume that both the qubits have equal energy splitting, and that the qubits are coupled through a hatsigma_x otimes hatsigma_x interaction with strength g = 005 (in units where the bare qubit energy splitting is unity). The Hamiltonian describing this system is:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"H = tensor(sigmaz(), qeye(2)) + \n tensor(qeye(2), sigmaz()) + \n 0.05 * tensor(sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/#Three-coupled-qubits","page":"Tensor Products and Partial Traces","title":"Three coupled qubits","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The two-qubit example is easily generalized to three coupled qubits:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"H = tensor(sigmaz(), qeye(2), qeye(2)) + \n tensor(qeye(2), sigmaz(), qeye(2)) + \n tensor(qeye(2), qeye(2), sigmaz()) + \n 0.5 * tensor(sigmax(), sigmax(), qeye(2)) + \n 0.25 * tensor(qeye(2), sigmax(), sigmax())","category":"page"},{"location":"users_guide/tensor/#A-two-level-system-coupled-to-a-cavity:-The-Jaynes-Cummings-model","page":"Tensor Products and Partial Traces","title":"A two-level system coupled to a cavity: The Jaynes-Cummings model","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The simplest possible quantum mechanical description for light-matter interaction is encapsulated in the Jaynes-Cummings model, which describes the coupling between a two-level atom and a single-mode electromagnetic field (a cavity mode). Denoting the energy splitting of the atom and cavity omega_a and omega_c, respectively, and the atom-cavity interaction strength g, the Jaynes-Cummings Hamiltonian can be constructed as:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"H = fracomega_a2hatsigma_z + omega_c hata^dagger hata + g (hata^dagger hatsigma_- + hata hatsigma_+)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"N = 6 # cavity fock space truncation\nωc = 1.25 # frequency of cavity\nωa = 1.0 # frequency of two-level atom\ng = 0.75 # interaction strength\n\na = tensor(qeye(2), destroy(N)) # cavity annihilation operator\n\n# two-level atom operators\nσm = tensor(destroy(2), qeye(N))\nσz = tensor(sigmaz(), qeye(N))\n\nH = 0.5 * ωa * σz + ωc * a' * a + g * (a' * σm + a * σm')","category":"page"},{"location":"users_guide/tensor/#doc:Partial-trace","page":"Tensor Products and Partial Traces","title":"Partial trace","text":"","category":"section"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"The partial trace is an operation that reduces the dimension of a Hilbert space by eliminating some degrees of freedom by averaging (tracing). In this sense it is therefore the converse of the tensor product. It is useful when one is interested in only a part of a coupled quantum system. For open quantum systems, this typically involves tracing over the environment leaving only the system of interest. In QuantumToolbox the function ptrace is used to take partial traces. ptrace takes one QuantumObject as an input, and also one argument sel, which marks the component systems that should be kept, and all the other components are traced out. ","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"Remember that the index of Julia starts from 1, and all the elements in sel should be positive Integer. Therefore, the type of sel can be either Integer, Tuple, SVector, or Vector.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"warning: Beware of type-stability!\nAlthough it supports also Vector type, it is recommended to use Tuple or SVector from StaticArrays.jl to improve performance. For a brief explanation on the impact of the type of sel, see the section The Importance of Type-Stability.","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"For example, the density matrix describing a single qubit obtained from a coupled two-qubit system is obtained via:","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ψ = tensor(\n basis(2, 0), \n basis(2, 1), \n normalize(basis(2, 0) + basis(2, 1))\n)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ψ, 1) # trace out 2nd and 3rd systems","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ψ, (1, 3)) # trace out 2nd system","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"Note that the partial trace always results in a Operator (density matrix), regardless of whether the composite system is a pure state (described by a Ket) or a mixed state (described by a Operator):","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ψ1 = normalize(basis(2, 0) + basis(2, 1))\nψ2 = basis(2, 0)\nψT = tensor(ψ1, ψ2)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ψT, 1)","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ρT = tensor(ket2dm(ψ1), ket2dm(ψ1))","category":"page"},{"location":"users_guide/tensor/","page":"Tensor Products and Partial Traces","title":"Tensor Products and Partial Traces","text":"ptrace(ρT, 1)","category":"page"},{"location":"users_guide/steadystate/#doc:Solving-for-Steady-State-Solutions","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"","category":"section"},{"location":"users_guide/steadystate/#Introduction","page":"Solving for Steady-State Solutions","title":"Introduction","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"For time-independent open quantum systems with decay rates larger than the corresponding excitation rates, the system will tend toward a steady state as trightarrowinfty that satisfies the equation","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"fracdhatrho_textrmssdt = mathcalLhatrho_textrmss=0","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Although the requirement for time-independence seems quite restrictive, one can often employ a transformation to the interaction picture that yields a time-independent Hamiltonian. For many these systems, solving for the asymptotic density matrix hatrho_textrmss can be achieved using direct or iterative solution methods faster than using master equation or Monte-Carlo simulations. Although the steady state equation has a simple mathematical form, the properties of the Liouvillian operator are such that the solutions to this equation are anything but straightforward to find.","category":"page"},{"location":"users_guide/steadystate/#Steady-State-solvers-in-QuantumToolbox.jl","page":"Solving for Steady-State Solutions","title":"Steady State solvers in QuantumToolbox.jl","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"In QuantumToolbox.jl, the steady-state solution for a system Hamiltonian or Liouvillian is given by steadystate. This function implements a number of different methods for finding the steady state, each with their own pros and cons, where the method used can be chosen using the solver keyword argument.","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Solver Description\nSteadyStateDirectSolver() Directly solve Ax=b using the standard method given in Julia LinearAlgebra\nSteadyStateLinearSolver() Directly solve Ax=b using the algorithms given in LinearSolve.jl\nSteadyStateEigenSolver() Find the zero (or lowest) eigenvalue of mathcalL using eigsolve\nSteadyStateODESolver() Solving time evolution with algorithms given in DifferentialEquations.jl (ODE Solvers)","category":"page"},{"location":"users_guide/steadystate/#Using-Steady-State-solvers","page":"Solving for Steady-State Solutions","title":"Using Steady State solvers","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"The function steadystate can take either a Hamiltonian and a list of collapse operators c_ops as input, generating internally the corresponding Liouvillian mathcalL in Lindblad form, or alternatively, a Liouvillian mathcalL passed by the user.","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"ρ_ss = steadystate(H) # Hamiltonian\nρ_ss = steadystate(H, c_ops) # Hamiltonian and collapse operators\nρ_ss = steadystate(L) # Liouvillian","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"where H is a quantum object representing the system Hamiltonian (Operator) or Liouvillian (SuperOperator), and c_ops (defaults to nothing) can be a list of QuantumObject for the system collapse operators. The output, labelled as ρ_ss, is the steady-state solution for the systems. If no other keywords are passed to the function, the default solver SteadyStateDirectSolver() is used.","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"To change a solver, use the keyword argument solver, for example:","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"ρ_ss = steadystate(H, c_ops; solver = SteadyStateLinearSolver())","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"note: Initial state for `SteadyStateODESolver()`\nIt is necessary to provide the initial state ψ0 for ODE solving method, namely steadystate(H, ψ0, tspan, c_ops, solver = SteadyStateODESolver()), where tspan::Real represents the final time step, defaults to Inf (infinity).","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Although it is not obvious, the SteadyStateDirectSolver() and SteadyStateEigenSolver() methods all use an LU decomposition internally and thus can have a large memory overhead. In contrast, for SteadyStateLinearSolver(), iterative algorithms provided by LinearSolve.jl, such as KrylovJL_GMRES() and KrylovJL_BICGSTAB(), do not factor the matrix and thus take less memory than the LU methods and allow, in principle, for extremely large system sizes. The downside is that these methods can take much longer than the direct method as the condition number of the Liouvillian matrix is large, indicating that these iterative methods require a large number of iterations for convergence. ","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"To overcome this, one can provide preconditioner that solves for an approximate inverse for the (modified) Liouvillian, thus better conditioning the problem, leading to faster convergence. The left and right preconditioner can be specified as the keyword argument Pl and Pr, respectively:","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"solver = SteadyStateLinearSolver(alg = KrylovJL_GMRES(), Pl = Pl, Pr = Pr)","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"The use of a preconditioner can actually make these iterative methods faster than the other solution methods. The problem with precondioning is that it is only well defined for Hermitian matrices. Since the Liouvillian is non-Hermitian, the ability to find a good preconditioner is not guaranteed. Moreover, if a preconditioner is found, it is not guaranteed to have a good condition number. ","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Furthermore, QuantiumToolbox can take advantage of the Intel (Pardiso) LU solver in the Intel Math Kernel library (Intel-MKL) by using LinearSolve.jl and either Pardiso.jl or MKL_jll.jl:","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"using QuantumToolbox\nusing LinearSolve # must be loaded\n\nusing Pardiso\nsolver = SteadyStateLinearSolver(alg = MKLPardisoFactorize())\n\nusing MKL_jll\nsolver = SteadyStateLinearSolver(alg = MKLLUFactorization())","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"See LinearSolve.jl Solvers for more details.","category":"page"},{"location":"users_guide/steadystate/#Example:-Harmonic-oscillator-in-thermal-bath","page":"Solving for Steady-State Solutions","title":"Example: Harmonic oscillator in thermal bath","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"Here, we demonstrate steadystate by using the example with the harmonic oscillator in thermal bath from the previous section (Lindblad Master Equation Solver).","category":"page"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"using QuantumToolbox\nusing CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\n# Define parameters\nN = 20 # number of basis states to consider\na = destroy(N)\nH = a' * a\nψ0 = basis(N, 10) # initial state\nκ = 0.1 # coupling to oscillator\nn_th = 2 # temperature with average of 2 excitations\n\n# collapse operators \nc_ops = [\n sqrt(κ * (n_th + 1)) * a, # emission\n sqrt(κ * n_th ) * a' # absorption\n]\n\n# find steady-state solution\nρ_ss = steadystate(H, c_ops)\n\n# find expectation value for particle number in steady state\ne_ops = [a' * a]\nexp_ss = real(expect(e_ops[1], ρ_ss))\n\ntlist = LinRange(0, 50, 100)\n\n# monte-carlo\nsol_mc = mcsolve(H, ψ0, tlist, c_ops, e_ops=e_ops, ntraj=100, progress_bar=false)\nexp_mc = real(sol_mc.expect[1, :])\n\n# master eq.\nsol_me = mesolve(H, ψ0, tlist, c_ops, e_ops=e_ops, progress_bar=false)\nexp_me = real(sol_me.expect[1, :])\n\n# plot the results\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], \n title = L\"Decay of Fock state $|10\\rangle$ in a thermal environment with $\\langle n\\rangle=2$\",\n xlabel = \"Time\", \n ylabel = \"Number of excitations\",\n)\nlines!(ax, tlist, exp_mc, label = \"Monte-Carlo\", linewidth = 2, color = :blue)\nlines!(ax, tlist, exp_me, label = \"Master Equation\", linewidth = 2, color = :orange, linestyle = :dash)\nlines!(ax, tlist, exp_ss .* ones(length(tlist)), label = \"Steady State\", linewidth = 2, color = :red)\naxislegend(ax, position = :rt)\n\nfig","category":"page"},{"location":"users_guide/steadystate/#Calculate-steady-state-for-periodically-driven-systems","page":"Solving for Steady-State Solutions","title":"Calculate steady state for periodically driven systems","text":"","category":"section"},{"location":"users_guide/steadystate/","page":"Solving for Steady-State Solutions","title":"Solving for Steady-State Solutions","text":"See the docstring of steadystate_floquet for more details.","category":"page"},{"location":"users_guide/time_evolution/solution/#doc-TE:Time-Evolution-Solutions","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/time_evolution/solution/#Solution","page":"Time Evolution Solutions","title":"Solution","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"QuantumToolbox utilizes the powerful DifferentialEquation.jl to simulate different kinds of quantum system dynamics. Thus, we will first look at the data structure used for returning the solution (sol) from DifferentialEquation.jl. The solution stores all the crucial data needed for analyzing and plotting the results of a simulation. A generic structure TimeEvolutionSol contains the following properties for storing simulation data:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Fields (Attributes) Description\nsol.times The time list of the evolution.\nsol.states The list of result states.\nsol.expect The expectation values corresponding to each time point in sol.times.\nsol.alg The algorithm which is used during the solving process.\nsol.abstol The absolute tolerance which is used during the solving process.\nsol.reltol The relative tolerance which is used during the solving process.\nsol.retcode (or sol.converged) The returned status from the solver.","category":"page"},{"location":"users_guide/time_evolution/solution/#Accessing-data-in-solutions","page":"Time Evolution Solutions","title":"Accessing data in solutions","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"To understand how to access the data in solution, we will use an example as a guide, although we do not worry about the simulation details at this stage. The Schrödinger equation solver (sesolve) used in this example returns TimeEvolutionSol:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"H = 0.5 * sigmay()\nψ0 = basis(2, 0)\ne_ops = [\n proj(basis(2, 0)),\n proj(basis(2, 1)),\n basis(2, 0) * basis(2, 1)'\n]\ntlist = LinRange(0, 10, 100)\nsol = sesolve(H, ψ0, tlist, e_ops = e_ops, progress_bar = Val(false))\nnothing # hide","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"To see what is contained inside the solution, we can use the print function:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"print(sol)","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"It tells us the number of expectation values are computed and the number of states are stored. Now we have all the information needed to analyze the simulation results. To access the data for the three expectation values, one can do:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"expt1 = real(sol.expect[1,:])\nexpt2 = real(sol.expect[2,:])\nexpt3 = real(sol.expect[3,:])\nnothing # hide","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Recall that Julia uses Fortran-style indexing that begins with one (i.e., [1,:] represents the 1-st observable, where : represents all values corresponding to tlist).","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Together with the array of times at which these expectation values are calculated:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"times = sol.times\nnothing # hide","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"we can plot the resulting expectation values:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"using CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = L\"t\")\nlines!(ax, times, expt1, label = L\"\\langle 0 | \\rho(t) | 0 \\rangle\")\nlines!(ax, times, expt2, label = L\"\\langle 1 | \\rho(t) | 1 \\rangle\")\nlines!(ax, times, expt3, label = L\"\\langle 0 | \\rho(t) | 1 \\rangle\")\n\nylims!(ax, (-0.5, 1.0))\naxislegend(ax, position = :lb)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"State vectors, or density matrices, are accessed in a similar manner:","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"sol.states","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Here, the solution contains only one (final) state. Because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). One can also specify e_ops and saveat separately.","category":"page"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"Some other solvers can have other output.","category":"page"},{"location":"users_guide/time_evolution/solution/#Multiple-trajectories-solution","page":"Time Evolution Solutions","title":"Multiple trajectories solution","text":"","category":"section"},{"location":"users_guide/time_evolution/solution/","page":"Time Evolution Solutions","title":"Time Evolution Solutions","text":"This part is still under construction, please visit API first.","category":"page"},{"location":"users_guide/time_evolution/intro/#doc:Time-Evolution-and-Quantum-System-Dynamics","page":"Introduction","title":"Time Evolution and Quantum System Dynamics","text":"","category":"section"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Table of contents","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Pages = [\n \"intro.md\",\n \"solution.md\",\n \"sesolve.md\",\n \"mesolve.md\",\n \"mcsolve.md\",\n \"stochastic.md\",\n \"time_dependent.md\",\n]\nDepth = 1:2","category":"page"},{"location":"users_guide/time_evolution/intro/#doc-TE:Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Although in some cases, we want to find the stationary states of a quantum system, often we are interested in the dynamics: how the state of a system or an ensemble of systems evolves with time. QuantumToolbox provides many ways to model dynamics.","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"There are two kinds of quantum systems: open systems that interact with a larger environment and closed systems that do not. In a closed system, the state can be described by a state vector. When we are modeling an open system, or an ensemble of systems, the use of the density matrix is mandatory.","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"The following table lists the solvers provided by QuantumToolbox for dynamic quantum systems and the corresponding type of solution returned by the solver:","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"Equation Function Call Problem Returned Solution\nUnitary evolution, Schrödinger equation sesolve sesolveProblem TimeEvolutionSol\nLindblad master eqn. or Von Neuman eqn. mesolve mesolveProblem TimeEvolutionSol\nMonte Carlo evolution mcsolve mcsolveProblem mcsolveEnsembleProblem TimeEvolutionMCSol\nStochastic Schrödinger equation ssesolve ssesolveProblem ssesolveEnsembleProblem TimeEvolutionSSESol","category":"page"},{"location":"users_guide/time_evolution/intro/","page":"Introduction","title":"Introduction","text":"note: Solving dynamics with pre-defined problems\nQuantumToolbox 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 problems by yourself and take it as an input of the function call, e.g., sesolve(prob).","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#doc:Functions-operating-on-Qobj","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"QuantumToolbox also provide functions (methods) that operates on QuantumObject.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"You can click the function links and see the corresponding docstring for more information.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#Linear-algebra-and-attributes","page":"Functions operating on Qobj","title":"Linear algebra and attributes","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"Here is a table that summarizes all the supported linear algebra functions and attribute functions operating on a given QuantumObject Q:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"Description Function call Synonyms\nconjugate conj(Q) -\ntranspose transpose(Q) trans(Q)\nconjugate transposition adjoint(Q) Q', dag(Q)\npartial transpose partial_transpose(Q, mask) -\ndot product dot(Q1, Q2) -\ngeneralized dot product dot(Q1, Q2, Q3) matrix_element(Q1, Q2, Q3)\ntrace tr(Q) -\npartial trace ptrace(Q, sel) -\nsingular values svdvals(Q) -\nstandard vector p-norm or Schatten p-norm norm(Q, p) -\nnormalization normalize(Q, p) unit(Q, p)\nnormalization (in-place) normalize!(Q, p) -\nmatrix inverse inv(Q) -\nmatrix square root sqrt(Q) √(Q), sqrtm(Q)\nmatrix logarithm log(Q) logm(Q)\nmatrix exponential exp(Q) expm(Q)\nmatrix sine sin(Q) sinm(Q)\nmatrix cosine cos(Q) cosm(Q)\ndiagonal elements diag(Q) -\nprojector proj(Q) -\npurity purity(Q) -\npermute permute(Q, order) -\nremove small elements tidyup(Q, tol) -\nremove small elements (in-place) tidyup!(Q, tol) -\nget data get_data(Q) -\nget coherence get_coherence(Q) -","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#Eigenvalue-decomposition","page":"Functions operating on Qobj","title":"Eigenvalue decomposition","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"eigenenergies: return eigenenergies (eigenvalues)\neigenstates: return EigsolveResult (contains eigenvalues and eigenvectors)\neigvals: return eigenvalues\neigen: using dense eigen solver and return EigsolveResult (contains eigenvalues and eigenvectors)\neigsolve: using sparse eigen solver and return EigsolveResult (contains eigenvalues and eigenvectors)\neigsolve_al: using the Arnoldi-Lindblad eigen solver and return EigsolveResult (contains eigenvalues and eigenvectors)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/#Examples","page":"Functions operating on Qobj","title":"Examples","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ψ = normalize(basis(4, 1) + basis(4, 2))","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ψ'","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ρ = coherent_dm(5, 1)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"diag(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"get_data(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"norm(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"sqrtm(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"tr(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"eigenenergies(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"result = eigenstates(ρ)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"λ, ψ = result\nλ # eigenvalues","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"ψ # eigenvectors","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject_functions/","page":"Functions operating on Qobj","title":"Functions operating on Qobj","text":"λ, ψ, T = result\nT # transformation matrix","category":"page"},{"location":"users_guide/time_evolution/mesolve/#doc-TE:Lindblad-Master-Equation-Solver","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Von-Neumann-equation","page":"Lindblad Master Equation Solver","title":"Von Neumann equation","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"While the evolution of the state vector in a closed quantum system is deterministic (as we discussed in the previous section: Schrödinger Equation Solver), open quantum systems are stochastic in nature. The effect of an environment on the system of interest is to induce stochastic transitions between energy levels, and to introduce uncertainty in the phase difference between states of the system. The state of an open quantum system is therefore described in terms of ensemble averaged states using the density matrix formalism. A density matrix hatrho describes a probability distribution of quantum states psi_nrangle in a matrix representation, namely","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"hatrho = sum_n p_n psi_nranglelanglepsi_n","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"where p_n is the classical probability that the system is in the quantum state psi_nrangle. The time evolution of a density matrix hatrho is the topic of the remaining portions of this section.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"The time evolution of the density matrix hatrho(t) under closed system dynamics is governed by the von Neumann equation: ","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"beginequation\nlabelvon-Neumann-Eq\nfracddthatrho(t) = -fracihbarlefthatH hatrho(t)right\nendequation","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"where cdot cdot represents the commutator. The above equation is equivalent to the Schrödinger equation described in the previous section under the density matrix formalism.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"In QuantumToolbox, given a Hamiltonian, we can calculate the unitary (non-dissipative) time-evolution of an arbitrary initial state using the QuantumToolbox time evolution problem mesolveProblem or directly call the function mesolve. It evolves the density matrix hatrho(t) and evaluates the expectation values for a set of operators e_ops at each given time points, using an ordinary differential equation solver provided by the powerful julia package DifferentialEquation.jl.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"H = 0.5 * sigmax()\nstate0 = basis(2, 0) # state vector\nstate0 = ket2dm(basis(2, 0)) # density matrix\ntlist = LinRange(0.0, 10.0, 20)\n\nsol = mesolve(H, state0, tlist, e_ops = [sigmaz()])","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"note: Type of initial state\nThe initial state state0 here can be given as a state vector psi(0)rangle (in the type of Ket) or a density matrix hatrho(0) (in the type of Operator). If it is given as a Ket, it will be transformed to density matrix hatrho(0) = psi(0)ranglelanglepsi(0) internally in mesolve.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"The function returns TimeEvolutionSol, as described in the previous section Time Evolution Solutions. The stored states will always be in the type of Operator (density matrix).","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"sol.states","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Here, only the final state is stored because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). ","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"One can also specify e_ops and saveat separately:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"tlist = [0, 5, 10]\nsol = mesolve(H, state0, tlist, e_ops = [sigmay()], saveat = tlist)","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"sol.expect","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"sol.states","category":"page"},{"location":"users_guide/time_evolution/mesolve/#The-Lindblad-master-equation","page":"Lindblad Master Equation Solver","title":"The Lindblad master equation","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"The standard approach for deriving the equations of motion for a system interacting with its environment is to expand the scope of the system to include the environment. The combined quantum system is then closed, and its evolution is governed by the von Neumann equation given in Eq. \\eqref{von-Neumann-Eq}","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"beginequation\nlabeltot-von-Neumann-Eq\nfracddthatrho_textrmtot(t) = -fracihbarlefthatH_textrmtot hatrho_textrmtot(t)right\nendequation","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Here, the total Hamiltonian","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"hatH_textrmtot = hatH_textrmsys + hatH_textrmenv + hatH_textrmint","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"includes the original system Hamiltonian hatH_textrmsys, the Hamiltonian for the environment hatH_textrmenv, and a term representing the interaction between the system and its environment hatH_textrmint. Since we are only interested in the dynamics of the system, we can, perform a partial trace over the environmental degrees of freedom in Eq. \\eqref{tot-von-Neumann-Eq}, and thereby obtain a master equation for the motion of the original system density matrix hatrho_textrmsys(t)=textrmTr_textrmenvhatrho_textrmtot(t). The most general trace-preserving and completely positive form of this evolution is the Lindblad master equation for the reduced density matrix, namely","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"beginequation\nlabelLindblad-master-Eq\nfracddthatrho_textrmsys(t) = -fracihbarlefthatH_textrmsys hatrho_textrmsys(t)right + sum_n hatC_n hatrho_textrmsys(t) hatC_n^dagger - frac12 hatC_n^dagger hatC_n hatrho_textrmsys(t) - frac12 hatrho_textrmsys(t) hatC_n^dagger hatC_n\nendequation","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"where hatC_n equiv sqrtgamma_nhatA_n are the collapse operators, hatA_n are the operators acting on the system in hatH_textrmint which describes the system-environment interaction, and gamma_n are the corresponding rates. The derivation of Eq. \\eqref{Lindblad-master-Eq} may be found in several sources, and will not be reproduced here. Instead, we emphasize the approximations that are required to arrive at the master equation in the form of Eq. \\eqref{Lindblad-master-Eq} from physical arguments, and hence perform a calculation in QuantumToolbox:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Separability: At t = 0, there are no correlations between the system and environment, such that the total density matrix can be written as a tensor product, namely hatrho_textrmtot(0)=hatrho_textrmsys(0)otimeshatrho_textrmenv(0).\nBorn approximation: Requires: (i) the state of the environment does not significantly change as a result of the interaction with the system; (ii) the system and the environment remain separable throughout the evolution. These assumptions are justified if the interaction is weak, and if the environment is much larger than the system. In summary, hatrho_textrmtot(t)approxhatrho_textrmsys(t)otimeshatrho_textrmenv(0).\nMarkov approximation: The time-scale of decay for the environment tau_textrmenv is much shorter than the smallest time-scale of the system dynamics, i.e., tau_textrmsysggtau_textrmenv. This approximation is often deemed a “short-memory environment” as it requires the environmental correlation functions decay in a fast time-scale compared to those of the system.\nSecular approximation: Stipulates that elements in the master equation corresponding to transition frequencies satisfy omega_ab-omega_cd ll 1tau_textrmsys, i.e., all fast rotating terms in the interaction picture can be neglected. It also ignores terms that lead to a small renormalization of the system energy levels. This approximation is not strictly necessary for all master-equation formalisms (e.g., the Block-Redfield master equation), but it is required for arriving at the Lindblad form in Eq. \\eqref{Lindblad-master-Eq} which is used in mesolve.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"For systems with environments satisfying the conditions outlined above, the Lindblad master equation in Eq. \\eqref{Lindblad-master-Eq} governs the time-evolution of the system density matrix, giving an ensemble average of the system dynamics. In order to ensure that these approximations are not violated, it is important that the decay rates gamma_n be smaller than the minimum energy splitting in the system Hamiltonian. Situations that demand special attention therefore include, for example, systems strongly coupled to their environment, and systems with degenerate or nearly degenerate energy levels.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"What is new in the master equation compared to the Schrödinger equation (or von Neumann equation) are processes that describe dissipation in the quantum system due to its interaction with an environment. For example, evolution that includes incoherent processes such as relaxation and dephasing. These environmental interactions are defined by the operators hatA_n through which the system couples to the environment, and rates gamma_n that describe the strength of the processes.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"In QuantumToolbox, the function mesolve can also be used for solving the master equation. This is done by passing a list of collapse operators (c_ops) as the fourth argument of the mesolve function in order to define the dissipation processes of the master equation in Eq. \\eqref{Lindblad-master-Eq}. As we mentioned above, each collapse operator hatC_n is the product of sqrtgamma_n (the square root of the rate) and hatA_n (operator which describes the dissipation process). ","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Furthermore, QuantumToolbox solves the master equation in the SuperOperator formalism. That is, a Liouvillian SuperOperator will be generated internally in mesolve by the input system Hamiltonian hatH_textrmsys and the collapse operators hatC_n. One can also generate the Liouvillian SuperOperator manually for special purposes, and pass it as the first argument of the mesolve function. To do so, it is useful to read the section Superoperators and Vectorized Operators, and also the docstrings of the following functions:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"spre\nspost\nsprepost\nliouvillian\nlindblad_dissipator","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Example:-Spin-dynamics","page":"Lindblad Master Equation Solver","title":"Example: Spin dynamics","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Using the example with the dynamics of spin-frac12 from the previous section (Schrödinger Equation Solver), we can easily add a relaxation process (describing the dissipation of energy from the spin to the environment), by adding [sqrt(γ) * sigmax()] in the fourth parameter of the mesolve function.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"H = 2 * π * 0.1 * sigmax()\nψ0 = basis(2, 0) # spin-up\ntlist = LinRange(0.0, 10.0, 100)\n\nγ = 0.05\nc_ops = [sqrt(γ) * sigmax()]\n\nsol = mesolve(H, ψ0, tlist, c_ops, e_ops = [sigmaz(), sigmay()])","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"We can therefore plot the expectation values:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"using CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\ntimes = sol.times\nexpt_z = real(sol.expect[1,:])\nexpt_y = real(sol.expect[2,:])\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = \"Time\", ylabel = \"Expectation values\")\nlines!(ax, times, expt_z, label = L\"\\langle\\hat{\\sigma}_z\\rangle\", linestyle = :solid)\nlines!(ax, times, expt_y, label = L\"\\langle\\hat{\\sigma}_y\\rangle\", linestyle = :dash)\n\naxislegend(ax, position = :rt)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Example:-Harmonic-oscillator-in-thermal-bath","page":"Lindblad Master Equation Solver","title":"Example: Harmonic oscillator in thermal bath","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Consider a harmonic oscillator (single-mode cavity) couples to a thermal bath. If the single-mode cavity initially is in a 10-photon fock state, the dynamics is calculated with the following code:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"# Define parameters\nN = 20 # number of basis states to consider\na = destroy(N)\nH = a' * a\nψ0 = fock(N, 10) # initial state\nκ = 0.1 # coupling to oscillator\nn_th = 2 # temperature with average of 2 excitations\ntlist = LinRange(0, 50, 100)\n\n# collapse operators \nc_ops = [\n sqrt(κ * (n_th + 1)) * a, # emission\n sqrt(κ * n_th ) * a' # absorption\n]\n\n# find expectation value for particle number\ne_ops = [a' * a]\n\nsol = mesolve(H, ψ0, tlist, c_ops, e_ops=e_ops)\nNum = real(sol.expect[1, :])\n\n# plot the results\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], \n title = L\"Decay of Fock state $|10\\rangle$ in a thermal environment with $\\langle n\\rangle=2$\",\n xlabel = \"Time\", \n ylabel = \"Number of excitations\",\n)\nlines!(ax, tlist, Num)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/mesolve/#Example:-Two-level-atom-coupled-to-dissipative-single-mode-cavity","page":"Lindblad Master Equation Solver","title":"Example: Two-level atom coupled to dissipative single-mode cavity","text":"","category":"section"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"Consider a two-level atom coupled to a dissipative single-mode cavity through a dipole-type interaction, which supports a coherent exchange of quanta between the two systems. If the atom initially is in its ground state and the cavity in a 5-photon fock state, the dynamics is calculated with the following code:","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"note: Generate Liouviilian superoperator manually\nIn this example, we demonstrate how to generate the Liouvillian SuperOperator manually and pass it as the first argument of the mesolve function.","category":"page"},{"location":"users_guide/time_evolution/mesolve/","page":"Lindblad Master Equation Solver","title":"Lindblad Master Equation Solver","text":"# two-level atom\nσm = tensor(destroy(2), qeye(10))\nH_a = 2 * π * σm' * σm\n\n# dissipative single-mode cavity\nγ = 0.1 # dissipation rate\na = tensor(qeye(2), destroy(10))\nH_c = 2 * π * a' * a\nc_ops = [sqrt(γ) * a]\n\n# coupling between two-level atom and single-mode cavity\ng = 0.25 # coupling strength\nH_I = 2 * π * g * (σm * a' + σm' * a)\n\nψ0 = tensor(basis(2,0), fock(10, 5)) # initial state\ntlist = LinRange(0.0, 10.0, 200)\n\n# generate Liouvillian superoperator manually\nL = liouvillian(H_a + H_c + H_I, c_ops)\nsol = mesolve(L, ψ0, tlist, e_ops=[σm' * σm, a' * a])\n\ntimes = sol.times\n\n# expectation value of Number operator\nN_atom = real(sol.expect[1,:])\nN_cavity = real(sol.expect[2,:])\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = \"Time\", ylabel = \"Expectation values\")\nlines!(ax, times, N_atom, label = \"atom excitation probability\", linestyle = :solid)\nlines!(ax, times, N_cavity, label = \"cavity photon number\", linestyle = :dash)\n\naxislegend(ax, position = :rt)\n\nfig","category":"page"},{"location":"api/","page":"API","title":"API","text":"CurrentModule = QuantumToolbox","category":"page"},{"location":"api/#doc-API","page":"API","title":"API","text":"","category":"section"},{"location":"api/#Contents","page":"API","title":"Contents","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Pages = [\"api.md\"]","category":"page"},{"location":"api/#doc-API:Quantum-object-and-type","page":"API","title":"Quantum object (Qobj) and type","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"BraQuantumObject\nBra\nKetQuantumObject\nKet\nOperatorQuantumObject\nOperator\nOperatorBraQuantumObject\nOperatorBra\nOperatorKetQuantumObject\nOperatorKet\nSuperOperatorQuantumObject\nSuperOperator\nQuantumObject\nOperatorSum\nsize\neltype\nlength\nisbra\nisket\nisoper\nisoperbra\nisoperket\nissuper\nLinearAlgebra.ishermitian\nLinearAlgebra.issymmetric\nLinearAlgebra.isposdef\nisunitary","category":"page"},{"location":"api/#QuantumToolbox.BraQuantumObject","page":"API","title":"QuantumToolbox.BraQuantumObject","text":"BraQuantumObject <: QuantumObjectType\n\nConstructor representing a bra state langlepsi.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.Bra","page":"API","title":"QuantumToolbox.Bra","text":"const Bra = BraQuantumObject()\n\nA constant representing the type of BraQuantumObject: a bra state langlepsi\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.KetQuantumObject","page":"API","title":"QuantumToolbox.KetQuantumObject","text":"KetQuantumObject <: QuantumObjectType\n\nConstructor representing a ket state psirangle.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.Ket","page":"API","title":"QuantumToolbox.Ket","text":"const Ket = KetQuantumObject()\n\nA constant representing the type of KetQuantumObject: a ket state psirangle\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.OperatorQuantumObject","page":"API","title":"QuantumToolbox.OperatorQuantumObject","text":"OperatorQuantumObject <: QuantumObjectType\n\nConstructor representing an operator hatO.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.Operator","page":"API","title":"QuantumToolbox.Operator","text":"const Operator = OperatorQuantumObject()\n\nA constant representing the type of OperatorQuantumObject: an operator hatO\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.OperatorBraQuantumObject","page":"API","title":"QuantumToolbox.OperatorBraQuantumObject","text":"OperatorBraQuantumObject <: QuantumObjectType\n\nConstructor representing a bra state in the SuperOperator formalism langlelanglerho.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.OperatorBra","page":"API","title":"QuantumToolbox.OperatorBra","text":"const OperatorBra = OperatorBraQuantumObject()\n\nA constant representing the type of OperatorBraQuantumObject: a bra state in the SuperOperator formalism langlelanglerho.\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.OperatorKetQuantumObject","page":"API","title":"QuantumToolbox.OperatorKetQuantumObject","text":"OperatorKetQuantumObject <: QuantumObjectType\n\nConstructor representing a ket state in the SuperOperator formalism rhoranglerangle.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.OperatorKet","page":"API","title":"QuantumToolbox.OperatorKet","text":"const OperatorKet = OperatorKetQuantumObject()\n\nA constant representing the type of OperatorKetQuantumObject: a ket state in the SuperOperator formalism rhoranglerangle\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.SuperOperatorQuantumObject","page":"API","title":"QuantumToolbox.SuperOperatorQuantumObject","text":"SuperOperatorQuantumObject <: QuantumObjectType\n\nConstructor representing a super-operator hatmathcalO acting on vectorized density operator matrices.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SuperOperator","page":"API","title":"QuantumToolbox.SuperOperator","text":"const SuperOperator = SuperOperatorQuantumObject()\n\nA constant representing the type of SuperOperatorQuantumObject: a super-operator hatmathcalO acting on vectorized density operator matrices\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.QuantumObject","page":"API","title":"QuantumToolbox.QuantumObject","text":"struct QuantumObject{MT<:AbstractArray,ObjType<:QuantumObjectType,N}\n data::MT\n type::ObjType\n dims::SVector{N, Int}\nend\n\nJulia struct representing any quantum objects.\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⎡⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⎤\n⎢⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⎥\n⎣⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⎦\n\njulia> a isa QuantumObject\ntrue\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.OperatorSum","page":"API","title":"QuantumToolbox.OperatorSum","text":"struct OperatorSum\n\nA constructor to represent a sum of operators sum_i c_i hatO_i with a list of coefficients c_i and a list of operators hatO_i.\n\nThis is very useful when we have to update only the coefficients, without allocating memory by performing the sum of the operators.\n\n\n\n\n\n","category":"type"},{"location":"api/#Base.size","page":"API","title":"Base.size","text":"size(A::QuantumObject)\nsize(A::QuantumObject, idx::Int)\n\nReturns a tuple containing each dimensions of the array in the QuantumObject.\n\nOptionally, you can specify an index (idx) to just get the corresponding dimension of the array.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.eltype","page":"API","title":"Base.eltype","text":"eltype(A::QuantumObject)\n\nReturns the elements type of the matrix or vector corresponding to the QuantumObject A.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.length","page":"API","title":"Base.length","text":"length(A::QuantumObject)\n\nReturns the length of the matrix or vector corresponding to the QuantumObject A.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isbra","page":"API","title":"QuantumToolbox.isbra","text":"isbra(A::QuantumObject)\n\nChecks if the QuantumObject A is a BraQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isket","page":"API","title":"QuantumToolbox.isket","text":"isket(A::QuantumObject)\n\nChecks if the QuantumObject A is a KetQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isoper","page":"API","title":"QuantumToolbox.isoper","text":"isoper(A::QuantumObject)\n\nChecks if the QuantumObject A is a OperatorQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isoperbra","page":"API","title":"QuantumToolbox.isoperbra","text":"isoperbra(A::QuantumObject)\n\nChecks if the QuantumObject A is a OperatorBraQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isoperket","page":"API","title":"QuantumToolbox.isoperket","text":"isoperket(A::QuantumObject)\n\nChecks if the QuantumObject A is a OperatorKetQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.issuper","page":"API","title":"QuantumToolbox.issuper","text":"issuper(A::QuantumObject)\n\nChecks if the QuantumObject A is a SuperOperatorQuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.ishermitian","page":"API","title":"LinearAlgebra.ishermitian","text":"ishermitian(A::QuantumObject)\n\nTest whether the QuantumObject is Hermitian.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.issymmetric","page":"API","title":"LinearAlgebra.issymmetric","text":"issymmetric(A::QuantumObject)\n\nTest whether the QuantumObject is symmetric.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.isposdef","page":"API","title":"LinearAlgebra.isposdef","text":"isposdef(A::QuantumObject)\n\nTest whether the QuantumObject is positive definite (and Hermitian) by trying to perform a Cholesky factorization of A.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isunitary","page":"API","title":"QuantumToolbox.isunitary","text":"isunitary(U::QuantumObject; kwargs...)\n\nTest whether the QuantumObject U is unitary operator. This function calls Base.isapprox to test whether U U^dagger is approximately equal to identity operator.\n\nNote that all the keyword arguments will be passed to Base.isapprox.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Qobj-arithmetic-and-attributes","page":"API","title":"Qobj arithmetic and attributes","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Base.conj\nLinearAlgebra.transpose\nLinearAlgebra.adjoint\nLinearAlgebra.dot\nLinearAlgebra.sqrt\nLinearAlgebra.log\nLinearAlgebra.exp\nLinearAlgebra.sin\nLinearAlgebra.cos\nLinearAlgebra.tr\nLinearAlgebra.svdvals\nLinearAlgebra.norm\nLinearAlgebra.normalize\nLinearAlgebra.normalize!\nLinearAlgebra.inv\nLinearAlgebra.diag\nproj\nptrace\npurity\npermute\ntidyup\ntidyup!\nget_data\nget_coherence\npartial_transpose","category":"page"},{"location":"api/#Base.conj","page":"API","title":"Base.conj","text":"conj(A::QuantumObject)\n\nReturn the element-wise complex conjugation of the QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.transpose","page":"API","title":"Base.transpose","text":"transpose(A::QuantumObject)\n\nLazy matrix transpose of the QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.adjoint","page":"API","title":"Base.adjoint","text":"A'\nadjoint(A::QuantumObject)\n\nLazy adjoint (conjugate transposition) of the QuantumObject\n\nNote that A' is a synonym for adjoint(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.dot","page":"API","title":"LinearAlgebra.dot","text":"dot(A::QuantumObject, B::QuantumObject)\n\nCompute the dot product between two QuantumObject: langle A B rangle\n\nNote that A and B should be Ket or OperatorKet\n\nA ⋅ B (where ⋅ can be typed by tab-completing \\cdot in the REPL) is a synonym for dot(A, B)\n\n\n\n\n\ndot(i::QuantumObject, A::QuantumObject j::QuantumObject)\n\nCompute the generalized dot product dot(i, A*j) between three QuantumObject: langle i hatA j rangle\n\nSupports the following inputs:\n\nA is in the type of Operator, with i and j are both Ket.\nA is in the type of SuperOperator, with i and j are both OperatorKet\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.sqrt","page":"API","title":"Base.sqrt","text":"√(A)\nsqrt(A::QuantumObject)\n\nMatrix square root of QuantumObject\n\nNote that √(A) is a synonym for sqrt(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.log","page":"API","title":"Base.log","text":"log(A::QuantumObject)\n\nMatrix logarithm of QuantumObject\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.exp","page":"API","title":"Base.exp","text":"exp(A::QuantumObject)\n\nMatrix exponential of QuantumObject\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.sin","page":"API","title":"Base.sin","text":"sin(A::QuantumObject)\n\nMatrix sine of QuantumObject, defined as\n\nsin left( hatA right) = frace^i hatA - e^-i hatA2 i\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.cos","page":"API","title":"Base.cos","text":"cos(A::QuantumObject)\n\nMatrix cosine of QuantumObject, defined as\n\ncos left( hatA right) = frace^i hatA + e^-i hatA2\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.tr","page":"API","title":"LinearAlgebra.tr","text":"tr(A::QuantumObject)\n\nReturns the trace of QuantumObject.\n\nNote that this function only supports for Operator and SuperOperator\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢\n\njulia> tr(a' * a)\n190.0 + 0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.svdvals","page":"API","title":"LinearAlgebra.svdvals","text":"svdvals(A::QuantumObject)\n\nReturn the singular values of a QuantumObject in descending order\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.norm","page":"API","title":"LinearAlgebra.norm","text":"norm(A::QuantumObject, p::Real)\n\nReturn the standard vector p-norm or Schatten p-norm of a QuantumObject depending on the type of A:\n\nIf A is either Ket, Bra, OperatorKet, or OperatorBra, returns the standard vector p-norm (default p=2) of A.\nIf A is either Operator or SuperOperator, returns Schatten p-norm (default p=1) of A.\n\nExamples\n\njulia> ψ = fock(10, 2)\nQuantum Object: type=Ket dims=[10] size=(10,)\n10-element Vector{ComplexF64}:\n 0.0 + 0.0im\n 0.0 + 0.0im\n 1.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n\njulia> norm(ψ)\n1.0\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.normalize","page":"API","title":"LinearAlgebra.normalize","text":"normalize(A::QuantumObject, p::Real)\n\nReturn normalized QuantumObject so that its p-norm equals to unity, i.e. norm(A, p) == 1.\n\nSupport for the following types of QuantumObject:\n\nIf A is Ket or Bra, default p = 2\nIf A is Operator, default p = 1\n\nAlso, see norm about its definition for different types of QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.normalize!","page":"API","title":"LinearAlgebra.normalize!","text":"normalize!(A::QuantumObject, p::Real)\n\nNormalize QuantumObject in-place so that its p-norm equals to unity, i.e. norm(A, p) == 1.\n\nSupport for the following types of QuantumObject:\n\nIf A is Ket or Bra, default p = 2\nIf A is Operator, default p = 1\n\nAlso, see norm about its definition for different types of QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.inv","page":"API","title":"Base.inv","text":"inv(A::QuantumObject)\n\nMatrix inverse of the QuantumObject\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.diag","page":"API","title":"LinearAlgebra.diag","text":"diag(A::QuantumObject, k::Int=0)\n\nReturn the k-th diagonal elements of a matrix-type QuantumObject\n\nNote that this function only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.proj","page":"API","title":"QuantumToolbox.proj","text":"proj(ψ::QuantumObject)\n\nReturn the projector for a Ket or Bra type of QuantumObject\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ptrace","page":"API","title":"QuantumToolbox.ptrace","text":"ptrace(QO::QuantumObject, sel)\n\nPartial trace of a quantum state QO leaving only the dimensions with the indices present in the sel vector.\n\nNote that this function will always return Operator. No matter the input QuantumObject is a Ket, Bra, or Operator.\n\nExamples\n\nTwo qubits in the state ketpsi = keteg:\n\njulia> ψ = kron(fock(2,0), fock(2,1))\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.0 + 0.0im\n 1.0 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n\njulia> ptrace(ψ, 2)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Matrix{ComplexF64}:\n 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 1.0+0.0im\n\nor in an entangled state ketpsi = frac1sqrt2 left( ketee + ketgg right):\n\njulia> ψ = 1 / √2 * (kron(fock(2,0), fock(2,0)) + kron(fock(2,1), fock(2,1)))\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n\njulia> ptrace(ψ, 1)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Matrix{ComplexF64}:\n 0.5+0.0im 0.0+0.0im\n 0.0+0.0im 0.5+0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.purity","page":"API","title":"QuantumToolbox.purity","text":"purity(ρ::QuantumObject)\n\nCalculate the purity of a QuantumObject: textrmTr(rho^2)\n\nNote that this function only supports for Ket, Bra, and Operator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.permute","page":"API","title":"QuantumToolbox.permute","text":"permute(A::QuantumObject, order::Union{AbstractVector{Int},Tuple})\n\nPermute the tensor structure of a QuantumObject A according to the specified order list\n\nNote that this method currently works for Ket, Bra, and Operator types of QuantumObject.\n\nExamples\n\nIf order = [2, 1, 3], the Hilbert space structure will be re-arranged: mathcalH_1 otimes mathcalH_2 otimes mathcalH_3 rightarrow mathcalH_2 otimes mathcalH_1 otimes mathcalH_3.\n\njulia> ψ1 = fock(2, 0)\njulia> ψ2 = fock(3, 1)\njulia> ψ3 = fock(4, 2)\njulia> ψ_123 = tensor(ψ1, ψ2, ψ3)\njulia> permute(ψ_123, [2, 1, 3]) ≈ tensor(ψ2, ψ1, ψ3)\ntrue\n\nwarning: Beware of type-stability!\nIt is highly recommended to use permute(A, order) with order as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tidyup","page":"API","title":"QuantumToolbox.tidyup","text":"tidyup(A::QuantumObject, tol::Real=1e-14)\n\nGiven a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tidyup!","page":"API","title":"QuantumToolbox.tidyup!","text":"tidyup!(A::QuantumObject, tol::Real=1e-14)\n\nGiven a QuantumObject A, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than tol.\n\nNote that this function is an in-place version of tidyup.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.get_data","page":"API","title":"QuantumToolbox.get_data","text":"get_data(A::QuantumObject)\n\nReturns the data of a QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.get_coherence","page":"API","title":"QuantumToolbox.get_coherence","text":"get_coherence(ψ::QuantumObject)\n\nGet the coherence value alpha by measuring the expectation value of the destruction operator hata on a state ketpsi or a density matrix hatrho.\n\nIt returns both alpha and the corresponding state with the coherence removed: ketdelta_alpha = exp ( alpha^* hata - alpha hata^dagger ) ketpsi for a pure state, and hatrho_alpha = exp ( alpha^* hata - alpha hata^dagger ) hatrho exp ( -baralpha hata + alpha hata^dagger ) for a density matrix. These states correspond to the quantum fluctuations around the coherent state ketalpha or alpharanglelanglealpha.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.partial_transpose","page":"API","title":"QuantumToolbox.partial_transpose","text":"partial_transpose(ρ::QuantumObject, mask::Vector{Bool})\n\nReturn the partial transpose of a density matrix rho, where mask is an array/vector with length that equals the length of ρ.dims. The elements in mask are boolean (true or false) which indicates whether or not the corresponding subsystem should be transposed.\n\nArguments\n\nρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).\nmask::Vector{Bool}: A boolean vector selects which subsystems should be transposed.\n\nReturns\n\nρ_pt::QuantumObject: The density matrix with the selected subsystems transposed.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Qobj-eigenvalues-and-eigenvectors","page":"API","title":"Qobj eigenvalues and eigenvectors","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"EigsolveResult\neigenenergies\neigenstates\nLinearAlgebra.eigen\nLinearAlgebra.eigvals\neigsolve\neigsolve_al","category":"page"},{"location":"api/#QuantumToolbox.EigsolveResult","page":"API","title":"QuantumToolbox.EigsolveResult","text":"struct EigsolveResult{T1<:Vector{<:Number}, T2<:AbstractMatrix{<:Number}, ObjType<:Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject},N}\n values::T1\n vectors::T2\n type::ObjType\n dims::SVector{N,Int}\n iter::Int\n numops::Int\n converged::Bool\nend\n\nA struct containing the eigenvalues, the eigenvectors, and some information from the solver\n\nFields\n\nvalues::AbstractVector: the eigenvalues\nvectors::AbstractMatrix: the transformation matrix (eigenvectors)\ntype::Union{Nothing,QuantumObjectType}: the type of QuantumObject, or nothing means solving eigen equation for general matrix\ndims::SVector: the dims of QuantumObject\niter::Int: the number of iteration during the solving process\nnumops::Int : number of times the linear map was applied in krylov methods\nconverged::Bool: Whether the result is converged\n\nExamples\n\nOne can obtain the eigenvalues and the corresponding QuantumObject-type eigenvectors by:\n\njulia> result = eigenstates(sigmax());\n\njulia> λ, ψ, T = result;\n\njulia> λ\n2-element Vector{ComplexF64}:\n -1.0 + 0.0im\n 1.0 + 0.0im\n\njulia> ψ\n2-element Vector{QuantumObject{Vector{ComplexF64}, KetQuantumObject}}:\n QuantumObject{Vector{ComplexF64}, KetQuantumObject}(ComplexF64[-0.7071067811865475 + 0.0im, 0.7071067811865475 + 0.0im], KetQuantumObject(), [2])\n QuantumObject{Vector{ComplexF64}, KetQuantumObject}(ComplexF64[0.7071067811865475 + 0.0im, 0.7071067811865475 + 0.0im], KetQuantumObject(), [2])\n\njulia> T\n2×2 Matrix{ComplexF64}:\n -0.707107+0.0im 0.707107+0.0im\n 0.707107+0.0im 0.707107+0.0im\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.eigenenergies","page":"API","title":"QuantumToolbox.eigenenergies","text":"eigenenergies(A::QuantumObject; sparse::Bool=false, kwargs...)\n\nCalculate the eigenenergies\n\nArguments\n\nA::QuantumObject: the QuantumObject to solve eigenvalues\nsparse::Bool: if false call eigvals(A::QuantumObject; kwargs...), otherwise call eigsolve. Default to false.\nkwargs: Additional keyword arguments passed to the solver\n\nReturns\n\n::Vector{<:Number}: a list of eigenvalues\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eigenstates","page":"API","title":"QuantumToolbox.eigenstates","text":"eigenstates(A::QuantumObject; sparse::Bool=false, kwargs...)\n\nCalculate the eigenvalues and corresponding eigenvectors\n\nArguments\n\nA::QuantumObject: the QuantumObject to solve eigenvalues and eigenvectors\nsparse::Bool: if false call eigen(A::QuantumObject; kwargs...), otherwise call eigsolve. Default to false.\nkwargs: Additional keyword arguments passed to the solver\n\nReturns\n\n::EigsolveResult: containing the eigenvalues, the eigenvectors, and some information from the solver. see also EigsolveResult\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.eigen","page":"API","title":"LinearAlgebra.eigen","text":"LinearAlgebra.eigen(A::QuantumObject; kwargs...)\n\nCalculates the eigenvalues and eigenvectors of the QuantumObject A using the Julia LinearAlgebra package.\n\njulia> a = destroy(5);\n\njulia> H = a + a'\nQuantum Object: type=Operator dims=[5] size=(5, 5) ishermitian=true\n5×5 SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ 1.0+0.0im ⋅ ⋅ ⋅\n 1.0+0.0im ⋅ 1.41421+0.0im ⋅ ⋅\n ⋅ 1.41421+0.0im ⋅ 1.73205+0.0im ⋅\n ⋅ ⋅ 1.73205+0.0im ⋅ 2.0+0.0im\n ⋅ ⋅ ⋅ 2.0+0.0im ⋅\n\njulia> E, ψ, U = eigen(H)\nEigsolveResult: type=Operator dims=[5]\nvalues:\n5-element Vector{Float64}:\n -2.8569700138728\n -1.3556261799742608\n 1.3322676295501878e-15\n 1.3556261799742677\n 2.8569700138728056\nvectors:\n5×5 Matrix{ComplexF64}:\n 0.106101+0.0im -0.471249-0.0im … 0.471249-0.0im 0.106101-0.0im\n -0.303127-0.0im 0.638838+0.0im 0.638838+0.0im 0.303127-0.0im\n 0.537348+0.0im -0.279149-0.0im 0.279149-0.0im 0.537348-0.0im\n -0.638838-0.0im -0.303127-0.0im -0.303127-0.0im 0.638838+0.0im\n 0.447214+0.0im 0.447214+0.0im -0.447214-0.0im 0.447214-0.0im\n\njulia> expect(H, ψ[1]) ≈ E[1]\ntrue\n\n\n\n\n\n","category":"function"},{"location":"api/#LinearAlgebra.eigvals","page":"API","title":"LinearAlgebra.eigvals","text":"LinearAlgebra.eigvals(A::QuantumObject; kwargs...)\n\nSame as eigen(A::QuantumObject; kwargs...) but for only the eigenvalues.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eigsolve","page":"API","title":"QuantumToolbox.eigsolve","text":"eigsolve(A::QuantumObject; \n v0::Union{Nothing,AbstractVector}=nothing, \n sigma::Union{Nothing, Real}=nothing,\n k::Int = 1,\n krylovdim::Int = max(20, 2*k+1),\n tol::Real = 1e-8,\n maxiter::Int = 200,\n solver::Union{Nothing, SciMLLinearSolveAlgorithm} = nothing,\n kwargs...)\n\nSolve for the eigenvalues and eigenvectors of a matrix A using the Arnoldi method.\n\nNotes\n\nFor more details about solver and extra kwargs, please refer to LinearSolve.jl\n\nReturns\n\nEigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eigsolve_al","page":"API","title":"QuantumToolbox.eigsolve_al","text":"eigsolve_al(H::QuantumObject,\n T::Real, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n H_t::Union{Nothing,Function}=nothing,\n params::NamedTuple=NamedTuple(),\n ρ0::Union{Nothing, AbstractMatrix} = nothing,\n k::Int=1,\n krylovdim::Int=min(10, size(H, 1)),\n maxiter::Int=200,\n eigstol::Real=1e-6,\n kwargs...)\n\nSolve the eigenvalue problem for a Liouvillian superoperator L using the Arnoldi-Lindblad method.\n\nArguments\n\nH: The Hamiltonian (or directly the Liouvillian) of the system.\nT: The time at which to evaluate the time evolution\nc_ops: A vector of collapse operators. Default is nothing meaning the system is closed.\nalg: The differential equation solver algorithm\nH_t: A function H_t(t) that returns the additional term at time t\nparams: A dictionary of additional parameters\nρ0: The initial density matrix. If not specified, a random density matrix is used\nk: The number of eigenvalues to compute\nkrylovdim: The dimension of the Krylov subspace\nmaxiter: The maximum number of iterations for the eigsolver\neigstol: The tolerance for the eigsolver\nkwargs: Additional keyword arguments passed to the differential equation solver\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nEigsolveResult: A struct containing the eigenvalues, the eigenvectors, and some information about the eigsolver\n\nReferences\n\n[1] Minganti, F., & Huybrechts, D. (2022). Arnoldi-Lindblad time evolution: Faster-than-the-clock algorithm for the spectrum of time-independent and Floquet open quantum systems. Quantum, 6, 649.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Qobj-manipulation","page":"API","title":"Qobj manipulation","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"ket2dm\nexpect\nvariance\nLinearAlgebra.kron\nsparse_to_dense\ndense_to_sparse\nvec2mat\nmat2vec","category":"page"},{"location":"api/#QuantumToolbox.ket2dm","page":"API","title":"QuantumToolbox.ket2dm","text":"ket2dm(ψ::QuantumObject)\n\nTransform the ket state ketpsi into a pure density matrix hatrho = dyadpsi.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.expect","page":"API","title":"QuantumToolbox.expect","text":"expect(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})\n\nExpectation value of the Operator O with the state ψ. The state can be a Ket, Bra or Operator.\n\nIf ψ is a Ket or Bra, the function calculates langlepsihatOpsirangle.\n\nIf ψ is a density matrix (Operator), the function calculates textrmTr left hatO hatpsi right\n\nThe function returns a real number if O is of Hermitian type or Symmetric type, and returns a complex number otherwise. You can make an operator O hermitian by using Hermitian(O).\n\nNote that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.\n\nExamples\n\njulia> ψ = 1 / √2 * (fock(10,2) + fock(10,4));\n\njulia> a = destroy(10);\n\njulia> expect(a' * a, ψ) |> round\n3.0 + 0.0im\n\njulia> expect(Hermitian(a' * a), ψ) |> round\n3.0\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.variance","page":"API","title":"QuantumToolbox.variance","text":"variance(O::QuantumObject, ψ::Union{QuantumObject,Vector{QuantumObject}})\n\nVariance of the Operator O: langlehatO^2rangle - langlehatOrangle^2,\n\nwhere langlehatOrangle is the expectation value of O with the state ψ (see also expect), and the state ψ can be a Ket, Bra or Operator.\n\nThe function returns a real number if O is hermitian, and returns a complex number otherwise.\n\nNote that ψ can also be given as a list of QuantumObject, it returns a list of expectation values.\n\n\n\n\n\n","category":"function"},{"location":"api/#Base.kron","page":"API","title":"Base.kron","text":"kron(A::QuantumObject, B::QuantumObject, ...)\n\nReturns the Kronecker product hatA otimes hatB otimes cdots.\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢\n\njulia> kron(a, a)\nQuantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian=false\n400×400 SparseMatrixCSC{ComplexF64, Int64} with 361 stored entries:\n⠀⠀⠘⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sparse_to_dense","page":"API","title":"QuantumToolbox.sparse_to_dense","text":"sparse_to_dense(A::QuantumObject)\n\nConverts a sparse QuantumObject to a dense QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dense_to_sparse","page":"API","title":"QuantumToolbox.dense_to_sparse","text":"dense_to_sparse(A::QuantumObject)\n\nConverts a dense QuantumObject to a sparse QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.vec2mat","page":"API","title":"QuantumToolbox.vec2mat","text":"vec2mat(A::AbstractVector)\n\nConverts a vector to a matrix.\n\n\n\n\n\nvec2mat(A::QuantumObject)\n\nConvert a quantum object from vector (OperatorKetQuantumObject-type) to matrix (OperatorQuantumObject-type)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mat2vec","page":"API","title":"QuantumToolbox.mat2vec","text":"mat2vec(A::QuantumObject)\n\nConvert a quantum object from matrix (OperatorQuantumObject-type) to vector (OperatorKetQuantumObject-type)\n\n\n\n\n\nmat2vec(A::AbstractMatrix)\n\nConverts a matrix to a vector.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Generate-states-and-operators","page":"API","title":"Generate states and operators","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"zero_ket\nfock\nbasis\ncoherent\nrand_ket\nfock_dm\ncoherent_dm\nthermal_dm\nmaximally_mixed_dm\nrand_dm\nspin_state\nspin_coherent\nbell_state\nsinglet_state\ntriplet_states\nw_state\nghz_state\nrand_unitary\nsigmap\nsigmam\nsigmax\nsigmay\nsigmaz\njmat\nspin_Jx\nspin_Jy\nspin_Jz\nspin_Jm\nspin_Jp\nspin_J_set\ndestroy\ncreate\ndisplace\nsqueeze\nnum\nQuantumToolbox.position\nQuantumToolbox.momentum\nphase\nfdestroy\nfcreate\ntunneling\nqft\neye\nprojection\ncommutator\nspre\nspost\nsprepost\nlindblad_dissipator","category":"page"},{"location":"api/#QuantumToolbox.zero_ket","page":"API","title":"QuantumToolbox.zero_ket","text":"zero_ket(dimensions)\n\nReturns a zero Ket vector with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int}, Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nwarning: Beware of type-stability!\nIt is highly recommended to use zero_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fock","page":"API","title":"QuantumToolbox.fock","text":"fock(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))\n\nGenerates a fock state ketpsi of dimension N. \n\nIt is also possible to specify the list of dimensions dims if different subsystems are present.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fock(N, j, dims=dims, sparse=Val(sparse)) instead of fock(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.basis","page":"API","title":"QuantumToolbox.basis","text":"basis(N::Int, j::Int = 0; dims::Union{Int,AbstractVector{Int},Tuple}=N)\n\nGenerates a fock state like fock.\n\nIt is also possible to specify the list of dimensions dims if different subsystems are present.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use basis(N, j, dims=dims) with dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.coherent","page":"API","title":"QuantumToolbox.coherent","text":"coherent(N::Int, α::Number)\n\nGenerates a coherent state alpharangle, which is defined as an eigenvector of the bosonic annihilation operator hata alpharangle = alpha alpharangle.\n\nThis state is constructed via the displacement operator displace and zero-fock state fock: alpharangle = hatD(alpha) 0rangle\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.rand_ket","page":"API","title":"QuantumToolbox.rand_ket","text":"rand_ket(dimensions)\n\nGenerate a random normalized Ket vector with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use rand_ket(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fock_dm","page":"API","title":"QuantumToolbox.fock_dm","text":"fock_dm(N::Int, j::Int=0; dims::Union{Int,AbstractVector{Int},Tuple}=N, sparse::Union{Bool,Val}=Val(false))\n\nDensity matrix representation of a Fock state.\n\nConstructed via outer product of fock.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fock_dm(N, j, dims=dims, sparse=Val(sparse)) instead of fock_dm(N, j, dims=dims, sparse=sparse). Consider also to use dims as a Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.coherent_dm","page":"API","title":"QuantumToolbox.coherent_dm","text":"coherent_dm(N::Int, α::Number)\n\nDensity matrix representation of a coherent state.\n\nConstructed via outer product of coherent.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.thermal_dm","page":"API","title":"QuantumToolbox.thermal_dm","text":"thermal_dm(N::Int, n::Real; sparse::Union{Bool,Val}=Val(false))\n\nDensity matrix for a thermal state (generating thermal state probabilities) with the following arguments:\n\nN::Int: Number of basis states in the Hilbert space\nn::Real: Expectation value for number of particles in the thermal state.\nsparse::Union{Bool,Val}: If true, return a sparse matrix representation.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use thermal_dm(N, n, sparse=Val(sparse)) instead of thermal_dm(N, n, sparse=sparse). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.maximally_mixed_dm","page":"API","title":"QuantumToolbox.maximally_mixed_dm","text":"maximally_mixed_dm(dimensions)\n\nReturns the maximally mixed density matrix with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use maximally_mixed_dm(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.rand_dm","page":"API","title":"QuantumToolbox.rand_dm","text":"rand_dm(dimensions; rank::Int=prod(dimensions))\n\nGenerate a random density matrix from Ginibre ensemble with given argument dimensions and rank, ensuring that it is positive semi-definite and trace equals to 1.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nThe default keyword argument rank = prod(dimensions) (full rank).\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use rand_dm(dimensions; rank=rank) with dimensions as Tuple or SVector instead of Vector. See this link and the related Section about type stability for more details.\n\nReferences\n\nJ. Ginibre, Statistical ensembles of complex, quaternion, and real matrices, Journal of Mathematical Physics 6.3 (1965): 440-449\nK. Życzkowski, et al., Generating random density matrices, Journal of Mathematical Physics 52, 062201 (2011)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_state","page":"API","title":"QuantumToolbox.spin_state","text":"spin_state(j::Real, m::Real)\n\nGenerate the spin state: j mrangle\n\nThe eigenstate of the Spin-j hatS_z operator with eigenvalue m, where where j is the spin quantum number and can be a non-negative integer or half-integer\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_coherent","page":"API","title":"QuantumToolbox.spin_coherent","text":"spin_coherent(j::Real, θ::Real, ϕ::Real)\n\nGenerate the coherent spin state (rotation of the j jrangle state), namely\n\ntheta phi rangle = hatR(theta phi) j jrangle\n\nwhere the rotation operator is defined as\n\nhatR(theta phi) = exp left( fractheta2 (hatS_- e^iphi - hatS_+ e^-iphi) right)\n\nand hatS_pm are plus and minus Spin-j operators, respectively.\n\nArguments\n\nj::Real: The spin quantum number and can be a non-negative integer or half-integer\nθ::Real: rotation angle from z-axis\nϕ::Real: rotation angle from x-axis\n\nSee also jmat and spin_state.\n\nReference\n\nRobert Jones, Spin Coherent States and Statistical Physics\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.bell_state","page":"API","title":"QuantumToolbox.bell_state","text":"bell_state(x::Union{Int}, z::Union{Int})\n\nReturn the Bell state depending on the arguments (x, z):\n\n(0, 0): Phi^+ rangle = ( 00rangle + 11rangle ) sqrt2\n(0, 1): Phi^- rangle = ( 00rangle - 11rangle ) sqrt2\n(1, 0): Psi^+ rangle = ( 01rangle + 10rangle ) sqrt2\n(1, 1): Psi^- rangle = ( 01rangle - 10rangle ) sqrt2\n\nHere, x = 1 (z = 1) means applying Pauli-X ( Pauli-Z) unitary transformation on Phi^+ rangle.\n\nExample\n\njulia> bell_state(0, 0)\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n\njulia> bell_state(Val(1), Val(0))\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use bell_state(Val(x), Val(z)) instead of bell_state(x, z). See this link and the related Section for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.singlet_state","page":"API","title":"QuantumToolbox.singlet_state","text":"singlet_state()\n\nReturn the two particle singlet state: frac1sqrt2 ( 01rangle - 10rangle )\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.triplet_states","page":"API","title":"QuantumToolbox.triplet_states","text":"triplet_states()\n\nReturn a list of the two particle triplet states: \n\n11rangle\n( 01rangle + 10rangle ) sqrt2\n00rangle\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.w_state","page":"API","title":"QuantumToolbox.w_state","text":"w_state(n::Union{Int,Val})\n\nReturns the n-qubit W-state:\n\nfrac1sqrtn left( 1000rangle + 0100rangle + cdots + 0001rangle right)\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use w_state(Val(n)) instead of w_state(n). See this link and the related Section for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ghz_state","page":"API","title":"QuantumToolbox.ghz_state","text":"ghz_state(n::Union{Int,Val}; d::Int=2)\n\nReturns the generalized n-qudit Greenberger–Horne–Zeilinger (GHZ) state:\n\nfrac1sqrtd sum_i=0^d-1 i rangle otimes cdots otimes i rangle\n\nHere, d specifies the dimension of each qudit. Default to d=2 (qubit).\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use ghz_state(Val(n)) instead of ghz_state(n). See this link and the related Section for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.rand_unitary","page":"API","title":"QuantumToolbox.rand_unitary","text":"rand_unitary(dimensions, distribution=Val(:haar))\n\nReturns a random unitary QuantumObject.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nThe distribution specifies which of the method used to obtain the unitary matrix:\n\n:haar: Haar random unitary matrix using the algorithm from reference 1\n:exp: Uses exp(-ihatH), where hatH is a randomly generated Hermitian operator.\n\nReferences\n\nF. Mezzadri, How to generate random matrices from the classical compact groups, arXiv:math-ph/0609050 (2007)\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use rand_unitary(dimensions, Val(distribution)) instead of rand_unitary(dimensions, distribution). Also, put dimensions as Tuple or SVector. See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmap","page":"API","title":"QuantumToolbox.sigmap","text":"sigmap()\n\nPauli ladder operator hatsigma_+ = (hatsigma_x + i hatsigma_y) 2.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmam","page":"API","title":"QuantumToolbox.sigmam","text":"sigmam()\n\nPauli ladder operator hatsigma_- = (hatsigma_x - i hatsigma_y) 2.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmax","page":"API","title":"QuantumToolbox.sigmax","text":"sigmax()\n\nPauli operator hatsigma_x = hatsigma_- + hatsigma_+.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmay","page":"API","title":"QuantumToolbox.sigmay","text":"sigmay()\n\nPauli operator hatsigma_y = i left( hatsigma_- - hatsigma_+ right).\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sigmaz","page":"API","title":"QuantumToolbox.sigmaz","text":"sigmaz()\n\nPauli operator hatsigma_z = commhatsigma_+hatsigma_-.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.jmat","page":"API","title":"QuantumToolbox.jmat","text":"jmat(j::Real, which::Union{Symbol,Val})\n\nGenerate higher-order Spin-j operators, where j is the spin quantum number and can be a non-negative integer or half-integer\n\nThe parameter which specifies which of the following operator to return.\n\n:x: hatS_x\n:y: hatS_y\n:z: hatS_z\n:+: hatS_+\n:-: hatS_-\n\nNote that if the parameter which is not specified, returns a set of Spin-j operators: (hatS_x hatS_y hatS_z)\n\nExamples\n\njulia> jmat(0.5, :x)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 0.5+0.0im\n 0.5+0.0im ⋅\n\njulia> jmat(0.5, :-)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 1 stored entry:\n ⋅ ⋅ \n 1.0+0.0im ⋅\n\njulia> jmat(1.5, Val(:z))\nQuantum Object: type=Operator dims=[4] size=(4, 4) ishermitian=true\n4×4 SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:\n 1.5+0.0im ⋅ ⋅ ⋅ \n ⋅ 0.5+0.0im ⋅ ⋅ \n ⋅ ⋅ -0.5+0.0im ⋅ \n ⋅ ⋅ ⋅ -1.5+0.0im\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use jmat(j, Val(which)) instead of jmat(j, which). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jx","page":"API","title":"QuantumToolbox.spin_Jx","text":"spin_Jx(j::Real)\n\nhatS_x operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jy","page":"API","title":"QuantumToolbox.spin_Jy","text":"spin_Jy(j::Real)\n\nhatS_y operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jz","page":"API","title":"QuantumToolbox.spin_Jz","text":"spin_Jz(j::Real)\n\nhatS_z operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jm","page":"API","title":"QuantumToolbox.spin_Jm","text":"spin_Jm(j::Real)\n\nhatS_- operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_Jp","page":"API","title":"QuantumToolbox.spin_Jp","text":"spin_Jp(j::Real)\n\nhatS_+ operator for Spin-j, where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nSee also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spin_J_set","page":"API","title":"QuantumToolbox.spin_J_set","text":"spin_J_set(j::Real)\n\nA set of Spin-j operators (hatS_x hatS_y hatS_z), where j is the spin quantum number and can be a non-negative integer or half-integer.\n\nNote that this functions is same as jmat(j). See also jmat.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.destroy","page":"API","title":"QuantumToolbox.destroy","text":"destroy(N::Int)\n\nBosonic annihilation operator with Hilbert space cutoff N. \n\nThis operator acts on a fock state as hata ketn = sqrtn ketn-1.\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⎡⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀⎤\n⎢⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⎥\n⎣⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⎦\n\njulia> fock(20, 3)' * a * fock(20, 4)\n2.0 + 0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.create","page":"API","title":"QuantumToolbox.create","text":"create(N::Int)\n\nBosonic creation operator with Hilbert space cutoff N.\n\nThis operator acts on a fock state as hata^dagger ketn = sqrtn+1 ketn+1.\n\nExamples\n\njulia> a_d = create(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⎡⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⎤\n⎢⠀⠈⠢⡀⠀⠀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⎥\n⎢⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⎥\n⎣⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⎦\n\njulia> fock(20, 4)' * a_d * fock(20, 3)\n2.0 + 0.0im\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.displace","page":"API","title":"QuantumToolbox.displace","text":"displace(N::Int, α::Number)\n\nGenerate a displacement operator:\n\nhatD(alpha)=expleft( alpha hata^dagger - alpha^* hata right)\n\nwhere hata is the bosonic annihilation operator, and alpha is the amount of displacement in optical phase space.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.squeeze","page":"API","title":"QuantumToolbox.squeeze","text":"squeeze(N::Int, z::Number)\n\nGenerate a single-mode squeeze operator:\n\nhatS(z)=expleft( frac12 (z^* hata^2 - z(hata^dagger)^2) right)\n\nwhere hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.num","page":"API","title":"QuantumToolbox.num","text":"num(N::Int)\n\nBosonic number operator with Hilbert space cutoff N. \n\nThis operator is defined as hatN=hata^dagger hata, where hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.position","page":"API","title":"QuantumToolbox.position","text":"position(N::Int)\n\nPosition operator with Hilbert space cutoff N. \n\nThis operator is defined as hatx=frac1sqrt2 (hata^dagger + hata), where hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.momentum","page":"API","title":"QuantumToolbox.momentum","text":"momentum(N::Int)\n\nMomentum operator with Hilbert space cutoff N. \n\nThis operator is defined as hatp= fracisqrt2 (hata^dagger - hata), where hata is the bosonic annihilation operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.phase","page":"API","title":"QuantumToolbox.phase","text":"phase(N::Int, ϕ0::Real=0)\n\nSingle-mode Pegg-Barnett phase operator with Hilbert space cutoff N and the reference phase phi_0.\n\nThis operator is defined as\n\nhatphi = sum_m=0^N-1 phi_m phi_mrangle langlephi_m\n\nwhere\n\nphi_m = phi_0 + frac2mpiN\n\nand\n\nphi_mrangle = frac1sqrtN sum_n=0^N-1 exp(i n phi_m) nrangle\n\nReference\n\nMichael Martin Nieto, QUANTUM PHASE AND QUANTUM PHASE OPERATORS: Some Physics and Some History, arXiv:hep-th/9304036, Equation (30-32).\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fdestroy","page":"API","title":"QuantumToolbox.fdestroy","text":"fdestroy(N::Union{Int,Val}, j::Int)\n\nConstruct a fermionic destruction operator acting on the j-th site, where the fock space has totally N-sites:\n\nHere, we use the Jordan-Wigner transformation, namely\n\nhatd_j = hatsigma_z^otimes j-1 otimes hatsigma_+ otimes hatmathbb1^otimes N-j\n\nThe site index j should satisfy: 1 ≤ j ≤ N.\n\nNote that we put hatsigma_+ = beginpmatrix 0 1 0 0 endpmatrix here because we consider 0rangle = beginpmatrix 1 0 endpmatrix to be ground (vacant) state, and 1rangle = beginpmatrix 0 1 endpmatrix to be excited (occupied) state.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fdestroy(Val(N), j) instead of fdestroy(N, j). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fcreate","page":"API","title":"QuantumToolbox.fcreate","text":"fcreate(N::Union{Int,Val}, j::Int)\n\nConstruct a fermionic creation operator acting on the j-th site, where the fock space has totally N-sites:\n\nHere, we use the Jordan-Wigner transformation, namely\n\nhatd^dagger_j = hatsigma_z^otimes j-1 otimes hatsigma_- otimes hatmathbb1^otimes N-j\n\nThe site index j should satisfy: 1 ≤ j ≤ N.\n\nNote that we put hatsigma_- = beginpmatrix 0 0 1 0 endpmatrix here because we consider 0rangle = beginpmatrix 1 0 endpmatrix to be ground (vacant) state, and 1rangle = beginpmatrix 0 1 endpmatrix to be excited (occupied) state.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use fcreate(Val(N), j) instead of fcreate(N, j). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tunneling","page":"API","title":"QuantumToolbox.tunneling","text":"tunneling(N::Int, m::Int=1; sparse::Union{Bool,Val{<:Bool}}=Val(false))\n\nGenerate a tunneling operator defined as:\n\nsum_n=0^N-m n ranglelangle n+m + n+m ranglelangle n \n\nwhere N is the number of basis states in the Hilbert space, and m is the number of excitations in tunneling event.\n\nIf sparse=true, the operator is returned as a sparse matrix, otherwise a dense matrix is returned.\n\nwarning: Beware of type-stability!\nIf you want to keep type stability, it is recommended to use tunneling(N, m, Val(sparse)) instead of tunneling(N, m, sparse). See this link and the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.qft","page":"API","title":"QuantumToolbox.qft","text":"qft(dimensions)\n\nGenerates a discrete Fourier transform matrix hatF_N for Quantum Fourier Transform (QFT) with given argument dimensions.\n\nThe dimensions can be either the following types:\n\ndimensions::Int: Number of basis states in the Hilbert space.\ndimensions::Union{AbstractVector{Int},Tuple}: list of dimensions representing the each number of basis in the subsystems.\n\nN represents the total dimension, and therefore the matrix is defined as\n\nhatF_N = frac1sqrtNbeginbmatrix\n1 1 1 1 cdots 1\n1 omega omega^2 omega^3 cdots omega^N-1\n1 omega^2 omega^4 omega^6 cdots omega^2(N-1)\n1 omega^3 omega^6 omega^9 cdots omega^3(N-1)\nvdots vdots vdots vdots ddots vdots\n1 omega^N-1 omega^2(N-1) omega^3(N-1) cdots omega^(N-1)(N-1)\nendbmatrix\n\nwhere omega = exp(frac2 pi iN).\n\nwarning: Beware of type-stability!\nIt is highly recommended to use qft(dimensions) with dimensions as Tuple or SVector to keep type stability. See the related Section about type stability for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.eye","page":"API","title":"QuantumToolbox.eye","text":"eye(N::Int; type=Operator, dims=nothing)\n\nIdentity operator hatmathbb1 with size N.\n\nIt is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.\n\nNote that type can only be either Operator or SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.projection","page":"API","title":"QuantumToolbox.projection","text":"projection(N::Int, i::Int, j::Int)\n\nGenerates the projection operator hatO = dyadij with Hilbert space dimension N.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.commutator","page":"API","title":"QuantumToolbox.commutator","text":"commutator(A::QuantumObject, B::QuantumObject; anti::Bool=false)\n\nReturn the commutator (or anti-commutator) of the two QuantumObject:\n\ncommutator (anti=false): hatAhatB-hatBhatA\nanticommutator (anti=true): hatAhatB+hatBhatA\n\nNote that A and B must be Operator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spre","page":"API","title":"QuantumToolbox.spre","text":"spre(A::QuantumObject, Id_cache=I(size(A,1)))\n\nReturns the SuperOperator form of A acting on the left of the density matrix operator: mathcalO left(hatAright) left hatrho right = hatA hatrho.\n\nSince the density matrix is vectorized in OperatorKet form: hatrhoranglerangle, this SuperOperator is always a matrix hatmathbb1 otimes hatA, namely \n\nmathcalO left(hatAright) left hatrho right = hatmathbb1 otimes hatA hatrhoranglerangle\n\n(see the section in documentation: Superoperators and Vectorized Operators for more details)\n\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spost","page":"API","title":"QuantumToolbox.spost","text":"spost(B::QuantumObject, Id_cache=I(size(B,1)))\n\nReturns the SuperOperator form of B acting on the right of the density matrix operator: mathcalO left(hatBright) left hatrho right = hatrho hatB.\n\nSince the density matrix is vectorized in OperatorKet form: hatrhoranglerangle, this SuperOperator is always a matrix hatB^T otimes hatmathbb1, namely\n\nmathcalO left(hatBright) left hatrho right = hatB^T otimes hatmathbb1 hatrhoranglerangle\n\n(see the section in documentation: Superoperators and Vectorized Operators for more details)\n\nThe 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sprepost","page":"API","title":"QuantumToolbox.sprepost","text":"sprepost(A::QuantumObject, B::QuantumObject)\n\nReturns the SuperOperator form of A and B acting on the left and right of the density matrix operator, respectively: mathcalO left( hatA hatB right) left hatrho right = hatA hatrho hatB.\n\nSince the density matrix is vectorized in OperatorKet form: hatrhoranglerangle, this SuperOperator is always a matrix hatB^T otimes hatA, namely\n\nmathcalO left(hatA hatBright) left hatrho right = hatB^T otimes hatA hatrhoranglerangle = textrmspre(hatA) * textrmspost(hatB) hatrhoranglerangle\n\n(see the section in documentation: Superoperators and Vectorized Operators for more details)\n\nSee also spre and spost.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.lindblad_dissipator","page":"API","title":"QuantumToolbox.lindblad_dissipator","text":"lindblad_dissipator(O::QuantumObject, Id_cache=I(size(O,1))\n\nReturns the Lindblad SuperOperator defined as\n\nmathcalD left( hatO right) left hatrho right = frac12 left( 2 hatO hatrho hatO^dagger - \nhatO^dagger hatO hatrho - hatrho hatO^dagger hatO right)\n\nThe 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.\n\nSee also spre and spost.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Synonyms-of-functions-for-Qobj","page":"API","title":"Synonyms of functions for Qobj","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Qobj\nshape\nisherm\ntrans\ndag\nmatrix_element\nunit\nsqrtm\nlogm\nexpm\nsinm\ncosm\ntensor\n⊗\nqeye","category":"page"},{"location":"api/#QuantumToolbox.Qobj","page":"API","title":"QuantumToolbox.Qobj","text":"Qobj(A::AbstractArray; type::QuantumObjectType, dims::Vector{Int})\n\nGenerate QuantumObject\n\nNote that this functions is same as QuantumObject(A; type=type, dims=dims)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.shape","page":"API","title":"QuantumToolbox.shape","text":"shape(A::QuantumObject)\n\nReturns a tuple containing each dimensions of the array in the QuantumObject.\n\nNote that this function is same as size(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.isherm","page":"API","title":"QuantumToolbox.isherm","text":"isherm(A::QuantumObject)\n\nTest whether the QuantumObject is Hermitian.\n\nNote that this functions is same as ishermitian(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.trans","page":"API","title":"QuantumToolbox.trans","text":"trans(A::QuantumObject)\n\nLazy matrix transpose of the QuantumObject.\n\nNote that this function is same as transpose(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dag","page":"API","title":"QuantumToolbox.dag","text":"dag(A::QuantumObject)\n\nLazy adjoint (conjugate transposition) of the QuantumObject\n\nNote that this function is same as adjoint(A)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.matrix_element","page":"API","title":"QuantumToolbox.matrix_element","text":"matrix_element(i::QuantumObject, A::QuantumObject j::QuantumObject)\n\nCompute the generalized dot product dot(i, A*j) between three QuantumObject: langle i hatA j rangle\n\nNote that this function is same as dot(i, A, j)\n\nSupports the following inputs:\n\nA is in the type of Operator, with i and j are both Ket.\nA is in the type of SuperOperator, with i and j are both OperatorKet\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.unit","page":"API","title":"QuantumToolbox.unit","text":"unit(A::QuantumObject, p::Real)\n\nReturn normalized QuantumObject so that its p-norm equals to unity, i.e. norm(A, p) == 1.\n\nSupport for the following types of QuantumObject:\n\nIf A is Ket or Bra, default p = 2\nIf A is Operator, default p = 1\n\nNote that this function is same as normalize(A, p)\n\nAlso, see norm about its definition for different types of QuantumObject.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sqrtm","page":"API","title":"QuantumToolbox.sqrtm","text":"sqrtm(A::QuantumObject)\n\nMatrix square root of Operator type of QuantumObject\n\nNote that for other types of QuantumObject use sprt(A) instead.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.logm","page":"API","title":"QuantumToolbox.logm","text":"logm(A::QuantumObject)\n\nMatrix logarithm of QuantumObject\n\nNote that this function is same as log(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.expm","page":"API","title":"QuantumToolbox.expm","text":"expm(A::QuantumObject)\n\nMatrix exponential of QuantumObject\n\nNote that this function is same as exp(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sinm","page":"API","title":"QuantumToolbox.sinm","text":"sinm(A::QuantumObject)\n\nMatrix sine of QuantumObject, defined as\n\nsin left( hatA right) = frace^i hatA - e^-i hatA2 i\n\nNote that this function is same as sin(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.cosm","page":"API","title":"QuantumToolbox.cosm","text":"cosm(A::QuantumObject)\n\nMatrix cosine of QuantumObject, defined as\n\ncos left( hatA right) = frace^i hatA + e^-i hatA2\n\nNote that this function is same as cos(A) and only supports for Operator and SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tensor","page":"API","title":"QuantumToolbox.tensor","text":"tensor(A::QuantumObject, B::QuantumObject, ...)\n\nReturns the Kronecker product hatA otimes hatB otimes cdots.\n\nNote that this function is same as kron(A, B, ...)\n\nExamples\n\njulia> x = sigmax()\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅\n\njulia> x_list = fill(x, 3);\n\njulia> tensor(x_list...)\nQuantum Object: type=Operator dims=[2, 2, 2] size=(8, 8) ishermitian=true\n8×8 SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:\n ⋅ ⋅ ⋅ … ⋅ ⋅ 1.0+0.0im\n ⋅ ⋅ ⋅ ⋅ 1.0+0.0im ⋅\n ⋅ ⋅ ⋅ 1.0+0.0im ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅\n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅\n ⋅ ⋅ 1.0+0.0im … ⋅ ⋅ ⋅\n ⋅ 1.0+0.0im ⋅ ⋅ ⋅ ⋅\n 1.0+0.0im ⋅ ⋅ ⋅ ⋅ ⋅\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.:⊗","page":"API","title":"QuantumToolbox.:⊗","text":"⊗(A::QuantumObject, B::QuantumObject)\n\nReturns the Kronecker product hatA otimes hatB.\n\nNote that this function is same as kron(A, B)\n\nExamples\n\njulia> a = destroy(20)\nQuantum Object: type=Operator dims=[20] size=(20, 20) ishermitian=false\n20×20 SparseMatrixCSC{ComplexF64, Int64} with 19 stored entries:\n⠈⠢⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠈⠢⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢\n\njulia> a ⊗ a\nQuantum Object: type=Operator dims=[20, 20] size=(400, 400) ishermitian=false\n400×400 SparseMatrixCSC{ComplexF64, Int64} with 361 stored entries:\n⠀⠀⠘⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀⠀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⡀⠀\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠦\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.qeye","page":"API","title":"QuantumToolbox.qeye","text":"qeye(N::Int; type=Operator, dims=nothing)\n\nIdentity operator hatmathbb1 with size N.\n\nIt is also possible to specify the list of Hilbert dimensions dims if different subsystems are present.\n\nNote that this function is same as eye(N, type=type, dims=dims), and type can only be either Operator or SuperOperator\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Time-evolution","page":"API","title":"Time evolution","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"TimeEvolutionSol\nTimeEvolutionMCSol\nTimeEvolutionSSESol\nsesolveProblem\nmesolveProblem\nmcsolveProblem\nmcsolveEnsembleProblem\nssesolveProblem\nssesolveEnsembleProblem\nlr_mesolveProblem\nsesolve\nmesolve\nmcsolve\nssesolve\ndfd_mesolve\ndsf_mesolve\ndsf_mcsolve\nlr_mesolve\nliouvillian\nliouvillian_generalized\nsteadystate\nsteadystate_floquet\nSteadyStateDirectSolver\nSteadyStateEigenSolver\nSteadyStateLinearSolver\nSteadyStateODESolver","category":"page"},{"location":"api/#QuantumToolbox.TimeEvolutionSol","page":"API","title":"QuantumToolbox.TimeEvolutionSol","text":"struct TimeEvolutionSol\n\nA structure storing the results and some information from solving time evolution.\n\nFields (Attributes)\n\ntimes::AbstractVector: The time list of the evolution.\nstates::Vector{QuantumObject}: The list of result states.\nexpect::Matrix: The expectation values corresponding to each time point in times.\nretcode: The return code from the solver.\nalg: The algorithm which is used during the solving process.\nabstol::Real: The absolute tolerance which is used during the solving process.\nreltol::Real: The relative tolerance which is used during the solving process.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.TimeEvolutionMCSol","page":"API","title":"QuantumToolbox.TimeEvolutionMCSol","text":"struct TimeEvolutionMCSol\n\nA structure storing the results and some information from solving quantum trajectories of the Monte Carlo wave function time evolution.\n\nFields (Attributes)\n\nntraj::Int: Number of trajectories\ntimes::AbstractVector: The time list of the evolution.\nstates::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.\nexpect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.\nexpect_all::Array: The expectation values corresponding to each trajectory and each time point in times\njump_times::Vector{Vector{Real}}: The time records of every quantum jump occurred in each trajectory.\njump_which::Vector{Vector{Int}}: The indices of the jump operators in c_ops that describe the corresponding quantum jumps occurred in each trajectory.\nconverged::Bool: Whether the solution is converged or not.\nalg: The algorithm which is used during the solving process.\nabstol::Real: The absolute tolerance which is used during the solving process.\nreltol::Real: The relative tolerance which is used during the solving process.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.TimeEvolutionSSESol","page":"API","title":"QuantumToolbox.TimeEvolutionSSESol","text":"struct TimeEvolutionSSESol\n\nA structure storing the results and some information from solving trajectories of the Stochastic Shrodinger equation time evolution.\n\nFields (Attributes)\n\nntraj::Int: Number of trajectories\ntimes::AbstractVector: The time list of the evolution.\nstates::Vector{Vector{QuantumObject}}: The list of result states in each trajectory.\nexpect::Matrix: The expectation values (averaging all trajectories) corresponding to each time point in times.\nexpect_all::Array: The expectation values corresponding to each trajectory and each time point in times\nconverged::Bool: Whether the solution is converged or not.\nalg: The algorithm which is used during the solving process.\nabstol::Real: The absolute tolerance which is used during the solving process.\nreltol::Real: The relative tolerance which is used during the solving process.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.sesolveProblem","page":"API","title":"QuantumToolbox.sesolveProblem","text":"sesolveProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n alg::OrdinaryDiffEqAlgorithm=Tsit5()\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the ODEProblem for the Schrödinger time evolution of a quantum system:\n\nfracpartialpartial t psi(t)rangle = -i hatH psi(t)rangle\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: The time list of the evolution.\nalg::OrdinaryDiffEqAlgorithm: The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: The list of operators to be evaluated during the evolution.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: The time-dependent Hamiltonian of the system. If nothing, the Hamiltonian is time-independent.\nparams::NamedTuple: The parameters of the system.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: The keyword arguments passed to the ODEProblem constructor.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob: The ODEProblem for the Schrödinger time evolution of the system.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mesolveProblem","page":"API","title":"QuantumToolbox.mesolveProblem","text":"mesolveProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector, \n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the ODEProblem for the master equation time evolution of an open quantum system:\n\nfracpartial hatrho(t)partial t = -ihatH hatrho(t) + sum_n mathcalD(hatC_n) hatrho(t)\n\nwhere \n\nmathcalD(hatC_n) hatrho(t) = hatC_n hatrho(t) hatC_n^dagger - frac12 hatC_n^dagger hatC_n hatrho(t) - frac12 hatrho(t) hatC_n^dagger hatC_n\n\nArguments\n\nH::QuantumObject: The Hamiltonian hatH or the Liouvillian of the system.\nψ0::QuantumObject: The initial state of the system.\ntlist::AbstractVector: The time list of the evolution.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm=Tsit5(): The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the operators for which the expectation values are calculated.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing: The time-dependent Hamiltonian or Liouvillian.\nparams::NamedTuple=NamedTuple(): The parameters of the time evolution.\nprogress_bar::Union{Val,Bool}=Val(true): Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: The keyword arguments for the ODEProblem.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::ODEProblem: The ODEProblem for the master equation time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mcsolveProblem","page":"API","title":"QuantumToolbox.mcsolveProblem","text":"mcsolveProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n rng::AbstractRNG=default_rng(),\n jump_callback::TJC=ContinuousLindbladJumpCallback(),\n kwargs...)\n\nGenerates the ODEProblem for a single trajectory of the Monte Carlo wave function time evolution of an open quantum system.\n\nGiven a system Hamiltonian hatH and a list of collapse (jump) operators hatC_n_n, the evolution of the state psi(t)rangle is governed by the Schrodinger equation:\n\nfracpartialpartial t psi(t)rangle= -i hatH_textrmeff psi(t)rangle\n\nwith a non-Hermitian effective Hamiltonian:\n\nhatH_textrmeff = hatH - fraci2 sum_n hatC_n^dagger hatC_n\n\nTo the first-order of the wave function in a small time delta t, the strictly negative non-Hermitian portion in hatH_textrmeff gives rise to a reduction in the norm of the wave function, namely\n\nlangle psi(t+delta t) psi(t+delta t) rangle = 1 - delta p\n\nwhere \n\ndelta p = delta t sum_n langle psi(t) hatC_n^dagger hatC_n psi(t) rangle\n\nis the corresponding quantum jump probability.\n\nIf the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting psi(t)rangle using the collapse operator hatC_n corresponding to the measurement, namely\n\n psi(t+delta t) rangle = frachatC_n psi(t)rangle sqrtlangle psi(t) hatC_n^dagger hatC_n psi(t) rangle \n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nrng::AbstractRNG: Random number generator for reproducibility.\njump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::ODEProblem: The ODEProblem for the Monte Carlo wave function time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mcsolveEnsembleProblem","page":"API","title":"QuantumToolbox.mcsolveEnsembleProblem","text":"mcsolveEnsembleProblem(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n jump_callback::TJC=ContinuousLindbladJumpCallback(),\n prob_func::Function=_mcsolve_prob_func,\n output_func::Function=_mcsolve_output_func,\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the EnsembleProblem of ODEProblems for the ensemble of trajectories of the Monte Carlo wave function time evolution of an open quantum system.\n\nGiven a system Hamiltonian hatH and a list of collapse (jump) operators hatC_n_n, the evolution of the state psi(t)rangle is governed by the Schrodinger equation:\n\nfracpartialpartial t psi(t)rangle= -i hatH_textrmeff psi(t)rangle\n\nwith a non-Hermitian effective Hamiltonian:\n\nhatH_textrmeff = hatH - fraci2 sum_n hatC_n^dagger hatC_n\n\nTo the first-order of the wave function in a small time delta t, the strictly negative non-Hermitian portion in hatH_textrmeff gives rise to a reduction in the norm of the wave function, namely\n\nlangle psi(t+delta t) psi(t+delta t) rangle = 1 - delta p\n\nwhere \n\ndelta p = delta t sum_n langle psi(t) hatC_n^dagger hatC_n psi(t) rangle\n\nis the corresponding quantum jump probability.\n\nIf the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting psi(t)rangle using the collapse operator hatC_n corresponding to the measurement, namely\n\n psi(t+delta t) rangle = frachatC_n psi(t)rangle sqrtlangle psi(t) hatC_n^dagger hatC_n psi(t) rangle \n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nrng::AbstractRNG: Random number generator for reproducibility.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\njump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.\nprob_func::Function: Function to use for generating the ODEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::EnsembleProblem with ODEProblem: The Ensemble ODEProblem for the Monte Carlo wave function time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ssesolveProblem","page":"API","title":"QuantumToolbox.ssesolveProblem","text":"ssesolveProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n sc_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::StochasticDiffEqAlgorithm=SRA1()\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n rng::AbstractRNG=default_rng(),\n kwargs...)\n\nGenerates the SDEProblem for the Stochastic Schrödinger time evolution of a quantum system. This is defined by the following stochastic differential equation:\n\n dpsi(t)rangle = -i K psi(t)rangle dt + sum_n M_n psi(t)rangle dW_n(t)\n \n\nwhere \n \n\nmath K = \\hat{H} + i \\sumn \\left(\\frac{ej} Cn - \\frac{1}{2} \\sum{j} Cn^\\dagger Cn - \\frac{ej^2}{8}\\right), math Mn = Cn - \\frac{en}{2}, andmath en = \\langle Cn + C_n^\\dagger \\rangle. ```\n\nAbove, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: The time list of the evolution.\nsc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators hatC_n_n.\nalg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of operators to be evaluated during the evolution.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: The time-dependent Hamiltonian of the system. If nothing, the Hamiltonian is time-independent.\nparams::NamedTuple: The parameters of the system.\nrng::AbstractRNG: The random number generator for reproducibility.\nkwargs...: The keyword arguments passed to the SDEProblem constructor.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.\nFor more details about alg please refer to DifferentialEquations.jl (SDE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob: The SDEProblem for the Stochastic Schrödinger time evolution of the system.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ssesolveEnsembleProblem","page":"API","title":"QuantumToolbox.ssesolveEnsembleProblem","text":"ssesolveEnsembleProblem(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n sc_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n alg::StochasticDiffEqAlgorithm=SRA1()\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n rng::AbstractRNG=default_rng(),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n prob_func::Function=_mcsolve_prob_func,\n output_func::Function=_ssesolve_dispatch_output_func(ensemble_method),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nGenerates the SDE EnsembleProblem for the Stochastic Schrödinger time evolution of a quantum system. This is defined by the following stochastic differential equation:\n\n dpsi(t)rangle = -i K psi(t)rangle dt + sum_n M_n psi(t)rangle dW_n(t)\n \n\nwhere \n \n\nmath K = \\hat{H} + i \\sumn \\left(\\frac{ej} Cn - \\frac{1}{2} \\sum{j} Cn^\\dagger Cn - \\frac{ej^2}{8}\\right), math Mn = Cn - \\frac{en}{2}, andmath en = \\langle Cn + C_n^\\dagger \\rangle. ```\n\nAbove, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: The time list of the evolution.\nsc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators hatC_n_n.\nalg::StochasticDiffEqAlgorithm: The algorithm used for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of operators to be evaluated during the evolution.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: The time-dependent Hamiltonian of the system. If nothing, the Hamiltonian is time-independent.\nparams::NamedTuple: The parameters of the system.\nrng::AbstractRNG: The random number generator for reproducibility.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\nprob_func::Function: Function to use for generating the SDEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nprogress_bar::Union{Val,Bool}: Whether to show a progress bar.\nkwargs...: The keyword arguments passed to the SDEProblem constructor.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.\nFor more details about alg please refer to DifferentialEquations.jl (SDE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nprob::EnsembleProblem with SDEProblem: The Ensemble SDEProblem for the Stochastic Shrödinger time evolution.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.lr_mesolveProblem","page":"API","title":"QuantumToolbox.lr_mesolveProblem","text":"lr_mesolveProblem(H, z, B, tlist, c_ops; e_ops=(), f_ops=(), opt=LRMesolveOptions(), kwargs...) where T\nFormulates the ODEproblem for the low-rank time evolution of the system. The function is called by lr_mesolve.\n\nParameters\n----------\nH : QuantumObject\n The Hamiltonian of the system.\nz : AbstractMatrix{T}\n The initial z matrix.\nB : AbstractMatrix{T}\n The initial B matrix.\ntlist : AbstractVector{T}\n The time steps at which the expectation values and function values are calculated.\nc_ops : AbstractVector{QuantumObject}\n The jump operators of the system.\ne_ops : Tuple{QuantumObject}\n The operators whose expectation values are calculated.\nf_ops : Tuple{Function}\n The functions whose values are calculated.\nopt : LRMesolveOptions\n The options of the problem.\nkwargs : NamedTuple\n Additional keyword arguments for the ODEProblem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.sesolve","page":"API","title":"QuantumToolbox.sesolve","text":"sesolve(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nTime evolution of a closed quantum system using the Schrödinger equation:\n\nfracpartialpartial t psi(t)rangle = -i hatH psi(t)rangle\n\nArguments\n\nH::QuantumObject: The Hamiltonian of the system hatH.\nψ0::QuantumObject: The initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mesolve","page":"API","title":"QuantumToolbox.mesolve","text":"mesolve(H::QuantumObject,\n ψ0::QuantumObject,\n tlist::AbstractVector, \n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n progress_bar::Union{Val,Bool}=Val(true),\n kwargs...)\n\nTime evolution of an open quantum system using Lindblad master equation:\n\nfracpartial hatrho(t)partial t = -ihatH hatrho(t) + sum_n mathcalD(hatC_n) hatrho(t)\n\nwhere \n\nmathcalD(hatC_n) hatrho(t) = hatC_n hatrho(t) hatC_n^dagger - frac12 hatC_n^dagger hatC_n hatrho(t) - frac12 hatrho(t) hatC_n^dagger hatC_n\n\nArguments\n\nH::QuantumObject: The Hamiltonian hatH or the Liouvillian of the system.\nψ0::QuantumObject: The initial state of the system.\ntlist::AbstractVector: The time list of the evolution.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Named Tuple of parameters to pass to the solver.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionSol: The solution of the time evolution. See also TimeEvolutionSol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.mcsolve","page":"API","title":"QuantumToolbox.mcsolve","text":"mcsolve(H::QuantumObject{<:AbstractArray{T1},OperatorQuantumObject},\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n alg::OrdinaryDiffEqAlgorithm = Tsit5(),\n e_ops::Union{Nothing,AbstractVector,Tuple} = nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum} = nothing,\n params::NamedTuple = NamedTuple(),\n rng::AbstractRNG = default_rng(),\n ntraj::Int = 1,\n ensemble_method = EnsembleThreads(),\n jump_callback::TJC = ContinuousLindbladJumpCallback(),\n prob_func::Function = _mcsolve_prob_func,\n output_func::Function = _mcsolve_dispatch_output_func(ensemble_method),\n progress_bar::Union{Val,Bool} = Val(true),\n kwargs...,\n)\n\nTime evolution of an open quantum system using quantum trajectories.\n\nGiven a system Hamiltonian hatH and a list of collapse (jump) operators hatC_n_n, the evolution of the state psi(t)rangle is governed by the Schrodinger equation:\n\nfracpartialpartial t psi(t)rangle= -i hatH_textrmeff psi(t)rangle\n\nwith a non-Hermitian effective Hamiltonian:\n\nhatH_textrmeff = hatH - fraci2 sum_n hatC_n^dagger hatC_n\n\nTo the first-order of the wave function in a small time delta t, the strictly negative non-Hermitian portion in hatH_textrmeff gives rise to a reduction in the norm of the wave function, namely\n\nlangle psi(t+delta t) psi(t+delta t) rangle = 1 - delta p\n\nwhere \n\ndelta p = delta t sum_n langle psi(t) hatC_n^dagger hatC_n psi(t) rangle\n\nis the corresponding quantum jump probability.\n\nIf the environmental measurements register a quantum jump, the wave function undergoes a jump into a state defined by projecting psi(t)rangle using the collapse operator hatC_n corresponding to the measurement, namely\n\n psi(t+delta t) rangle = frachatC_n psi(t)rangle sqrtlangle psi(t) hatC_n^dagger hatC_n psi(t) rangle \n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}: List of collapse operators hatC_n_n.\nalg::OrdinaryDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nrng::AbstractRNG: Random number generator for reproducibility.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\njump_callback::LindbladJumpCallbackType: The Jump Callback type: Discrete or Continuous.\nprob_func::Function: Function to use for generating the ODEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nkwargs...: Additional keyword arguments to pass to the solver.\nprogress_bar::Union{Val,Bool}: Whether to show the progress bar. Using non-Val types might lead to type instabilities.\n\nNotes\n\nensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-6 and abstol=1e-8.\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionMCSol: The solution of the time evolution. See also TimeEvolutionMCSol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.ssesolve","page":"API","title":"QuantumToolbox.ssesolve","text":"ssesolve(H::QuantumObject,\n ψ0::QuantumObject{<:AbstractArray{T2},KetQuantumObject},\n tlist::AbstractVector,\n sc_ops::Union{Nothing, AbstractVector}=nothing;\n alg::StochasticDiffEqAlgorithm=SRA1(),\n e_ops::Union{Nothing,AbstractVector,Tuple}=nothing,\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n rng::AbstractRNG=default_rng(),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n prob_func::Function=_ssesolve_prob_func,\n output_func::Function=_ssesolve_dispatch_output_func(ensemble_method),\n progress_bar::Union{Val,Bool} = Val(true),\n kwargs...)\n\nStochastic Schrödinger equation evolution of a quantum system given the system Hamiltonian hatH and a list of stochadtic collapse (jump) operators hatC_n_n. The stochastic evolution of the state psi(t)rangle is defined by:\n\n dpsi(t)rangle = -i K psi(t)rangle dt + sum_n M_n psi(t)rangle dW_n(t)\n \n\nwhere \n \n\nmath K = \\hat{H} + i \\sumn \\left(\\frac{ej} Cn - \\frac{1}{2} \\sum{j} Cn^\\dagger Cn - \\frac{ej^2}{8}\\right), math Mn = Cn - \\frac{en}{2}, andmath en = \\langle Cn + C_n^\\dagger \\rangle. ```\n\nAbove, C_n is the n-th collapse operator and dW_j(t) is the real Wiener increment associated to C_n.\n\nArguments\n\nH::QuantumObject: Hamiltonian of the system hatH.\nψ0::QuantumObject: Initial state of the system psi(0)rangle.\ntlist::AbstractVector: List of times at which to save the state of the system.\nsc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: List of stochastic collapse operators hatC_n_n.\nalg::StochasticDiffEqAlgorithm: Algorithm to use for the time evolution.\ne_ops::Union{Nothing,AbstractVector,Tuple}: List of operators for which to calculate expectation values.\nH_t::Union{Nothing,Function,TimeDependentOperatorSum}: Time-dependent part of the Hamiltonian.\nparams::NamedTuple: Dictionary of parameters to pass to the solver.\nrng::AbstractRNG: Random number generator for reproducibility.\nntraj::Int: Number of trajectories to use.\nensemble_method: Ensemble method to use.\nprob_func::Function: Function to use for generating the SDEProblem.\noutput_func::Function: Function to use for generating the output of a single trajectory.\nprogress_bar::Union{Val,Bool}: Whether to show a progress bar.\nkwargs...: Additional keyword arguments to pass to the solver.\n\nNotes\n\nensemble_method can be one of EnsembleThreads(), EnsembleSerial(), EnsembleDistributed()\nThe states will be saved depend on the keyword argument saveat in kwargs.\nIf e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). You can also specify e_ops and saveat separately.\nThe default tolerances in kwargs are given as reltol=1e-2 and abstol=1e-2.\nFor more details about alg please refer to DifferentialEquations.jl (SDE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\nReturns\n\nsol::TimeEvolutionSSESol: The solution of the time evolution. See also TimeEvolutionSSESol\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dfd_mesolve","page":"API","title":"QuantumToolbox.dfd_mesolve","text":"dfd_mesolve(H::Function, ψ0::QuantumObject,\n t_l::AbstractVector, c_ops::Function, maxdims::AbstractVector,\n dfd_params::NamedTuple=NamedTuple();\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Function=(dim_list) -> Vector{Vector{T1}}([]),\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n tol_list::Vector{<:Number}=fill(1e-8, length(maxdims)),\n kwargs...)\n\nTime evolution of an open quantum system using master equation, dynamically changing the dimension of the Hilbert subspaces.\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dsf_mesolve","page":"API","title":"QuantumToolbox.dsf_mesolve","text":"dsf_mesolve(H::Function,\n ψ0::QuantumObject,\n t_l::AbstractVector, c_ops::Function,\n op_list::Vector{TOl},\n α0_l::Vector{<:Number}=zeros(length(op_list)),\n dsf_params::NamedTuple=NamedTuple();\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Function=(op_list,p) -> Vector{TOl}([]),\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n δα_list::Vector{<:Number}=fill(0.2, length(op_list)),\n krylov_dim::Int=max(6, min(10, cld(length(ket2dm(ψ0).data), 4))),\n kwargs...)\n\nTime evolution of an open quantum system using master equation and the Dynamical Shifted Fock algorithm.\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dsf_mcsolve","page":"API","title":"QuantumToolbox.dsf_mcsolve","text":"dsf_mcsolve(H::Function,\n ψ0::QuantumObject,\n t_l::AbstractVector, c_ops::Function,\n op_list::Vector{TOl},\n α0_l::Vector{<:Number}=zeros(length(op_list)),\n dsf_params::NamedTuple=NamedTuple();\n alg::OrdinaryDiffEqAlgorithm=Tsit5(),\n e_ops::Function=(op_list,p) -> Vector{TOl}([]),\n H_t::Union{Nothing,Function,TimeDependentOperatorSum}=nothing,\n params::NamedTuple=NamedTuple(),\n δα_list::Vector{<:Real}=fill(0.2, length(op_list)),\n ntraj::Int=1,\n ensemble_method=EnsembleThreads(),\n jump_callback::LindbladJumpCallbackType=ContinuousLindbladJumpCallback(),\n krylov_dim::Int=max(6, min(10, cld(length(ket2dm(ψ0).data), 4))),\n progress_bar::Union{Bool,Val} = Val(true)\n kwargs...)\n\nTime evolution of a quantum system using the Monte Carlo wave function method and the Dynamical Shifted Fock algorithm.\n\nNotes\n\nFor more details about alg please refer to DifferentialEquations.jl (ODE Solvers)\nFor more details about kwargs please refer to DifferentialEquations.jl (Keyword Arguments)\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.lr_mesolve","page":"API","title":"QuantumToolbox.lr_mesolve","text":"lr_mesolve(prob::ODEProblem; kwargs...)\nSolves the ODEProblem formulated by lr_mesolveProblem. The function is called by lr_mesolve.\n\nParameters\n----------\nprob : ODEProblem\n The ODEProblem formulated by lr_mesolveProblem.\nkwargs : NamedTuple\n Additional keyword arguments for the ODEProblem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.liouvillian","page":"API","title":"QuantumToolbox.liouvillian","text":"liouvillian(H::QuantumObject, c_ops::Union{Nothing,AbstractVector,Tuple}=nothing, Id_cache=I(prod(H.dims)))\n\nConstruct the Liouvillian SuperOperator for a system Hamiltonian hatH and a set of collapse operators hatC_n_n:\n\nmathcalL cdot = -ihatH cdot + sum_n mathcalD(hatC_n) cdot\n\nwhere \n\nmathcalD(hatC_n) cdot = hatC_n cdot hatC_n^dagger - frac12 hatC_n^dagger hatC_n cdot - frac12 cdot hatC_n^dagger hatC_n\n\nThe 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.\n\nSee also spre, spost, and lindblad_dissipator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.liouvillian_generalized","page":"API","title":"QuantumToolbox.liouvillian_generalized","text":"liouvillian_generalized(H::QuantumObject, fields::Vector, \nT_list::Vector; N_trunc::Int=size(H,1), tol::Float64=0.0, σ_filter::Union{Nothing, Real}=nothing)\n\nConstructs the generalized Liouvillian for a system coupled to a bath of harmonic oscillators.\n\nSee, 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.steadystate","page":"API","title":"QuantumToolbox.steadystate","text":"steadystate(\n H::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n solver::SteadyStateSolver = SteadyStateDirectSolver(),\n kwargs...\n)\n\nSolve the stationary state based on different solvers.\n\nParameters\n\nH::QuantumObject: The Hamiltonian or the Liouvillian of the system.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.\nsolver::SteadyStateSolver=SteadyStateDirectSolver(): see documentation Solving for Steady-State Solutions for different solvers.\nkwargs...: The keyword arguments for the solver.\n\n\n\n\n\nsteadystate(\n H::QuantumObject,\n ψ0::QuantumObject,\n tspan::Real = Inf,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n solver::SteadyStateODESolver = SteadyStateODESolver(),\n reltol::Real = 1.0e-8,\n abstol::Real = 1.0e-10,\n kwargs...\n)\n\nSolve the stationary state based on time evolution (ordinary differential equations; OrdinaryDiffEq.jl) with a given initial state.\n\nThe termination condition of the stationary state rhoranglerangle is that either the following condition is true:\n\nlVertfracpartial hatrhorangleranglepartial trVert leq textrmreltol timeslVertfracpartial hatrhorangleranglepartial t+hatrhorangleranglerVert\n\nor\n\nlVertfracpartial hatrhorangleranglepartial trVert leq textrmabstol\n\nParameters\n\nH::QuantumObject: The Hamiltonian or the Liouvillian of the system.\nψ0::QuantumObject: The initial state of the system.\ntspan::Real=Inf: The final time step for the steady state problem.\nc_ops::Union{Nothing,AbstractVector,Tuple}=nothing: The list of the collapse operators.\nsolver::SteadyStateODESolver=SteadyStateODESolver(): see SteadyStateODESolver for more details.\nreltol::Real=1.0e-8: Relative tolerance in steady state terminate condition and solver adaptive timestepping.\nabstol::Real=1.0e-10: Absolute tolerance in steady state terminate condition and solver adaptive timestepping.\nkwargs...: The keyword arguments for the ODEProblem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.steadystate_floquet","page":"API","title":"QuantumToolbox.steadystate_floquet","text":"steadystate_floquet(\n H_0::QuantumObject{MT,OpType1},\n H_p::QuantumObject{<:AbstractArray,OpType2},\n H_m::QuantumObject{<:AbstractArray,OpType3},\n ωd::Number,\n c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;\n n_max::Integer = 2,\n tol::R = 1e-8,\n solver::FSolver = SSFloquetLinearSystem,\n kwargs...,\n)\n\nCalculates the steady state of a periodically driven system. Here H_0 is the Hamiltonian or the Liouvillian of the undriven system. Considering a monochromatic drive at frequency omega_d, we divide it into two parts, H_p and H_m, where H_p oscillates as e^i omega t and H_m oscillates as e^-i omega t. There are two solvers available for this function:\n\nSSFloquetLinearSystem: Solves the linear system of equations.\nSSFloquetEffectiveLiouvillian: Solves the effective Liouvillian.\n\nFor both cases, n_max is the number of Fourier components to consider, and tol is the tolerance for the solver.\n\nIn the case of SSFloquetLinearSystem, the full linear system is solved at once:\n\n( mathcalL_0 - i n omega_d ) hatrho_n + mathcalL_1 hatrho_n-1 + mathcalL_-1 hatrho_n+1 = 0\n\nThis is a tridiagonal linear system of the form\n\nmathbfA cdot mathbfb = 0\n\nwhere\n\nmathbfA = beginpmatrix\nmathcalL_0 - i (-n_textrmmax) omega_textrmd mathcalL_-1 0 cdots 0 \nmathcalL_1 mathcalL_0 - i (-n_textrmmax+1) omega_textrmd mathcalL_-1 cdots 0 \n0 mathcalL_1 mathcalL_0 - i (-n_textrmmax+2) omega_textrmd cdots 0 \nvdots vdots vdots ddots vdots \n0 0 0 cdots mathcalL_0 - i n_textrmmax omega_textrmd\nendpmatrix\n\nand\n\nmathbfb = beginpmatrix\nhatrho_-n_textrmmax \nhatrho_-n_textrmmax+1 \nvdots \nhatrho_0 \nvdots \nhatrho_n_textrmmax-1 \nhatrho_n_textrmmax\nendpmatrix\n\nThis will allow to simultaneously obtain all the hatrho_n.\n\nIn the case of SSFloquetEffectiveLiouvillian, instead, the effective Liouvillian is calculated using the matrix continued fraction method.\n\nnote: different return\nThe two solvers returns different objects. The SSFloquetLinearSystem returns a list of QuantumObject, containing the density matrices for each Fourier component (hatrho_-n, with n from 0 to n_textrmmax), while the SSFloquetEffectiveLiouvillian returns only hatrho_0. \n\nArguments\n\nH_0::QuantumObject: The Hamiltonian or the Liouvillian of the undriven system.\nH_p::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as e^i omega t.\nH_m::QuantumObject: The Hamiltonian or the Liouvillian of the part of the drive that oscillates as e^-i omega t.\nωd::Number: The frequency of the drive.\nc_ops::Union{Nothing,AbstractVector} = nothing: The optional collapse operators.\nn_max::Integer = 2: The number of Fourier components to consider.\ntol::R = 1e-8: The tolerance for the solver.\nsolver::FSolver = SSFloquetLinearSystem: The solver to use.\nkwargs...: Additional keyword arguments to be passed to the solver.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.SteadyStateDirectSolver","page":"API","title":"QuantumToolbox.SteadyStateDirectSolver","text":"SteadyStateDirectSolver()\n\nA solver which solves steadystate by finding the inverse of Liouvillian SuperOperator using the standard method given in LinearAlgebra.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SteadyStateEigenSolver","page":"API","title":"QuantumToolbox.SteadyStateEigenSolver","text":"SteadyStateEigenSolver()\n\nA solver which solves steadystate by finding the zero (or lowest) eigenvalue of Liouvillian SuperOperator using eigsolve.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SteadyStateLinearSolver","page":"API","title":"QuantumToolbox.SteadyStateLinearSolver","text":"SteadyStateLinearSolver(alg = KrylovJL_GMRES(), Pl = nothing, Pr = nothing)\n\nA solver which solves steadystate by finding the inverse of Liouvillian SuperOperator using the algorithms given in LinearSolve.jl.\n\nParameters\n\nalg::SciMLLinearSolveAlgorithm=KrylovJL_GMRES(): algorithms given in LinearSolve.jl\nPl::Union{Function,Nothing}=nothing: left preconditioner, see documentation Solving for Steady-State Solutions for more details.\nPr::Union{Function,Nothing}=nothing: right preconditioner, see documentation Solving for Steady-State Solutions for more details.\n\n\n\n\n\n","category":"type"},{"location":"api/#QuantumToolbox.SteadyStateODESolver","page":"API","title":"QuantumToolbox.SteadyStateODESolver","text":"SteadyStateODESolver(alg = Tsit5())\n\nAn ordinary differential equation (ODE) solver for solving steadystate.\n\nIt includes a field (attribute) SteadyStateODESolver.alg that specifies the solving algorithm. Default to Tsit5().\n\nFor more details about the solvers, please refer to OrdinaryDiffEq.jl\n\n\n\n\n\n","category":"type"},{"location":"api/#doc-API:Correlations-and-Spectrum","page":"API","title":"Correlations and Spectrum","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"correlation_3op_2t\ncorrelation_2op_2t\ncorrelation_2op_1t\nspectrum","category":"page"},{"location":"api/#QuantumToolbox.correlation_3op_2t","page":"API","title":"QuantumToolbox.correlation_3op_2t","text":"correlation_3op_2t(H::QuantumObject,\n ψ0::QuantumObject,\n t_l::AbstractVector,\n τ_l::AbstractVector,\n A::QuantumObject,\n B::QuantumObject,\n C::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n kwargs...)\n\nReturns the two-times correlation function of three operators hatA, hatB and hatC: expvalhatA(t) hatB(t + tau) hatC(t)\n\nfor a given initial state ketpsi_0.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.correlation_2op_2t","page":"API","title":"QuantumToolbox.correlation_2op_2t","text":"correlation_2op_2t(H::QuantumObject,\n ψ0::QuantumObject,\n t_l::AbstractVector,\n τ_l::AbstractVector,\n A::QuantumObject,\n B::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n reverse::Bool=false,\n kwargs...)\n\nReturns the two-times correlation function of two operators hatA and hatB at different times: expvalhatA(t + tau) hatB(t).\n\nWhen reverse=true, the correlation function is calculated as expvalhatA(t) hatB(t + tau).\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.correlation_2op_1t","page":"API","title":"QuantumToolbox.correlation_2op_1t","text":"correlation_2op_1t(H::QuantumObject,\n ψ0::QuantumObject,\n τ_l::AbstractVector,\n A::QuantumObject,\n B::QuantumObject,\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n reverse::Bool=false,\n kwargs...)\n\nReturns the one-time correlation function of two operators hatA and hatB at different times expvalhatA(tau) hatB(0).\n\nWhen reverse=true, the correlation function is calculated as expvalhatA(0) hatB(tau).\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.spectrum","page":"API","title":"QuantumToolbox.spectrum","text":"spectrum(H::QuantumObject,\n ω_list::AbstractVector,\n A::QuantumObject{<:AbstractArray{T2},OperatorQuantumObject},\n B::QuantumObject{<:AbstractArray{T3},OperatorQuantumObject},\n c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;\n solver::MySolver=ExponentialSeries(),\n kwargs...)\n\nReturns the emission spectrum \n\nS(omega) = int_-infty^infty expvalhatA(tau) hatB(0) e^-i omega tau d tau\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Metrics","page":"API","title":"Metrics","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"entropy_vn\nentanglement\ntracedist\nfidelity","category":"page"},{"location":"api/#QuantumToolbox.entropy_vn","page":"API","title":"QuantumToolbox.entropy_vn","text":"entropy_vn(ρ::QuantumObject; base::Int=0, tol::Real=1e-15)\n\nCalculates the Von Neumann entropy S = - Tr left hatrho log left( hatrho right) right where hatrho is the density matrix of the system.\n\nThe base parameter specifies the base of the logarithm to use, and when using the default value 0, the natural logarithm is used. The tol parameter describes the absolute tolerance for detecting the zero-valued eigenvalues of the density matrix hatrho.\n\nExamples\n\nPure state:\n\njulia> ψ = fock(2,0)\nQuantum Object: type=Ket dims=[2] size=(2,)\n2-element Vector{ComplexF64}:\n 1.0 + 0.0im\n 0.0 + 0.0im\n\njulia> ρ = ket2dm(ψ)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Matrix{ComplexF64}:\n 1.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im\n\njulia> entropy_vn(ρ, base=2)\n-0.0\n\nMixed state:\n\njulia> ρ = maximally_mixed_dm(2)\nQuantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 Diagonal{ComplexF64, Vector{ComplexF64}}:\n 0.5-0.0im ⋅ \n ⋅ 0.5-0.0im\n\njulia> entropy_vn(ρ, base=2)\n1.0\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.entanglement","page":"API","title":"QuantumToolbox.entanglement","text":"entanglement(QO::QuantumObject, sel::Union{Int,AbstractVector{Int},Tuple})\n\nCalculates 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.tracedist","page":"API","title":"QuantumToolbox.tracedist","text":"tracedist(ρ::QuantumObject, σ::QuantumObject)\n\nCalculates the trace distance between two QuantumObject: T(hatrho hatsigma) = frac12 lVert hatrho - hatsigma rVert_1\n\nNote that ρ and σ must be either Ket or Operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.fidelity","page":"API","title":"QuantumToolbox.fidelity","text":"fidelity(ρ::QuantumObject, σ::QuantumObject)\n\nCalculate the fidelity of two QuantumObject: F(hatrho hatsigma) = textrmTr sqrtsqrthatrho hatsigma sqrthatrho\n\nHere, the definition is from Nielsen & Chuang, \"Quantum Computation and Quantum Information\". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994).\n\nNote that ρ and σ must be either Ket or Operator.\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Miscellaneous","page":"API","title":"Miscellaneous","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"wigner\nnegativity","category":"page"},{"location":"api/#QuantumToolbox.wigner","page":"API","title":"QuantumToolbox.wigner","text":"wigner(state::QuantumObject, xvec::AbstractVector, yvec::AbstractVector; g::Real=√2,\n solver::WignerSolver=WignerLaguerre())\n\nGenerates the Wigner quasipropability distribution of state at points xvec + 1im * yvec. The g parameter is a scaling factor related to the value of hbar in the commutation relation x y = i hbar via hbar=2g^2 giving the default value hbar=1.\n\nThe solver parameter can be either WignerLaguerre() or WignerClenshaw(). The former uses the Laguerre polynomial expansion of the Wigner function, while the latter uses the Clenshaw algorithm. The Laguerre expansion is faster for 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.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.negativity","page":"API","title":"QuantumToolbox.negativity","text":"negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool=false)\n\nCompute the negativity N(hatrho) = fracVert hatrho^GammaVert_1 - 12 where hatrho^Gamma is the partial transpose of hatrho with respect to the subsystem, and Vert hatX Vert_1=textrmTrsqrthatX^dagger hatX is the trace norm.\n\nArguments\n\nρ::QuantumObject: The density matrix (ρ.type must be OperatorQuantumObject).\nsubsys::Int: an index that indicates which subsystem to compute the negativity for.\nlogarithmic::Bool: choose whether to calculate logarithmic negativity or not. Default as false\n\nReturns\n\nN::Real: The value of negativity.\n\nExamples\n\njulia> Ψ = bell_state(0, 0)\nQuantum Object: type=Ket dims=[2, 2] size=(4,)\n4-element Vector{ComplexF64}:\n 0.7071067811865475 + 0.0im\n 0.0 + 0.0im\n 0.0 + 0.0im\n 0.7071067811865475 + 0.0im\n\njulia> ρ = ket2dm(Ψ)\nQuantum Object: type=Operator dims=[2, 2] size=(4, 4) ishermitian=true\n4×4 Matrix{ComplexF64}:\n 0.5+0.0im 0.0+0.0im 0.0+0.0im 0.5+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.5+0.0im 0.0+0.0im 0.0+0.0im 0.5+0.0im\n\njulia> negativity(ρ, 2)\n0.4999999999999998\n\n\n\n\n\n","category":"function"},{"location":"api/#doc-API:Linear-Maps","page":"API","title":"Linear Maps","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractLinearMap","category":"page"},{"location":"api/#QuantumToolbox.AbstractLinearMap","page":"API","title":"QuantumToolbox.AbstractLinearMap","text":"AbstractLinearMap{T, TS}\n\nRepresents a general linear map with element type T and size TS.\n\nOverview\n\nA linear map is a transformation L that satisfies:\n\nAdditivity: math L(u + v) = L(u) + L(v)\nHomogeneity: math L(cu) = cL(u)\n\nIt is typically represented as a matrix with dimensions given by size, and this abtract type helps to define this map when the matrix is not explicitly available.\n\nMethods\n\nBase.eltype(A): Returns the element type T.\nBase.size(A): Returns the size A.size.\nBase.size(A, i): Returns the i-th dimension.\n\nExample\n\nAs an example, we now define the linear map used in the eigsolve_al function for Arnoldi-Lindblad eigenvalue solver:\n\nstruct ArnoldiLindbladIntegratorMap{T,TS,TI} <: AbstractLinearMap{T,TS}\n elty::Type{T}\n size::TS\n integrator::TI\nend\n\nfunction LinearAlgebra.mul!(y::AbstractVector, A::ArnoldiLindbladIntegratorMap, x::AbstractVector)\n reinit!(A.integrator, x)\n solve!(A.integrator)\n return copyto!(y, A.integrator.u)\nend\n\nwhere integrator is the ODE integrator for the time-evolution. In this way, we can diagonalize this linear map using the eigsolve function.\n\n\n\n\n\n","category":"type"},{"location":"api/#doc-API:Utility-functions","page":"API","title":"Utility functions","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"QuantumToolbox.versioninfo\nQuantumToolbox.about\ngaussian\nn_thermal\nPhysicalConstants\nconvert_unit\nrow_major_reshape\nmeshgrid\n_calculate_expectation!\n_adjM_condition_variational\n_adjM_affect!\n_adjM_condition_ratio\n_pinv!\ndBdz!","category":"page"},{"location":"api/#QuantumToolbox.versioninfo","page":"API","title":"QuantumToolbox.versioninfo","text":"QuantumToolbox.versioninfo(io::IO=stdout)\n\nCommand line output of information on QuantumToolbox, dependencies, and system information, same as QuantumToolbox.about.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.about","page":"API","title":"QuantumToolbox.about","text":"QuantumToolbox.about(io::IO=stdout)\n\nCommand line output of information on QuantumToolbox, dependencies, and system information, same as QuantumToolbox.versioninfo.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.gaussian","page":"API","title":"QuantumToolbox.gaussian","text":"gaussian(x::Number, μ::Number, σ::Number)\n\nReturns the gaussian function exp left- frac(x - mu)^22 sigma^2 right, where mu and sigma^2 are the mean and the variance respectively.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.n_thermal","page":"API","title":"QuantumToolbox.n_thermal","text":"n_thermal(ω::Real, ω_th::Real)\n\nReturn the number of photons in thermal equilibrium for an harmonic oscillator mode with frequency omega, at the temperature described by omega_textrmth equiv k_B T hbar:\n\nn(omega omega_textrmth) = frac1e^omegaomega_textrmth - 1\n\nwhere hbar is the reduced Planck constant, and k_B is the Boltzmann constant.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.PhysicalConstants","page":"API","title":"QuantumToolbox.PhysicalConstants","text":"const PhysicalConstants\n\nA NamedTuple which stores some constant values listed in CODATA recommended values of the fundamental physical constants: 2022\n\nThe current stored constants are:\n\nc : (exact) speed of light in vacuum with unit textrmmcdottextrms^-1\nG : Newtonian constant of gravitation with unit textrmm^3cdottextrmkg^1cdottextrms^2\nh : (exact) Planck constant with unit textrmJcdottextrms\nħ : reduced Planck constant with unit textrmJcdottextrms\ne : (exact) elementary charge with unit textrmC\nμ0 : vacuum magnetic permeability with unit textrmNcdottextrmA^-2\nϵ0 : vacuum electric permittivity with unit textrmFcdottextrmm^-1\nk : (exact) Boltzmann constant with unit textrmJcdottextrmK^-1\nNA : (exact) Avogadro constant with unit textrmmol^-1\n\nExamples\n\njulia> PhysicalConstants.ħ\n1.0545718176461565e-34\n\n\n\n\n\n","category":"constant"},{"location":"api/#QuantumToolbox.convert_unit","page":"API","title":"QuantumToolbox.convert_unit","text":"convert_unit(value::Real, unit1::Symbol, unit2::Symbol)\n\nConvert the energy value from unit1 to unit2. The unit1 and unit2 can be either the following Symbol:\n\n:J : Joule\n:eV : electron volt\n:meV : milli-electron volt\n:MHz : Mega-Hertz multiplied by Planck constant h\n:GHz : Giga-Hertz multiplied by Planck constant h\n:K : Kelvin multiplied by Boltzmann constant k\n:mK : milli-Kelvin multiplied by Boltzmann constant k\n\nNote that we use the values stored in PhysicalConstants to do the conversion.\n\nExamples\n\njulia> convert_unit(1, :eV, :J)\n1.602176634e-19\n\njulia> convert_unit(1, :GHz, :J)\n6.62607015e-25\n\njulia> convert_unit(1, :meV, :mK)\n11604.518121550082\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.row_major_reshape","page":"API","title":"QuantumToolbox.row_major_reshape","text":"row_major_reshape(Q::AbstractArray, shapes...)\n\nReshapes Q in the row-major order, as numpy.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.meshgrid","page":"API","title":"QuantumToolbox.meshgrid","text":"meshgrid(x::AbstractVector, y::AbstractVector)\n\nEquivalent to numpy meshgrid.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._calculate_expectation!","page":"API","title":"QuantumToolbox._calculate_expectation!","text":"_calculate_expectation!(p,z,B,idx) where T\nCalculates 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.\nThe function is called by the callback _save_affect_lr_mesolve!.\n\nParameters\n----------\np : NamedTuple\n The parameters of the problem.\nz : AbstractMatrix{T}\n The z matrix.\nB : AbstractMatrix{T}\n The B matrix.\nidx : Integer\n The index of the current time step.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._adjM_condition_variational","page":"API","title":"QuantumToolbox._adjM_condition_variational","text":"_adjM_condition_variational(u, t, integrator) where T\nCondition for the dynamical rank adjustment based on the leakage out of the low-rank manifold.\n\nParameters\n----------\nu : AbstractVector{T}\n The current state of the system.\nt : Real\n The current time.\nintegrator : ODEIntegrator\n The integrator of the problem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._adjM_affect!","page":"API","title":"QuantumToolbox._adjM_affect!","text":"_adjM_affect!(integrator)\nAffect function for the dynamical rank adjustment. It increases the rank of the low-rank manifold by one, and updates the matrices accordingly.\nIf Δt>0, it rewinds the integrator to the previous time step.\n\nParameters\n----------\nintegrator : ODEIntegrator\n The integrator of the problem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._adjM_condition_ratio","page":"API","title":"QuantumToolbox._adjM_condition_ratio","text":"_adjM_condition_ratio(u, t, integrator) where T\nCondition for the dynamical rank adjustment based on the ratio between the smallest and largest eigenvalues of the density matrix.\nThe spectrum of the density matrix is calculated efficiently using the properties of the SVD decomposition of the matrix.\n\nParameters\n----------\nu : AbstractVector{T}\n The current state of the system.\nt : Real\n The current time.\nintegrator : ODEIntegrator\n The integrator of the problem.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox._pinv!","page":"API","title":"QuantumToolbox._pinv!","text":"_pinv!(A, T1, T2; atol::Real=0.0, rtol::Real=(eps(real(float(oneunit(T))))*min(size(A)...))*iszero(atol)) where T\nComputes the pseudo-inverse of a matrix A, and stores it in T1. If T2 is provided, it is used as a temporary matrix. \nThe algorithm is based on the SVD decomposition of A, and is taken from the Julia package LinearAlgebra.\nThe difference with respect to the original function is that the cutoff is done with a smooth function instead of a step function.\n\nParameters\n----------\nA : AbstractMatrix{T}\n The matrix to be inverted.\nT1 : AbstractMatrix{T}\nT2 : AbstractMatrix{T}\n Temporary matrices used in the calculation.\natol : Real\n Absolute tolerance for the calculation of the pseudo-inverse. \nrtol : Real\n Relative tolerance for the calculation of the pseudo-inverse.\n\n\n\n\n\n","category":"function"},{"location":"api/#QuantumToolbox.dBdz!","page":"API","title":"QuantumToolbox.dBdz!","text":"dBdz!(du, u, p, t) where T\nDynamical evolution equations for the low-rank manifold. The function is called by the ODEProblem.\n\nParameters\n----------\ndu : AbstractVector{T}\n The derivative of the state of the system.\nu : AbstractVector{T}\n The current state of the system.\np : NamedTuple\n The parameters of the problem.\nt : Real\n The current time.\n\n\n\n\n\n","category":"function"},{"location":"users_guide/time_evolution/time_dependent/#doc-TE:Solving-Problems-with-Time-dependent-Hamiltonians","page":"Solving Problems with Time-dependent Hamiltonians","title":"Solving Problems with Time-dependent Hamiltonians","text":"","category":"section"},{"location":"users_guide/time_evolution/time_dependent/","page":"Solving Problems with Time-dependent Hamiltonians","title":"Solving Problems with Time-dependent Hamiltonians","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"users_guide/time_evolution/stochastic/#doc-TE:Stochastic-Solver","page":"Stochastic Solver","title":"Stochastic Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/stochastic/","page":"Stochastic Solver","title":"Stochastic Solver","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"users_guide/time_evolution/stochastic/#Stochastic-Schrodinger-equation","page":"Stochastic Solver","title":"Stochastic Schrodinger equation","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/#doc-TE:Schrödinger-Equation-Solver","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/#Unitary-evolution","page":"Schrödinger Equation Solver","title":"Unitary evolution","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"The dynamics of a closed (pure) quantum system is governed by the Schrödinger equation","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"ihbarfracpartialpartial tPsi(vecx t) = hatHPsi(vecx t)","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"where Psi(vecx t) is the wave function, hatH is the Hamiltonian, and hbar is reduced Planck constant. In general, the Schrödinger equation is a partial differential equation (PDE) where both Psi and hatH are functions of space vecx and time t. For computational purposes it is useful to expand the PDE in a set of basis functions that span the Hilbert space of the Hamiltonian, and to write the equation in matrix and vector form, namely","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"ihbarfracddtpsi(t)rangle = hatHpsi(t)rangle","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"where psi(t)rangle is the state vector, and the Hamiltonian hatH is now under matrix representation. This matrix equation can, in principle, be solved by diagonalizing the Hamiltonian matrix hatH. In practice, however, it is difficult to perform this diagonalization unless the size of the Hilbert space (dimension of the matrix hatH) is small. Analytically, it is a formidable task to calculate the dynamics for systems with more than two states. If, in addition, we consider dissipation due to the inevitable interaction with a surrounding environment, the computational complexity grows even larger, and we have to resort to numerical calculations in all realistic situations. This illustrates the importance of numerical calculations in describing the dynamics of open quantum systems, and the need for efficient and accessible tools for this task.","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"The Schrödinger equation, which governs the time-evolution of closed quantum systems, is defined by its Hamiltonian and state vector. In the previous sections, Manipulating States and Operators and Tensor Products and Partial Traces, we showed how Hamiltonians and state vectors are constructed in QuantumToolbox.jl. Given a Hamiltonian, we can calculate the unitary (non-dissipative) time-evolution of an arbitrary initial state vector psi(0)rangle using the QuantumToolbox time evolution problem sesolveProblem or directly call the function sesolve. It evolves the state vector psi(t)rangle and evaluates the expectation values for a set of operators e_ops at each given time points, using an ordinary differential equation solver provided by the powerful julia package DifferentialEquation.jl.","category":"page"},{"location":"users_guide/time_evolution/sesolve/#Example:-Spin-dynamics","page":"Schrödinger Equation Solver","title":"Example: Spin dynamics","text":"","category":"section"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"For example, the time evolution of a quantum spin-frac12 system (initialized in spin-uparrow) with tunneling rate 01 is calculated, and the expectation values of the Pauli-Z operator hatsigma_z is also evaluated, with the following code","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"H = 2 * π * 0.1 * sigmax()\nψ0 = basis(2, 0) # spin-up\ntlist = LinRange(0.0, 10.0, 20)\n\nprob = sesolveProblem(H, ψ0, tlist, e_ops = [sigmaz()])\nsol = sesolve(prob)","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"note: Note\nHere, we generate the time evolution problem by sesolveProblem first and then put it into the function sesolve. One can also directly call sesolve, which we also demonstrates in below.","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"The function returns TimeEvolutionSol, as described in the previous section Time Evolution Solutions. The attribute expect in solution is a list of expectation values for the operator(s) that are passed to the e_ops keyword argument. ","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"sol.expect","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"Passing multiple operators to e_ops as a Vector results in the expectation values for each operators at each time points.","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"tlist = LinRange(0.0, 10.0, 100)\nsol = sesolve(H, ψ0, tlist, e_ops = [sigmaz(), sigmay()])","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"note: Note\nHere, we call sesolve directly instead of pre-defining sesolveProblem first (as shown previously).","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"times = sol.times\nprint(size(times))","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"expt = sol.expect\nprint(size(expt))","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"We can therefore plot the expectation values:","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"using CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())\n\nexpt_z = real(expt[1,:])\nexpt_y = real(expt[2,:])\n\nfig = Figure(size = (500, 350))\nax = Axis(fig[1, 1], xlabel = \"Time\", ylabel = \"Expectation values\")\nlines!(ax, times, expt_z, label = L\"\\langle\\hat{\\sigma}_z\\rangle\", linestyle = :solid)\nlines!(ax, times, expt_y, label = L\"\\langle\\hat{\\sigma}_y\\rangle\", linestyle = :dash)\n\naxislegend(ax, position = :rb)\n\nfig","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"If the keyword argument e_ops is not specified (or given as an empty Vector), the sesolve and functions return a TimeEvolutionSol that contains a list of state vectors which corresponds to the time points specified in tlist:","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"tlist = [0, 10]\nsol = sesolve(H, ψ0, tlist) # or specify: e_ops = []\n\nsol.states","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"This is because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). ","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"One can also specify e_ops and saveat separately:","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"tlist = [0, 5, 10]\nsol = sesolve(H, ψ0, tlist, e_ops = [sigmay()], saveat = tlist)","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"sol.expect","category":"page"},{"location":"users_guide/time_evolution/sesolve/","page":"Schrödinger Equation Solver","title":"Schrödinger Equation Solver","text":"sol.states","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#doc:Qobj","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/#Introduction","page":"Quantum Objects (Qobj)","title":"Introduction","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"The key difference between classical and quantum mechanics is the use of operators instead of numbers as variables. Moreover, we need to specify state vectors and their properties. Therefore, in computing the dynamics of quantum systems, we need a data structure that encapsulates the properties of a quantum operator and ket/bra vectors. The quantum object structure, QuantumObject, accomplishes this using array representation.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"QuantumObject supports general Julia arrays (Base.AbstractArray). For example, it can be:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Base.Vector (dense vector)\nBase.Matrix (dense matrix)\nSparseArrays.SparseVector (sparse vector)\nSparseArrays.SparseMatrixCSC (sparse matrix)\nCUDA.CuArray (dense GPU vector / matrix)\nCUDA.CUSPARSE.CuSparseVector (sparse GPU vector)\nCUDA.CUSPARSE.CuSparseMatrixCSC (sparse GPU matrix)\nCUDA.CUSPARSE.CuSparseMatrixCSR (sparse GPU matrix)\nand even more ...","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"note: Support for GPU arrays\nSee CUDA extension for more details.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"We can create a QuantumObject with a user defined data set by passing an array of data into the QuantumObject:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"using QuantumToolbox","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"QuantumObject([1, 2, 3, 4, 5])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"We can also use the same function Qobj in QuTiP (Python):","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj([1, 2, 3, 4, 5])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj([1 2 3 4 5])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj(rand(4, 4))","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"M = rand(ComplexF64, 4, 4)\nQobj(M, dims = [2, 2]) # dims as Vector\nQobj(M, dims = (2, 2)) # dims as Tuple (recommended)\nQobj(M, dims = SVector(2, 2)) # dims as StaticArrays.SVector (recommended)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"warning: Beware of type-stability!\nPlease note that here we put the dims as a tuple (2, 2). Although it supports also Vector type (dims = [2, 2]), it is recommended to use Tuple or SVector from StaticArrays.jl to improve performance. For a brief explanation on the impact of the type of dims, see the Section The Importance of Type-Stability.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Qobj(rand(4, 4), type = SuperOperator)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"note: Difference between `dims` and `size`\nNotice that type, dims, and size will change according to the input data. Although dims and size appear to be the same, dims keep tracking the dimension of individual Hilbert spaces of a multipartite system, while size does not. We refer the reader to the section Tensor Products and Partial Traces for more information.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#States-and-operators","page":"Quantum Objects (Qobj)","title":"States and operators","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Manually specifying the data for each quantum object is inefficient. Even more so when most objects correspond to commonly used types such as the ladder operators of a harmonic oscillator, the Pauli spin operators for a two-level system, or state vectors such as Fock states. Therefore, QuantumToolbox includes predefined functions to construct variety of states and operators (you can click the function links and see the corresponding docstring):","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#States","page":"Quantum Objects (Qobj)","title":"States","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"zero_ket: zero ket vector\nfock or basis: fock state ket vector\nfock_dm: density matrix of a fock state\ncoherent: coherent state ket vector \nrand_ket: random ket vector\ncoherent_dm: density matrix of a coherent state\nthermal_dm: density matrix of a thermal state\nmaximally_mixed_dm: density matrix of a maximally mixed state\nrand_dm: random density matrix\nspin_state: spin state\nspin_coherent: coherent spin state\nbell_state: Bell state\nsinglet_state: two particle singlet state\ntriplet_states: list of the two particle triplet states\nw_state: n-qubit W-state\nghz_state: n-qudit GHZ state","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#Operators","page":"Quantum Objects (Qobj)","title":"Operators","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"eye or qeye: identity operator\ndestroy: lowering (destruction) operator\ncreate: raising (creation) operator\nprojection: projection operator\ndisplace: displacement operator\nsqueeze: single-mode squeeze operator\nnum: bosonic number operator\nphase: single-mode Pegg-Barnett phase operator\nQuantumToolbox.position: position operator\nQuantumToolbox.momentum: momentum operator\nrand_unitary: random unitary operator\nsigmax: Pauli-X operator\nsigmay: Pauli-Y operator\nsigmaz: Pauli-Z operator\nsigmap: Pauli ladder (sigma_+) operator\nsigmam: Pauli ladder (sigma_-) operator\njmat: high-order Spin-j operator\nspin_Jx: S_x operator for Spin-j\nspin_Jy: S_y operator for Spin-j\nspin_Jz: S_z operator for Spin-j\nspin_Jm: S_- operator for Spin-j\nspin_Jp: S_+ operator for Spin-j\nspin_J_set: a set of Spin-j operators (S_x S_y S_z)\nfdestroy: fermion destruction operator\nfcreate: fermion creation operator\ncommutator: commutator or anti-commutator\ntunneling: tunneling operator\nqft: discrete quantum Fourier transform matrix","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"As an example, we give the output for a few of these functions:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"basis(5, 3)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"coherent(5, 0.5 - 0.5im)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"destroy(4)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"sigmaz()","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#Qobj-fields-(attributes)","page":"Quantum Objects (Qobj)","title":"Qobj fields (attributes)","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"We have seen that a structure QuantumObject has several fields (attributes), such as data, type and dims. These can be accessed in the following way:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a = destroy(4)\na.data","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a[2, 3] # the indexing in Julia starts from `1`","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a.type","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a.dims","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"In general, the properties of a QuantumObject can be retrieved using several functions with inputting QuantumObject:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"size(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"shape(a) # synonym of size(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"length(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"eltype(a) # element type","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"println(isket(a)) # ket\nprintln(isbra(a)) # bra\nprintln(isoper(a)) # operator\nprintln(isoperket(a)) # operator-ket\nprintln(isoperbra(a)) # operator-bra\nprintln(issuper(a)) # super operator\nprintln(ishermitian(a)) # Hermitian\nprintln(isherm(a)) # synonym of ishermitian(a)\nprintln(issymmetric(a)) # symmetric\nprintln(isposdef(a)) # positive definite (and Hermitian)\nprintln(isunitary(a)) # unitary","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#data-conversions","page":"Quantum Objects (Qobj)","title":"data conversions","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"As we mentioned above, QuantumObject.data supports general Julia arrays. The conversion between different type of QuantumObject.data is done using the standard type-conversion for arrays in Julia:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v_d = basis(2, 0)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Vector{Int64}(v_d)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v_s = SparseVector(v_d)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"SparseVector{Float64}(v_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x_s = sigmax()","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"SparseMatrixCSC{Int64}(x_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Matrix{Float64}(x_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"To convert between dense and sparse arrays, one can also use dense_to_sparse and sparse_to_dense:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x_d = sparse_to_dense(x_s)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"dense_to_sparse(x_d)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"note: Convert to GPU arrays\nSee CUDA extension for more details.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"QuantumToolbox will do conversion when needed to keep everything working in any format. However these conversions could slow down computation and it is recommended to keep to one format family where possible.","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/#Qobj-math","page":"Quantum Objects (Qobj)","title":"Qobj math","text":"","category":"section"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"The rules for mathematical operations on QuantumObject are similar to the standard scalar, vector, and matrix arithmetic:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a = destroy(4)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a' # synonym of adjoint(a)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a + 5","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a' * a","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a ^ 3","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x = sigmax()","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x / sqrt(2)","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"x ^ 3 == x","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"# type \\approx + to get symbol ≈\nx ^ 3 ≈ x ","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Of course, like matrices, multiplying two objects of incompatible dims or size throws an error:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"a * x","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Note that there is a special case for multiplying Ket and Bra, which results in outer product urangle otimes langle v:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"u = Qobj([1, 2, 3])","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v = Qobj([4, 5, 6])\nv'","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"u * v'","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"Of course, if you switch the order of multiplication, it becomes inner product langle v u rangle:","category":"page"},{"location":"users_guide/QuantumObject/QuantumObject/","page":"Quantum Objects (Qobj)","title":"Quantum Objects (Qobj)","text":"v' * u","category":"page"},{"location":"tutorials/logo/#doc-tutor:Create-QuantumToolbox.jl-logo","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"","category":"section"},{"location":"tutorials/logo/#Introduction","page":"Create QuantumToolbox.jl logo","title":"Introduction","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"In this tutorial, we will demonstrate how to create the logo for the QuantumToolbox.jl package. The logo represents the Wigner function of the triangular cat state, which is a linear superposition of three coherent states. The resulting Wigner function has a triangular shape that resembles the Julia logo. We will also define a custom colormap that varies based on the value of the Wigner function and the spatial coordinates, such that the three blobs corresponding to the coherent states have different colors (matching the colors of the Julia logo).","category":"page"},{"location":"tutorials/logo/#Triangular-Cat-State","page":"Create QuantumToolbox.jl logo","title":"Triangular Cat State","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"A cat state, often referred to as a Schrödinger cat state, is a quantum state that is a superposition of two coherent states with opposite phases:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":" psi_textcat rangle = frac1sqrt2 left( alpha rangle + -alpha rangle right)","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where alpha rangle is a coherent state with amplitude alpha.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The triangular cat state is a generalization of the standard cat state. It is a superposition of three coherent states with phases theta_0 theta_1 theta_2 separated by 120^circ(or 2pi3radians):","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":" psi_texttri-cat rangle = frac1sqrt3 left( alpha_0 rangle + alpha_1 rangle + alpha_2 rangle right)","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where alpha_j = rho e^itheta_jwith theta_j = fracpi2 + frac2pi j3and j = 0 1 2.","category":"page"},{"location":"tutorials/logo/#Wigner-Function","page":"Create QuantumToolbox.jl logo","title":"Wigner Function","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The Wigner function W(x p)is a quasi-probability distribution used in quantum mechanics to represent quantum states in phase space. It is defined as:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"W(x p) = frac1pi hbar int_-infty^infty psi^*(x + y) psi(x - y) e^2ipy hbar dy","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where psi(x)is the wave function of the quantum state, xis the position, pis the momentum, and hbaris the reduced Planck constant. Unlike classical probability distributions, the Wigner function can take negative values, which indicates non-classical behavior.","category":"page"},{"location":"tutorials/logo/#Generating-the-Logo","page":"Create QuantumToolbox.jl logo","title":"Generating the Logo","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"First, let's load the required packages:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"using QuantumToolbox\nusing CairoMakie\nCairoMakie.activate!(type = \"svg\", pt_per_unit = 1)\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())","category":"page"},{"location":"tutorials/logo/#Parameters","page":"Create QuantumToolbox.jl logo","title":"Parameters","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Here we define the parameters for the triangular cat state:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"N = 30 # Cutoff of the Hilbert space for the harmonic oscillator\nρ = 2.5 # Amplitude of the coherent state\nθ1 = π / 2\nθ2 = π / 2 + 2π / 3\nθ3 = π / 2 + 4π / 3\nα1 = ρ * exp(im * θ1)\nα2 = ρ * exp(im * θ2)\nα3 = ρ * exp(im * θ3)","category":"page"},{"location":"tutorials/logo/#Constructing-the-State","page":"Create QuantumToolbox.jl logo","title":"Constructing the State","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Next, we construct the triangular cat state as a normalized superposition of three coherent states:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"ψ = coherent(N, α1) + coherent(N, α2) + coherent(N, α3)\nnormalize!(ψ)","category":"page"},{"location":"tutorials/logo/#Defining-the-Grid-and-calculating-the-Wigner-function","page":"Create QuantumToolbox.jl logo","title":"Defining the Grid and calculating the Wigner function","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"We define the grid for the Wigner function and calculate it using the wigner function. We shift the grid in the imaginary direction to ensure that the Wigner function is centered around the origin of the figure. The wigner function also supports the g scaling factor, which we put here equal to 2.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"xvec = range(-ρ, ρ, 500) .* 1.5\nyvec = xvec .+ (abs(imag(α1)) - abs(imag(α2))) / 2\n\nwig = wigner(ψ, xvec, yvec, g = 2)","category":"page"},{"location":"tutorials/logo/#Plotting-the-Wigner-function","page":"Create QuantumToolbox.jl logo","title":"Plotting the Wigner function","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Finally, we plot the Wigner function using the heatmap function from the CairoMakie package.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"fig = Figure(size = (250, 250), figure_padding = 0)\nax = Axis(fig[1, 1])\nheatmap!(ax, xvec, yvec, wig', colormap = :RdBu, interpolate = true, rasterize = 1)\nhidespines!(ax)\nhidexdecorations!(ax)\nhideydecorations!(ax)\nfig","category":"page"},{"location":"tutorials/logo/#Introducing-some-decoherence","page":"Create QuantumToolbox.jl logo","title":"Introducing some decoherence","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The figure obtained above coulb be already a potential logo for the package. However, we see that the fringe patterns are more intense than the three coherent gaussian amplitudes. We can introduce some decoherence to reduce this effect. Thus, we evolve the system under the evolution of a damped quantum harmonic oscillator, which is described by the Lindblad master equation:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"fracd hatrhodt = -i hatH hatrho + gamma left( 2 hata hatrho hata^dagger - hata^dagger hata hatrho - hatrho hata^dagger hata right)","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"where hatrho is the density matrix, hatH = omega hata^dagger hatais the Hamiltonian of the harmonic oscillator (hbar = 1), hataand hata^daggerare the annihilation and creation operators, and gammais the damping rate. Thus, we initialize the system in the triangular cat state and evolve it under the Lindblad master equation, using the mesolve function.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"γ = 0.012\n\na = destroy(N)\nH = a' * a\nc_ops = [sqrt(γ) * a]\n\ntlist = range(0, 2π, 100)\n\nsol = mesolve(H, ψ, tlist, c_ops, progress_bar = Val(false))\nnothing # hide","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"And the Wigner function becomes more uniform:","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"wig = wigner(sol.states[end], xvec, yvec, g = 2)\n\nfig = Figure(size = (250, 250), figure_padding = 0)\nax = Axis(fig[1, 1])\n\nimg_wig = heatmap!(ax, xvec, yvec, wig', colormap = :RdBu, interpolate = true, rasterize = 1)\nhidespines!(ax)\nhidexdecorations!(ax)\nhideydecorations!(ax)\n\nfig","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"At this stage, we have finished to use the QuantumToolbox package. From now on, we will use the CairoMakie package to define custom colormaps and plot the Wigner function in a Julia logo style.","category":"page"},{"location":"tutorials/logo/#Custom-Colormap","page":"Create QuantumToolbox.jl logo","title":"Custom Colormap","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"We define a custom colormap that changes depending on the Wigner function and spatial coordinates. Indeed, we want the three different colormaps, in the regions corresponding to the three coherent states, to match the colors of the Julia logo. We also want the colormap change to be smooth, so we use a Gaussian function to blend the colors. We introduce also a Wigner function dependent transparency to make the logo more appealing.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"function set_color_julia(x, y, wig::T, α1, α2, α3, cmap1, cmap2, cmap3, δ) where {T}\n amp1 = gaussian(x, real(α1), δ) * gaussian(y, imag(α1), δ)\n amp2 = gaussian(x, real(α2), δ) * gaussian(y, imag(α2), δ)\n amp3 = gaussian(x, real(α3), δ) * gaussian(y, imag(α3), δ)\n\n c1 = get(cmap1, wig)\n c2 = get(cmap2, wig)\n c3 = get(cmap3, wig)\n\n c_tot = (amp1 * c1 + amp2 * c2 + amp3 * c3) / (amp1 + amp2 + amp3)\n\n wig_abs = abs(2 * (wig - 1 / 2))\n # We introduce some non-linearity to increase the contrast\n alpha = 2 * (1 / (1 + exp(-5 * wig_abs)) - 1 / 2)\n\n return RGBAf(c_tot.r, c_tot.g, c_tot.b, alpha)\nend\n\nX, Y = meshgrid(xvec, yvec)\nδ = 1.25 # Smoothing parameter for the Gaussian functions","category":"page"},{"location":"tutorials/logo/#Colormaps-from-the-Julia-colors","page":"Create QuantumToolbox.jl logo","title":"Colormaps from the Julia colors","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"We define the colormaps for the three coherent states using the colors of the Julia logo. We use the cgrad function from the CairoMakie package to create the colormaps.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"julia_red = RGBAf(0.796, 0.235, 0.2, 1.0)\njulia_green = RGBAf(0.22, 0.596, 0.149, 1.0)\njulia_blue = RGBAf(0.251, 0.388, 0.847, 1.0)\njulia_purple = RGBAf(0.584, 0.345, 0.698, 1.0)\nn_repeats = 2\n\ncmap1 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_green, n_repeats)))\ncmap2 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_red, n_repeats)))\ncmap3 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_purple, n_repeats)))","category":"page"},{"location":"tutorials/logo/#Normalizing-the-Wigner-function-and-applying-the-custom-colormap","page":"Create QuantumToolbox.jl logo","title":"Normalizing the Wigner function and applying the custom colormap","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"The colormaps require the input to be in the range 0 1. We normalize the Wigner function such that the maximum value is 1and the zeros are set to 05.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"vmax = maximum(wig)\nwig_normalized = wig ./ (vmax * 2) .+ 1 / 2\nnothing # hide","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"And we now apply this custom colormap to make an image (a Matrix{RGBAf}).","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"img = set_color_julia.(X, Y, wig_normalized, α1, α2, α3, Ref(cmap1), Ref(cmap2), Ref(cmap3), δ)","category":"page"},{"location":"tutorials/logo/#Final-Plot","page":"Create QuantumToolbox.jl logo","title":"Final Plot","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"Finally, we plot the Wigner function with the custom colormap.","category":"page"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"fig = Figure(size = (250, 250), figure_padding = 0, backgroundcolor = :transparent)\nax = Axis(fig[1, 1], backgroundcolor = :transparent)\nimage!(ax, img', rasterize = 1)\nhidespines!(ax)\nhidexdecorations!(ax)\nhideydecorations!(ax)\nfig","category":"page"},{"location":"tutorials/logo/#Conclusion","page":"Create QuantumToolbox.jl logo","title":"Conclusion","text":"","category":"section"},{"location":"tutorials/logo/","page":"Create QuantumToolbox.jl logo","title":"Create QuantumToolbox.jl logo","text":"This tutorial demonstrates how to generate the QuantumToolbox.jl logo using the package itself and Makie.jl for visualization. The logo is a visualization of the Wigner function of a triangular cat state, with a custom colormap that highlights the different coherent states with colors matching the Julia logo.","category":"page"},{"location":"users_guide/extensions/cuda/#doc:CUDA","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"","category":"section"},{"location":"users_guide/extensions/cuda/#Introduction","page":"Extension for CUDA.jl","title":"Introduction","text":"","category":"section"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"This is an extension to support QuantumObject.data conversion from standard dense and sparse CPU arrays to GPU (CUDA.jl) arrays.","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"This extension will be automatically loaded if user imports both QuantumToolbox and CUDA.jl:","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"using QuantumToolbox\nusing CUDA\nusing CUDA.CUSPARSE\nCUDA.allowscalar(false) # Avoid unexpected scalar indexing","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"We wrapped several functions in CUDA and CUDA.CUSPARSE in order to not only converting QuantumObject.data into GPU arrays, but also changing the element type and word size (32 and 64) since some of the GPUs perform better in 32-bit. The functions are listed as follows (where input A is a QuantumObject):","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(A; word_size=64): return a new QuantumObject with CUDA arrays and specified word_size.\nCuArray(A): If A.data is a dense array, return a new QuantumObject with CUDA.CuArray.\nCuArray{T}(A): If A.data is a dense array, return a new QuantumObject with CUDA.CuArray under element type T.\nCuSparseVector(A): If A.data is a sparse vector, return a new QuantumObject with CUDA.CUSPARSE.CuSparseVector.\nCuSparseVector{T}(A): If A.data is a sparse vector, return a new QuantumObject with CUDA.CUSPARSE.CuSparseVector under element type T.\nCuSparseMatrixCSC(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSC.\nCuSparseMatrixCSC{T}(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSC under element type T.\nCuSparseMatrixCSR(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSR.\nCuSparseMatrixCSR{T}(A): If A.data is a sparse matrix, return a new QuantumObject with CUDA.CUSPARSE.CuSparseMatrixCSR under element type T.","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"We suggest to convert the arrays from CPU to GPU memory by using the function cu because it allows different data-types of input QuantumObject.","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Here are some examples:","category":"page"},{"location":"users_guide/extensions/cuda/#Converting-dense-arrays","page":"Extension for CUDA.jl","title":"Converting dense arrays","text":"","category":"section"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"V = fock(2, 0) # CPU dense vector","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element Vector{ComplexF64}:\n 1.0 + 0.0im\n 0.0 + 0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuArray{ComplexF64, 1, CUDA.DeviceMemory}:\n 1.0 + 0.0im\n 0.0 + 0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuArray{ComplexF32, 1, CUDA.DeviceMemory}:\n 1.0 + 0.0im\n 0.0 + 0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"M = Qobj([1 2; 3 4]) # CPU dense matrix","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 Matrix{Int64}:\n 1 2\n 3 4","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 CuArray{Int64, 2, CUDA.DeviceMemory}:\n 1 2\n 3 4","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=false\n2×2 CuArray{Int32, 2, CUDA.DeviceMemory}:\n 1 2\n 3 4","category":"page"},{"location":"users_guide/extensions/cuda/#Converting-sparse-arrays","page":"Extension for CUDA.jl","title":"Converting sparse arrays","text":"","category":"section"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"V = fock(2, 0; sparse=true) # CPU sparse vector","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element SparseVector{ComplexF64, Int64} with 1 stored entry:\n [1] = 1.0+0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuSparseVector{ComplexF64, Int32} with 1 stored entry:\n [1] = 1.0+0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(V; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Ket dims=[2] size=(2,)\n2-element CuSparseVector{ComplexF32, Int32} with 1 stored entry:\n [1] = 1.0+0.0im","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"M = sigmax() # CPU sparse matrix","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 SparseMatrixCSC{ComplexF64, Int64} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅ ","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 CuSparseMatrixCSC{ComplexF64, Int32} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅ ","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"cu(M; word_size = 32)","category":"page"},{"location":"users_guide/extensions/cuda/","page":"Extension for CUDA.jl","title":"Extension for CUDA.jl","text":"Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true\n2×2 CuSparseMatrixCSC{ComplexF32, Int32} with 2 stored entries:\n ⋅ 1.0+0.0im\n 1.0+0.0im ⋅ ","category":"page"},{"location":"users_guide/time_evolution/mcsolve/#doc-TE:Monte-Carlo-Solver","page":"Monte-Carlo Solver","title":"Monte-Carlo Solver","text":"","category":"section"},{"location":"users_guide/time_evolution/mcsolve/","page":"Monte-Carlo Solver","title":"Monte-Carlo Solver","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"qutip_differences/","page":"Key differences from QuTiP","title":"Key differences from QuTiP","text":"CurrentModule = QuantumToolbox","category":"page"},{"location":"qutip_differences/#doc:Key-differences-from-QuTiP","page":"Key differences from QuTiP","title":"Key differences from QuTiP","text":"","category":"section"},{"location":"qutip_differences/","page":"Key differences from QuTiP","title":"Key differences from QuTiP","text":"This page is still under construction, please visit API first.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"CurrentModule = QuantumToolbox","category":"page"},{"location":"#QuantumToolbox.jl-Documentation","page":"Introduction","title":"QuantumToolbox.jl Documentation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"QuantumToolbox.jl is a cutting-edge Julia package designed for quantum physics simulations, closely emulating the popular Python QuTiP package. It uniquely combines the simplicity and power of Julia with advanced features like GPU acceleration and distributed computing, making simulation of quantum systems more accessible and efficient.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"With this package, moving from Python to Julia for quantum physics simulations has never been easier, due to the similar syntax and functionalities.","category":"page"},{"location":"#Features","page":"Introduction","title":"Features","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"QuantumToolbox.jl is equipped with a robust set of features:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Quantum State and Operator Manipulation: Easily handle quantum states and operators with a rich set of tools, with the same functionalities as QuTiP.\nDynamical Evolution: Advanced solvers for time evolution of quantum systems, thanks to the powerful DifferentialEquations.jl package.\nGPU Computing: Leverage GPU resources for high-performance computing. For example, you run the master equation direclty on the GPU with the same syntax as the CPU case.\nDistributed Computing: Distribute the computation over multiple nodes (e.g., a cluster). For example, you can run undreds of quantum trajectories in parallel on a cluster, with, again, the same syntax as the simple case.\nEasy Extension: Easily extend the package, taking advantage of the Julia language features, like multiple dispatch and metaprogramming.","category":"page"},{"location":"#doc:Installation","page":"Introduction","title":"Installation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"note: Requirements\nQuantumToolbox.jl requires Julia 1.10+.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"To install QuantumToolbox.jl, run the following commands inside Julia's interactive session (also known as REPL):","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using Pkg\nPkg.add(\"QuantumToolbox\")","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Alternatively, this can also be done in Julia's Pkg REPL by pressing the key ] in the REPL to use the package mode, and then type the following command:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"(1.10) pkg> add QuantumToolbox","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"More information about Julia's package manager can be found at Pkg.jl.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"To load the package and check the version information, use either QuantumToolbox.versioninfo() or QuantumToolbox.about(), namely","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using QuantumToolbox\nQuantumToolbox.versioninfo()\nQuantumToolbox.about()","category":"page"},{"location":"#Brief-Example","page":"Introduction","title":"Brief Example","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"We now provide a brief example to demonstrate the similarity between QuantumToolbox.jl and QuTiP.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Let's consider a quantum harmonic oscillator with a Hamiltonian given by:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"hatH = omega hata^dagger hata","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"where hata and hata^dagger are the annihilation and creation operators, respectively. We can define the Hamiltonian as follows:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using QuantumToolbox\n\nN = 20 # cutoff of the Hilbert space dimension\nω = 1.0 # frequency of the harmonic oscillator\n\na = destroy(N) # annihilation operator\n\nH = ω * a' * a","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"We now introduce some losses in a thermal environment, described by the Lindblad master equation:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"fracd hatrhodt = -i hatH hatrho + gamma mathcalDhata hatrho","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"where hatrho is the density matrix, gamma is the damping rate, and mathcalDhata is the Lindblad dissipator, defined as:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"mathcalDhatahatrho = hatahatrhohata^dagger - frac12hata^daggerhatahatrho - frac12hatrhohata^daggerhata","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"We now compute the time evolution of the system using the mesolve function, starting from the initial state ketpsi (0) = ket3:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"γ = 0.1 # damping rate\n\nψ0 = fock(N, 3) # initial state\n\ntlist = range(0, 10, 100) # time list\n\nc_ops = [sqrt(γ) * a]\ne_ops = [a' * a]\n\nsol = mesolve(H, ψ0, tlist, c_ops, e_ops = e_ops)","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"We can extract the expectation value of the number operator hata^dagger hata with the command sol.expect, and the states with the command sol.states.","category":"page"},{"location":"#Support-for-GPU-calculation","page":"Introduction","title":"Support for GPU calculation","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"We can easily pass the computation to the GPU, by simply passing all the Qobjs to the GPU:","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"using QuantumToolbox\nusing CUDA\nCUDA.allowscalar(false) # Avoid unexpected scalar indexing\n\na_gpu = cu(destroy(N)) # The only difference in the code is the cu() function\n\nH_gpu = ω * a_gpu' * a_gpu\n\nψ0_gpu = cu(fock(N, 3))\n\nc_ops = [sqrt(γ) * a_gpu]\ne_ops = [a_gpu' * a_gpu]\n\nsol = mesolve(H_gpu, ψ0_gpu, tlist, c_ops, e_ops = e_ops)","category":"page"},{"location":"tutorials/lowrank/#doc-tutor:Low-rank-master-equation","page":"Low Rank Master Equation","title":"Low rank master equation","text":"","category":"section"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"We start by importing the packages","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"using QuantumToolbox\nusing CairoMakie\nCairoMakie.enable_only_mime!(MIME\"image/svg+xml\"())","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define lattice","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Nx, Ny = 2, 3\nlatt = Lattice(Nx = Nx, Ny = Ny)","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define lr-space dimensions","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"N_cut = 2 # Number of states of each mode\nN_modes = latt.N # Number of modes\nN = N_cut^N_modes # Total number of states\nM = Nx * Ny + 1 # Number of states in the LR basis","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define lr states. Take as initial state all spins up. All other N states are taken as those with miniman Hamming distance to the initial state.","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"ϕ = Vector{QuantumObject{Vector{ComplexF64},KetQuantumObject}}(undef, M)\nϕ[1] = kron(repeat([basis(2, 0)], N_modes)...)\n\nglobal i = 1\nfor j in 1:N_modes\n global i += 1\n i <= M && (ϕ[i] = mb(sp, j, latt) * ϕ[1])\nend\nfor k in 1:N_modes-1\n for l in k+1:N_modes\n global i += 1\n i <= M && (ϕ[i] = mb(sp, k, latt) * mb(sp, l, latt) * ϕ[1])\n end\nend\nfor i in i+1:M\n ϕ[i] = QuantumObject(rand(ComplexF64, size(ϕ[1])[1]), dims = ϕ[1].dims)\n normalize!(ϕ[i])\nend","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define the initial state","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"z = hcat(broadcast(x -> x.data, ϕ)...)\np0 = 0.0 # Population of the lr states other than the initial state\nB = Matrix(Diagonal([1 + 0im; p0 * ones(M - 1)]))\nS = z' * z # Overlap matrix\nB = B / tr(S * B) # Normalize B\n\nρ = QuantumObject(z * B * z', dims = ones(Int, N_modes) * N_cut); # Full density matrix","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define the Hamiltonian and collapse operators","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"# Define Hamiltonian and collapse operators\nJx = 0.9\nJy = 1.04\nJz = 1.0\nhx = 0.0\nγ = 1\n\nSx = sum([mb(sx, i, latt) for i in 1:latt.N])\nSy = sum([mb(sy, i, latt) for i in 1:latt.N])\nSz = sum([mb(sz, i, latt) for i in 1:latt.N])\nSFxx = sum([mb(sx, i, latt) * mb(sx, j, latt) for i in 1:latt.N for j in 1:latt.N])\n\nH, c_ops = TFIM(Jx, Jy, Jz, hx, γ, latt; bc = pbc, order = 1)\ne_ops = (Sx, Sy, Sz, SFxx)\n\ntl = LinRange(0, 10, 100);","category":"page"},{"location":"tutorials/lowrank/#Full-evolution","page":"Low Rank Master Equation","title":"Full evolution","text":"","category":"section"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"@time mesol = mesolve(H, ρ, tl, c_ops; e_ops = [e_ops...]);\nA = Matrix(mesol.states[end].data)\nλ = eigvals(Hermitian(A))\nStrue = -sum(λ .* log2.(λ)) / latt.N;","category":"page"},{"location":"tutorials/lowrank/#Low-Rank-evolution","page":"Low Rank Master Equation","title":"Low Rank evolution","text":"","category":"section"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define functions to be evaluated during the low-rank evolution","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"function f_purity(p, z, B)\n N = p.N\n M = p.M\n S = p.S\n T = p.temp_MM\n\n mul!(T, S, B)\n return tr(T^2)\nend\n\nfunction f_trace(p, z, B)\n N = p.N\n M = p.M\n S = p.S\n T = p.temp_MM\n\n mul!(T, S, B)\n return tr(T)\nend\n\nfunction f_entropy(p, z, B)\n C = p.A0\n σ = p.Bi\n\n mul!(C, z, sqrt(B))\n mul!(σ, C', C)\n λ = eigvals(Hermitian(σ))\n λ = λ[λ.>1e-10]\n return -sum(λ .* log2.(λ))\nend;","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Define the options for the low-rank evolution","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"opt =\n LRMesolveOptions(err_max = 1e-3, p0 = 0.0, atol_inv = 1e-6, adj_condition = \"variational\", Δt = 0.0);\n\n@time lrsol = lr_mesolve(H, z, B, tl, c_ops; e_ops = e_ops, f_ops = (f_purity, f_entropy, f_trace), opt = opt);","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"Plot the results","category":"page"},{"location":"tutorials/lowrank/","page":"Low Rank Master Equation","title":"Low Rank Master Equation","text":"m_me = real(mesol.expect[3, :]) / Nx / Ny\nm_lr = real(lrsol.expvals[3, :]) / Nx / Ny\n\nfig = Figure(size = (500, 350), fontsize = 15)\nax = Axis(fig[1, 1], xlabel = L\"\\gamma t\", ylabel = L\"M_{z}\", xlabelsize = 20, ylabelsize = 20)\nlines!(ax, tl, m_lr, label = L\"LR $[M=M(t)]$\", linewidth = 2)\nlines!(ax, tl, m_me, label = \"Fock\", linewidth = 2, linestyle = :dash)\naxislegend(ax, position = :rb)\n\nax2 = Axis(fig[1, 2], xlabel = L\"\\gamma t\", ylabel = \"Value\", xlabelsize = 20, ylabelsize = 20)\nlines!(ax2, tl, 1 .- real(lrsol.funvals[1, :]), label = L\"$1-P$\", linewidth = 2)\nlines!(\n ax2,\n tl,\n 1 .- real(lrsol.funvals[3, :]),\n label = L\"$1-\\mathrm{Tr}(\\rho)$\",\n linewidth = 2,\n linestyle = :dash,\n color = :orange,\n)\nlines!(ax2, tl, real(lrsol.funvals[2, :]) / Nx / Ny, color = :blue, label = L\"S\", linewidth = 2)\nhlines!(ax2, [Strue], color = :blue, linestyle = :dash, linewidth = 2, label = L\"S^{\\,\\mathrm{true}}_{\\mathrm{ss}}\")\naxislegend(ax2, position = :rb)\n\nfig","category":"page"}] } diff --git a/dev/tutorials/logo/bd1c4db3.svg b/dev/tutorials/logo/460466ec.svg similarity index 99% rename from dev/tutorials/logo/bd1c4db3.svg rename to dev/tutorials/logo/460466ec.svg index f648ea9b..336d14a8 100644 --- a/dev/tutorials/logo/bd1c4db3.svg +++ b/dev/tutorials/logo/460466ec.svg @@ -1,7 +1,7 @@ - + - + diff --git a/dev/tutorials/logo/0d57b77b.svg b/dev/tutorials/logo/fb60d36e.svg similarity index 99% rename from dev/tutorials/logo/0d57b77b.svg rename to dev/tutorials/logo/fb60d36e.svg index dc3b8456..b8e5e11a 100644 --- a/dev/tutorials/logo/0d57b77b.svg +++ b/dev/tutorials/logo/fb60d36e.svg @@ -5,12 +5,12 @@ width="180mm" height="25mm" viewBox="0 0 100 1" stroke="none" preserveAspectRatio="none" shape-rendering="crispEdges"> - - + diff --git a/dev/tutorials/logo/index.html b/dev/tutorials/logo/index.html index 988459a4..7e9916a7 100644 --- a/dev/tutorials/logo/index.html +++ b/dev/tutorials/logo/index.html @@ -105,7 +105,7 @@ cmap1 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_green, n_repeats))) cmap2 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_red, n_repeats))) -cmap3 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_purple, n_repeats)))Example block output

Normalizing the Wigner function and applying the custom colormap

The colormaps require the input to be in the range $[0, 1]$. We normalize the Wigner function such that the maximum value is $1$and the zeros are set to $0.5$.

vmax = maximum(wig)
+cmap3 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_purple, n_repeats)))
Example block output

Normalizing the Wigner function and applying the custom colormap

The colormaps require the input to be in the range $[0, 1]$. We normalize the Wigner function such that the maximum value is $1$and the zeros are set to $0.5$.

vmax = maximum(wig)
 wig_normalized = wig ./ (vmax * 2) .+ 1 / 2

And we now apply this custom colormap to make an image (a Matrix{RGBAf}).

img = set_color_julia.(X, Y, wig_normalized, α1, α2, α3, Ref(cmap1), Ref(cmap2), Ref(cmap3), δ)
500×500 Array{RGBA{Float32},2} with eltype ColorTypes.RGBA{Float32}:
  RGBA{Float32}(0.523498,0.311502,0.523505,6.26417f-6)   …  RGBA{Float32}(0.417504,0.366499,0.772491,6.26426f-6)
  RGBA{Float32}(0.523498,0.311502,0.523505,7.01657f-6)      RGBA{Float32}(0.417504,0.366499,0.772491,7.01667f-6)
@@ -132,4 +132,4 @@
 hidespines!(ax)
 hidexdecorations!(ax)
 hideydecorations!(ax)
-fig
Example block output

Conclusion

This tutorial demonstrates how to generate the QuantumToolbox.jl logo using the package itself and Makie.jl for visualization. The logo is a visualization of the Wigner function of a triangular cat state, with a custom colormap that highlights the different coherent states with colors matching the Julia logo.

+figExample block output

Conclusion

This tutorial demonstrates how to generate the QuantumToolbox.jl logo using the package itself and Makie.jl for visualization. The logo is a visualization of the Wigner function of a triangular cat state, with a custom colormap that highlights the different coherent states with colors matching the Julia logo.

diff --git a/dev/tutorials/lowrank/index.html b/dev/tutorials/lowrank/index.html index 4a9d95bd..19097d72 100644 --- a/dev/tutorials/lowrank/index.html +++ b/dev/tutorials/lowrank/index.html @@ -124,4 +124,4 @@ hlines!(ax2, [Strue], color = :blue, linestyle = :dash, linewidth = 2, label = L"S^{\,\mathrm{true}}_{\mathrm{ss}}") axislegend(ax2, position = :rb) -figExample block output +figExample block output diff --git a/dev/type_stability/index.html b/dev/type_stability/index.html index bb918f3f..05ecf541 100644 --- a/dev/type_stability/index.html +++ b/dev/type_stability/index.html @@ -76,13 +76,13 @@ └── return %24

While in the last example of the foo function we got a weak form of type instability, returning a Union{Int, Float64}, in this case the return type of bar is Any, meaning that the compiler doesn't know anything about the return type. Thus, this function has nothing different from a dynamically typed language like Python. We can benchmark the performance of bar using the BenchmarkTools.jl package:

using BenchmarkTools
 
 @benchmark bar(3.2)
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
- Range (minmax):  41.347 μs 33.972 ms   GC (min … max): 0.00% … 99.74%
- Time  (median):     61.003 μs                GC (median):    0.00%
- Time  (mean ± σ):   60.101 μs ± 339.359 μs   GC (mean ± σ):  5.64% ±  1.00%
+ Range (minmax):  43.842 μs 34.820 ms   GC (min … max): 0.00% … 99.72%
+ Time  (median):     63.610 μs                GC (median):    0.00%
+ Time  (mean ± σ):   64.253 μs ± 347.792 μs   GC (mean ± σ):  5.40% ±  1.00%
 
-      ▅▂                               ▅█▃                     
-  ▃▅▃███▄▂▂▂▁▂▂▁▂▂▂▂▂▂▂▂▂▂▂▂▁▁▂▂▁▂▃▄▃███▅▄▃▂▂▂▂▂▂▂▂▂▂▂▃▃▃▂▂ ▃
-  41.3 μs         Histogram: frequency by time         73.2 μs <
+                            █▅                                 
+  ▃█▅▇▅▃▂▂▂▁▂▁▂▂▂▂▂▂▂▂▂▂▃▃█▇██▆▃▂▂▂▂▂▂▂▃▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
+  43.8 μs         Histogram: frequency by time         88.5 μs <
 
  Memory estimate: 46.88 KiB, allocs estimate: 3000.

Here we see a lot of memory allocations and low performances in general. To fix this, we can declare a const (constant) variable instead:

const z = 2.4
 
@@ -95,12 +95,12 @@
 end
 
 @benchmark bar(3.2)
BenchmarkTools.Trial: 10000 samples with 57 evaluations.
- Range (minmax):  868.632 ns 1.239 μs   GC (min … max): 0.00% … 0.00%
- Time  (median):     869.684 ns               GC (median):    0.00%
- Time  (mean ± σ):   876.616 ns ± 29.119 ns   GC (mean ± σ):  0.00% ± 0.00%
+ Range (minmax):  868.807 ns 1.240 μs   GC (min … max): 0.00% … 0.00%
+ Time  (median):     869.702 ns               GC (median):    0.00%
+ Time  (mean ± σ):   876.405 ns ± 28.897 ns   GC (mean ± σ):  0.00% ± 0.00%
 
-                                                        ▁▁▁   ▁
-  ▇▄▄▆█▄▄▃▄▅▅▆▇▇▆▄▄▃▃▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▇█████▇ █
+                                                        ▁▁▁   ▁
+  ▅▃▄▅▇▅▄▄▄▃▃▆▇▆▅▅▄▄▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃▄▇█████▇ █
   869 ns        Histogram: log(frequency) by time         1 μs <
 
  Memory estimate: 0 bytes, allocs estimate: 0.

And we can see that the performance has improved significantly. Hence, we highly recommend using global variables as const, but only when truly necessary. This choice is problem-dependent, but in the case of QuantumToolbox.jl, this can be applied for example in the case of defining the Hilbert space dimensions, static parameters, or the system operators.

Although it is always a good practice to avoid such kind of type instabilities, in the actual implementation of QuantumToolbox.jl (where we mainly deal with linear algebra operations), the compiler may perform only a few runtime dispatches, and the performance penalty may be negligible compared to the heavy linear algebra operations.

Vectors vs Tuples vs StaticArrays

Julia has many ways to represent arrays or lists of general objects. The most common are Vectors and Tuples. The former is a dynamic array that can change its size at runtime, while the latter is a fixed-size array that is immutable, and where the type of each element is already known at compile time. For example:

v1 = [1, 2, 3] # Vector of Int64
@@ -218,23 +218,23 @@
  %23 = op_dims::SVector{3, Int64}
  %24 = (%21)(%22, %23)::SVector{6, Int64}
  %25 = Core._apply_iterate(Base.iterate, %18, %20, %24)::Array{Float64, 6}
-└──       return %25

Finally, let's look at the benchmarks

@benchmark reshape_operator_data($[2, 2, 2])
BenchmarkTools.Trial: 10000 samples with 8 evaluations.
- Range (minmax):  2.939 μs 25.197 μs   GC (min … max): 0.00% … 0.00%
- Time  (median):     3.160 μs                GC (median):    0.00%
- Time  (mean ± σ):   3.324 μs ± 749.097 ns   GC (mean ± σ):  0.00% ± 0.00%
+└──       return %25

Finally, let's look at the benchmarks

@benchmark reshape_operator_data($[2, 2, 2])
BenchmarkTools.Trial: 10000 samples with 9 evaluations.
+ Range (minmax):  2.956 μs 31.016 μs   GC (min … max): 0.00% … 0.00%
+ Time  (median):     3.276 μs                GC (median):    0.00%
+ Time  (mean ± σ):   3.376 μs ± 780.700 ns   GC (mean ± σ):  0.00% ± 0.00%
 
-   ▁█▆▂                                                        
-  ▂████▆▄▃▄▅▃▂▁▂▆█▇▅▂▂▂▃▄▃▂▂▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
-  2.94 μs         Histogram: frequency by time        4.76 μs <
+   ▁▇█▄          ▂▅▂                                           
+  ▃█████▆▄▅▄▄▂▂███▅▃▂▄▆▇▅▃▂▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▃
+  2.96 μs         Histogram: frequency by time        4.72 μs <
 
- Memory estimate: 1.69 KiB, allocs estimate: 32.
@benchmark reshape_operator_data($((2, 2, 2)))
BenchmarkTools.Trial: 10000 samples with 516 evaluations.
- Range (minmax):  212.467 ns98.057 μs   GC (min … max):  0.00% … 99.69%
- Time  (median):     227.196 ns               GC (median):     0.00%
- Time  (mean ± σ):   375.620 ns ±  1.570 μs   GC (mean ± σ):  16.68% ±  7.53%
+ Memory estimate: 1.69 KiB, allocs estimate: 32.
@benchmark reshape_operator_data($((2, 2, 2)))
BenchmarkTools.Trial: 10000 samples with 496 evaluations.
+ Range (minmax):  213.446 ns101.425 μs   GC (min … max):  0.00% … 99.63%
+ Time  (median):     239.967 ns                GC (median):     0.00%
+ Time  (mean ± σ):   393.874 ns ±   1.653 μs   GC (mean ± σ):  16.99% ±  7.33%
 
-  ▆█▆▄▄▂▁▁                                   ▃▆▆▄▄▄▃▁         ▂
-  █████████▇▇▇▆▅▆▅▆▆▄▆▇▇▇▇▇▅▅▅▄▁▃▄▁▁▁▃▃▄▇▇▆▆█████████▇▇▄▆▆▆▅ █
-  212 ns        Histogram: log(frequency) by time       545 ns <
+  ▂▇█▆▄▄▃▂▁▁▁▁                                   ▄▆▆▅▄▄▄▃▂     ▂
+  ██████████████▇▇▆▆▆▆▆▆▆▇▇▇▇▇▆▅▃▆▄▄▃▁▁▄▁▃▁▄▆█▇▇███████████▇▆ █
+  213 ns        Histogram: log(frequency) by time        526 ns <
 
  Memory estimate: 672 bytes, allocs estimate: 3.

Which is an innocuous but huge difference in terms of performance. Hence, we highly recommend using Tuple or SVector when defining the dimensions of a user-defined QuantumObject.

The use of Val in some QuantumToolbox.jl functions

In some functions of QuantumToolbox.jl, you may find the use of the Val type in the arguments. This is a trick to pass a value at compile time, and it is very useful to avoid type instabilities. Let's make a very simple example, where we want to create a Fock state $|j\rangle$ of a given dimension N, and we give the possibility to create it as a sparse or dense vector. At first, we can write the function without using Val:

function my_fock(N::Int, j::Int = 0; sparse::Bool = false)
     if sparse
@@ -360,4 +360,4 @@
 9 ──       Core.Const(:(Base.kwerr(@_2, @_3, N, j)))
 10 ┄ %22 = Main.var"Main".:(var"#my_fock_good#2")::Core.Const(Main.var"Main".var"#my_fock_good#2")
  %23 = (%22)(%14, @_3, N, j)::QuantumObject{Vector{ComplexF64}, KetQuantumObject, 1}
-└───       return %23

This is exactly how the current fock function is implemented in QuantumToolbox.jl. There are many other functions that support this feature, and we highly recommend using it when necessary.

Conclusions

In this page, we have seen the importance of type stability in Julia, and how to write efficient code in the context of QuantumToolbox.jl. We have seen that the internal structure of the QuantumObject type is already optimized for the compiler, and we have seen some practical examples of how to write efficient code. We have seen that the use of Vector should be avoided when the elements don't have the same type, and that the use of Tuple or SVector is highly recommended when the size of the array is known at compile time. Finally, we have seen the use of Val to pass values at compile time, to avoid type instabilities in some functions. ```

+└─── return %23

This is exactly how the current fock function is implemented in QuantumToolbox.jl. There are many other functions that support this feature, and we highly recommend using it when necessary.

Conclusions

In this page, we have seen the importance of type stability in Julia, and how to write efficient code in the context of QuantumToolbox.jl. We have seen that the internal structure of the QuantumObject type is already optimized for the compiler, and we have seen some practical examples of how to write efficient code. We have seen that the use of Vector should be avoided when the elements don't have the same type, and that the use of Tuple or SVector is highly recommended when the size of the array is known at compile time. Finally, we have seen the use of Val to pass values at compile time, to avoid type instabilities in some functions. ```

diff --git a/dev/users_guide/QuantumObject/QuantumObject/index.html b/dev/users_guide/QuantumObject/QuantumObject/index.html index afe6f890..86cf8183 100644 --- a/dev/users_guide/QuantumObject/QuantumObject/index.html +++ b/dev/users_guide/QuantumObject/QuantumObject/index.html @@ -15,23 +15,23 @@ 1×5 Matrix{Int64}: 1 2 3 4 5
Qobj(rand(4, 4))
Quantum Object:   type=Operator   dims=[4]   size=(4, 4)   ishermitian=false
 4×4 Matrix{Float64}:
- 0.536095  0.381325  0.0782642  0.298162
- 0.973848  0.277871  0.496003   0.466421
- 0.595195  0.678611  0.302912   0.974798
- 0.674973  0.8564    0.0249046  0.326487
M = rand(ComplexF64, 4, 4)
+ 0.320084  0.392731  0.436426  0.776258
+ 0.471992  0.869675  0.337456  0.537068
+ 0.998959  0.366158  0.171088  0.985993
+ 0.152935  0.944469  0.714862  0.642425
M = rand(ComplexF64, 4, 4)
 Qobj(M, dims = [2, 2])  # dims as Vector
 Qobj(M, dims = (2, 2))  # dims as Tuple (recommended)
 Qobj(M, dims = SVector(2, 2)) # dims as StaticArrays.SVector (recommended)
Quantum Object:   type=Operator   dims=[2, 2]   size=(4, 4)   ishermitian=false
 4×4 Matrix{ComplexF64}:
- 0.503973+0.31021im    0.782871+0.713833im  …  0.262207+0.624505im
- 0.130708+0.775705im   0.884618+0.293643im     0.411552+0.346719im
- 0.881074+0.0836584im  0.651225+0.115064im     0.184343+0.988678im
- 0.936828+0.844488im   0.774589+0.737919im     0.578852+0.865192im
Beware of type-stability!

Please note that here we put the dims as a tuple (2, 2). Although it supports also Vector type (dims = [2, 2]), it is recommended to use Tuple or SVector from StaticArrays.jl to improve performance. For a brief explanation on the impact of the type of dims, see the Section The Importance of Type-Stability.

Qobj(rand(4, 4), type = SuperOperator)
Quantum Object:   type=SuperOperator   dims=[2]   size=(4, 4)
+ 0.430485+0.88556im   0.0995443+0.440566im  …  0.235996+0.811501im
+ 0.418485+0.552494im   0.292331+0.812606im     0.656686+0.977346im
+ 0.907975+0.261837im   0.742778+0.642109im     0.097796+0.434482im
+ 0.692839+0.756418im    0.20529+0.53916im      0.047205+0.2018im
Beware of type-stability!

Please note that here we put the dims as a tuple (2, 2). Although it supports also Vector type (dims = [2, 2]), it is recommended to use Tuple or SVector from StaticArrays.jl to improve performance. For a brief explanation on the impact of the type of dims, see the Section The Importance of Type-Stability.

Qobj(rand(4, 4), type = SuperOperator)
Quantum Object:   type=SuperOperator   dims=[2]   size=(4, 4)
 4×4 Matrix{Float64}:
- 0.771987  0.29691   0.269038   0.494975
- 0.835478  0.252084  0.0887695  0.725297
- 0.443212  0.96649   0.0470561  0.578043
- 0.140278  0.863108  0.265059   0.0416476
Difference between `dims` and `size`

Notice that type, dims, and size will change according to the input data. Although dims and size appear to be the same, dims keep tracking the dimension of individual Hilbert spaces of a multipartite system, while size does not. We refer the reader to the section Tensor Products and Partial Traces for more information.

States and operators

Manually specifying the data for each quantum object is inefficient. Even more so when most objects correspond to commonly used types such as the ladder operators of a harmonic oscillator, the Pauli spin operators for a two-level system, or state vectors such as Fock states. Therefore, QuantumToolbox includes predefined functions to construct variety of states and operators (you can click the function links and see the corresponding docstring):

States

Operators

As an example, we give the output for a few of these functions:

basis(5, 3)
Quantum Object:   type=Ket   dims=[5]   size=(5,)
+ 0.670443   0.125285   0.963542  0.658871
+ 0.0151289  0.652064   0.136913  0.573461
+ 0.545672   0.770726   0.669115  0.00290161
+ 0.940839   0.0663737  0.313666  0.367779
Difference between `dims` and `size`

Notice that type, dims, and size will change according to the input data. Although dims and size appear to be the same, dims keep tracking the dimension of individual Hilbert spaces of a multipartite system, while size does not. We refer the reader to the section Tensor Products and Partial Traces for more information.

States and operators

Manually specifying the data for each quantum object is inefficient. Even more so when most objects correspond to commonly used types such as the ladder operators of a harmonic oscillator, the Pauli spin operators for a two-level system, or state vectors such as Fock states. Therefore, QuantumToolbox includes predefined functions to construct variety of states and operators (you can click the function links and see the corresponding docstring):

States

Operators

As an example, we give the output for a few of these functions:

basis(5, 3)
Quantum Object:   type=Ket   dims=[5]   size=(5,)
 5-element Vector{ComplexF64}:
  0.0 + 0.0im
  0.0 + 0.0im
@@ -145,4 +145,4 @@
 3×3 Matrix{Int64}:
   4   5   6
   8  10  12
- 12  15  18

Of course, if you switch the order of multiplication, it becomes inner product $\langle v | u \rangle$:

v' * u
32
+ 12 15 18

Of course, if you switch the order of multiplication, it becomes inner product $\langle v | u \rangle$:

v' * u
32
diff --git a/dev/users_guide/QuantumObject/QuantumObject_functions/index.html b/dev/users_guide/QuantumObject/QuantumObject_functions/index.html index a551373e..bece62f8 100644 --- a/dev/users_guide/QuantumObject/QuantumObject_functions/index.html +++ b/dev/users_guide/QuantumObject/QuantumObject_functions/index.html @@ -94,4 +94,4 @@ -0.698381+0.0im -0.132457+0.0im -0.0891762+0.0im -0.606281+0.0im 0.596321+0.0im -0.648729+0.0im -0.0633045+0.0im -0.430387+0.0im -0.186568+0.0im -0.268811+0.0im -0.0354544+0.0im -0.241044+0.0im - 0.0+0.0im 0.0+0.0im 0.989355+0.0im -0.145521-0.0im + 0.0+0.0im 0.0+0.0im 0.989355+0.0im -0.145521-0.0im diff --git a/dev/users_guide/extensions/cuda/index.html b/dev/users_guide/extensions/cuda/index.html index 6246b897..27df9238 100644 --- a/dev/users_guide/extensions/cuda/index.html +++ b/dev/users_guide/extensions/cuda/index.html @@ -35,4 +35,4 @@ 1.0+0.0im ⋅
cu(M; word_size = 32)
Quantum Object:   type=Operator   dims=[2]   size=(2, 2)   ishermitian=true
 2×2 CuSparseMatrixCSC{ComplexF32, Int32} with 2 stored entries:
      ⋅      1.0+0.0im
- 1.0+0.0im      ⋅    
+ 1.0+0.0im ⋅ diff --git a/dev/users_guide/states_and_operators/index.html b/dev/users_guide/states_and_operators/index.html index 3e8da6aa..858f91fc 100644 --- a/dev/users_guide/states_and_operators/index.html +++ b/dev/users_guide/states_and_operators/index.html @@ -294,4 +294,4 @@ 1.0+0.0im ⋅ ⋅ 0.550671+0.0im ⋅ -0.641938-0.192987im ⋅ ⋅ ⋅ ⋅ -0.641938+0.192987im ⋅ - ⋅ ⋅ ⋅ 0.449329+0.0im

See the section Lindblad Master Equation Solver for more details.

+ ⋅ ⋅ ⋅ 0.449329+0.0im

See the section Lindblad Master Equation Solver for more details.

diff --git a/dev/users_guide/steadystate/fadf8cc6.svg b/dev/users_guide/steadystate/7d4fc66e.svg similarity index 80% rename from dev/users_guide/steadystate/fadf8cc6.svg rename to dev/users_guide/steadystate/7d4fc66e.svg index 5d514832..ac359ec1 100644 --- a/dev/users_guide/steadystate/fadf8cc6.svg +++ b/dev/users_guide/steadystate/7d4fc66e.svg @@ -2,285 +2,279 @@ - + - + - + - + - + - + - + - + - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - + + - + - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -290,427 +284,427 @@ - - - - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + + - - - - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/dev/users_guide/steadystate/index.html b/dev/users_guide/steadystate/index.html index 52baa9b1..01694a19 100644 --- a/dev/users_guide/steadystate/index.html +++ b/dev/users_guide/steadystate/index.html @@ -55,4 +55,4 @@ lines!(ax, tlist, exp_ss .* ones(length(tlist)), label = "Steady State", linewidth = 2, color = :red) axislegend(ax, position = :rt) -figExample block output

Calculate steady state for periodically driven systems

See the docstring of steadystate_floquet for more details.

+figExample block output

Calculate steady state for periodically driven systems

See the docstring of steadystate_floquet for more details.

diff --git a/dev/users_guide/tensor/index.html b/dev/users_guide/tensor/index.html index 53216ef5..18cc7b59 100644 --- a/dev/users_guide/tensor/index.html +++ b/dev/users_guide/tensor/index.html @@ -130,4 +130,4 @@ 0.25+0.0im 0.25+0.0im 0.25+0.0im 0.25+0.0im
ptrace(ρT, 1)
Quantum Object:   type=Operator   dims=[2]   size=(2, 2)   ishermitian=true
 2×2 Matrix{ComplexF64}:
  0.5+0.0im  0.5+0.0im
- 0.5+0.0im  0.5+0.0im
+ 0.5+0.0im 0.5+0.0im diff --git a/dev/users_guide/time_evolution/intro/index.html b/dev/users_guide/time_evolution/intro/index.html index a448f490..554cfb51 100644 --- a/dev/users_guide/time_evolution/intro/index.html +++ b/dev/users_guide/time_evolution/intro/index.html @@ -1,2 +1,2 @@ -Introduction · QuantumToolbox.jl

Time Evolution and Quantum System Dynamics

Table of contents

Introduction

Although in some cases, we want to find the stationary states of a quantum system, often we are interested in the dynamics: how the state of a system or an ensemble of systems evolves with time. QuantumToolbox provides many ways to model dynamics.

There are two kinds of quantum systems: open systems that interact with a larger environment and closed systems that do not. In a closed system, the state can be described by a state vector. When we are modeling an open system, or an ensemble of systems, the use of the density matrix is mandatory.

The following table lists the solvers provided by QuantumToolbox for dynamic quantum systems and the corresponding type of solution returned by the solver:

EquationFunction CallProblemReturned Solution
Unitary evolution, Schrödinger equationsesolvesesolveProblemTimeEvolutionSol
Lindblad master eqn. or Von Neuman eqn.mesolvemesolveProblemTimeEvolutionSol
Monte Carlo evolutionmcsolvemcsolveProblem mcsolveEnsembleProblemTimeEvolutionMCSol
Stochastic Schrödinger equationssesolvessesolveProblem ssesolveEnsembleProblemTimeEvolutionSSESol
Solving dynamics with pre-defined problems

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 problems by yourself and take it as an input of the function call, e.g., sesolve(prob).

+Introduction · QuantumToolbox.jl

Time Evolution and Quantum System Dynamics

Table of contents

Introduction

Although in some cases, we want to find the stationary states of a quantum system, often we are interested in the dynamics: how the state of a system or an ensemble of systems evolves with time. QuantumToolbox provides many ways to model dynamics.

There are two kinds of quantum systems: open systems that interact with a larger environment and closed systems that do not. In a closed system, the state can be described by a state vector. When we are modeling an open system, or an ensemble of systems, the use of the density matrix is mandatory.

The following table lists the solvers provided by QuantumToolbox for dynamic quantum systems and the corresponding type of solution returned by the solver:

EquationFunction CallProblemReturned Solution
Unitary evolution, Schrödinger equationsesolvesesolveProblemTimeEvolutionSol
Lindblad master eqn. or Von Neuman eqn.mesolvemesolveProblemTimeEvolutionSol
Monte Carlo evolutionmcsolvemcsolveProblem mcsolveEnsembleProblemTimeEvolutionMCSol
Stochastic Schrödinger equationssesolvessesolveProblem ssesolveEnsembleProblemTimeEvolutionSSESol
Solving dynamics with pre-defined problems

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 problems by yourself and take it as an input of the function call, e.g., sesolve(prob).

diff --git a/dev/users_guide/time_evolution/mcsolve/index.html b/dev/users_guide/time_evolution/mcsolve/index.html index f25bb90d..e2943c15 100644 --- a/dev/users_guide/time_evolution/mcsolve/index.html +++ b/dev/users_guide/time_evolution/mcsolve/index.html @@ -1,2 +1,2 @@ -Monte-Carlo Solver · QuantumToolbox.jl
+Monte-Carlo Solver · QuantumToolbox.jl
diff --git a/dev/users_guide/time_evolution/mesolve/index.html b/dev/users_guide/time_evolution/mesolve/index.html index 2d5d9c75..bbe58603 100644 --- a/dev/users_guide/time_evolution/mesolve/index.html +++ b/dev/users_guide/time_evolution/mesolve/index.html @@ -140,4 +140,4 @@ axislegend(ax, position = :rt) -figExample block output +figExample block output diff --git a/dev/users_guide/time_evolution/sesolve/index.html b/dev/users_guide/time_evolution/sesolve/index.html index 68bd28d2..7ce42d37 100644 --- a/dev/users_guide/time_evolution/sesolve/index.html +++ b/dev/users_guide/time_evolution/sesolve/index.html @@ -70,4 +70,4 @@ Quantum Object: type=Ket dims=[2] size=(2,) 2-element Vector{ComplexF64}: 0.9999999627203573 + 0.0im - 0.0 - 4.42094083968742e-8im + 0.0 - 4.42094083968742e-8im diff --git a/dev/users_guide/time_evolution/solution/index.html b/dev/users_guide/time_evolution/solution/index.html index 1e1c7c37..feb3eed9 100644 --- a/dev/users_guide/time_evolution/solution/index.html +++ b/dev/users_guide/time_evolution/solution/index.html @@ -32,4 +32,4 @@ Quantum Object: type=Ket dims=[2] size=(2,) 2-element Vector{ComplexF64}: 0.28366218546240907 + 0.0im - -0.9589242745990754 + 0.0im

Here, the solution contains only one (final) state. Because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). One can also specify e_ops and saveat separately.

Some other solvers can have other output.

Multiple trajectories solution

This part is still under construction, please visit API first.

+ -0.9589242745990754 + 0.0im

Here, the solution contains only one (final) state. Because the states will be saved depend on the keyword argument saveat in kwargs. If e_ops is empty, the default value of saveat=tlist (saving the states corresponding to tlist), otherwise, saveat=[tlist[end]] (only save the final state). One can also specify e_ops and saveat separately.

Some other solvers can have other output.

Multiple trajectories solution

This part is still under construction, please visit API first.

diff --git a/dev/users_guide/time_evolution/stochastic/index.html b/dev/users_guide/time_evolution/stochastic/index.html index e209b8e2..ee839603 100644 --- a/dev/users_guide/time_evolution/stochastic/index.html +++ b/dev/users_guide/time_evolution/stochastic/index.html @@ -1,2 +1,2 @@ -Stochastic Solver · QuantumToolbox.jl
+Stochastic Solver · QuantumToolbox.jl
diff --git a/dev/users_guide/time_evolution/time_dependent/index.html b/dev/users_guide/time_evolution/time_dependent/index.html index ae6cffb5..17664f45 100644 --- a/dev/users_guide/time_evolution/time_dependent/index.html +++ b/dev/users_guide/time_evolution/time_dependent/index.html @@ -1,2 +1,2 @@ -Solving Problems with Time-dependent Hamiltonians · QuantumToolbox.jl +Solving Problems with Time-dependent Hamiltonians · QuantumToolbox.jl