Skip to content

Commit d48371c

Browse files
Align eigenstates and eigenenergies to QuTiP (#411)
1 parent 9e3ddf3 commit d48371c

File tree

5 files changed

+39
-27
lines changed

5 files changed

+39
-27
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased](https://github.com/qutip/QuantumToolbox.jl/tree/main)
99

1010
- Support for single `AbstractQuantumObject` in `sc_ops` for faster specific method in `ssesolve` and `smesolve`. ([#408])
11+
- Align `eigenstates` and `eigenenergies` to QuTiP. ([#411])
1112

1213
## [v0.27.0]
1314
Release date: 2025-02-14
@@ -143,3 +144,4 @@ Release date: 2024-11-13
143144
[#404]: https://github.com/qutip/QuantumToolbox.jl/issues/404
144145
[#405]: https://github.com/qutip/QuantumToolbox.jl/issues/405
145146
[#408]: https://github.com/qutip/QuantumToolbox.jl/issues/408
147+
[#411]: https://github.com/qutip/QuantumToolbox.jl/issues/411

benchmarks/eigenvalues.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ function benchmark_eigenvalues!(SUITE)
1616
L = liouvillian(H, c_ops)
1717

1818
SUITE["Eigenvalues"]["eigenstates"]["dense"] = @benchmarkable eigenstates($L)
19-
SUITE["Eigenvalues"]["eigenstates"]["sparse"] = @benchmarkable eigenstates($L, sparse = true, sigma = 0.01, k = 5)
19+
SUITE["Eigenvalues"]["eigenstates"]["sparse"] =
20+
@benchmarkable eigenstates($L, sparse = true, sigma = 0.01, eigvals = 5)
2021

2122
return nothing
2223
end

src/qobj/eigsolve.jl

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ end
257257
eigsolve(A::QuantumObject;
258258
v0::Union{Nothing,AbstractVector}=nothing,
259259
sigma::Union{Nothing, Real}=nothing,
260-
k::Int = 1,
260+
eigvals::Int = 1,
261261
krylovdim::Int = max(20, 2*k+1),
262262
tol::Real = 1e-8,
263263
maxiter::Int = 200,
@@ -266,6 +266,17 @@ end
266266
267267
Solve for the eigenvalues and eigenvectors of a matrix `A` using the Arnoldi method.
268268
269+
# Arguments
270+
- `A::QuantumObject`: the [`QuantumObject`](@ref) to solve eigenvalues and eigenvectors.
271+
- `v0::Union{Nothing,AbstractVector}`: the initial vector for the Arnoldi method. Default is a random vector.
272+
- `sigma::Union{Nothing, Real}`: the shift for the eigenvalue problem. Default is `nothing`.
273+
- `eigvals::Int`: the number of eigenvalues to compute. Default is `1`.
274+
- `krylovdim::Int`: the dimension of the Krylov subspace. Default is `max(20, 2*k+1)`.
275+
- `tol::Real`: the tolerance for the Arnoldi method. Default is `1e-8`.
276+
- `maxiter::Int`: the maximum number of iterations for the Arnoldi method. Default is `200`.
277+
- `solver::Union{Nothing, SciMLLinearSolveAlgorithm}`: the linear solver algorithm. Default is `nothing`.
278+
- `kwargs`: Additional keyword arguments passed to the solver.
279+
269280
# Notes
270281
- For more details about `solver` and extra `kwargs`, please refer to [`LinearSolve.jl`](https://docs.sciml.ai/LinearSolve/stable/)
271282
@@ -276,8 +287,8 @@ function eigsolve(
276287
A::QuantumObject;
277288
v0::Union{Nothing,AbstractVector} = nothing,
278289
sigma::Union{Nothing,Real} = nothing,
279-
k::Int = 1,
280-
krylovdim::Int = max(20, 2 * k + 1),
290+
eigvals::Int = 1,
291+
krylovdim::Int = max(20, 2 * eigvals + 1),
281292
tol::Real = 1e-8,
282293
maxiter::Int = 200,
283294
solver::Union{Nothing,SciMLLinearSolveAlgorithm} = nothing,
@@ -289,7 +300,7 @@ function eigsolve(
289300
type = A.type,
290301
dimensions = A.dimensions,
291302
sigma = sigma,
292-
k = k,
303+
eigvals = eigvals,
293304
krylovdim = krylovdim,
294305
tol = tol,
295306
maxiter = maxiter,
@@ -304,8 +315,8 @@ function eigsolve(
304315
type::Union{Nothing,OperatorQuantumObject,SuperOperatorQuantumObject} = nothing,
305316
dimensions = nothing,
306317
sigma::Union{Nothing,Real} = nothing,
307-
k::Int = 1,
308-
krylovdim::Int = max(20, 2 * k + 1),
318+
eigvals::Int = 1,
319+
krylovdim::Int = max(20, 2 * eigvals + 1),
309320
tol::Real = 1e-8,
310321
maxiter::Int = 200,
311322
solver::Union{Nothing,SciMLLinearSolveAlgorithm} = nothing,
@@ -316,7 +327,7 @@ function eigsolve(
316327
v0 === nothing && (v0 = normalize!(rand(T, size(A, 1))))
317328

318329
if sigma === nothing
319-
res = _eigsolve(A, v0, type, dimensions, k, krylovdim, tol = tol, maxiter = maxiter)
330+
res = _eigsolve(A, v0, type, dimensions, eigvals, krylovdim, tol = tol, maxiter = maxiter)
320331
vals = res.values
321332
else
322333
Aₛ = A - sigma * I
@@ -334,7 +345,7 @@ function eigsolve(
334345

335346
Amap = EigsolveInverseMap(T, size(A), linsolve)
336347

337-
res = _eigsolve(Amap, v0, type, dimensions, k, krylovdim, tol = tol, maxiter = maxiter)
348+
res = _eigsolve(Amap, v0, type, dimensions, eigvals, krylovdim, tol = tol, maxiter = maxiter)
338349
vals = @. (1 + sigma * res.values) / res.values
339350
end
340351

@@ -349,7 +360,7 @@ end
349360
alg::OrdinaryDiffEqAlgorithm = Tsit5(),
350361
params::NamedTuple = NamedTuple(),
351362
ρ0::AbstractMatrix = rand_dm(prod(H.dimensions)).data,
352-
k::Int = 1,
363+
eigvals::Int = 1,
353364
krylovdim::Int = min(10, size(H, 1)),
354365
maxiter::Int = 200,
355366
eigstol::Real = 1e-6,
@@ -365,7 +376,7 @@ Solve the eigenvalue problem for a Liouvillian superoperator `L` using the Arnol
365376
- `alg`: The differential equation solver algorithm. Default is `Tsit5()`.
366377
- `params`: A `NamedTuple` containing the parameters of the system.
367378
- `ρ0`: The initial density matrix. If not specified, a random density matrix is used.
368-
- `k`: The number of eigenvalues to compute.
379+
- `eigvals`: The number of eigenvalues to compute.
369380
- `krylovdim`: The dimension of the Krylov subspace.
370381
- `maxiter`: The maximum number of iterations for the eigsolver.
371382
- `eigstol`: The tolerance for the eigsolver.
@@ -388,7 +399,7 @@ function eigsolve_al(
388399
alg::OrdinaryDiffEqAlgorithm = Tsit5(),
389400
params::NamedTuple = NamedTuple(),
390401
ρ0::AbstractMatrix = rand_dm(prod(H.dimensions)).data,
391-
k::Int = 1,
402+
eigvals::Int = 1,
392403
krylovdim::Int = min(10, size(H, 1)),
393404
maxiter::Int = 200,
394405
eigstol::Real = 1e-6,
@@ -406,12 +417,10 @@ function eigsolve_al(
406417
).prob
407418
integrator = init(prob, alg)
408419

409-
# prog = ProgressUnknown(desc="Applications:", showspeed = true, enabled=progress)
410-
411420
Lmap = ArnoldiLindbladIntegratorMap(eltype(H), size(L_evo), integrator)
412421

413-
res = _eigsolve(Lmap, mat2vec(ρ0), L_evo.type, L_evo.dimensions, k, krylovdim, maxiter = maxiter, tol = eigstol)
414-
# finish!(prog)
422+
res =
423+
_eigsolve(Lmap, mat2vec(ρ0), L_evo.type, L_evo.dimensions, eigvals, krylovdim, maxiter = maxiter, tol = eigstol)
415424

416425
vals = similar(res.values)
417426
vecs = similar(res.vectors)
@@ -488,7 +497,7 @@ Calculate the eigenenergies
488497
# Arguments
489498
- `A::QuantumObject`: the [`QuantumObject`](@ref) to solve eigenvalues
490499
- `sparse::Bool`: if `false` call [`eigvals(A::QuantumObject; kwargs...)`](@ref), otherwise call [`eigsolve`](@ref). Default to `false`.
491-
- `kwargs`: Additional keyword arguments passed to the solver
500+
- `kwargs`: Additional keyword arguments passed to the solver. If `sparse=true`, the keyword arguments are passed to [`eigsolve`](@ref), otherwise to [`eigen`](@ref).
492501
493502
# Returns
494503
- `::Vector{<:Number}`: a list of eigenvalues
@@ -513,7 +522,7 @@ Calculate the eigenvalues and corresponding eigenvectors
513522
# Arguments
514523
- `A::QuantumObject`: the [`QuantumObject`](@ref) to solve eigenvalues and eigenvectors
515524
- `sparse::Bool`: if `false` call [`eigen(A::QuantumObject; kwargs...)`](@ref), otherwise call [`eigsolve`](@ref). Default to `false`.
516-
- `kwargs`: Additional keyword arguments passed to the solver
525+
- `kwargs`: Additional keyword arguments passed to the solver. If `sparse=true`, the keyword arguments are passed to [`eigsolve`](@ref), otherwise to [`eigen`](@ref).
517526
518527
# Returns
519528
- `::EigsolveResult`: containing the eigenvalues, the eigenvectors, and some information from the solver. see also [`EigsolveResult`](@ref)

src/steadystate.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ end
141141
function _steadystate(L::QuantumObject{SuperOperatorQuantumObject}, solver::SteadyStateEigenSolver; kwargs...)
142142
N = prod(L.dimensions)
143143

144-
kwargs = merge((sigma = 1e-8, k = 1), (; kwargs...))
144+
kwargs = merge((sigma = 1e-8, eigvals = 1), (; kwargs...))
145145

146146
ρss_vec = eigsolve(L; kwargs...).vectors[:, 1]
147147
ρss = reshape(ρss_vec, N, N)

test/core-test/eigenvalues_and_operators.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
resstring = sprint((t, s) -> show(t, "text/plain", s), result)
66
valstring = sprint((t, s) -> show(t, "text/plain", s), result.values)
77
vecsstring = sprint((t, s) -> show(t, "text/plain", s), result.vectors)
8-
λs, ψs, Ts = eigenstates(σx, sparse = true, k = 2)
9-
λs1, ψs1, Ts1 = eigenstates(σx, sparse = true, k = 1)
8+
λs, ψs, Ts = eigenstates(σx, sparse = true, eigvals = 2)
9+
λs1, ψs1, Ts1 = eigenstates(σx, sparse = true, eigvals = 1)
1010

1111
@test all([ψ.type isa KetQuantumObject for ψ in ψd])
1212
@test typeof(Td) <: AbstractMatrix
1313
@test typeof(Ts) <: AbstractMatrix
1414
@test typeof(Ts1) <: AbstractMatrix
1515
@test all(abs.(eigenenergies(σx, sparse = false)) .≈ abs.(λd))
16-
@test all(abs.(eigenenergies(σx, sparse = true, k = 2)) .≈ abs.(λs))
16+
@test all(abs.(eigenenergies(σx, sparse = true, eigvals = 2)) .≈ abs.(λs))
1717
@test resstring ==
1818
"EigsolveResult: type=$(Operator) dims=$(result.dims)\nvalues:\n$(valstring)\nvectors:\n$vecsstring"
1919

@@ -33,7 +33,7 @@
3333

3434
vals_d, vecs_d, mat_d = eigenstates(H_d)
3535
vals_c, vecs_c, mat_c = eigenstates(H_c)
36-
vals2, vecs2, mat2 = eigenstates(H_d, sparse = true, sigma = -0.9, k = 10, krylovdim = 30)
36+
vals2, vecs2, mat2 = eigenstates(H_d, sparse = true, sigma = -0.9, eigvals = 10, krylovdim = 30)
3737
sort!(vals_c, by = real)
3838
sort!(vals2, by = real)
3939

@@ -57,9 +57,9 @@
5757
L = liouvillian(H, c_ops)
5858

5959
# eigen solve for general matrices
60-
vals, _, vecs = eigsolve(L.data, sigma = 0.01, k = 10, krylovdim = 50)
60+
vals, _, vecs = eigsolve(L.data, sigma = 0.01, eigvals = 10, krylovdim = 50)
6161
vals2, vecs2 = eigen(to_dense(L.data))
62-
vals3, state3, vecs3 = eigsolve_al(L, 1 \ (40 * κ), k = 10, krylovdim = 50)
62+
vals3, state3, vecs3 = eigsolve_al(L, 1 \ (40 * κ), eigvals = 10, krylovdim = 50)
6363
idxs = sortperm(vals2, by = abs)
6464
vals2 = vals2[idxs][1:10]
6565
vecs2 = vecs2[:, idxs][:, 1:10]
@@ -70,7 +70,7 @@
7070
@test isapprox(vec2mat(vecs[:, 1]) * exp(-1im * angle(vecs[1, 1])), vec2mat(vecs3[:, 1]), atol = 1e-5)
7171

7272
# eigen solve for QuantumObject
73-
result = eigenstates(L, sparse = true, sigma = 0.01, k = 10, krylovdim = 50)
73+
result = eigenstates(L, sparse = true, sigma = 0.01, eigvals = 10, krylovdim = 50)
7474
vals, vecs = result
7575
resstring = sprint((t, s) -> show(t, "text/plain", s), result)
7676
valstring = sprint((t, s) -> show(t, "text/plain", s), result.values)
@@ -112,6 +112,6 @@
112112
@inferred eigenstates(H, sparse = false)
113113
@inferred eigenstates(H, sparse = true)
114114
@inferred eigenstates(L, sparse = true)
115-
@inferred eigsolve_al(L, 1 \ (40 * κ), k = 10)
115+
@inferred eigsolve_al(L, 1 \ (40 * κ), eigvals = 10)
116116
end
117117
end

0 commit comments

Comments
 (0)