Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix bug in general schur eigenvalues computation #30

Merged
merged 1 commit into from
Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions src/schur.jl
Original file line number Diff line number Diff line change
Expand Up @@ -363,27 +363,29 @@ for (gges, elty) in ((:dgges_, :Float64),
end
chklapackerror(info[])
@inbounds for i in axes(A, 1)
ws.eigen_values[i] = complex(ws.αr[i], ws.αi[i])
ws.eigen_values[i] = complex(ws.αr[i], ws.αi[i])/ws.β[i]
end
return A, B, ws.eigen_values, ws.β, ws.vsl, ws.vsr
return A, B, complex.(ws.αr, ws.αi), ws.β, ws.vsl, ws.vsr
end
end
end

"""
gges!(ws, jobvsl, jobvsr, A, B; select=nothing, resize=true) -> (A, B, ws.eigen_values, ws.β, ws.vsl, ws.vsr)
gges!(ws, jobvsl, jobvsr, A, B; select=nothing, resize=true) -> (A, B, ws.α, ws.β, ws.vsl, ws.vsr)

Computes the generalized eigenvalues, generalized Schur form, left Schur
vectors (`jobsvl = V`), or right Schur vectors (`jobvsr = V`) of `A` and
`B`, using preallocated [`GeneralizedSchurWs`](@ref) workspace `ws`.
If `ws` is not of the right size, and `resize==true` it will be resized appropriately.

It is possible to specify `select`, a function used to sort the eigenvalues during the decomposition.
The function should have the signature `f(αr::T, αi::T, β::T) -> Bool`, where
`αr` and `αi` are the real and imaginary parts of the eigenvalue, `β` the factor, and `T == eltype(A).

The generalized eigenvalues are returned in `ws.eigen_values` and `ws.β`. The left Schur
vectors are returned in `ws.vsl` and the right Schur vectors are returned in `ws.vsr`.
It is possible to specify `select`, a function used to sort the eigenvalues to the top left corner of the Schur form.
The function should have the signature `f(αr::T, αi::T, β::T) -> Bool` where `T == eltype(A)`.
An eigenvalue `(αr[j]+αi[j])/β[j]` is selected if `f(αr[j],αi[j],β[j])` is true,
i.e. if either one of a complex conjugate pair of eigenvalues is selected,
then both complex eigenvalues are selected.
The generalized eigenvalues components are returned in `ws.α` and `ws.β` where `ws.α` is a complex vector and `ẁs.β`, a real vector.
The generalized eigenvalues (`ws.α./ws.β`) are returned in `ws.eigen_values`, a complex vector.
The left Schur vectors are returned in `ws.vsl` and the right Schur vectors are returned in `ws.vsr`.
"""
gges!(ws::GeneralizedSchurWs, jobvsl::AbstractChar, jobvsr::AbstractChar, A::AbstractMatrix,
B::AbstractMatrix)
20 changes: 12 additions & 8 deletions test/schur_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,26 @@ end
B0 = randn(n, n)
ws = GeneralizedSchurWs(copy(A0))

A1, B1, eig1, β1, vsl1, vsr1 = LAPACK.gges!('V', 'V', copy(A0), copy(B0))
A2, B2, eig2, β2, vsl2, vsr2 = LAPACK.gges!(ws, 'V', 'V', copy(A0), copy(B0))
A1, B1, α1, β1, vsl1, vsr1 = LAPACK.gges!('V', 'V', copy(A0), copy(B0))
A2, B2, α2, β2, vsl2, vsr2 = LAPACK.gges!(ws, 'V', 'V', copy(A0), copy(B0))
@test isapprox(A1, A2)
@test isapprox(B1, B2)
@test isapprox(eig1, eig2)
@test isapprox(α1, α2)
@test isapprox(β1, β2)
@test isapprox(vsl1, vsl2)
@test isapprox(vsr1, vsr2)

# Using Workspace, factorize!
ws = Workspace(LAPACK.gges!, copy(A0))
A2, B2, eig2, β2, vsl2, vsr2 = factorize!(ws, 'V', 'V', copy(A0), copy(B0))
A2, B2, α2, β2, vsl2, vsr2 = factorize!(ws, 'V', 'V', copy(A0), copy(B0))
@test isapprox(A1, A2)
@test isapprox(B1, B2)
@test isapprox(eig1, eig2)
@test isapprox(α1, α2)
@test isapprox(β1, β2)
@test isapprox(vsl1, vsl2)
@test isapprox(vsr1, vsr2)
@test isapprox(sort(abs.(eigen(A0, B0).values)), sort(abs.(ws.eigen_values)))

show(devnull, "text/plain", ws)

for div in (-1,1)
Expand All @@ -91,14 +93,16 @@ end
0.86268 -0.212549 -0.211994]
ws = GeneralizedSchurWs(copy(A0))

A0, B0, eig, β, vsl, vsr = LAPACK.gges!(ws, 'V', 'V', copy(A0),
A0, B0, α, β, vsl, vsr = LAPACK.gges!(ws, 'V', 'V', copy(A0),
copy(B0);
select = (ar, ai, b) -> ar^2 + ai^2 <
FastLapackInterface.SCHUR_CRITERIUM *
b^2)
@test ws.sdim[] == 1
@test sign(real(eig[1])) == -1
@test sign(real(eig[2])) == 1
@test (real(α[1])/β[1])^2 < FastLapackInterface.SCHUR_CRITERIUM
@test (real(α[2])/β[2])^2 > FastLapackInterface.SCHUR_CRITERIUM
@test (real(α[3])/β[3])^2 > FastLapackInterface.SCHUR_CRITERIUM
@test isapprox(sort(abs.(eigen(A0, B0).values)), sort(abs.(ws.eigen_values)))
show(devnull, "text/plain", ws)
end
end