gonum.org/v1/gonum@v0.14.0/lapack/gonum/dorgqr.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/lapack" 10 ) 11 12 // Dorgqr generates an m×n matrix Q with orthonormal columns defined by the 13 // product of elementary reflectors 14 // 15 // Q = H_0 * H_1 * ... * H_{k-1} 16 // 17 // as computed by Dgeqrf. 18 // Dorgqr is the blocked version of Dorg2r that makes greater use of level-3 BLAS 19 // routines. 20 // 21 // The length of tau must be at least k, and the length of work must be at least n. 22 // It also must be that 0 <= k <= n and 0 <= n <= m. 23 // 24 // work is temporary storage, and lwork specifies the usable memory length. At 25 // minimum, lwork >= n, and the amount of blocking is limited by the usable 26 // length. If lwork == -1, instead of computing Dorgqr the optimal work length 27 // is stored into work[0]. 28 // 29 // Dorgqr will panic if the conditions on input values are not met. 30 // 31 // Dorgqr is an internal routine. It is exported for testing purposes. 32 func (impl Implementation) Dorgqr(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) { 33 switch { 34 case m < 0: 35 panic(mLT0) 36 case n < 0: 37 panic(nLT0) 38 case n > m: 39 panic(nGTM) 40 case k < 0: 41 panic(kLT0) 42 case k > n: 43 panic(kGTN) 44 case lda < max(1, n) && lwork != -1: 45 // Normally, we follow the reference and require the leading 46 // dimension to be always valid, even in case of workspace 47 // queries. However, if a caller provided a placeholder value 48 // for lda (and a) when doing a workspace query that didn't 49 // fulfill the condition here, it would cause a panic. This is 50 // exactly what Dgesvd does. 51 panic(badLdA) 52 case lwork < max(1, n) && lwork != -1: 53 panic(badLWork) 54 case len(work) < max(1, lwork): 55 panic(shortWork) 56 } 57 58 if n == 0 { 59 work[0] = 1 60 return 61 } 62 63 nb := impl.Ilaenv(1, "DORGQR", " ", m, n, k, -1) 64 // work is treated as an n×nb matrix 65 if lwork == -1 { 66 work[0] = float64(n * nb) 67 return 68 } 69 70 switch { 71 case len(a) < (m-1)*lda+n: 72 panic(shortA) 73 case len(tau) < k: 74 panic(shortTau) 75 } 76 77 nbmin := 2 // Minimum block size 78 var nx int // Crossover size from blocked to unblocked code 79 iws := n // Length of work needed 80 var ldwork int 81 if 1 < nb && nb < k { 82 nx = max(0, impl.Ilaenv(3, "DORGQR", " ", m, n, k, -1)) 83 if nx < k { 84 ldwork = nb 85 iws = n * ldwork 86 if lwork < iws { 87 nb = lwork / n 88 ldwork = nb 89 nbmin = max(2, impl.Ilaenv(2, "DORGQR", " ", m, n, k, -1)) 90 } 91 } 92 } 93 var ki, kk int 94 if nbmin <= nb && nb < k && nx < k { 95 // The first kk columns are handled by the blocked method. 96 ki = ((k - nx - 1) / nb) * nb 97 kk = min(k, ki+nb) 98 for i := 0; i < kk; i++ { 99 for j := kk; j < n; j++ { 100 a[i*lda+j] = 0 101 } 102 } 103 } 104 if kk < n { 105 // Perform the operation on columns kk to the end. 106 impl.Dorg2r(m-kk, n-kk, k-kk, a[kk*lda+kk:], lda, tau[kk:], work) 107 } 108 if kk > 0 { 109 // Perform the operation on column-blocks. 110 for i := ki; i >= 0; i -= nb { 111 ib := min(nb, k-i) 112 if i+ib < n { 113 impl.Dlarft(lapack.Forward, lapack.ColumnWise, 114 m-i, ib, 115 a[i*lda+i:], lda, 116 tau[i:], 117 work, ldwork) 118 119 impl.Dlarfb(blas.Left, blas.NoTrans, lapack.Forward, lapack.ColumnWise, 120 m-i, n-i-ib, ib, 121 a[i*lda+i:], lda, 122 work, ldwork, 123 a[i*lda+i+ib:], lda, 124 work[ib*ldwork:], ldwork) 125 } 126 impl.Dorg2r(m-i, ib, ib, a[i*lda+i:], lda, tau[i:], work) 127 // Set rows 0:i-1 of current block to zero. 128 for j := i; j < i+ib; j++ { 129 for l := 0; l < i; l++ { 130 a[l*lda+j] = 0 131 } 132 } 133 } 134 } 135 work[0] = float64(iws) 136 }