gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dorgr2.go (about) 1 // Copyright ©2021 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 "math" 10 "testing" 11 12 "golang.org/x/exp/rand" 13 14 "gonum.org/v1/gonum/blas" 15 "gonum.org/v1/gonum/blas/blas64" 16 "gonum.org/v1/gonum/floats" 17 "gonum.org/v1/gonum/lapack" 18 ) 19 20 type Dorgr2er interface { 21 Dorgr2(m, n, k int, a []float64, lda int, tau []float64, work []float64) 22 23 Dgerqfer 24 } 25 26 func Dorgr2Test(t *testing.T, impl Dorgr2er) { 27 rnd := rand.New(rand.NewSource(1)) 28 for _, k := range []int{0, 1, 2, 5} { 29 for _, m := range []int{k, k + 1, k + 2, k + 4} { 30 for _, n := range []int{m, m + 1, m + 2, m + 4, m + 7} { 31 for _, lda := range []int{max(1, n), n + 5} { 32 dorgr2Test(t, impl, rnd, m, n, k, lda) 33 } 34 } 35 } 36 } 37 } 38 39 func dorgr2Test(t *testing.T, impl Dorgr2er, rnd *rand.Rand, m, n, k, lda int) { 40 const tol = 1e-14 41 42 name := fmt.Sprintf("m=%v,n=%v,k=%v,lda=%v", m, n, k, lda) 43 44 // Generate a random m×n matrix A. 45 a := randomGeneral(m, n, lda, rnd) 46 47 // Compute the RQ decomposition of A. 48 rq := cloneGeneral(a) 49 tau := make([]float64, m) 50 work := make([]float64, 1) 51 impl.Dgerqf(m, n, rq.Data, rq.Stride, tau, work, -1) 52 work = make([]float64, int(work[0])) 53 impl.Dgerqf(m, n, rq.Data, rq.Stride, tau, work, len(work)) 54 55 tauCopy := make([]float64, len(tau)) 56 copy(tauCopy, tau) 57 58 // Compute the matrix Q using Dorg2r. 59 q := cloneGeneral(rq) 60 impl.Dorgr2(m, n, k, q.Data, q.Stride, tau[m-k:m], work) 61 62 if m == 0 { 63 return 64 } 65 66 // Check that tau hasn't been modified. 67 if !floats.Equal(tau, tauCopy) { 68 t.Errorf("%v: unexpected modification in tau", name) 69 } 70 71 // Check that Q has orthonormal rows. 72 res := residualOrthogonal(q, true) 73 if res > tol || math.IsNaN(res) { 74 t.Errorf("%v: residual |I - Q*Qᵀ| too large, got %v, want <= %v", name, res, tol) 75 } 76 77 if k == 0 { 78 return 79 } 80 81 // Extract the k×m upper triangular matrix R from RQ[m-k:m,n-k:n]. 82 r := zeros(k, m, m) 83 for i := 0; i < k; i++ { 84 for j := 0; j < k; j++ { 85 ii := rq.Rows - k + i 86 jj := rq.Cols - k + j 87 jr := r.Cols - k + j 88 if i <= j { 89 r.Data[i*r.Stride+jr] = rq.Data[ii*rq.Stride+jj] 90 } 91 } 92 } 93 94 // Construct a view A[m-k:m,0:n] of the last k rows of A. 95 aRec := blas64.General{ 96 Rows: k, 97 Cols: n, 98 Data: a.Data[(m-k)*a.Stride:], 99 Stride: a.Stride, 100 } 101 // Compute A - R*Q. 102 blas64.Gemm(blas.NoTrans, blas.NoTrans, -1, r, q, 1, aRec) 103 // Check that |A - R*Q| is small. 104 res = dlange(lapack.MaxColumnSum, aRec.Rows, aRec.Cols, aRec.Data, aRec.Stride) 105 if res > tol || math.IsNaN(res) { 106 t.Errorf("%v: residual |A - R*Q| too large, got %v, want <= %v", name, res, tol) 107 } 108 }