gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dtrcon.go (about) 1 // Copyright ©2015 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package testlapack 6 7 import ( 8 "fmt" 9 "testing" 10 11 "golang.org/x/exp/rand" 12 13 "gonum.org/v1/gonum/blas" 14 "gonum.org/v1/gonum/floats" 15 "gonum.org/v1/gonum/lapack" 16 ) 17 18 type Dtrconer interface { 19 Dtrcon(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int, work []float64, iwork []int) float64 20 21 Dtrtri(uplo blas.Uplo, diag blas.Diag, n int, a []float64, lda int) bool 22 Dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 23 } 24 25 func DtrconTest(t *testing.T, impl Dtrconer) { 26 rnd := rand.New(rand.NewSource(1)) 27 for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 50} { 28 for _, uplo := range []blas.Uplo{blas.Lower, blas.Upper} { 29 for _, diag := range []blas.Diag{blas.NonUnit, blas.Unit} { 30 for _, lda := range []int{max(1, n), n + 3} { 31 for _, mattype := range []int{0, 1, 2} { 32 dtrconTest(t, impl, rnd, uplo, diag, n, lda, mattype) 33 } 34 } 35 } 36 } 37 } 38 } 39 40 func dtrconTest(t *testing.T, impl Dtrconer, rnd *rand.Rand, uplo blas.Uplo, diag blas.Diag, n, lda, mattype int) { 41 const ratioThresh = 10 42 43 a := make([]float64, max(0, (n-1)*lda+n)) 44 for i := range a { 45 a[i] = rnd.Float64() 46 } 47 switch mattype { 48 default: 49 panic("bad mattype") 50 case 0: 51 // Matrix filled with consecutive integer values. 52 // For lapack.MaxRowSum norm (infinity-norm) these matrices 53 // sometimes lead to a slightly inaccurate estimate of the condition 54 // number. 55 c := 2.0 56 for i := 0; i < n; i++ { 57 for j := 0; j < n; j++ { 58 a[i*lda+j] = c 59 c += 1 60 } 61 } 62 case 1: 63 // Identity matrix. 64 if uplo == blas.Upper { 65 for i := 0; i < n; i++ { 66 for j := i + 1; j < n; j++ { 67 a[i*lda+j] = 0 68 } 69 } 70 } else { 71 for i := 0; i < n; i++ { 72 for j := 0; j < i; j++ { 73 a[i*lda+j] = 0 74 } 75 } 76 } 77 if diag == blas.NonUnit { 78 for i := 0; i < n; i++ { 79 a[i*lda+i] = 1 80 } 81 } 82 case 2: 83 // Matrix filled with random values uniformly in [-1,1). 84 // These matrices often lead to a slightly inaccurate estimate 85 // of the condition number. 86 for i := 0; i < n; i++ { 87 for j := 0; j < n; j++ { 88 a[i*lda+j] = 2*rnd.Float64() - 1 89 } 90 } 91 } 92 aCopy := make([]float64, len(a)) 93 copy(aCopy, a) 94 95 // Compute the inverse A^{-1}. 96 aInv := make([]float64, len(a)) 97 copy(aInv, a) 98 ok := impl.Dtrtri(uplo, diag, n, aInv, lda) 99 if !ok { 100 t.Fatalf("uplo=%v,diag=%v,n=%v,lda=%v,mattype=%v: bad matrix, Dtrtri failed", string(uplo), string(diag), n, lda, mattype) 101 } 102 103 work := make([]float64, 3*n) 104 iwork := make([]int, n) 105 for _, norm := range []lapack.MatrixNorm{lapack.MaxColumnSum, lapack.MaxRowSum} { 106 name := fmt.Sprintf("norm=%v,uplo=%v,diag=%v,n=%v,lda=%v,mattype=%v", string(norm), string(uplo), string(diag), n, lda, mattype) 107 108 // Compute the norm of A and A^{-1}. 109 aNorm := impl.Dlantr(norm, uplo, diag, n, n, a, lda, work) 110 aInvNorm := impl.Dlantr(norm, uplo, diag, n, n, aInv, lda, work) 111 112 // Compute a good estimate of the condition number 113 // rcondWant := 1/(norm(A) * norm(inv(A))) 114 rcondWant := 1.0 115 if aNorm > 0 && aInvNorm > 0 { 116 rcondWant = 1 / aNorm / aInvNorm 117 } 118 119 // Compute an estimate of rcond using Dtrcon. 120 rcondGot := impl.Dtrcon(norm, uplo, diag, n, a, lda, work, iwork) 121 if !floats.Equal(a, aCopy) { 122 t.Errorf("%v: unexpected modification of a", name) 123 } 124 125 ratio := rCondTestRatio(rcondGot, rcondWant) 126 if ratio >= ratioThresh { 127 t.Errorf("%v: unexpected value of rcond; got=%v, want=%v (ratio=%v)", 128 name, rcondGot, rcondWant, ratio) 129 } 130 } 131 }