Skip to content

Commit 680603e

Browse files
authored
Merge branch 'main' into dev/visualization
2 parents 84c22ce + e754148 commit 680603e

File tree

9 files changed

+91
-9
lines changed

9 files changed

+91
-9
lines changed

CHANGELOG.md

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

88
## [Unreleased](https://github.com/qutip/QuantumToolbox.jl/tree/main)
99

10-
- Introduce `plot_wigner` function for easy plotting of Wigner functions. ([#86], [#292])
11-
10+
- Improve the construction of `QobjEvo`. ([#338], [#339])
11+
- Support `Base.zero` and `Base.one` for `AbstractQuantumObject`. ([#342], [#346])
12+
- Introduce visualization and function `plot_wigner` for easy plotting of Wigner functions. ([#86], [#292], [#347])
1213

1314
## [v0.23.1]
1415
Release date: 2024-12-06
@@ -56,3 +57,7 @@ Release date: 2024-11-13
5657
[#324]: https://github.com/qutip/QuantumToolbox.jl/issues/324
5758
[#330]: https://github.com/qutip/QuantumToolbox.jl/issues/330
5859
[#335]: https://github.com/qutip/QuantumToolbox.jl/issues/335
60+
[#338]: https://github.com/qutip/QuantumToolbox.jl/issues/338
61+
[#339]: https://github.com/qutip/QuantumToolbox.jl/issues/339
62+
[#342]: https://github.com/qutip/QuantumToolbox.jl/issues/342
63+
[#346]: https://github.com/qutip/QuantumToolbox.jl/issues/346

docs/src/resources/api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ SciMLOperators.isconstant
5252
## [Qobj arithmetic and attributes](@id doc-API:Qobj-arithmetic-and-attributes)
5353

5454
```@docs
55+
Base.zero
56+
Base.one
5557
Base.conj
5658
LinearAlgebra.transpose
5759
LinearAlgebra.adjoint

docs/src/users_guide/QuantumObject/QuantumObject_functions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Here is a table that summarizes all the supported linear algebra functions and a
1010

1111
| **Description** | **Function call** | **Synonyms** |
1212
|:----------------|:------------------|:-------------|
13+
| zero-like array | [`zero(Q)`](@ref zero) | - |
14+
| identity-like matrix | [`one(Q)`](@ref one) | - |
1315
| conjugate | [`conj(Q)`](@ref conj) | - |
1416
| transpose | [`transpose(Q)`](@ref transpose) | [`trans(Q)`](@ref trans) |
1517
| conjugate transposition | [`adjoint(Q)`](@ref adjoint) | [`Q'`](@ref adjoint), [`dag(Q)`](@ref dag) |

src/qobj/arithmetic_and_attributes.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,25 @@ function LinearAlgebra.dot(
156156
return LinearAlgebra.dot(i.data, A.data, j.data)
157157
end
158158

159+
@doc raw"""
160+
zero(A::AbstractQuantumObject)
161+
162+
Return a similar [`AbstractQuantumObject`](@ref) with `dims` and `type` are same as `A`, but `data` is a zero-array.
163+
"""
164+
Base.zero(A::AbstractQuantumObject) = get_typename_wrapper(A)(zero(A.data), A.type, A.dims)
165+
166+
@doc raw"""
167+
one(A::AbstractQuantumObject)
168+
169+
Return a similar [`AbstractQuantumObject`](@ref) with `dims` and `type` are same as `A`, but `data` is an identity matrix.
170+
171+
Note that `A` must be [`Operator`](@ref) or [`SuperOperator`](@ref).
172+
"""
173+
Base.one(
174+
A::AbstractQuantumObject{DT,OpType},
175+
) where {DT,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} =
176+
get_typename_wrapper(A)(one(A.data), A.type, A.dims)
177+
159178
@doc raw"""
160179
conj(A::AbstractQuantumObject)
161180

src/qobj/quantum_object_evo.jl

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,19 @@ function QuantumObjectEvolution(
180180
return QuantumObjectEvolution(data, type, dims)
181181
end
182182

183-
QuantumObjectEvolution(op::QuantumObject, f::Function; type::Union{Nothing,QuantumObjectType} = nothing) =
184-
QuantumObjectEvolution(((op, f),); type = type)
183+
# this is a extra method if user accidentally specify `QuantumObjectEvolution( (op, func) )` or `QuantumObjectEvolution( ((op, func)) )`
184+
QuantumObjectEvolution(
185+
op_func::Tuple{QuantumObject,Function},
186+
α::Union{Nothing,Number} = nothing;
187+
type::Union{Nothing,QuantumObjectType} = nothing,
188+
) = QuantumObjectEvolution((op_func,), α; type = type)
189+
190+
QuantumObjectEvolution(
191+
op::QuantumObject,
192+
f::Function,
193+
α::Union{Nothing,Number} = nothing;
194+
type::Union{Nothing,QuantumObjectType} = nothing,
195+
) = QuantumObjectEvolution(((op, f),), α; type = type)
185196

186197
function QuantumObjectEvolution(
187198
op::QuantumObject,
@@ -229,13 +240,15 @@ Parse the `op_func_list` and generate the data for the `QuantumObjectEvolution`
229240
N = length(op_func_list_types)
230241

231242
dims_expr = ()
243+
func_methods_expr = ()
232244
first_op = nothing
233245
data_expr = :(0)
234246
qobj_expr_const = :(0)
235247

236248
for i in 1:N
237249
op_func_type = op_func_list_types[i]
238250
if op_func_type <: Tuple
251+
# check the structure of the tuple
239252
length(op_func_type.parameters) == 2 || throw(ArgumentError("The tuple must have two elements."))
240253
op_type = op_func_type.parameters[1]
241254
func_type = op_func_type.parameters[2]
@@ -248,6 +261,7 @@ Parse the `op_func_list` and generate the data for the `QuantumObjectEvolution`
248261
op = :(op_func_list[$i][1])
249262
data_type = op_type.parameters[1]
250263
dims_expr = (dims_expr..., :($op.dims))
264+
func_methods_expr = (func_methods_expr..., :(methods(op_func_list[$i][2], [Any, Real]))) # [Any, Real] means each func must accept 2 arguments
251265
if i == 1
252266
first_op = :($op)
253267
end
@@ -267,10 +281,20 @@ Parse the `op_func_list` and generate the data for the `QuantumObjectEvolution`
267281
end
268282

269283
quote
284+
# check the dims of the operators
270285
dims = tuple($(dims_expr...))
271-
272286
allequal(dims) || throw(ArgumentError("The dimensions of the operators must be the same."))
273287

288+
# check if each func accepts 2 arguments
289+
func_methods = tuple($(func_methods_expr...))
290+
for f_method in func_methods
291+
length(f_method.ms) == 0 && throw(
292+
ArgumentError(
293+
"The following function must accept two arguments: `$(f_method.mt.name)(p, t)` with t<:Real",
294+
),
295+
)
296+
end
297+
274298
data_expr_const = $qobj_expr_const isa Integer ? $qobj_expr_const : _make_SciMLOperator($qobj_expr_const, α)
275299

276300
data_expr = data_expr_const + $data_expr

src/time_evolution/sesolve.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ export sesolveProblem, sesolve
22

33
_sesolve_make_U_QobjEvo(H::QuantumObjectEvolution{<:MatrixOperator}) =
44
QobjEvo(MatrixOperator(-1im * H.data.A), dims = H.dims, type = Operator)
5-
_sesolve_make_U_QobjEvo(H) = QobjEvo(H, -1im)
5+
_sesolve_make_U_QobjEvo(H::QuantumObject) = QobjEvo(MatrixOperator(-1im * H.data), dims = H.dims, type = Operator)
6+
_sesolve_make_U_QobjEvo(H::Union{QuantumObjectEvolution,Tuple}) = QobjEvo(H, -1im)
67

78
@doc raw"""
89
sesolveProblem(

test/core-test/quantum_objects.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@
166166
@test (a2 + 2).data == a2.data + 2 * I
167167
@test a2 * 2 == 2 * a2
168168

169+
zero_like = zero(a2)
170+
iden_like = one(a3)
171+
zero_array = spzeros(ComplexF64, 100, 100)
172+
iden_array = sparse(1:100, 1:100, ones(ComplexF64, 100))
173+
@test zero_like == Qobj(zero_array, type = a2.type, dims = a2.dims)
174+
@test typeof(zero_like.data) == typeof(zero_array)
175+
@test iden_like == Qobj(iden_array, type = a3.type, dims = a3.dims)
176+
@test typeof(iden_like.data) == typeof(iden_array)
169177
@test trans(trans(a2)) == a2
170178
@test trans(a2).data == transpose(a2.data)
171179
@test adjoint(a2) trans(conj(a2))

test/core-test/quantum_objects_evo.jl

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@
7474
@test (a2 + 2).data == a2.data + 2 * I
7575
@test a2 * 2 == 2 * a2
7676

77+
zero_like = zero(a2)
78+
iden_like = one(a3)
79+
zero_array = NullOperator(100)
80+
iden_array = IdentityOperator(100)
81+
@test zero_like == QobjEvo(zero_array, type = a2.type, dims = a2.dims)
82+
@test typeof(zero_like.data) == typeof(zero_array)
83+
@test iden_like == QobjEvo(iden_array, type = a3.type, dims = a3.dims)
84+
@test typeof(iden_like.data) == typeof(iden_array)
7785
@test trans(trans(a2)) == a2
7886
@test trans(a2).data == transpose(a2.data)
7987
# @test adjoint(a2) ≈ trans(conj(a2)) # Currently doesn't work
@@ -119,16 +127,24 @@
119127
"Quantum Object Evo.: type=SuperOperator dims=$L_dims size=$L_size ishermitian=$L_isherm isconstant=$L_isconst\n$datastring"
120128
end
121129

122-
@testset "Type Inference (QuantumObject)" begin
130+
@testset "Type Inference (QobjEvo)" begin
131+
N = 4
123132
for T in [ComplexF32, ComplexF64]
124-
N = 4
125133
a = MatrixOperator(rand(T, N, N))
126134
@inferred QobjEvo(a)
127135
for type in [Operator, SuperOperator]
128136
@inferred QobjEvo(a, type = type)
129137
end
130138
end
131139

140+
a = destroy(N)
141+
coef1(p, t) = exp(-t)
142+
coef2(p::Vector, t) = sin(p[1] * t)
143+
coef3(p::NamedTuple, t) = cos(p.ω * t)
144+
@inferred QobjEvo(a, coef1)
145+
@inferred QobjEvo((a', coef2))
146+
@inferred QobjEvo((a' * a, (a, coef1), (a', coef2), (a + a', coef3)))
147+
132148
@testset "Math Operation" begin
133149
a = QobjEvo(destroy(20))
134150
σx = QobjEvo(sigmax())
@@ -182,6 +198,7 @@
182198
@test isconstant(H_td) == false
183199
@test isconstant(QobjEvo(a)) == true
184200
@test isoper(H_td) == true
201+
@test QobjEvo(a, coef1) == QobjEvo((a, coef1))
185202

186203
# SuperOperator
187204
X = a * a'
@@ -205,7 +222,11 @@
205222
@test isconstant(L_td) == false
206223
@test issuper(L_td) == true
207224

225+
coef_wrong1(t) = nothing
226+
coef_wrong2(p, t::ComplexF64) = nothing
208227
@test_logs (:warn,) (:warn,) liouvillian(H_td * H_td) # warnings from lazy tensor
228+
@test_throws ArgumentError QobjEvo(a, coef_wrong1)
229+
@test_throws ArgumentError QobjEvo(a, coef_wrong2)
209230
@test_throws MethodError QobjEvo([[a, coef1], a' * a, [a', coef2]])
210231
@test_throws ArgumentError H_td(ρvec, p, t)
211232
@test_throws ArgumentError cache_operator(H_td, ρvec)

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ if (GROUP == "All") || (GROUP == "Core")
3939
using QuantumToolbox
4040
import QuantumToolbox: position, momentum
4141
import Random: MersenneTwister
42-
import SciMLOperators: MatrixOperator
42+
import SciMLOperators: MatrixOperator, NullOperator, IdentityOperator
4343

4444
QuantumToolbox.about()
4545

0 commit comments

Comments
 (0)