github.com/gopherd/gonum@v0.0.4/lapack/testlapack/dpotri.go (about) 1 // Copyright ©2019 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 "math/rand" 12 13 "github.com/gopherd/gonum/blas" 14 "github.com/gopherd/gonum/blas/blas64" 15 ) 16 17 type Dpotrier interface { 18 Dpotri(uplo blas.Uplo, n int, a []float64, lda int) bool 19 20 Dpotrf(uplo blas.Uplo, n int, a []float64, lda int) bool 21 } 22 23 func DpotriTest(t *testing.T, impl Dpotrier) { 24 for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { 25 name := uploToString(uplo) 26 t.Run(name, func(t *testing.T) { 27 // Include small and large sizes to make sure that both 28 // unblocked and blocked paths are taken. 29 ns := []int{0, 1, 2, 3, 4, 5, 10, 25, 31, 32, 33, 63, 64, 65, 127, 128, 129} 30 const tol = 1e-12 31 32 bi := blas64.Implementation() 33 rnd := rand.New(rand.NewSource(1)) 34 for _, n := range ns { 35 for _, lda := range []int{max(1, n), n + 11} { 36 prefix := fmt.Sprintf("n=%v,lda=%v", n, lda) 37 38 // Generate a random diagonal matrix D with positive entries. 39 d := make([]float64, n) 40 Dlatm1(d, 3, 10000, false, 2, rnd) 41 42 // Construct a positive definite matrix A as 43 // A = U * D * Uᵀ 44 // where U is a random orthogonal matrix. 45 a := make([]float64, n*lda) 46 Dlagsy(n, 0, d, a, lda, rnd, make([]float64, 2*n)) 47 // Create a copy of A. 48 aCopy := make([]float64, len(a)) 49 copy(aCopy, a) 50 // Compute the Cholesky factorization of A. 51 ok := impl.Dpotrf(uplo, n, a, lda) 52 if !ok { 53 t.Fatalf("%v: unexpected Cholesky failure", prefix) 54 } 55 56 // Compute the inverse inv(A). 57 ok = impl.Dpotri(uplo, n, a, lda) 58 if !ok { 59 t.Errorf("%v: unexpected failure", prefix) 60 continue 61 } 62 63 // Check that the triangle of A opposite to uplo has not been modified. 64 if uplo == blas.Upper && !sameLowerTri(n, aCopy, lda, a, lda) { 65 t.Errorf("%v: unexpected modification in lower triangle", prefix) 66 continue 67 } 68 if uplo == blas.Lower && !sameUpperTri(n, aCopy, lda, a, lda) { 69 t.Errorf("%v: unexpected modification in upper triangle", prefix) 70 continue 71 } 72 73 // Change notation for the sake of clarity. 74 ainv := a 75 ldainv := lda 76 77 // Expand ainv into a full dense matrix so that we can call Dsymm below. 78 if uplo == blas.Upper { 79 for i := 1; i < n; i++ { 80 for j := 0; j < i; j++ { 81 ainv[i*ldainv+j] = ainv[j*ldainv+i] 82 } 83 } 84 } else { 85 for i := 0; i < n-1; i++ { 86 for j := i + 1; j < n; j++ { 87 ainv[i*ldainv+j] = ainv[j*ldainv+i] 88 } 89 } 90 } 91 92 // Compute A*inv(A) and store the result into want. 93 ldwant := max(1, n) 94 want := make([]float64, n*ldwant) 95 bi.Dsymm(blas.Left, uplo, n, n, 1, aCopy, lda, ainv, ldainv, 0, want, ldwant) 96 97 // Check that want is close to the identity matrix. 98 dist := distFromIdentity(n, want, ldwant) 99 if dist > tol { 100 t.Errorf("%v: |A * inv(A) - I| = %v is too large", prefix, dist) 101 } 102 } 103 } 104 }) 105 } 106 }