Skip to content

Implement schur_full for Diagonal inputs, deprecate schur_vals - #277

Open
lkdvos wants to merge 3 commits into
mainfrom
diagonal-schur
Open

Implement schur_full for Diagonal inputs, deprecate schur_vals#277
lkdvos wants to merge 3 commits into
mainfrom
diagonal-schur

Conversation

@lkdvos

@lkdvos lkdvos commented Aug 26, 2026

Copy link
Copy Markdown
Member

Fixes #276: Diagonal input selects DiagonalAlgorithm, which schur never implemented, so schur_full threw a MethodError.

A diagonal matrix is already in Schur form, so T = A, Z = I (kept Diagonal, as qr/lq keep Q and R) and vals = diagview(A), complexified as everywhere else. One choice worth flagging: no reordering, unlike the Diagonal path of eig, which sorts.

Also deprecates schur_vals/schur_vals! in favour of eig_vals/eig_vals!, answering the # TODO: is this useful? Is there any difference with simply eig_vals? that stood above it. There is a difference, and it is not in schur's favour: LAPACK's gees balances with permutation only where geev also scales, so schur_vals returns exactly eig_vals(A; scale = false). On a matrix graded over 1e12 that is a relative error of 33 against 1e-15 for eig_vals, and it is no faster — gees computes the Schur form where geev asks hseqr for eigenvalues only. schur_full still returns the gees eigenvalues alongside T and Z. Callers of schur_vals(A; expert = true) need to drop the keyword; eig_vals has no equivalent.

Enables the Diagonal schur tests that were commented out as "not supported yet", CPU and CUDA. Note this alone does not fix schur_full(::DiagonalTensorMap): TensorKit omits schur from its default_algorithm forwarding, so selection fails there for every tensor, diagonal or not. That needs a separate PR.

🤖 Generated with Claude Code

Schur reuses eig's algorithm selection, which routes `Diagonal` to
`DiagonalAlgorithm`, but no such implementation existed, so both threw a
`MethodError`. A diagonal matrix is already in Schur form: `T = A`, `Z = I`
and `vals = diagview(A)`, without any reordering.

Fixes #276

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.81818% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/implementations/schur.jl 80.00% 4 Missing ⚠️
Files with missing lines Coverage Δ
ext/MatrixAlgebraKitGenericSchurExt.jl 81.25% <ø> (ø)
src/interface/schur.jl 100.00% <100.00%> (ø)
src/precompile.jl 100.00% <ø> (ø)
src/implementations/schur.jl 85.18% <80.00%> (-1.03%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Jutho

Jutho commented Aug 27, 2026

Copy link
Copy Markdown
Member

What is the rational for schur_vals of a real diagonal not changing to complex? eig_vals does do this, and schur_vals on the equivalent full matrix would also return complex results.

@lkdvos

lkdvos commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

No rationale... I forgot we had this whole discussion with the eigenvalues as well, I'll change it

lkdvos and others added 2 commits August 29, 2026 10:26
The eigenvalues of a `Diagonal` are now complex, as for any other input
and as `eig_vals` already does. That makes `schur_vals!`'s `check_input`
and `initialize_output` identical to those of `eig_vals!` for every
algorithm, so they simply forward, as `copy_input` already did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
LAPACK's `gees` balances with permutation only, where `geev` also scales,
so `schur_vals` returns the eigenvalues of `eig_vals(A; scale = false)`.
On a matrix graded over 1e12 that is a relative error of 33 against 1e-15
for `eig_vals`, and `gees` is no faster: it computes the Schur form where
`geev` asks `hseqr` for eigenvalues only.

This answers the `# TODO: is this useful? Is there any difference with
simply eig_vals?` that stood above `schur_vals`. `schur_full` keeps
returning the eigenvalues it gets from `gees` alongside `T` and `Z`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lkdvos lkdvos changed the title Implement schur_full/schur_vals for Diagonal inputs Implement schur_full for Diagonal inputs, deprecate schur_vals Aug 29, 2026
@lkdvos

lkdvos commented Aug 29, 2026

Copy link
Copy Markdown
Member Author

After some reconsideration I decided to just deprecate the schur_vals altogether, since it is just the same as eig_vals anyways, and we already had a TODO comment somewhere in the source about this. I quite like deleting more code, so this seems like a good thing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

schur_full/schur_vals select DiagonalAlgorithm for Diagonal but it is not implemented

2 participants