gonum.org/v1/gonum@v0.14.0/lapack/gonum/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 gonum 6 7 import ( 8 "gonum.org/v1/gonum/blas" 9 "gonum.org/v1/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 // 15 // Qᵀ * A * P = B. 16 // 17 // The diagonal elements of B are stored in d and the off-diagonal elements are stored 18 // in e. These are additionally stored along the diagonal of A and the off-diagonal 19 // of A. If m >= n B is an upper-bidiagonal matrix, and if m < n B is a 20 // lower-bidiagonal matrix. 21 // 22 // The remaining elements of A store the data needed to construct Q and P. 23 // The matrices Q and P are products of elementary reflectors 24 // 25 // if m >= n, Q = H_0 * H_1 * ... * H_{n-1}, 26 // P = G_0 * G_1 * ... * G_{n-2}, 27 // if m < n, Q = H_0 * H_1 * ... * H_{m-2}, 28 // P = G_0 * G_1 * ... * G_{m-1}, 29 // 30 // where 31 // 32 // H_i = I - tauQ[i] * v_i * v_iᵀ, 33 // G_i = I - tauP[i] * u_i * u_iᵀ. 34 // 35 // As an example, on exit the entries of A when m = 6, and n = 5 36 // 37 // [ d e u1 u1 u1] 38 // [v1 d e u2 u2] 39 // [v1 v2 d e u3] 40 // [v1 v2 v3 d e] 41 // [v1 v2 v3 v4 d] 42 // [v1 v2 v3 v4 v5] 43 // 44 // and when m = 5, n = 6 45 // 46 // [ d u1 u1 u1 u1 u1] 47 // [ e d u2 u2 u2 u2] 48 // [v1 e d u3 u3 u3] 49 // [v1 v2 e d u4 u4] 50 // [v1 v2 v3 e d u5] 51 // 52 // d, tauQ, and tauP must all have length at least min(m,n), and e must have 53 // length min(m,n) - 1, unless lwork is -1 when there is no check except for 54 // work which must have a length of at least one. 55 // 56 // work is temporary storage, and lwork specifies the usable memory length. 57 // At minimum, lwork >= max(1,m,n) or be -1 and this function will panic otherwise. 58 // Dgebrd is blocked decomposition, but the block size is limited 59 // by the temporary space available. If lwork == -1, instead of performing Dgebrd, 60 // the optimal work length will be stored into work[0]. 61 // 62 // Dgebrd is an internal routine. It is exported for testing purposes. 63 func (impl Implementation) Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int) { 64 switch { 65 case m < 0: 66 panic(mLT0) 67 case n < 0: 68 panic(nLT0) 69 case lda < max(1, n): 70 panic(badLdA) 71 case lwork < max(1, max(m, n)) && lwork != -1: 72 panic(badLWork) 73 case len(work) < max(1, lwork): 74 panic(shortWork) 75 } 76 77 // Quick return if possible. 78 minmn := min(m, n) 79 if minmn == 0 { 80 work[0] = 1 81 return 82 } 83 84 nb := impl.Ilaenv(1, "DGEBRD", " ", m, n, -1, -1) 85 lwkopt := (m + n) * nb 86 if lwork == -1 { 87 work[0] = float64(lwkopt) 88 return 89 } 90 91 switch { 92 case len(a) < (m-1)*lda+n: 93 panic(shortA) 94 case len(d) < minmn: 95 panic(shortD) 96 case len(e) < minmn-1: 97 panic(shortE) 98 case len(tauQ) < minmn: 99 panic(shortTauQ) 100 case len(tauP) < minmn: 101 panic(shortTauP) 102 } 103 104 nx := minmn 105 ws := max(m, n) 106 if 1 < nb && nb < minmn { 107 // At least one blocked operation can be done. 108 // Get the crossover point nx. 109 nx = max(nb, impl.Ilaenv(3, "DGEBRD", " ", m, n, -1, -1)) 110 // Determine when to switch from blocked to unblocked code. 111 if nx < minmn { 112 // At least one blocked operation will be done. 113 ws = (m + n) * nb 114 if lwork < ws { 115 // Not enough work space for the optimal nb, 116 // consider using a smaller block size. 117 nbmin := impl.Ilaenv(2, "DGEBRD", " ", m, n, -1, -1) 118 if lwork >= (m+n)*nbmin { 119 // Enough work space for minimum block size. 120 nb = lwork / (m + n) 121 } else { 122 nb = minmn 123 nx = minmn 124 } 125 } 126 } 127 } 128 bi := blas64.Implementation() 129 ldworkx := nb 130 ldworky := nb 131 var i int 132 for i = 0; i < minmn-nx; i += nb { 133 // Reduce rows and columns i:i+nb to bidiagonal form and return 134 // the matrices X and Y which are needed to update the unreduced 135 // part of the matrix. 136 // X is stored in the first m rows of work, y in the next rows. 137 x := work[:m*ldworkx] 138 y := work[m*ldworkx:] 139 impl.Dlabrd(m-i, n-i, nb, a[i*lda+i:], lda, 140 d[i:], e[i:], tauQ[i:], tauP[i:], 141 x, ldworkx, y, ldworky) 142 143 // Update the trailing submatrix A[i+nb:m,i+nb:n], using an update 144 // of the form A := A - V*Y**T - X*U**T 145 bi.Dgemm(blas.NoTrans, blas.Trans, m-i-nb, n-i-nb, nb, 146 -1, a[(i+nb)*lda+i:], lda, y[nb*ldworky:], ldworky, 147 1, a[(i+nb)*lda+i+nb:], lda) 148 149 bi.Dgemm(blas.NoTrans, blas.NoTrans, m-i-nb, n-i-nb, nb, 150 -1, x[nb*ldworkx:], ldworkx, a[i*lda+i+nb:], lda, 151 1, a[(i+nb)*lda+i+nb:], lda) 152 153 // Copy diagonal and off-diagonal elements of B back into A. 154 if m >= n { 155 for j := i; j < i+nb; j++ { 156 a[j*lda+j] = d[j] 157 a[j*lda+j+1] = e[j] 158 } 159 } else { 160 for j := i; j < i+nb; j++ { 161 a[j*lda+j] = d[j] 162 a[(j+1)*lda+j] = e[j] 163 } 164 } 165 } 166 // Use unblocked code to reduce the remainder of the matrix. 167 impl.Dgebd2(m-i, n-i, a[i*lda+i:], lda, d[i:], e[i:], tauQ[i:], tauP[i:], work) 168 work[0] = float64(ws) 169 }