fix(linalg): converge the Hermitian Jacobi sweep on near-diagonal matrices

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-27 11:58:07 +02:00
parent 7bc030c78b
commit 2764a18075
3 changed files with 49 additions and 1 deletions
+12 -1
View File
@@ -122,6 +122,17 @@ func hermitianJacobi(h []complex128, v []complex128, n int) error {
// the floor already diagonal and return its raw diagonal, identity
// eigenvectors included.
threshold := 1e-13 * norm
// The per-entry skip must sit where a matrix whose every
// off-diagonal entry is skippable also passes the aggregate
// convergence test: with P pairs the off-norm of all-skipped entries
// reaches skip·√P, so a skip at the plain threshold leaves a matrix
// whose entries are uniformly just under it frozen above the test,
// and the sweep exhausts its passes without turning a single
// rotation.
skip := threshold
if pairs := float64(n * (n - 1) / 2); pairs > 1 {
skip = threshold / math.Sqrt(pairs)
}
offMass := func() float64 {
off := 0.0
for p := range n {
@@ -139,7 +150,7 @@ func hermitianJacobi(h []complex128, v []complex128, n int) error {
for p := range n {
for q := p + 1; q < n; q++ {
z := h[p*n+q]
if base.AbsComplex(z) <= threshold {
if base.AbsComplex(z) <= skip {
continue
}
// Step 1: a diagonal phase turn makes the pair entry