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