Skip to content

Commit 54ded38

Browse files
authored
A lazy method to construct QobjEvo (#282)
* add a lazy method to construct `QobjEvo` * format files * improve tests to make sure time-independent problems are `MatrixOperator` * modify docstrings * fix typo * fix extra `ScalarOperator` in `mcsolve` * rebase to `ScaledOperator` in time-independent `mcsolve` * add missing import in test
1 parent 380d017 commit 54ded38

File tree

5 files changed

+56
-9
lines changed

5 files changed

+56
-9
lines changed

src/qobj/quantum_object_evo.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=fal
2727
⎢⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⎥
2828
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⎦
2929
30+
julia> coef1(p, t) = exp(-1im * t)
31+
coef1 (generic function with 1 method)
32+
33+
julia> op = QuantumObjectEvolution(a, coef1)
34+
Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=true
35+
ScalarOperator(0.0 + 0.0im) * MatrixOperator(20 × 20)
36+
```
37+
38+
If there are more than 2 operators, we need to put each set of operator and coefficient function into a two-element `Tuple`, and put all these `Tuple`s together in a larger `Tuple`:
39+
40+
```
3041
julia> σm = tensor(qeye(10), sigmam())
3142
Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=false
3243
20×20 SparseMatrixCSC{ComplexF64, Int64} with 10 stored entries:
@@ -36,9 +47,6 @@ Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=fal
3647
⎢⠀⠀⠀⠀⠀⠀⠂⡀⠀⠀⎥
3748
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠂⡀⎦
3849
39-
julia> coef1(p, t) = exp(-1im * t)
40-
coef1 (generic function with 1 method)
41-
4250
julia> coef2(p, t) = sin(t)
4351
coef2 (generic function with 1 method)
4452
@@ -134,7 +142,7 @@ function QuantumObjectEvolution(data::AbstractSciMLOperator, type::QuantumObject
134142
return QuantumObjectEvolution(data, type, SVector{1,Int}(dims))
135143
end
136144

137-
"""
145+
@doc raw"""
138146
QuantumObjectEvolution(data::AbstractSciMLOperator; type::QuantumObjectType = Operator, dims = nothing)
139147
140148
Generate a [`QuantumObjectEvolution`](@ref) object from a [`SciMLOperator`](https://github.com/SciML/SciMLOperators.jl), in the same way as [`QuantumObject`](@ref) for `AbstractArray` inputs.
@@ -172,6 +180,9 @@ function QuantumObjectEvolution(
172180
return QuantumObjectEvolution(data, type, dims)
173181
end
174182

183+
QuantumObjectEvolution(op::QuantumObject, f::Function; type::Union{Nothing,QuantumObjectType} = nothing) =
184+
QuantumObjectEvolution(((op, f),); type = type)
185+
175186
function QuantumObjectEvolution(
176187
op::QuantumObject,
177188
α::Union{Nothing,Number} = nothing;

src/qobj/synonyms.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,35 @@ Note that this functions is same as `QuantumObject(A; type=type, dims=dims)`.
1717
"""
1818
Qobj(A; kwargs...) = QuantumObject(A; kwargs...)
1919

20+
@doc raw"""
21+
QobjEvo(op::QuantumObject, f::Function; type::Union{Nothing,QuantumObjectType} = nothing)
22+
23+
Generate [`QuantumObjectEvolution`](@ref).
24+
25+
Note that this functions is same as `QuantumObjectEvolution(op, f; type = type)`. The `f` parameter is used to pre-apply a function to the operators before converting them to SciML operators. The `type` parameter is used to specify the type of the [`QuantumObject`](@ref), either `Operator` or `SuperOperator`.
26+
27+
# Examples
28+
```
29+
julia> a = tensor(destroy(10), qeye(2))
30+
Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=false
31+
20×20 SparseMatrixCSC{ComplexF64, Int64} with 18 stored entries:
32+
⎡⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⎤
33+
⎢⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⎥
34+
⎢⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⎥
35+
⎢⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⎥
36+
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⎦
37+
38+
julia> coef(p, t) = exp(-1im * t)
39+
coef1 (generic function with 1 method)
40+
41+
julia> op = QobjEvo(a, coef)
42+
Quantum Object: type=Operator dims=[10, 2] size=(20, 20) ishermitian=true
43+
ScalarOperator(0.0 + 0.0im) * MatrixOperator(20 × 20)
44+
```
45+
"""
46+
QobjEvo(op::QuantumObject, f::Function; type::Union{Nothing,QuantumObjectType} = nothing) =
47+
QuantumObjectEvolution(op, f; type = type)
48+
2049
@doc raw"""
2150
QobjEvo(op_func_list::Union{Tuple,AbstractQuantumObject}, α::Union{Nothing,Number}=nothing; type::Union{Nothing, QuantumObjectType}=nothing)
2251

test/core-test/quantum_objects_evo.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@
185185

186186
# SuperOperator
187187
X = a * a'
188-
c_op1 = QobjEvo(((a', coef1),))
188+
c_op1 = QobjEvo(a', coef1)
189189
c_op2 = QobjEvo(((a, coef2), (X, coef3)))
190190
c_ops = [c_op1, c_op2]
191191
D1_ti = abs2(coef1(p, t)) * lindblad_dissipator(a')
@@ -213,7 +213,7 @@
213213
@test_throws ArgumentError cache_operator(L_td, ψ)
214214

215215
@testset "Type Inference" begin
216-
@inferred liouvillian(H_td, (a, QobjEvo(((a', coef1),))))
216+
@inferred liouvillian(H_td, (a, QobjEvo(a', coef1)))
217217
end
218218
end
219219
end

test/core-test/time_evolution.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
psi0 = kron(fock(N, 0), fock(2, 0))
1212
t_l = LinRange(0, 1000, 1000)
1313
e_ops = [a_d * a]
14-
sol = sesolve(H, psi0, t_l, e_ops = e_ops, progress_bar = Val(false))
14+
prob = sesolveProblem(H, psi0, t_l, e_ops = e_ops, progress_bar = Val(false))
15+
sol = sesolve(prob)
1516
sol2 = sesolve(H, psi0, t_l, progress_bar = Val(false))
1617
sol3 = sesolve(H, psi0, t_l, e_ops = e_ops, saveat = t_l, progress_bar = Val(false))
1718
sol_string = sprint((t, s) -> show(t, "text/plain", s), sol)
19+
@test prob.f.f isa MatrixOperator
1820
@test sum(abs.(sol.expect[1, :] .- sin.(η * t_l) .^ 2)) / length(t_l) < 0.1
1921
@test length(sol.times) == length(t_l)
2022
@test length(sol.states) == 1
@@ -55,9 +57,11 @@
5557
e_ops = [a_d * a]
5658
psi0 = basis(N, 3)
5759
t_l = LinRange(0, 100, 1000)
58-
sol_me = mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, progress_bar = Val(false))
60+
prob_me = mesolveProblem(H, psi0, t_l, c_ops, e_ops = e_ops, progress_bar = Val(false))
61+
sol_me = mesolve(prob_me)
5962
sol_me2 = mesolve(H, psi0, t_l, c_ops, progress_bar = Val(false))
6063
sol_me3 = mesolve(H, psi0, t_l, c_ops, e_ops = e_ops, saveat = t_l, progress_bar = Val(false))
64+
prob_mc = mcsolveProblem(H, psi0, t_l, c_ops, e_ops = e_ops, progress_bar = Val(false))
6165
sol_mc = mcsolve(H, psi0, t_l, c_ops, ntraj = 500, e_ops = e_ops, progress_bar = Val(false))
6266
sol_mc2 = mcsolve(
6367
H,
@@ -93,6 +97,8 @@
9397
sol_me_string = sprint((t, s) -> show(t, "text/plain", s), sol_me)
9498
sol_mc_string = sprint((t, s) -> show(t, "text/plain", s), sol_mc)
9599
sol_sse_string = sprint((t, s) -> show(t, "text/plain", s), sol_sse)
100+
@test prob_me.f.f isa MatrixOperator
101+
@test prob_mc.f.f isa ScaledOperator # TODO: can be optimized as MatrixOperator
96102
@test sum(abs.(sol_mc.expect .- sol_me.expect)) / length(t_l) < 0.1
97103
@test sum(abs.(sol_mc2.expect .- sol_me.expect)) / length(t_l) < 0.1
98104
@test sum(abs.(vec(expect_mc_states_mean) .- vec(sol_me.expect))) / length(t_l) < 0.1
@@ -230,7 +236,7 @@
230236

231237
@testset "Type Inference mesolve" begin
232238
coef(p, t) = exp(-t)
233-
ad_t = QobjEvo(((a', coef),))
239+
ad_t = QobjEvo(a', coef)
234240
@inferred mesolveProblem(H, ψ0, tlist, c_ops, e_ops = e_ops, progress_bar = Val(false))
235241
@inferred mesolveProblem(H, ψ0, [0, 10], c_ops, e_ops = e_ops, progress_bar = Val(false))
236242
@inferred mesolveProblem(

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using QuantumToolbox
44
using QuantumToolbox: position, momentum
55
using Random
66
using SciMLOperators
7+
import SciMLOperators: ScaledOperator
78

89
const GROUP = get(ENV, "GROUP", "All")
910

0 commit comments

Comments
 (0)