gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dorgtr.go (about) 1 // Copyright ©2016 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/blas/blas64" 15 "gonum.org/v1/gonum/floats" 16 ) 17 18 type Dorgtrer interface { 19 Dorgtr(uplo blas.Uplo, n int, a []float64, lda int, tau, work []float64, lwork int) 20 Dsytrder 21 } 22 23 func DorgtrTest(t *testing.T, impl Dorgtrer) { 24 const tol = 1e-14 25 26 rnd := rand.New(rand.NewSource(1)) 27 for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} { 28 for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} { 29 for _, test := range []struct { 30 n, lda int 31 }{ 32 {1, 0}, 33 {2, 0}, 34 {3, 0}, 35 {6, 0}, 36 {33, 0}, 37 {100, 0}, 38 39 {1, 3}, 40 {2, 5}, 41 {3, 7}, 42 {6, 10}, 43 {33, 50}, 44 {100, 120}, 45 } { 46 n := test.n 47 lda := test.lda 48 if lda == 0 { 49 lda = n 50 } 51 // Allocate n×n matrix A and fill it with random numbers. 52 a := make([]float64, n*lda) 53 for i := range a { 54 a[i] = rnd.NormFloat64() 55 } 56 aCopy := make([]float64, len(a)) 57 copy(aCopy, a) 58 59 // Allocate slices for the main diagonal and the 60 // first off-diagonal of the tri-diagonal matrix. 61 d := make([]float64, n) 62 e := make([]float64, n-1) 63 // Allocate slice for elementary reflector scales. 64 tau := make([]float64, n-1) 65 66 // Compute optimum workspace size for Dorgtr call. 67 work := make([]float64, 1) 68 impl.Dsytrd(uplo, n, a, lda, d, e, tau, work, -1) 69 work = make([]float64, int(work[0])) 70 71 // Compute elementary reflectors that reduce the 72 // symmetric matrix defined by the uplo triangle 73 // of A to a tridiagonal matrix. 74 impl.Dsytrd(uplo, n, a, lda, d, e, tau, work, len(work)) 75 76 // Compute workspace size for Dorgtr call. 77 var lwork int 78 switch wl { 79 case minimumWork: 80 lwork = max(1, n-1) 81 case mediumWork: 82 work := make([]float64, 1) 83 impl.Dorgtr(uplo, n, a, lda, tau, work, -1) 84 lwork = (int(work[0]) + n - 1) / 2 85 lwork = max(1, lwork) 86 case optimumWork: 87 work := make([]float64, 1) 88 impl.Dorgtr(uplo, n, a, lda, tau, work, -1) 89 lwork = int(work[0]) 90 } 91 work = nanSlice(lwork) 92 93 // Generate an orthogonal matrix Q that reduces 94 // the uplo triangle of A to a tridiagonal matrix. 95 impl.Dorgtr(uplo, n, a, lda, tau, work, len(work)) 96 q := blas64.General{ 97 Rows: n, 98 Cols: n, 99 Stride: lda, 100 Data: a, 101 } 102 103 name := fmt.Sprintf("uplo=%c,n=%v,lda=%v,work=%v", uplo, n, lda, wl) 104 105 if resid := residualOrthogonal(q, false); resid > tol*float64(n) { 106 t.Errorf("Case %v: Q is not orthogonal; resid=%v, want<=%v", name, resid, tol*float64(n)) 107 } 108 109 // Create the tridiagonal matrix explicitly in 110 // dense representation from the diagonals d and e. 111 tri := blas64.General{ 112 Rows: n, 113 Cols: n, 114 Stride: n, 115 Data: make([]float64, n*n), 116 } 117 for i := 0; i < n; i++ { 118 tri.Data[i*tri.Stride+i] = d[i] 119 if i != n-1 { 120 tri.Data[i*tri.Stride+i+1] = e[i] 121 tri.Data[(i+1)*tri.Stride+i] = e[i] 122 } 123 } 124 125 // Create the symmetric matrix A from the uplo 126 // triangle of aCopy, storing it explicitly in dense form. 127 aMat := blas64.General{ 128 Rows: n, 129 Cols: n, 130 Stride: n, 131 Data: make([]float64, n*n), 132 } 133 if uplo == blas.Upper { 134 for i := 0; i < n; i++ { 135 for j := i; j < n; j++ { 136 v := aCopy[i*lda+j] 137 aMat.Data[i*aMat.Stride+j] = v 138 aMat.Data[j*aMat.Stride+i] = v 139 } 140 } 141 } else { 142 for i := 0; i < n; i++ { 143 for j := 0; j <= i; j++ { 144 v := aCopy[i*lda+j] 145 aMat.Data[i*aMat.Stride+j] = v 146 aMat.Data[j*aMat.Stride+i] = v 147 } 148 } 149 } 150 151 // Compute Qᵀ * A * Q and store the result in ans. 152 tmp := blas64.General{Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n)} 153 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, aMat, q, 0, tmp) 154 ans := blas64.General{Rows: n, Cols: n, Stride: n, Data: make([]float64, n*n)} 155 blas64.Gemm(blas.Trans, blas.NoTrans, 1, q, tmp, 0, ans) 156 157 // Compare the tridiagonal matrix tri from 158 // Dorgtr with the explicit computation ans. 159 if !floats.EqualApprox(ans.Data, tri.Data, tol) { 160 t.Errorf("Case %v: Recombination mismatch", name) 161 } 162 } 163 } 164 } 165 }