Skip to content

Commit b2beabd

Browse files
committed
Merge branch 'main' into multi-traj-sol
2 parents 3c6d246 + c6283fe commit b2beabd

File tree

14 files changed

+113
-83
lines changed

14 files changed

+113
-83
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +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+
- Improve efficiency of `bloch_redfield_tensor` by avoiding unnecessary conversions. ([#509])
11+
- Support `SciMLOperators v1.4+`. ([#470])
12+
- Fix compatibility with `Makie v0.24+`. ([#513])
1013
- Add `keep_runs_results` option for multi-trajectory solvers to align with `QuTiP`. ([#512])
1114
- Breaking changes for multi-trajectory solutions:
1215
- the original fields `expect` and `states` now store the results depend on keyword argument `keep_runs_results` (decide whether to store all trajectories results or not).
@@ -263,6 +266,7 @@ Release date: 2024-11-13
263266
[#455]: https://github.com/qutip/QuantumToolbox.jl/issues/455
264267
[#456]: https://github.com/qutip/QuantumToolbox.jl/issues/456
265268
[#460]: https://github.com/qutip/QuantumToolbox.jl/issues/460
269+
[#470]: https://github.com/qutip/QuantumToolbox.jl/issues/470
266270
[#472]: https://github.com/qutip/QuantumToolbox.jl/issues/472
267271
[#473]: https://github.com/qutip/QuantumToolbox.jl/issues/473
268272
[#476]: https://github.com/qutip/QuantumToolbox.jl/issues/476
@@ -277,4 +281,6 @@ Release date: 2024-11-13
277281
[#504]: https://github.com/qutip/QuantumToolbox.jl/issues/504
278282
[#506]: https://github.com/qutip/QuantumToolbox.jl/issues/506
279283
[#507]: https://github.com/qutip/QuantumToolbox.jl/issues/507
284+
[#509]: https://github.com/qutip/QuantumToolbox.jl/issues/509
280285
[#512]: https://github.com/qutip/QuantumToolbox.jl/issues/512
286+
[#513]: https://github.com/qutip/QuantumToolbox.jl/issues/513

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ KernelAbstractions = "0.9.2"
5656
LaTeXStrings = "1.2"
5757
LinearAlgebra = "1"
5858
LinearSolve = "2, 3"
59-
Makie = "0.20, 0.21, 0.22, 0.23, 0.24"
59+
Makie = "0.24"
6060
OrdinaryDiffEqCore = "1"
6161
OrdinaryDiffEqTsit5 = "1"
6262
Pkg = "1"
6363
Random = "1"
6464
SciMLBase = "2"
65-
SciMLOperators = "0.3, 0.4"
65+
SciMLOperators = "1.4"
6666
SparseArrays = "1"
6767
SpecialFunctions = "2"
6868
StaticArraysCore = "1"

docs/src/users_guide/plotting_the_bloch_sphere.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ At the end of the last section we saw that the colors and marker shapes of the d
195195
| `b.sphere_color` | Color of Bloch sphere surface | `0.2` |
196196
| `b.sphere_alpha` | Transparency of sphere surface | `"#FFDDDD"` |
197197
| `b.vector_color` | Colors for vectors | `["green", "#CC6600", "blue", "red"]` |
198-
| `b.vector_width` | Width of vectors | `0.025` |
199-
| `b.vector_arrowsize` | Scales the size of the arrow head. The first two elements scale the radius (in `x/y` direction) and the last one is the length of the cone. | `[0.07, 0.08, 0.08]` |
198+
| `b.vector_width` | Width of vectors | `0.02` |
199+
| `b.vector_tiplength` | Length of vector arrow head | `0.08` |
200+
| `b.vector_tipradius` | Radius of vector arrow head | `0.05` |
200201
| `b.view` | Azimuthal and elevation viewing angles in degrees | `[30, 30]` |
201202
| `b.xlabel` | Labels for x-axis | `[L"x", ""]` (``+x`` and ``-x``) |
202203
| `b.xlpos` | Positions of x-axis labels | `[1.2, -1.2]` |

docs/src/users_guide/settings.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ Here, we list out each setting along with the specific functions that will use i
1313

1414
- `tidyup_tol::Float64 = 1e-14` : tolerance for [`tidyup`](@ref) and [`tidyup!`](@ref).
1515
- `auto_tidyup::Bool = true` : Automatically tidyup during the following situations:
16-
* Solving for eigenstates, including [`eigenstates`](@ref), [`eigsolve`](@ref), and [`eigsolve_al`](@ref).
16+
* Solving for eigenstates, including [`eigenstates`](@ref), [`eigsolve`](@ref), [`eigsolve_al`](@ref)
17+
* Creating [`bloch_redfield_tensor`](@ref) or [`brterm`](@ref), and solving [`brmesolve`](@ref).
1718
- (to be announced)
1819

1920
## Change default settings

docs/src/users_guide/time_evolution/brmesolve.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ H = -Δ/2.0 * sigmax() - ε0/2 * sigmaz()
162162
163163
ohmic_spectrum(ω) = (ω == 0.0) ? γ1 : γ1 / 2 * (ω / (2 * π)) * (ω > 0.0)
164164
165-
R, U = bloch_redfield_tensor(H, [(sigmax(), ohmic_spectrum)])
165+
R, U = bloch_redfield_tensor(H, ((sigmax(), ohmic_spectrum), ))
166166
167167
R
168168
```
@@ -183,6 +183,8 @@ H = - Δ/2.0 * sigmax() - ϵ0/2.0 * sigmaz()
183183
ohmic_spectrum(ω) = (ω == 0.0) ? γ1 : γ1 / 2 * (ω / (2 * π)) * (ω > 0.0)
184184
185185
a_ops = ((sigmax(), ohmic_spectrum),)
186+
R = bloch_redfield_tensor(H, a_ops; fock_basis = Val(true))
187+
186188
e_ops = [sigmax(), sigmay(), sigmaz()]
187189
188190
# same initial random ket state in QuTiP doc
@@ -192,7 +194,7 @@ e_ops = [sigmax(), sigmay(), sigmaz()]
192194
])
193195
194196
tlist = LinRange(0, 15.0, 1000)
195-
sol = brmesolve(H, ψ0, tlist, a_ops, e_ops=e_ops)
197+
sol = mesolve(R, ψ0, tlist, e_ops=e_ops)
196198
expt_list = real(sol.expect)
197199
198200
# plot the evolution of state on Bloch sphere

ext/QuantumToolboxMakieExt.jl

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Makie:
2222
Sphere,
2323
lines!,
2424
scatter!,
25-
arrows!,
25+
arrows3d!,
2626
text!,
2727
Point3f,
2828
mesh!,
@@ -656,26 +656,17 @@ Scales vectors appropriately and adds `3D` arrow markers.
656656
function _plot_vectors!(b::Bloch, lscene)
657657
isempty(b.vectors) && return nothing
658658

659-
arrow_head_length = b.vector_arrowsize[3]
660659
for (i, v) in enumerate(b.vectors)
661660
color = get(b.vector_color, i, RGBAf(0.2, 0.5, 0.8, 0.9))
662-
nv = norm(v)
663-
(arrow_head_length < nv) || throw(
664-
ArgumentError(
665-
"The length of vector arrow head (Bloch.vector_arrowsize[3]=$arrow_head_length) should be shorter than vector norm: $nv",
666-
),
667-
)
668661

669-
# multiply by the following factor makes the end point of arrow head represent the actual vector position.
670-
vec = (1 - arrow_head_length / nv) * Vec3f(v...)
671-
arrows!(
662+
arrows3d!(
672663
lscene,
673664
[Point3f(0, 0, 0)],
674-
[vec],
665+
[v],
675666
color = color,
676-
linewidth = b.vector_width,
677-
arrowsize = Vec3f(b.vector_arrowsize...),
678-
arrowcolor = color,
667+
shaftradius = b.vector_width,
668+
tiplength = b.vector_tiplength,
669+
tipradius = b.vector_tipradius,
679670
rasterize = 3,
680671
)
681672
end

src/QuantumToolbox.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import SciMLBase:
1717
u_modified!,
1818
NullParameters,
1919
ODEFunction,
20+
SDEFunction,
2021
ODEProblem,
2122
SDEProblem,
2223
EnsembleProblem,

src/qobj/quantum_object_evo.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ function (A::QuantumObjectEvolution)(
512512
)
513513
end
514514

515-
A.data(ψout.data, ψin.data, p, t)
515+
A.data(ψout.data, ψin.data, nothing, p, t)
516516

517517
return ψout
518518
end

src/time_evolution/brmesolve.jl

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,28 @@ function bloch_redfield_tensor(
3737
U = QuantumObject(rst.vectors, Operator(), H.dimensions)
3838
sec_cutoff = float(sec_cutoff)
3939

40-
# in fock basis
41-
R0 = liouvillian(H, c_ops)
40+
H_new = getVal(fock_basis) ? H : QuantumObject(Diagonal(rst.values), Operator(), H.dimensions)
41+
c_ops_new = isnothing(c_ops) ? nothing : map(x -> getVal(fock_basis) ? x : U' * x * U, c_ops)
42+
L0 = liouvillian(H_new, c_ops_new)
4243

43-
# set fock_basis=Val(false) and change basis together at the end
44-
R1 = 0
45-
isempty(a_ops) || (R1 += mapreduce(x -> _brterm(rst, x[1], x[2], sec_cutoff, Val(false)), +, a_ops))
44+
# Check whether we can rotate the terms to the eigenbasis directly in the Hamiltonian space
45+
fock_basis_hamiltonian = getVal(fock_basis) && sec_cutoff == -1
4646

47-
SU = sprepost(U, U') # transformation matrix from eigen basis back to fock basis
47+
R = isempty(a_ops) ? 0 : sum(x -> _brterm(rst, x[1], x[2], sec_cutoff, fock_basis_hamiltonian), a_ops)
48+
49+
# If in fock basis, we need to transform the terms back to the fock basis
50+
# Note: we can transform the terms in the Hamiltonian space only if sec_cutoff is -1
51+
# otherwise, we need to use the SU superoperator below to transform the entire Liouvillian
52+
# at the end, due to the action of M_cut
4853
if getVal(fock_basis)
49-
return R0 + SU * R1 * SU'
54+
if fock_basis_hamiltonian
55+
return L0 + R # Already rotated in the Hamiltonian space
56+
else
57+
SU = sprepost(U, U')
58+
return L0 + SU * R * SU'
59+
end
5060
else
51-
return SU' * R0 * SU + R1, U
61+
return L0 + R, U
5262
end
5363
end
5464

@@ -86,11 +96,21 @@ function brterm(
8696
fock_basis::Union{Bool,Val} = Val(false),
8797
)
8898
rst = eigenstates(H)
89-
term = _brterm(rst, a_op, spectra, sec_cutoff, makeVal(fock_basis))
99+
U = QuantumObject(rst.vectors, Operator(), H.dimensions)
100+
101+
# Check whether we can rotate the terms to the eigenbasis directly in the Hamiltonian space
102+
fock_basis_hamiltonian = getVal(fock_basis) && sec_cutoff == -1
103+
104+
term = _brterm(rst, a_op, spectra, sec_cutoff, fock_basis_hamiltonian)
90105
if getVal(fock_basis)
91-
return term
106+
if fock_basis_hamiltonian
107+
return term # Already rotated in the Hamiltonian space
108+
else
109+
SU = sprepost(U, U')
110+
return SU * term * SU'
111+
end
92112
else
93-
return term, Qobj(rst.vectors, Operator(), rst.dimensions)
113+
return term, U
94114
end
95115
end
96116

@@ -99,7 +119,7 @@ function _brterm(
99119
a_op::T,
100120
spectra::F,
101121
sec_cutoff::Real,
102-
fock_basis::Union{Val{true},Val{false}},
122+
fock_basis_hamiltonian::Union{Bool,Val},
103123
) where {T<:QuantumObject{Operator},F<:Function}
104124
_check_br_spectra(spectra)
105125

@@ -110,9 +130,11 @@ function _brterm(
110130
spectrum = spectra.(skew)
111131

112132
A_mat = U' * a_op.data * U
133+
A_mat_spec = A_mat .* spectrum
134+
A_mat_spec_t = A_mat .* transpose(spectrum)
113135

114-
ac_term = (A_mat .* spectrum) * A_mat
115-
bd_term = A_mat * (A_mat .* trans(spectrum))
136+
ac_term = A_mat_spec * A_mat
137+
bd_term = A_mat * A_mat_spec_t
116138

117139
if sec_cutoff != -1
118140
m_cut = similar(skew)
@@ -124,20 +146,29 @@ function _brterm(
124146
M_cut = @. abs(vec_skew - vec_skew') < sec_cutoff
125147
end
126148

127-
out =
128-
0.5 * (
129-
+ _sprepost(A_mat .* trans(spectrum), A_mat) + _sprepost(A_mat, A_mat .* spectrum) - _spost(ac_term, Id) -
130-
_spre(bd_term, Id)
131-
)
149+
# Rotate the terms to the eigenbasis if possible
150+
if getVal(fock_basis_hamiltonian)
151+
A_mat = U * A_mat * U'
152+
A_mat_spec = U * A_mat_spec * U'
153+
A_mat_spec_t = U * A_mat_spec_t * U'
154+
ac_term = U * ac_term * U'
155+
bd_term = U * bd_term * U'
156+
end
157+
158+
# Remove small values before passing in the Liouville space
159+
if settings.auto_tidyup
160+
tidyup!(A_mat)
161+
tidyup!(A_mat_spec)
162+
tidyup!(A_mat_spec_t)
163+
tidyup!(ac_term)
164+
tidyup!(bd_term)
165+
end
166+
167+
out = (_sprepost(A_mat_spec_t, A_mat) + _sprepost(A_mat, A_mat_spec) - _spost(ac_term, Id) - _spre(bd_term, Id)) / 2
132168

133169
(sec_cutoff != -1) && (out .*= M_cut)
134170

135-
if getVal(fock_basis)
136-
SU = _sprepost(U, U')
137-
return QuantumObject(SU * out * SU', SuperOperator(), rst.dimensions)
138-
else
139-
return QuantumObject(out, SuperOperator(), rst.dimensions)
140-
end
171+
return QuantumObject(out, SuperOperator(), rst.dimensions)
141172
end
142173

143174
@doc raw"""

src/time_evolution/time_evolution.jl

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -481,40 +481,37 @@ end
481481
482482
A struct to represent the diffusion operator. This is used to perform the diffusion process on N different Wiener processes.
483483
=#
484-
struct DiffusionOperator{T,OpType<:Tuple{Vararg{AbstractSciMLOperator}}} <: AbstractSciMLOperator{T}
484+
struct DiffusionOperator{T,OpType<:Tuple{Vararg{AbstractSciMLOperator}}}
485485
ops::OpType
486486
function DiffusionOperator(ops::OpType) where {OpType}
487487
T = mapreduce(eltype, promote_type, ops)
488488
return new{T,OpType}(ops)
489489
end
490490
end
491491

492-
@generated function update_coefficients!(L::DiffusionOperator, u, p, t)
493-
ops_types = L.parameters[2].parameters
494-
N = length(ops_types)
495-
return quote
496-
Base.@nexprs $N i -> begin
497-
update_coefficients!(L.ops[i], u, p, t)
498-
end
499-
500-
nothing
501-
end
502-
end
503-
504-
@generated function LinearAlgebra.mul!(v::AbstractVecOrMat, L::DiffusionOperator, u::AbstractVecOrMat)
492+
@generated function (L::DiffusionOperator)(w, v, p, t)
505493
ops_types = L.parameters[2].parameters
506494
N = length(ops_types)
507495
quote
508-
M = length(u)
509-
S = (size(v, 1), size(v, 2)) # This supports also `v` as a `Vector`
496+
M = length(v)
497+
S = (size(w, 1), size(w, 2)) # This supports also `w` as a `Vector`
510498
(S[1] == M && S[2] == $N) || throw(DimensionMismatch("The size of the output vector is incorrect."))
511499
Base.@nexprs $N i -> begin
512-
mul!(@view(v[:, i]), L.ops[i], u)
500+
op = L.ops[i]
501+
op(@view(w[:, i]), v, v, p, t)
513502
end
514-
return v
503+
return w
515504
end
516505
end
517506

507+
#TODO: Remove when a new release of SciMLBase.jl >2.104.0 is available
508+
(f::SDEFunction)(du, u, p, t) =
509+
if f.f isa AbstractSciMLOperator
510+
f.f(du, u, u, p, t)
511+
else
512+
f.f(du, u, p, t)
513+
end
514+
518515
#######################################
519516

520517
function liouvillian_floquet(

0 commit comments

Comments
 (0)