gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dgetri.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  	"testing"
     9  
    10  	"golang.org/x/exp/rand"
    11  
    12  	"gonum.org/v1/gonum/blas"
    13  	"gonum.org/v1/gonum/blas/blas64"
    14  )
    15  
    16  type Dgetrier interface {
    17  	Dgetrfer
    18  	Dgetri(n int, a []float64, lda int, ipiv []int, work []float64, lwork int) bool
    19  }
    20  
    21  func DgetriTest(t *testing.T, impl Dgetrier) {
    22  	const tol = 1e-13
    23  	rnd := rand.New(rand.NewSource(1))
    24  	bi := blas64.Implementation()
    25  	for _, test := range []struct {
    26  		n, lda int
    27  	}{
    28  		{5, 0},
    29  		{5, 8},
    30  		{45, 0},
    31  		{45, 50},
    32  		{63, 70},
    33  		{64, 70},
    34  		{65, 0},
    35  		{65, 70},
    36  		{66, 70},
    37  		{150, 0},
    38  		{150, 250},
    39  	} {
    40  		n := test.n
    41  		lda := test.lda
    42  		if lda == 0 {
    43  			lda = n
    44  		}
    45  		// Generate a random well conditioned matrix
    46  		perm := rnd.Perm(n)
    47  		a := make([]float64, n*lda)
    48  		for i := 0; i < n; i++ {
    49  			a[i*lda+perm[i]] = 1
    50  		}
    51  		for i := range a {
    52  			a[i] += 0.01 * rnd.Float64()
    53  		}
    54  		aCopy := make([]float64, len(a))
    55  		copy(aCopy, a)
    56  		ipiv := make([]int, n)
    57  		// Compute LU decomposition.
    58  		impl.Dgetrf(n, n, a, lda, ipiv)
    59  		// Test with various workspace sizes.
    60  		for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} {
    61  			ainv := make([]float64, len(a))
    62  			copy(ainv, a)
    63  
    64  			var lwork int
    65  			switch wl {
    66  			case minimumWork:
    67  				lwork = max(1, n)
    68  			case mediumWork:
    69  				work := make([]float64, 1)
    70  				impl.Dgetri(n, ainv, lda, ipiv, work, -1)
    71  				lwork = max(int(work[0])-2*n, n)
    72  			case optimumWork:
    73  				work := make([]float64, 1)
    74  				impl.Dgetri(n, ainv, lda, ipiv, work, -1)
    75  				lwork = int(work[0])
    76  			}
    77  			work := make([]float64, lwork)
    78  
    79  			// Compute inverse.
    80  			ok := impl.Dgetri(n, ainv, lda, ipiv, work, lwork)
    81  			if !ok {
    82  				t.Errorf("Unexpected singular matrix.")
    83  			}
    84  
    85  			// Check that A(inv) * A = I.
    86  			ans := make([]float64, len(ainv))
    87  			bi.Dgemm(blas.NoTrans, blas.NoTrans, n, n, n, 1, aCopy, lda, ainv, lda, 0, ans, lda)
    88  			// The tolerance is so high because computing matrix inverses is very unstable.
    89  			dist := distFromIdentity(n, ans, lda)
    90  			if dist > tol {
    91  				t.Errorf("|Inv(A) * A - I|_inf = %v is too large. n = %v, lda = %v", dist, n, lda)
    92  			}
    93  		}
    94  	}
    95  }