Skip to content

Commit 0066cdb

Browse files
authored
Check for orthogonality breakdown in Lanczos (#502)
1 parent 3028fe0 commit 0066cdb

File tree

3 files changed

+28
-9
lines changed

3 files changed

+28
-9
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

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

10+
- Check for orthogonality breakdown in `Lanczos` solver for `spectrum`. ([#501])
11+
1012
## [v0.32.1]
1113
Release date: 2025-06-24
1214

@@ -253,3 +255,4 @@ Release date: 2024-11-13
253255
[#487]: https://github.com/qutip/QuantumToolbox.jl/issues/487
254256
[#489]: https://github.com/qutip/QuantumToolbox.jl/issues/489
255257
[#494]: https://github.com/qutip/QuantumToolbox.jl/issues/494
258+
[#501]: https://github.com/qutip/QuantumToolbox.jl/issues/501

src/spectrum.jl

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,14 @@ function _spectrum(
186186
Ivec = SparseVector(D^2, [1 + n * (D + 1) for n in 0:(D-1)], ones(cT, D)) # same as vec(system_identity_matrix)
187187
wₖ = spre(A).data' * vT(Ivec)
188188

189-
# Store the norm of the Green's function before renormalizing |v₁> and <w₁|
190-
gfNorm = abs(dot(wₖ, vₖ))
191-
vₖ ./= sqrt(gfNorm)
192-
wₖ ./= sqrt(gfNorm)
189+
# Store the normalization factor for the Green's function before renormalizing |v₁> and <w₁|
190+
gfNorm = dot(wₖ, vₖ)
191+
if gfNorm 0.0
192+
throw(AssertionError("⟨w₀|v₀⟩ = 0, please check your A and B operators."))
193+
end
194+
scalingF = sqrt(abs(gfNorm))
195+
vₖ ./= scalingF
196+
wₖ ./= conj(gfNorm/scalingF)
193197

194198
# Handle input frequency range
195199
ωList = vT(convert(Vector{fT}, ωlist)) # Make sure they're real frequencies and potentially on GPU
@@ -203,6 +207,7 @@ function _spectrum(
203207
αₖ = cT(0)
204208
βₖ = cT(-1)
205209
δₖ = fT(+1)
210+
βₖδₖ = βₖ * δₖ
206211

207212
# Current and up to second-to-last A and B Euler sequences
208213
A₋₂ = vT(ones(cT, Length))
@@ -232,8 +237,8 @@ function _spectrum(
232237
αₖ = dot(w₊₁, vₖ)
233238

234239
# Update A(k), B(k) and continuous fraction; normalization avoids overflow
235-
Aₖ .= (-1im .* ωList .+ αₖ) .* A₋₁ .- (βₖ * δₖ) .* A₋₂
236-
Bₖ .= (-1im .* ωList .+ αₖ) .* B₋₁ .- (βₖ * δₖ) .* B₋₂
240+
Aₖ .= (-1im .* ωList .+ αₖ) .* A₋₁ .- βₖδₖ .* A₋₂
241+
Bₖ .= (-1im .* ωList .+ αₖ) .* B₋₁ .- βₖδₖ .* B₋₂
237242
lanczosFactor₋₁ .= lanczosFactor
238243
lanczosFactor .= Aₖ ./ Bₖ
239244

@@ -268,9 +273,16 @@ function _spectrum(
268273
wₖ, w₊₁ = w₊₁, wₖ
269274

270275
# k-th off-diagonal elements
271-
buf = dot(wₖ, vₖ)
272-
δₖ = sqrt(abs(buf))
273-
βₖ = buf / δₖ
276+
βₖδₖ = dot(wₖ, vₖ)
277+
if βₖδₖ 0.0
278+
if solver.verbose > 0
279+
@warn "spectrum(): solver::Lanczos experienced orthogonality breakdown after $(k) iterations"
280+
@warn "spectrum(): βₖδₖ = $(βₖδₖ)"
281+
end
282+
break
283+
end
284+
δₖ = sqrt(abs(βₖδₖ))
285+
βₖ = βₖδₖ / δₖ
274286

275287
# Normalize (k+1)-th left/right vectors
276288
vₖ ./= δₖ

test/core-test/correlations_and_spectrum.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
@test last(outlines) == "spectrum(): Consider increasing maxiter and/or tol"
5151
end
5252

53+
@testset "Orthogonal input vectors Lanczos" begin
54+
@test_throws AssertionError spectrum(H, ω_l2, [c_ops[1]], a', a; solver = Lanczos())
55+
end
56+
5357
# tlist and τlist checks
5458
t_fft_wrong = [0, 1, 10]
5559
t_wrong1 = [1, 2, 3]

0 commit comments

Comments
 (0)