github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/dgebrd.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 native 6 7 import ( 8 "github.com/gonum/blas" 9 "github.com/gonum/blas/blas64" 10 ) 11 12 // Dgebrd reduces a general m×n matrix A to upper or lower bidiagonal form B by 13 // an orthogonal transformation: 14 // Q^T * A * P = B. 15 // The diagonal elements of B are stored in d and the off-diagonal elements are stored 16 // in e. These are additionally stored along the diagonal of A and the off-diagonal 17 // of A. If m >= n B is an upper-bidiagonal matrix, and if m < n B is a 18 // lower-bidiagonal matrix. 19 // 20 // The remaining elements of A store the data needed to construct Q and P. 21 // The matrices Q and P are products of elementary reflectors 22 // if m >= n, Q = H_0 * H_1 * ... * H_{n-1}, 23 // P = G_0 * G_1 * ... * G_{n-2}, 24 // if m < n, Q = H_0 * H_1 * ... * H_{m-2}, 25 // P = G_0 * G_1 * ... * G_{m-1}, 26 // where 27 // H_i = I - tauQ[i] * v_i * v_i^T, 28 // G_i = I - tauP[i] * u_i * u_i^T. 29 // 30 // As an example, on exit the entries of A when m = 6, and n = 5 31 // [ d e u1 u1 u1] 32 // [v1 d e u2 u2] 33 // [v1 v2 d e u3] 34 // [v1 v2 v3 d e] 35 // [v1 v2 v3 v4 d] 36 // [v1 v2 v3 v4 v5] 37 // and when m = 5, n = 6 38 // [ d u1 u1 u1 u1 u1] 39 // [ e d u2 u2 u2 u2] 40 // [v1 e d u3 u3 u3] 41 // [v1 v2 e d u4 u4] 42 // [v1 v2 v3 e d u5] 43 // 44 // d, tauQ, and tauP must all have length at least min(m,n), and e must have 45 // length min(m,n) - 1, unless lwork is -1 when there is no check except for 46 // work which must have a length of at least one. 47 // 48 // work is temporary storage, and lwork specifies the usable memory length. 49 // At minimum, lwork >= max(1,m,n) or be -1 and this function will panic otherwise. 50 // Dgebrd is blocked decomposition, but the block size is limited 51 // by the temporary space available. If lwork == -1, instead of performing Dgebrd, 52 // the optimal work length will be stored into work[0]. 53 // 54 // Dgebrd is an internal routine. It is exported for testing purposes. 55 func (impl Implementation) Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int) { 56 checkMatrix(m, n, a, lda) 57 // Calculate optimal work. 58 nb := impl.Ilaenv(1, "DGEBRD", " ", m, n, -1, -1) 59 var lworkOpt int 60 if lwork == -1 { 61 if len(work) < 1 { 62 panic(badWork) 63 } 64 lworkOpt = ((m + n) * nb) 65 work[0] = float64(max(1, lworkOpt)) 66 return 67 } 68 minmn := min(m, n) 69 if len(d) < minmn { 70 panic(badD) 71 } 72 if len(e) < minmn-1 { 73 panic(badE) 74 } 75 if len(tauQ) < minmn { 76 panic(badTauQ) 77 } 78 if len(tauP) < minmn { 79 panic(badTauP) 80 } 81 ws := max(m, n) 82 if lwork < max(1, ws) { 83 panic(badWork) 84 } 85 if len(work) < lwork { 86 panic(badWork) 87 } 88 var nx int 89 if nb > 1 && nb < minmn { 90 nx = max(nb, impl.Ilaenv(3, "DGEBRD", " ", m, n, -1, -1)) 91 if nx < minmn { 92 ws = (m + n) * nb 93 if lwork < ws { 94 nbmin := impl.Ilaenv(2, "DGEBRD", " ", m, n, -1, -1) 95 if lwork >= (m+n)*nbmin { 96 nb = lwork / (m + n) 97 } else { 98 nb = minmn 99 nx = minmn 100 } 101 } 102 } 103 } else { 104 nx = minmn 105 } 106 bi := blas64.Implementation() 107 ldworkx := nb 108 ldworky := nb 109 var i int 110 // Netlib lapack has minmn - nx, but this makes the last nx rows (which by 111 // default is large) be unblocked. As written here, the blocking is more 112 // consistent. 113 for i = 0; i < minmn-nb; i += nb { 114 // Reduce rows and columns i:i+nb to bidiagonal form and return 115 // the matrices X and Y which are needed to update the unreduced 116 // part of the matrix. 117 // X is stored in the first m rows of work, y in the next rows. 118 x := work[:m*ldworkx] 119 y := work[m*ldworkx:] 120 impl.Dlabrd(m-i, n-i, nb, a[i*lda+i:], lda, 121 d[i:], e[i:], tauQ[i:], tauP[i:], 122 x, ldworkx, y, ldworky) 123 124 // Update the trailing submatrix A[i+nb:m,i+nb:n], using an update 125 // of the form A := A - V*Y**T - X*U**T 126 bi.Dgemm(blas.NoTrans, blas.Trans, m-i-nb, n-i-nb, nb, 127 -1, a[(i+nb)*lda+i:], lda, y[nb*ldworky:], ldworky, 128 1, a[(i+nb)*lda+i+nb:], lda) 129 130 bi.Dgemm(blas.NoTrans, blas.NoTrans, m-i-nb, n-i-nb, nb, 131 -1, x[nb*ldworkx:], ldworkx, a[i*lda+i+nb:], lda, 132 1, a[(i+nb)*lda+i+nb:], lda) 133 134 // Copy diagonal and off-diagonal elements of B back into A. 135 if m >= n { 136 for j := i; j < i+nb; j++ { 137 a[j*lda+j] = d[j] 138 a[j*lda+j+1] = e[j] 139 } 140 } else { 141 for j := i; j < i+nb; j++ { 142 a[j*lda+j] = d[j] 143 a[(j+1)*lda+j] = e[j] 144 } 145 } 146 } 147 // Use unblocked code to reduce the remainder of the matrix. 148 impl.Dgebd2(m-i, n-i, a[i*lda+i:], lda, d[i:], e[i:], tauQ[i:], tauP[i:], work) 149 work[0] = float64(lworkOpt) 150 }