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  }