From ff1ac41eba7f8783b29f8767556131845a54b9b5 Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Wed, 3 Sep 2025 19:17:55 +0800 Subject: [PATCH 1/6] generalize the definition of `liouvillian` --- CHANGELOG.md | 3 +++ src/qobj/superoperators.jl | 7 ++++--- test/core-test/quantum_objects_evo.jl | 4 ++-- test/core-test/steady_state.jl | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a743899..ef1c3145f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) +- Generalize the definition of `liouvillian`. It no longer expects the Hamiltonian to be Hermitian. ([#541]) + ## [v0.35.0] Release date: 2025-09-03 @@ -315,4 +317,5 @@ Release date: 2024-11-13 [#536]: https://github.com/qutip/QuantumToolbox.jl/issues/536 [#537]: https://github.com/qutip/QuantumToolbox.jl/issues/537 [#539]: https://github.com/qutip/QuantumToolbox.jl/issues/539 +[#541]: https://github.com/qutip/QuantumToolbox.jl/issues/541 [#546]: https://github.com/qutip/QuantumToolbox.jl/issues/546 diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index 6bc9a71c3..cc716a5f6 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -41,9 +41,10 @@ end ## intrinsic liouvillian _liouvillian(H::MT, Id::AbstractMatrix) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}} = - -1im * (_spre(H, Id) - _spost(H, Id)) + -1im * _spre(H, Id) + 1im * _spost(H', Id) # don't extract the prefactor -1im seems to be better for AbstractSciMLOperator _liouvillian(H::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_liouvillian(H.A, Id)) -_liouvillian(H::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(H.λ, _liouvillian(H.L, Id)) +# _liouvillian(H::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(H.λ, _liouvillian(H.L, Id)) +# we can remove above implementation for ScaledOperator, since it should just call the first method for AbstractSciMLOperator _liouvillian(H::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _liouvillian(op, Id), H.ops)) # intrinsic lindblad_dissipator @@ -144,7 +145,7 @@ lindblad_dissipator(O::AbstractQuantumObject{SuperOperator}, Id_cache = nothing) Construct the Liouvillian [`SuperOperator`](@ref) for a system Hamiltonian ``\hat{H}`` and a set of collapse operators ``\{\hat{C}_n\}_n``: ```math -\mathcal{L} [\cdot] = -i[\hat{H}, \cdot] + \sum_n \mathcal{D}(\hat{C}_n) [\cdot] +\mathcal{L} [\cdot] = -i\left(\hat{H}[\cdot] - [\cdot]\hat{H}^\dagger\right) + \sum_n \mathcal{D}(\hat{C}_n) [\cdot] ``` where diff --git a/test/core-test/quantum_objects_evo.jl b/test/core-test/quantum_objects_evo.jl index a417f52ac..8a2c5bf6c 100644 --- a/test/core-test/quantum_objects_evo.jl +++ b/test/core-test/quantum_objects_evo.jl @@ -243,9 +243,9 @@ c_ops2 = (destroy(N), QobjEvo(create(N), coef1)) @inferred liouvillian(H_td, c_ops1) - @inferred liouvillian(H_td, c_ops2) + # @inferred liouvillian(H_td, c_ops2) @inferred liouvillian(H_td2, c_ops1) - @inferred liouvillian(H_td2, c_ops2) + # @inferred liouvillian(H_td2, c_ops2) end end end diff --git a/test/core-test/steady_state.jl b/test/core-test/steady_state.jl index 6151af349..4643be509 100644 --- a/test/core-test/steady_state.jl +++ b/test/core-test/steady_state.jl @@ -64,9 +64,9 @@ H_td = (H, (H_t, coeff)) sol_me = mesolve(H_td, psi0, t_l, c_ops, e_ops = e_ops, progress_bar = Val(false)) - ρ_ss1 = steadystate_fourier(H, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1, c_ops, solver = SteadyStateLinearSolver())[1] + ρ_ss1 = steadystate_fourier(H, 0.5 * H_t, 0.5 * H_t, 1, c_ops, solver = SteadyStateLinearSolver())[1] ρ_ss2 = - steadystate_fourier(H, -1im * 0.5 * H_t, 1im * 0.5 * H_t, 1, c_ops, solver = SSFloquetEffectiveLiouvillian()) + steadystate_fourier(H, 0.5 * H_t, 0.5 * H_t, 1, c_ops, solver = SSFloquetEffectiveLiouvillian()) @test abs(sum(sol_me.expect[1, (end-100):end]) / 101 - expect(e_ops[1], ρ_ss1)) < 1e-3 @test abs(sum(sol_me.expect[1, (end-100):end]) / 101 - expect(e_ops[1], ρ_ss2)) < 1e-3 From dc40ca967bb728b2e15d609cd56de13bbcc78a80 Mon Sep 17 00:00:00 2001 From: Yi-Te Huang Date: Wed, 3 Sep 2025 19:31:13 +0800 Subject: [PATCH 2/6] minor changes --- src/qobj/superoperators.jl | 4 +--- test/core-test/steady_state.jl | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index cc716a5f6..4d911241a 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -41,10 +41,8 @@ end ## intrinsic liouvillian _liouvillian(H::MT, Id::AbstractMatrix) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}} = - -1im * _spre(H, Id) + 1im * _spost(H', Id) # don't extract the prefactor -1im seems to be better for AbstractSciMLOperator + -1im * _spre(H, Id) + 1im * _spost(H', Id) # without extracting the prefactor -1im seems to be better for AbstractSciMLOperator _liouvillian(H::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_liouvillian(H.A, Id)) -# _liouvillian(H::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(H.λ, _liouvillian(H.L, Id)) -# we can remove above implementation for ScaledOperator, since it should just call the first method for AbstractSciMLOperator _liouvillian(H::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _liouvillian(op, Id), H.ops)) # intrinsic lindblad_dissipator diff --git a/test/core-test/steady_state.jl b/test/core-test/steady_state.jl index 4643be509..b95273631 100644 --- a/test/core-test/steady_state.jl +++ b/test/core-test/steady_state.jl @@ -65,8 +65,7 @@ sol_me = mesolve(H_td, psi0, t_l, c_ops, e_ops = e_ops, progress_bar = Val(false)) ρ_ss1 = steadystate_fourier(H, 0.5 * H_t, 0.5 * H_t, 1, c_ops, solver = SteadyStateLinearSolver())[1] - ρ_ss2 = - steadystate_fourier(H, 0.5 * H_t, 0.5 * H_t, 1, c_ops, solver = SSFloquetEffectiveLiouvillian()) + ρ_ss2 = steadystate_fourier(H, 0.5 * H_t, 0.5 * H_t, 1, c_ops, solver = SSFloquetEffectiveLiouvillian()) @test abs(sum(sol_me.expect[1, (end-100):end]) / 101 - expect(e_ops[1], ρ_ss1)) < 1e-3 @test abs(sum(sol_me.expect[1, (end-100):end]) / 101 - expect(e_ops[1], ρ_ss2)) < 1e-3 From affcfc93f2148401e57c09ea85d37d50c5d63ac7 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 9 Sep 2025 13:24:13 +0200 Subject: [PATCH 3/6] Fix type instabilities --- src/qobj/superoperators.jl | 19 ++----------------- test/core-test/quantum_objects_evo.jl | 11 +++++------ 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index 4d911241a..7e717e1ca 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -41,7 +41,7 @@ end ## intrinsic liouvillian _liouvillian(H::MT, Id::AbstractMatrix) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}} = - -1im * _spre(H, Id) + 1im * _spost(H', Id) # without extracting the prefactor -1im seems to be better for AbstractSciMLOperator + -1im * (_spre(H, Id) - _spost(H', Id)) _liouvillian(H::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_liouvillian(H.A, Id)) _liouvillian(H::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _liouvillian(op, Id), H.ops)) @@ -178,19 +178,4 @@ liouvillian(H::AbstractQuantumObject{Operator}, Id_cache::Diagonal = I(prod(H.di liouvillian(H::AbstractQuantumObject{SuperOperator}, Id_cache::Diagonal) = H -function _sum_lindblad_dissipators(c_ops, Id_cache::Diagonal) - D = 0 - # sum all the (time-independent) c_ops first - c_ops_ti = filter(op -> isa(op, QuantumObject), c_ops) - if !isempty(c_ops_ti) - D += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_ti) - end - - # sum rest of the QobjEvo together - c_ops_td = filter(op -> isa(op, QuantumObjectEvolution), c_ops) - if !isempty(c_ops_td) - D += mapreduce(op -> lindblad_dissipator(op, Id_cache), +, c_ops_td) - end - - return D -end +_sum_lindblad_dissipators(c_ops, Id_cache::Diagonal) = sum(op -> lindblad_dissipator(op, Id_cache), c_ops) diff --git a/test/core-test/quantum_objects_evo.jl b/test/core-test/quantum_objects_evo.jl index 8a2c5bf6c..c4d797244 100644 --- a/test/core-test/quantum_objects_evo.jl +++ b/test/core-test/quantum_objects_evo.jl @@ -237,15 +237,14 @@ @test_throws ArgumentError cache_operator(L_td, ψ) @testset "Type Inference" begin - # we use destroy and create here because they somehow causes type instability before - H_td2 = H_td + QobjEvo(destroy(N) + create(N), coef3) - c_ops1 = (destroy(N), create(N)) - c_ops2 = (destroy(N), QobjEvo(create(N), coef1)) + H_td2 = H_td + QobjEvo(a + a', coef3) + c_ops1 = (a, a') + c_ops2 = (a, QobjEvo(a', coef1)) @inferred liouvillian(H_td, c_ops1) - # @inferred liouvillian(H_td, c_ops2) + @inferred liouvillian(H_td, c_ops2) @inferred liouvillian(H_td2, c_ops1) - # @inferred liouvillian(H_td2, c_ops2) + @inferred liouvillian(H_td2, c_ops2) end end end From a17ce34a3453918c70a36982a0312e34c40a946d Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 9 Sep 2025 13:45:52 +0200 Subject: [PATCH 4/6] Fix dissipator init error --- src/qobj/superoperators.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index 7e717e1ca..4364df10a 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -178,4 +178,4 @@ liouvillian(H::AbstractQuantumObject{Operator}, Id_cache::Diagonal = I(prod(H.di liouvillian(H::AbstractQuantumObject{SuperOperator}, Id_cache::Diagonal) = H -_sum_lindblad_dissipators(c_ops, Id_cache::Diagonal) = sum(op -> lindblad_dissipator(op, Id_cache), c_ops) +_sum_lindblad_dissipators(c_ops, Id_cache::Diagonal) = sum(op -> lindblad_dissipator(op, Id_cache), c_ops; init = 0) From d8711a0f39366f13155452a325f2ca0c4cd0f5dd Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 15 Sep 2025 22:50:49 +0200 Subject: [PATCH 5/6] Fix errors --- src/qobj/superoperators.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index 4364df10a..33ddda5b4 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -43,6 +43,7 @@ end _liouvillian(H::MT, Id::AbstractMatrix) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}} = -1im * (_spre(H, Id) - _spost(H', Id)) _liouvillian(H::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_liouvillian(H.A, Id)) +_liouvillian(H::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(H.λ, _liouvillian(H.L, Id)) _liouvillian(H::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _liouvillian(op, Id), H.ops)) # intrinsic lindblad_dissipator From c035fc9ed44e4e469327f47df00854baebf75f77 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 16 Sep 2025 00:29:19 +0200 Subject: [PATCH 6/6] Fix wrong adjoint for ScaledOperator --- src/qobj/superoperators.jl | 3 ++- test/core-test/quantum_objects_evo.jl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qobj/superoperators.jl b/src/qobj/superoperators.jl index 33ddda5b4..acf21a9cb 100644 --- a/src/qobj/superoperators.jl +++ b/src/qobj/superoperators.jl @@ -43,7 +43,8 @@ end _liouvillian(H::MT, Id::AbstractMatrix) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}} = -1im * (_spre(H, Id) - _spost(H', Id)) _liouvillian(H::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_liouvillian(H.A, Id)) -_liouvillian(H::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(H.λ, _liouvillian(H.L, Id)) +_liouvillian(H::ScaledOperator, Id::AbstractMatrix) = + -1im * (ScaledOperator(H.λ, _spre(H.L, Id)) - ScaledOperator(conj(H.λ), _spost(H.L', Id))) _liouvillian(H::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _liouvillian(op, Id), H.ops)) # intrinsic lindblad_dissipator diff --git a/test/core-test/quantum_objects_evo.jl b/test/core-test/quantum_objects_evo.jl index c4d797244..9e8479449 100644 --- a/test/core-test/quantum_objects_evo.jl +++ b/test/core-test/quantum_objects_evo.jl @@ -207,7 +207,7 @@ X = a * a' c_op1 = QobjEvo(a', coef1) c_op2 = QobjEvo(((a, coef2), (X, coef3))) - c_ops = [c_op1, c_op2] + c_ops = (c_op1, c_op2) D1_ti = abs2(coef1(p, t)) * lindblad_dissipator(a') D2_ti = abs2(coef2(p, t)) * lindblad_dissipator(a) + # normal dissipator for first element in c_op2