Skip to content

Commit 8f3ea3b

Browse files
Use FillArrays.jl for handling superoperators (#589)
1 parent 720304d commit 8f3ea3b

File tree

12 files changed

+106
-86
lines changed

12 files changed

+106
-86
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
- Change default solver detection in `eigensolve` when using `sigma` keyword argument (shift-inverse algorithm). If the operator is a `SparseMatrixCSC`, the default solver is `UMFPACKFactorization`, otherwise it is automatically chosen by LinearSolve.jl, depending on the type of the operator. ([#580])
1111
- Add keyword argument `assume_hermitian` to `liouvillian`. This allows users to disable the assumption that the Hamiltonian is Hermitian. ([#581])
1212
- Use LinearSolve's internal methods for preconditioners in `SteadyStateLinearSolver`. ([#588])
13+
- Use `FillArrays.jl` for handling superoperators. This makes the code cleaner and potentially more efficient. ([#589])
1314

1415
## [v0.38.1]
1516
Release date: 2025-10-27
@@ -364,3 +365,4 @@ Release date: 2024-11-13
364365
[#580]: https://github.com/qutip/QuantumToolbox.jl/issues/580
365366
[#581]: https://github.com/qutip/QuantumToolbox.jl/issues/581
366367
[#588]: https://github.com/qutip/QuantumToolbox.jl/issues/588
368+
[#589]: https://github.com/qutip/QuantumToolbox.jl/issues/589

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"
1010
DiffEqNoiseProcess = "77a26b50-5914-5dd7-bc55-306e6241c503"
1111
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1212
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
13+
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
1314
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1415
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
1516
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
@@ -50,6 +51,7 @@ DiffEqCallbacks = "4.2.1 - 4"
5051
DiffEqNoiseProcess = "5"
5152
Distributed = "1"
5253
FFTW = "1.5"
54+
FillArrays = "1"
5355
GPUArrays = "10, 11"
5456
Graphs = "1.7"
5557
IncompleteLU = "0.2"

src/QuantumToolbox.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import DiffEqNoiseProcess: RealWienerProcess!, RealWienerProcess
5959
import ArrayInterface: allowed_getindex, allowed_setindex!
6060
import Distributed: RemoteChannel
6161
import FFTW: fft, ifft, fftfreq, fftshift
62+
import FillArrays: Eye
6263
import Graphs: connected_components, DiGraph
6364
import IncompleteLU: ilu
6465
import LaTeXStrings: @L_str

src/deprecated.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,44 @@ function ProgressBar(args...; kwargs...)
138138
"`ProgressBar` is deprecated and will be removed in next major release. Use `Progress` from `ProgressMeter.jl` instead.",
139139
)
140140
end
141+
142+
function spre(A::AbstractQuantumObject{Operator}, Id_cache)
143+
Base.depwarn(
144+
"The argument `Id_cache` for `spre` is now deprecated, as we now internally use FillArrays.jl, which preserves the same efficiency without requiring this parameter.",
145+
:spre,
146+
force = true,
147+
)
148+
return spre(A)
149+
end
150+
151+
function spost(A::AbstractQuantumObject{Operator}, Id_cache)
152+
Base.depwarn(
153+
"The argument `Id_cache` for `spost` is now deprecated, as we now internally use FillArrays.jl, which preserves the same efficiency without requiring this parameter.",
154+
:spost,
155+
force = true,
156+
)
157+
return spost(A)
158+
end
159+
160+
function lindblad_dissipator(C::QuantumObject{Operator}, Id_cache)
161+
Base.depwarn(
162+
"The argument `Id_cache` for `lindblad_dissipator` is now deprecated, as we now internally use FillArrays.jl, which preserves the same efficiency without requiring this parameter.",
163+
:lindblad_dissipator,
164+
force = true,
165+
)
166+
return lindblad_dissipator(C)
167+
end
168+
169+
function liouvillian(
170+
H::QuantumObject{HOpType},
171+
c_ops::AbstractVector,
172+
Id_cache;
173+
kwargs...,
174+
) where {HOpType<:Union{Operator,SuperOperator}}
175+
Base.depwarn(
176+
"The argument `Id_cache` for `liouvillian` is now deprecated, as we now internally use FillArrays.jl, which preserves the same efficiency without requiring this parameter.",
177+
:liouvillian,
178+
force = true,
179+
)
180+
return liouvillian(H, c_ops; kwargs...)
181+
end

src/qobj/boolean_functions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Test whether the [`QuantumObject`](@ref) ``U`` is unitary operator. This functio
8585
8686
Note that all the keyword arguments will be passed to `Base.isapprox`.
8787
"""
88-
isunitary(U::QuantumObject; kwargs...) = isoper(U) ? isapprox(U.data * U.data', I(size(U, 1)); kwargs...) : false
88+
isunitary(U::QuantumObject; kwargs...) = isoper(U) ? isapprox(U.data * U.data', Eye(size(U, 1)); kwargs...) : false
8989

9090
@doc raw"""
9191
SciMLOperators.iscached(A::AbstractQuantumObject)

src/qobj/states.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,10 @@ The `dimensions` can be either the following types:
149149
If you want to keep type stability, it is recommended to use `maximally_mixed_dm(dimensions)` with `dimensions` as `Tuple` or `SVector` from [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl) to keep type stability. See the [related Section](@ref doc:Type-Stability) about type stability for more details.
150150
"""
151151
maximally_mixed_dm(dimensions::Int) =
152-
QuantumObject(I(dimensions) / complex(dimensions), Operator(), SVector(dimensions))
152+
QuantumObject(Eye(dimensions) / complex(dimensions), Operator(), SVector(dimensions))
153153
function maximally_mixed_dm(dimensions::Union{Dimensions,AbstractVector{Int},Tuple})
154154
N = prod(dimensions)
155-
return QuantumObject(I(N) / complex(N), Operator(), dimensions)
155+
return QuantumObject(Eye(N) / complex(N), Operator(), dimensions)
156156
end
157157

158158
@doc raw"""

src/qobj/superoperators.jl

Lines changed: 49 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,76 +6,73 @@ export spre, spost, sprepost, liouvillian, lindblad_dissipator
66

77
# intrinsic functions for super-operators
88
## keep these because they take AbstractMatrix as input and ensure the output is sparse matrix
9-
_spre(A::AbstractMatrix, Id::AbstractMatrix) = kron(Id, sparse(A))
10-
_spre(A::AbstractSparseMatrix, Id::AbstractMatrix) = kron(Id, A)
11-
_spost(B::AbstractMatrix, Id::AbstractMatrix) = kron(transpose(sparse(B)), Id)
12-
_spost(B::AbstractSparseMatrix, Id::AbstractMatrix) = kron(transpose(B), Id)
9+
_spre(A::AbstractMatrix) = kron(Eye(size(A, 1)), sparse(A))
10+
_spre(A::AbstractSparseMatrix) = kron(Eye(size(A, 1)), A)
11+
_spost(B::AbstractMatrix) = kron(transpose(sparse(B)), Eye(size(B, 1)))
12+
_spost(B::AbstractSparseMatrix) = kron(transpose(B), Eye(size(B, 1)))
1313
_sprepost(A::AbstractMatrix, B::AbstractMatrix) = kron(transpose(sparse(B)), sparse(A))
1414
_sprepost(A::AbstractMatrix, B::AbstractSparseMatrix) = kron(transpose(B), sparse(A))
1515
_sprepost(A::AbstractSparseMatrix, B::AbstractMatrix) = kron(transpose(sparse(B)), A)
1616
_sprepost(A::AbstractSparseMatrix, B::AbstractSparseMatrix) = kron(transpose(B), A)
17-
function _sprepost(A, B) # for any other input types
18-
Id_cache = I(size(A, 1))
19-
return _spre(A, Id_cache) * _spost(B, Id_cache)
20-
end
17+
_sprepost(A, B) = _spre(A) * _spost(B) # for any other input types
2118

2219
## if input is AbstractSciMLOperator
2320
## some of them are optimized to speed things up
2421
## the rest of the SciMLOperators will just use lazy tensor (and prompt a warning)
25-
_spre(A::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_spre(A.A, Id))
26-
_spre(A::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(A.λ, _spre(A.L, Id))
27-
_spre(A::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _spre(op, Id), A.ops))
28-
function _spre(A::AbstractSciMLOperator, Id::AbstractMatrix)
22+
_spre(A::MatrixOperator) = MatrixOperator(_spre(A.A))
23+
_spre(A::ScaledOperator) = ScaledOperator(A.λ, _spre(A.L))
24+
_spre(A::AddedOperator) = AddedOperator(map(op -> _spre(op), A.ops))
25+
function _spre(A::AbstractSciMLOperator)
26+
Id = Eye(size(A, 1))
2927
_lazy_tensor_warning(Id, A)
3028
return kron(Id, A)
3129
end
3230

33-
_spost(B::MatrixOperator, Id::AbstractMatrix) = MatrixOperator(_spost(B.A, Id))
34-
_spost(B::ScaledOperator, Id::AbstractMatrix) = ScaledOperator(B.λ, _spost(B.L, Id))
35-
_spost(B::AddedOperator, Id::AbstractMatrix) = AddedOperator(map(op -> _spost(op, Id), B.ops))
36-
function _spost(B::AbstractSciMLOperator, Id::AbstractMatrix)
31+
_spost(B::MatrixOperator) = MatrixOperator(_spost(B.A))
32+
_spost(B::ScaledOperator) = ScaledOperator(B.λ, _spost(B.L))
33+
_spost(B::AddedOperator) = AddedOperator(map(op -> _spost(op), B.ops))
34+
function _spost(B::AbstractSciMLOperator)
3735
B_T = transpose(B)
36+
Id = Eye(size(B, 1))
3837
_lazy_tensor_warning(B_T, Id)
3938
return kron(B_T, Id)
4039
end
4140

4241
## intrinsic liouvillian
4342
function _liouvillian(
4443
H::MT,
45-
Id::AbstractMatrix,
4644
::Val{assume_hermitian},
4745
) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator},assume_hermitian}
48-
H_spre = _spre(H, Id)
49-
H_spost = assume_hermitian ? _spost(H, Id) : _spost(H', Id)
46+
H_spre = _spre(H)
47+
H_spost = assume_hermitian ? _spost(H) : _spost(H')
5048
return -1im * (H_spre - H_spost)
5149
end
52-
function _liouvillian(H::MatrixOperator, Id::AbstractMatrix, assume_hermitian::Val)
50+
function _liouvillian(H::MatrixOperator, assume_hermitian::Val)
5351
isconstant(H) ||
5452
throw(ArgumentError("The given Hamiltonian for constructing Liouvillian must be constant MatrixOperator."))
55-
return MatrixOperator(_liouvillian(H.A, Id, assume_hermitian))
53+
return MatrixOperator(_liouvillian(H.A, assume_hermitian))
5654
end
57-
_liouvillian(H::ScaledOperator, Id::AbstractMatrix, assume_hermitian::Val{true}) =
58-
ScaledOperator(H.λ, _liouvillian(H.L, Id, assume_hermitian))
59-
_liouvillian(H::AddedOperator, Id::AbstractMatrix, assume_hermitian::Val) =
60-
AddedOperator(map(op -> _liouvillian(op, Id, assume_hermitian), H.ops))
55+
_liouvillian(H::ScaledOperator, assume_hermitian::Val{true}) = ScaledOperator(H.λ, _liouvillian(H.L, assume_hermitian))
56+
_liouvillian(H::AddedOperator, assume_hermitian::Val) =
57+
AddedOperator(map(op -> _liouvillian(op, assume_hermitian), H.ops))
6158

6259
# intrinsic lindblad_dissipator
63-
function _lindblad_dissipator(O::MT, Id::AbstractMatrix) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}}
60+
function _lindblad_dissipator(O::MT) where {MT<:Union{AbstractMatrix,AbstractSciMLOperator}}
6461
Od_O = O' * O
65-
return _sprepost(O, O') - (_spre(Od_O, Id) + _spost(Od_O, Id)) / 2
62+
return _sprepost(O, O') - (_spre(Od_O) + _spost(Od_O)) / 2
6663
end
67-
function _lindblad_dissipator(O::MatrixOperator, Id::AbstractMatrix)
64+
function _lindblad_dissipator(O::MatrixOperator)
6865
_O = O.A
6966
Od_O = _O' * _O
70-
return MatrixOperator(_sprepost(_O, _O') - (_spre(Od_O, Id) + _spost(Od_O, Id)) / 2)
67+
return MatrixOperator(_sprepost(_O, _O') - (_spre(Od_O) + _spost(Od_O)) / 2)
7168
end
72-
function _lindblad_dissipator(O::ScaledOperator, Id::AbstractMatrix)
69+
function _lindblad_dissipator(O::ScaledOperator)
7370
λc_λ = conj(O.λ) * O.λ
74-
return ScaledOperator(λc_λ, _lindblad_dissipator(O.L, Id))
71+
return ScaledOperator(λc_λ, _lindblad_dissipator(O.L))
7572
end
7673

7774
@doc raw"""
78-
spre(A::AbstractQuantumObject, Id_cache=I(size(A,1)))
75+
spre(A::AbstractQuantumObject)
7976
8077
Returns the [`SuperOperator`](@ref) form of `A` acting on the left of the density matrix operator: ``\mathcal{O} \left(\hat{A}\right) \left[ \hat{\rho} \right] = \hat{A} \hat{\rho}``.
8178
@@ -86,15 +83,12 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r
8683
```
8784
(see the section in documentation: [Superoperators and Vectorized Operators](@ref doc:Superoperators-and-Vectorized-Operators) for more details)
8885
89-
The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension.
90-
9186
See also [`spost`](@ref) and [`sprepost`](@ref).
9287
"""
93-
spre(A::AbstractQuantumObject{Operator}, Id_cache = I(size(A, 1))) =
94-
get_typename_wrapper(A)(_spre(A.data, Id_cache), SuperOperator(), A.dimensions)
88+
spre(A::AbstractQuantumObject{Operator}) = get_typename_wrapper(A)(_spre(A.data), SuperOperator(), A.dimensions)
9589

9690
@doc raw"""
97-
spost(B::AbstractQuantumObject, Id_cache=I(size(B,1)))
91+
spost(B::AbstractQuantumObject)
9892
9993
Returns the [`SuperOperator`](@ref) form of `B` acting on the right of the density matrix operator: ``\mathcal{O} \left(\hat{B}\right) \left[ \hat{\rho} \right] = \hat{\rho} \hat{B}``.
10094
@@ -105,12 +99,9 @@ Since the density matrix is vectorized in [`OperatorKet`](@ref) form: ``|\hat{\r
10599
```
106100
(see the section in documentation: [Superoperators and Vectorized Operators](@ref doc:Superoperators-and-Vectorized-Operators) for more details)
107101
108-
The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension.
109-
110102
See also [`spre`](@ref) and [`sprepost`](@ref).
111103
"""
112-
spost(B::AbstractQuantumObject{Operator}, Id_cache = I(size(B, 1))) =
113-
get_typename_wrapper(B)(_spost(B.data, Id_cache), SuperOperator(), B.dimensions)
104+
spost(B::AbstractQuantumObject{Operator}) = get_typename_wrapper(B)(_spost(B.data), SuperOperator(), B.dimensions)
114105

115106
@doc raw"""
116107
sprepost(A::AbstractQuantumObject, B::AbstractQuantumObject)
@@ -132,7 +123,7 @@ function sprepost(A::AbstractQuantumObject{Operator}, B::AbstractQuantumObject{O
132123
end
133124

134125
@doc raw"""
135-
lindblad_dissipator(O::AbstractQuantumObject, Id_cache=I(size(O,1))
126+
lindblad_dissipator(O::AbstractQuantumObject)
136127
137128
Returns the Lindblad [`SuperOperator`](@ref) defined as
138129
@@ -141,21 +132,18 @@ Returns the Lindblad [`SuperOperator`](@ref) defined as
141132
\hat{O}^\dagger \hat{O} \hat{\rho} - \hat{\rho} \hat{O}^\dagger \hat{O} \right)
142133
```
143134
144-
The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension.
145-
146135
See also [`spre`](@ref), [`spost`](@ref), and [`sprepost`](@ref).
147136
"""
148-
lindblad_dissipator(O::AbstractQuantumObject{Operator}, Id_cache = I(size(O, 1))) =
149-
get_typename_wrapper(O)(_lindblad_dissipator(O.data, Id_cache), SuperOperator(), O.dimensions)
137+
lindblad_dissipator(O::AbstractQuantumObject{Operator}) =
138+
get_typename_wrapper(O)(_lindblad_dissipator(O.data), SuperOperator(), O.dimensions)
150139

151140
# It is already a SuperOperator
152-
lindblad_dissipator(O::AbstractQuantumObject{SuperOperator}, Id_cache = nothing) = O
141+
lindblad_dissipator(O::AbstractQuantumObject{SuperOperator}) = O
153142

154143
@doc raw"""
155144
liouvillian(
156145
H::AbstractQuantumObject,
157-
c_ops::Union{Nothing,AbstractVector,Tuple}=nothing,
158-
Id_cache=I(prod(H.dimensions));
146+
c_ops::Union{Nothing,AbstractVector,Tuple}=nothing;
159147
assume_hermitian::Union{Bool,Val} = Val(true),
160148
)
161149
@@ -179,54 +167,44 @@ where
179167
\mathcal{D}(\hat{C}_n) [\cdot] = \hat{C}_n [\cdot] \hat{C}_n^\dagger - \frac{1}{2} \hat{C}_n^\dagger \hat{C}_n [\cdot] - \frac{1}{2} [\cdot] \hat{C}_n^\dagger \hat{C}_n
180168
```
181169
182-
The optional argument `Id_cache` can be used to pass a precomputed identity matrix. This can be useful when the same function is applied multiple times with a known Hilbert space dimension.
183-
184170
See also [`spre`](@ref), [`spost`](@ref), and [`lindblad_dissipator`](@ref).
185171
186172
!!! warning "Beware of type-stability!"
187173
If you want to keep type stability, it is recommended to use `assume_hermitian = Val(true)` instead of `assume_hermitian = true`. See [this link](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and the [related Section](@ref doc:Type-Stability) about type stability for more details.
188174
"""
189175
function liouvillian(
190176
H::AbstractQuantumObject{OpType},
191-
c_ops::Union{Nothing,AbstractVector,Tuple} = nothing,
192-
Id_cache::Diagonal = I(prod(H.dimensions));
177+
c_ops::Union{Nothing,AbstractVector,Tuple} = nothing;
193178
assume_hermitian::Union{Bool,Val} = Val(true),
194179
) where {OpType<:Union{Operator,SuperOperator}}
195-
L = liouvillian(H, Id_cache; assume_hermitian = assume_hermitian)
180+
L = liouvillian(H; assume_hermitian = assume_hermitian)
196181
if !isnothing(c_ops)
197-
return L + _sum_lindblad_dissipators(c_ops, Id_cache)
182+
return L + _sum_lindblad_dissipators(c_ops)
198183
end
199184
return L
200185
end
201186

202-
liouvillian(H::Nothing, c_ops::Union{AbstractVector,Tuple}, Id_cache::Diagonal = I(prod(c_ops[1].dims)); kwargs...) =
203-
_sum_lindblad_dissipators(c_ops, Id_cache)
187+
liouvillian(H::Nothing, c_ops::Union{AbstractVector,Tuple}; kwargs...) = _sum_lindblad_dissipators(c_ops)
204188

205189
liouvillian(H::Nothing, c_ops::Nothing; kwargs...) = 0
206190

207-
liouvillian(
208-
H::AbstractQuantumObject{Operator},
209-
Id_cache::Diagonal = I(prod(H.dimensions));
210-
assume_hermitian::Union{Bool,Val} = Val(true),
211-
) = get_typename_wrapper(H)(_liouvillian(H.data, Id_cache, makeVal(assume_hermitian)), SuperOperator(), H.dimensions)
212-
213-
liouvillian(H::AbstractQuantumObject{SuperOperator}, Id_cache::Diagonal; kwargs...) = H
191+
liouvillian(H::AbstractQuantumObject{Operator}; assume_hermitian::Union{Bool,Val} = Val(true)) =
192+
get_typename_wrapper(H)(_liouvillian(H.data, makeVal(assume_hermitian)), SuperOperator(), H.dimensions)
214193

215-
_sum_lindblad_dissipators(c_ops::Nothing, Id_cache::Diagonal) = 0
194+
liouvillian(H::AbstractQuantumObject{SuperOperator}; kwargs...) = H
195+
_sum_lindblad_dissipators(c_ops::Nothing) = 0
216196

217-
function _sum_lindblad_dissipators(c_ops::AbstractVector, Id_cache::Diagonal)
218-
return sum(op -> lindblad_dissipator(op, Id_cache), c_ops; init = 0)
219-
end
197+
_sum_lindblad_dissipators(c_ops::AbstractVector) = sum(op -> lindblad_dissipator(op), c_ops; init = 0)
220198

221199
# Help the compiler to unroll the sum at compile time
222-
@generated function _sum_lindblad_dissipators(c_ops::Tuple, Id_cache::Diagonal)
200+
@generated function _sum_lindblad_dissipators(c_ops::Tuple)
223201
N = length(c_ops.parameters)
224202
if N == 0
225203
return :(0)
226204
end
227-
ex = :(lindblad_dissipator(c_ops[1], Id_cache))
205+
ex = :(lindblad_dissipator(c_ops[1]))
228206
for i in 2:N
229-
ex = :($ex + lindblad_dissipator(c_ops[$i], Id_cache))
207+
ex = :($ex + lindblad_dissipator(c_ops[$i]))
230208
end
231209
return ex
232210
end

src/spectrum.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ function _spectrum(
140140
_tr = SparseVector(D^2, [1 + n * (D + 1) for n in 0:(D-1)], ones(_complex_float_type(L), D)) # same as vec(system_identity_matrix)
141141
_tr_A = transpose(_tr) * spre(A).data
142142

143-
Id = I(D^2)
143+
Id = Eye(D^2)
144144

145145
# DO the idx = 1 case
146146
ω = ωList[1]

src/spin_lattice.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ function multisite_operator(dims::Union{AbstractVector,Tuple}, pairs::Pair{<:Int
5353

5454
_dims[sites] == [get_dimensions_to(op)[1].size for op in ops] || throw(ArgumentError("The dimensions of the operators do not match the dimensions of the lattice."))
5555

56-
data = kron(I(prod(_dims[1:(sites[1]-1)])), ops[1].data)
56+
data = kron(Eye(prod(_dims[1:(sites[1]-1)])), ops[1].data)
5757
for i in 2:length(sites)
58-
data = kron(data, I(prod(_dims[(sites[i-1]+1):(sites[i]-1)])), ops[i].data)
58+
data = kron(data, Eye(prod(_dims[(sites[i-1]+1):(sites[i]-1)])), ops[i].data)
5959
end
60-
data = kron(data, I(prod(_dims[(sites[end]+1):end])))
60+
data = kron(data, Eye(prod(_dims[(sites[end]+1):end])))
6161

6262
return QuantumObject(data; type = Operator(), dims = dims)
6363
end

src/time_evolution/brmesolve.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ function _brterm(
126126
_check_br_spectra(spectra)
127127

128128
U = rst.vectors
129-
Id = I(prod(rst.dimensions))
130129

131130
skew = @. rst.values - rst.values' |> real
132131
spectrum = spectra.(skew)
@@ -166,7 +165,7 @@ function _brterm(
166165
tidyup!(bd_term)
167166
end
168167

169-
out = (_sprepost(A_mat_spec_t, A_mat) + _sprepost(A_mat, A_mat_spec) - _spost(ac_term, Id) - _spre(bd_term, Id)) / 2
168+
out = (_sprepost(A_mat_spec_t, A_mat) + _sprepost(A_mat, A_mat_spec) - _spost(ac_term) - _spre(bd_term)) / 2
170169

171170
(sec_cutoff != -1) && (out .*= M_cut)
172171

0 commit comments

Comments
 (0)