Skip to content
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

- Improve efficiency of `bloch_redfield_tensor` by avoiding unnecessary conversions. ([#509])

## [v0.33.0]
Release date: 2025-07-22

Expand Down Expand Up @@ -267,3 +269,4 @@ Release date: 2024-11-13
[#504]: https://github.com/qutip/QuantumToolbox.jl/issues/504
[#506]: https://github.com/qutip/QuantumToolbox.jl/issues/506
[#507]: https://github.com/qutip/QuantumToolbox.jl/issues/507
[#509]: https://github.com/qutip/QuantumToolbox.jl/issues/509
2 changes: 1 addition & 1 deletion docs/src/users_guide/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Here, we list out each setting along with the specific functions that will use i

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

## Change default settings
Expand Down
6 changes: 4 additions & 2 deletions docs/src/users_guide/time_evolution/brmesolve.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ H = -Δ/2.0 * sigmax() - ε0/2 * sigmaz()

ohmic_spectrum(ω) = (ω == 0.0) ? γ1 : γ1 / 2 * (ω / (2 * π)) * (ω > 0.0)

R, U = bloch_redfield_tensor(H, [(sigmax(), ohmic_spectrum)])
R, U = bloch_redfield_tensor(H, ((sigmax(), ohmic_spectrum), ))

R
```
Expand All @@ -183,6 +183,8 @@ H = - Δ/2.0 * sigmax() - ϵ0/2.0 * sigmaz()
ohmic_spectrum(ω) = (ω == 0.0) ? γ1 : γ1 / 2 * (ω / (2 * π)) * (ω > 0.0)

a_ops = ((sigmax(), ohmic_spectrum),)
R = bloch_redfield_tensor(H, a_ops; fock_basis = Val(true))

e_ops = [sigmax(), sigmay(), sigmaz()]

# same initial random ket state in QuTiP doc
Expand All @@ -192,7 +194,7 @@ e_ops = [sigmax(), sigmay(), sigmaz()]
])

tlist = LinRange(0, 15.0, 1000)
sol = brmesolve(H, ψ0, tlist, a_ops, e_ops=e_ops)
sol = mesolve(R, ψ0, tlist, e_ops=e_ops)
expt_list = real(sol.expect)

# plot the evolution of state on Bloch sphere
Expand Down
23 changes: 14 additions & 9 deletions src/time_evolution/brmesolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,16 @@ function bloch_redfield_tensor(
U = QuantumObject(rst.vectors, Operator(), H.dimensions)
sec_cutoff = float(sec_cutoff)

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

# set fock_basis=Val(false) and change basis together at the end
R1 = 0
isempty(a_ops) || (R1 += mapreduce(x -> _brterm(rst, x[1], x[2], sec_cutoff, Val(false)), +, a_ops))
isempty(a_ops) || (R += sum(x -> _brterm(rst, x[1], x[2], sec_cutoff, fock_basis), a_ops))

SU = sprepost(U, U') # transformation matrix from eigen basis back to fock basis
if getVal(fock_basis)
return R0 + SU * R1 * SU'
return R
else
return SU' * R0 * SU + R1, U
return R, U
end
end

Expand Down Expand Up @@ -99,7 +97,7 @@ function _brterm(
a_op::T,
spectra::F,
sec_cutoff::Real,
fock_basis::Union{Val{true},Val{false}},
fock_basis::Union{Bool,Val},
) where {T<:QuantumObject{Operator},F<:Function}
_check_br_spectra(spectra)

Expand All @@ -124,6 +122,13 @@ function _brterm(
M_cut = @. abs(vec_skew - vec_skew') < sec_cutoff
end

# Remove small values before passing in the Liouville space
if settings.auto_tidyup
tidyup!(A_mat)
tidyup!(ac_term)
tidyup!(bd_term)
end

out =
0.5 * (
+ _sprepost(A_mat .* trans(spectrum), A_mat) + _sprepost(A_mat, A_mat .* spectrum) - _spost(ac_term, Id) -
Expand Down
17 changes: 9 additions & 8 deletions test/core-test/brmesolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
A_op = a+a'
spectra(x) = (x>0) * 0.5
for sec_cutoff in [0, 0.1, 1, 3, -1]
R = bloch_redfield_tensor(H, [(A_op, spectra)], [a^2], sec_cutoff = sec_cutoff, fock_basis = true)
R_eig, evecs = bloch_redfield_tensor(H, [(A_op, spectra)], [a^2], sec_cutoff = sec_cutoff, fock_basis = false)
R = bloch_redfield_tensor(H, ((A_op, spectra),), [a^2], sec_cutoff = sec_cutoff, fock_basis = Val(true))
R_eig, evecs =
bloch_redfield_tensor(H, ((A_op, spectra),), [a^2], sec_cutoff = sec_cutoff, fock_basis = Val(false))
@test isa(R, QuantumObject)
@test isa(R_eig, QuantumObject)
@test isa(evecs, QuantumObject)
Expand All @@ -27,7 +28,7 @@ end

# this test applies for limited cutoff
lindblad = lindblad_dissipator(a)
computation = brterm(H, A_op, spectra, sec_cutoff = 1.5, fock_basis = true)
computation = brterm(H, A_op, spectra, sec_cutoff = 1.5, fock_basis = Val(true))
@test isapprox(lindblad, computation, atol = 1e-15)
end

Expand All @@ -38,8 +39,8 @@ end
A_op = a+a'
spectra(x) = x>0
for sec_cutoff in [0, 0.1, 1, 3, -1]
R = brterm(H, A_op, spectra, sec_cutoff = sec_cutoff, fock_basis = true)
R_eig, evecs = brterm(H, A_op, spectra, sec_cutoff = sec_cutoff, fock_basis = false)
R = brterm(H, A_op, spectra, sec_cutoff = sec_cutoff, fock_basis = Val(true))
R_eig, evecs = brterm(H, A_op, spectra, sec_cutoff = sec_cutoff, fock_basis = Val(false))
@test isa(R, QuantumObject)
@test isa(R_eig, QuantumObject)
@test isa(evecs, QuantumObject)
Expand Down Expand Up @@ -76,8 +77,8 @@ end
a = destroy(N) + destroy(N)^2/2
A_op = a+a'
for spectra in spectra_list
R = brterm(H, A_op, spectra, sec_cutoff = 0.1, fock_basis = true)
R_eig, evecs = brterm(H, A_op, spectra, sec_cutoff = 0.1, fock_basis = false)
R = brterm(H, A_op, spectra, sec_cutoff = 0.1, fock_basis = Val(true))
R_eig, evecs = brterm(H, A_op, spectra, sec_cutoff = 0.1, fock_basis = Val(false))
@test isa(R, QuantumObject)
@test isa(R_eig, QuantumObject)
@test isa(evecs, QuantumObject)
Expand Down Expand Up @@ -112,4 +113,4 @@ end

@test all(me.expect .== brme.expect)
end
end;
end
Loading