gonum.org/v1/gonum@v0.14.0/lapack/gonum/dorgql.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 gonum 6 7 import ( 8 "gonum.org/v1/gonum/blas" 9 "gonum.org/v1/gonum/lapack" 10 ) 11 12 // Dorgql generates the m×n matrix Q with orthonormal columns defined as the 13 // last n columns of a product of k elementary reflectors of order m 14 // 15 // Q = H_{k-1} * ... * H_1 * H_0. 16 // 17 // It must hold that 18 // 19 // 0 <= k <= n <= m, 20 // 21 // and Dorgql will panic otherwise. 22 // 23 // On entry, the (n-k+i)-th column of A must contain the vector which defines 24 // the elementary reflector H_i, for i=0,...,k-1, and tau[i] must contain its 25 // scalar factor. On return, a contains the m×n matrix Q. 26 // 27 // tau must have length at least k, and Dorgql will panic otherwise. 28 // 29 // work must have length at least max(1,lwork), and lwork must be at least 30 // max(1,n), otherwise Dorgql will panic. For optimum performance lwork must 31 // be a sufficiently large multiple of n. 32 // 33 // If lwork == -1, instead of computing Dorgql the optimal work length is stored 34 // into work[0]. 35 // 36 // Dorgql is an internal routine. It is exported for testing purposes. 37 func (impl Implementation) Dorgql(m, n, k int, a []float64, lda int, tau, work []float64, lwork int) { 38 switch { 39 case m < 0: 40 panic(mLT0) 41 case n < 0: 42 panic(nLT0) 43 case n > m: 44 panic(nGTM) 45 case k < 0: 46 panic(kLT0) 47 case k > n: 48 panic(kGTN) 49 case lda < max(1, n): 50 panic(badLdA) 51 case lwork < max(1, n) && lwork != -1: 52 panic(badLWork) 53 case len(work) < max(1, lwork): 54 panic(shortWork) 55 } 56 57 // Quick return if possible. 58 if n == 0 { 59 work[0] = 1 60 return 61 } 62 63 nb := impl.Ilaenv(1, "DORGQL", " ", m, n, k, -1) 64 if lwork == -1 { 65 work[0] = float64(n * nb) 66 return 67 } 68 69 switch { 70 case len(a) < (m-1)*lda+n: 71 panic(shortA) 72 case len(tau) < k: 73 panic(shortTau) 74 } 75 76 nbmin := 2 77 var nx, ldwork int 78 iws := n 79 if 1 < nb && nb < k { 80 // Determine when to cross over from blocked to unblocked code. 81 nx = max(0, impl.Ilaenv(3, "DORGQL", " ", m, n, k, -1)) 82 if nx < k { 83 // Determine if workspace is large enough for blocked code. 84 iws = n * nb 85 if lwork < iws { 86 // Not enough workspace to use optimal nb: reduce nb and determine 87 // the minimum value of nb. 88 nb = lwork / n 89 nbmin = max(2, impl.Ilaenv(2, "DORGQL", " ", m, n, k, -1)) 90 } 91 ldwork = nb 92 } 93 } 94 95 var kk int 96 if nbmin <= nb && nb < k && nx < k { 97 // Use blocked code after the first block. The last kk columns are handled 98 // by the block method. 99 kk = min(k, ((k-nx+nb-1)/nb)*nb) 100 101 // Set A(m-kk:m, 0:n-kk) to zero. 102 for i := m - kk; i < m; i++ { 103 for j := 0; j < n-kk; j++ { 104 a[i*lda+j] = 0 105 } 106 } 107 } 108 109 // Use unblocked code for the first or only block. 110 impl.Dorg2l(m-kk, n-kk, k-kk, a, lda, tau, work) 111 if kk > 0 { 112 // Use blocked code. 113 for i := k - kk; i < k; i += nb { 114 ib := min(nb, k-i) 115 if n-k+i > 0 { 116 // Form the triangular factor of the block reflector 117 // H = H_{i+ib-1} * ... * H_{i+1} * H_i. 118 impl.Dlarft(lapack.Backward, lapack.ColumnWise, m-k+i+ib, ib, 119 a[n-k+i:], lda, tau[i:], work, ldwork) 120 121 // Apply H to A[0:m-k+i+ib, 0:n-k+i] from the left. 122 impl.Dlarfb(blas.Left, blas.NoTrans, lapack.Backward, lapack.ColumnWise, 123 m-k+i+ib, n-k+i, ib, a[n-k+i:], lda, work, ldwork, 124 a, lda, work[ib*ldwork:], ldwork) 125 } 126 127 // Apply H to rows 0:m-k+i+ib of current block. 128 impl.Dorg2l(m-k+i+ib, ib, ib, a[n-k+i:], lda, tau[i:], work) 129 130 // Set rows m-k+i+ib:m of current block to zero. 131 for j := n - k + i; j < n-k+i+ib; j++ { 132 for l := m - k + i + ib; l < m; l++ { 133 a[l*lda+j] = 0 134 } 135 } 136 } 137 } 138 work[0] = float64(iws) 139 }