Skip to content

Commit 2fdcc04

Browse files
committed
introduce groundstate
1 parent 300fd5d commit 2fdcc04

File tree

5 files changed

+62
-5
lines changed

5 files changed

+62
-5
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
- Support for single `AbstractQuantumObject` in `sc_ops` for faster specific method in `ssesolve` and `smesolve`. ([#408])
1111
- Change save callbacks from `PresetTimeCallback` to `FunctionCallingCallback`. ([#410])
1212
- Align `eigenstates` and `eigenenergies` to QuTiP. ([#411])
13+
- Introduce `groundstate`. ([#412])
1314

1415
## [v0.27.0]
1516
Release date: 2025-02-14
@@ -147,3 +148,4 @@ Release date: 2024-11-13
147148
[#408]: https://github.com/qutip/QuantumToolbox.jl/issues/408
148149
[#410]: https://github.com/qutip/QuantumToolbox.jl/issues/410
149150
[#411]: https://github.com/qutip/QuantumToolbox.jl/issues/411
151+
[#412]: https://github.com/qutip/QuantumToolbox.jl/issues/412

docs/src/resources/api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ partial_transpose
9090
EigsolveResult
9191
eigenenergies
9292
eigenstates
93+
groundstate
9394
LinearAlgebra.eigen
9495
LinearAlgebra.eigvals
9596
eigsolve

docs/src/users_guide/QuantumObject/QuantumObject_functions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Here is a table that summarizes all the supported linear algebra functions and a
4343

4444
- [`eigenenergies`](@ref): return eigenenergies (eigenvalues)
4545
- [`eigenstates`](@ref): return [`EigsolveResult`](@ref) (contains eigenvalues and eigenvectors)
46+
- [`groundstate`](@ref): return the ground state eigenvalue and corresponding eigenvector
4647
- [`eigvals`](@ref): return eigenvalues
4748
- [`eigen`](@ref): using dense eigen solver and return [`EigsolveResult`](@ref) (contains eigenvalues and eigenvectors)
4849
- [`eigsolve`](@ref): using sparse eigen solver and return [`EigsolveResult`](@ref) (contains eigenvalues and eigenvectors)

src/qobj/eigsolve.jl

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Eigen solvers and results for QuantumObject
33
=#
44

55
export EigsolveResult
6-
export eigenenergies, eigenstates, eigsolve
6+
export eigenenergies, eigenstates, groundstate, eigsolve
77
export eigsolve_al
88

99
@doc raw"""
@@ -87,13 +87,19 @@ function Base.getproperty(res::EigsolveResult, key::Symbol)
8787
end
8888
end
8989

90+
_eigenvector_type(::Type{OperatorQuantumObject}) = Ket
91+
_eigenvector_type(::Type{SuperOperatorQuantumObject}) = OperatorKet
92+
9093
Base.iterate(res::EigsolveResult) = (res.values, Val(:vector_list))
9194
Base.iterate(res::EigsolveResult{T1,T2,Nothing}, ::Val{:vector_list}) where {T1,T2} =
9295
([res.vectors[:, k] for k in 1:length(res.values)], Val(:vectors))
93-
Base.iterate(res::EigsolveResult{T1,T2,OperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} =
94-
([QuantumObject(res.vectors[:, k], Ket, res.dimensions) for k in 1:length(res.values)], Val(:vectors))
95-
Base.iterate(res::EigsolveResult{T1,T2,SuperOperatorQuantumObject}, ::Val{:vector_list}) where {T1,T2} =
96-
([QuantumObject(res.vectors[:, k], OperatorKet, res.dimensions) for k in 1:length(res.values)], Val(:vectors))
96+
Base.iterate(
97+
res::EigsolveResult{T1,T2,OpType},
98+
::Val{:vector_list},
99+
) where {T1,T2,OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}} = (
100+
[QuantumObject(res.vectors[:, k], _eigenvector_type(OpType), res.dimensions) for k in 1:length(res.values)],
101+
Val(:vectors),
102+
)
97103
Base.iterate(res::EigsolveResult, ::Val{:vectors}) = (res.vectors, Val(:done))
98104
Base.iterate(res::EigsolveResult, ::Val{:done}) = nothing
99105

@@ -538,3 +544,40 @@ function eigenstates(
538544
return eigsolve(A; kwargs...)
539545
end
540546
end
547+
548+
@doc raw"""
549+
groundstate(A::QuantumObject; safe::Bool=true, tol::Real=1e-8, kwargs...)
550+
551+
Calculate the ground state eigenvalue and corresponding eigenvector
552+
553+
# Arguments
554+
- `A::QuantumObject`: the [`QuantumObject`](@ref) to solve ground state eigenvalue and eigenvector
555+
- `safe::Bool`: if `true` check for degenerate ground state. Default to `true`.
556+
- `tol::Real`: the tolerance. Default is `1e-8`.
557+
- `kwargs`: Additional keyword arguments passed to the solver. If `sparse=true`, the keyword arguments are passed to [`eigsolve`](@ref), otherwise to [`eigen`](@ref).
558+
559+
# Returns
560+
- `eigval::Number`: the ground state eigenvalue
561+
- `eigvec::QuantumObject`: the ground state eigenvector
562+
"""
563+
function groundstate(
564+
A::QuantumObject{OpType};
565+
safe::Bool = true,
566+
tol::Real = 1e-8,
567+
kwargs...,
568+
) where {OpType<:Union{OperatorQuantumObject,SuperOperatorQuantumObject}}
569+
# TODO: support for sparse eigsolve
570+
#if !sparse
571+
result = eigen(A; kwargs...)
572+
#else
573+
# eigvals = safe ? 2 : 1 # number of eigenvalues to calculate
574+
# result = eigsolve(A; eigvals = eigvals, tol = tol, kwargs...)
575+
#end
576+
577+
# the tolarence should be less strick than the `tol` for the eigensolver
578+
# so it's numerical errors are not seen as degenerate states.
579+
evals = result.values
580+
safe && (abs(evals[2] - evals[1]) < (10 * tol)) && @warn "Ground state may be degenerate."
581+
582+
return evals[1], QuantumObject(result.vectors[:, 1], _eigenvector_type(OpType), result.dimensions)
583+
end

test/core-test/eigenvalues_and_operators.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@
9292
@test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(vecs2[1]).data, atol = 1e-7)
9393
@test isapprox(vec2mat(vecs[1]).data * exp(-1im * angle(vecs[1][1])), vec2mat(state3[1]).data, atol = 1e-5)
9494

95+
# ground state # TODO: support for sparse eigsolve
96+
U = rand_unitary(5)
97+
M = U * Qobj(diagm([1, 1, 2, 3, 4])) * U' # degenerate ground state
98+
gval_1, gvec_1 = @test_logs (:warn,) groundstate(M)
99+
# gval_2, gvec_2 = @test_logs (:warn,) groundstate(M, sparse = true)
100+
@test gval_1 1# ≈ gval_2
101+
#@test isapprox(gvec_1, gvec_2, atol = 1e-6)
102+
95103
@testset "Type Inference (eigen)" begin
96104
N = 5
97105
a = kron(destroy(N), qeye(N))
@@ -112,6 +120,8 @@
112120
@inferred eigenstates(H, sparse = false)
113121
@inferred eigenstates(H, sparse = true)
114122
@inferred eigenstates(L, sparse = true)
123+
@inferred groundstate(H)#, sparse = false) # TODO: support for sparse eigsolve
124+
#@inferred groundstate(H, sparse = true)
115125
@inferred eigsolve_al(L, 1 \ (40 * κ), eigvals = 10)
116126
end
117127
end

0 commit comments

Comments
 (0)