lapack/gonum: handle NaN and Inf input to Dgecon

See https://github.com/Reference-LAPACK/lapack/pull/926
This commit is contained in:
Vladimir Chalupecky
2023-11-13 09:45:04 +01:00
committed by Vladimír Chalupecký
parent db43f45c2b
commit fa306f215a
2 changed files with 39 additions and 12 deletions

View File

@@ -12,14 +12,20 @@ import (
"gonum.org/v1/gonum/lapack" "gonum.org/v1/gonum/lapack"
) )
// Dgecon estimates the reciprocal of the condition number of the n×n matrix A // Dgecon estimates and returns the reciprocal of the condition number of the
// given the LU decomposition of the matrix. The condition number computed may // n×n matrix A, in either the 1-norm or the ∞-norm, using the LU factorization
// be based on the 1-norm or the ∞-norm. // computed by Dgetrf.
// //
// The slice a contains the result of the LU decomposition of A as computed by Dgetrf. // An estimate is obtained for norm(A⁻¹), and the reciprocal of the condition
// number rcond is computed as
// //
// anorm is the corresponding 1-norm or ∞-norm of the original matrix A. anorm // rcond 1 / ( norm(A) * norm(A⁻¹) ).
// must be non-negative. //
// If n is zero, rcond is always 1.
//
// anorm is the 1-norm or the ∞-norm of the original matrix A. anorm must be
// non-negative, otherwise Dgecon will panic. If anorm is 0 or infinity, Dgecon
// returns 0. If anorm is NaN, Dgecon returns NaN.
// //
// work must have length at least 4*n and iwork must have length at least n, // work must have length at least 4*n and iwork must have length at least n,
// otherwise Dgecon will panic. // otherwise Dgecon will panic.
@@ -50,14 +56,14 @@ func (impl Implementation) Dgecon(norm lapack.MatrixNorm, n int, a []float64, ld
} }
// Quick return if possible. // Quick return if possible.
if anorm == 0 { switch {
case anorm == 0:
return 0 return 0
} case math.IsNaN(anorm):
if math.IsNaN(anorm) { // Propagate NaN.
// The reference implementation treats the NaN anorm as invalid and
// returns an error code. Our error handling is to panic which seems too
// harsh for a runtime condition, so we just propagate the NaN instead.
return anorm return anorm
case math.IsInf(anorm, 1):
return 0
} }
bi := blas64.Implementation() bi := blas64.Implementation()

View File

@@ -6,6 +6,7 @@ package testlapack
import ( import (
"fmt" "fmt"
"math"
"testing" "testing"
"golang.org/x/exp/rand" "golang.org/x/exp/rand"
@@ -87,5 +88,25 @@ func dgeconTest(t *testing.T, impl Dgeconer, rnd *rand.Rand, n, lda int) {
t.Errorf("%v: unexpected value of rcond; got=%v, want=%v (ratio=%v)", t.Errorf("%v: unexpected value of rcond; got=%v, want=%v (ratio=%v)",
name, rcondGot, rcondWant, ratio) name, rcondGot, rcondWant, ratio)
} }
// Check for corner-case values of anorm.
for _, anorm := range []float64{0, math.Inf(1), math.NaN()} {
rcondGot = impl.Dgecon(norm, n, aFac, lda, anorm, work, iwork)
if n == 0 {
if rcondGot != 1 {
t.Errorf("%v: unexpected rcond when anorm=%v: got=%v, want=1", name, anorm, rcondGot)
}
continue
}
if math.IsNaN(anorm) {
if !math.IsNaN(rcondGot) {
t.Errorf("%v: NaN not propagated when anorm=NaN: got=%v", name, rcondGot)
}
continue
}
if rcondGot != 0 {
t.Errorf("%v: unexpected rcond when anorm=%v: got=%v, want=0", name, anorm, rcondGot)
}
}
} }
} }