github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/dgeqrf.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/lapack" 10 ) 11 12 // Dgeqrf computes the QR factorization of the m×n matrix A using a blocked 13 // algorithm. See the documentation for Dgeqr2 for a description of the 14 // parameters at entry and exit. 15 // 16 // work is temporary storage, and lwork specifies the usable memory length. 17 // The length of work must be at least max(1, lwork) and lwork must be -1 18 // or at least n, otherwise this function will panic. 19 // Dgeqrf is a blocked QR factorization, but the block size is limited 20 // by the temporary space available. If lwork == -1, instead of performing Dgeqrf, 21 // the optimal work length will be stored into work[0]. 22 // 23 // tau must have length at least min(m,n), and this function will panic otherwise. 24 func (impl Implementation) Dgeqrf(m, n int, a []float64, lda int, tau, work []float64, lwork int) { 25 if len(work) < max(1, lwork) { 26 panic(shortWork) 27 } 28 // nb is the optimal blocksize, i.e. the number of columns transformed at a time. 29 nb := impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1) 30 lworkopt := n * max(nb, 1) 31 lworkopt = max(n, lworkopt) 32 if lwork == -1 { 33 work[0] = float64(lworkopt) 34 return 35 } 36 checkMatrix(m, n, a, lda) 37 if lwork < n { 38 panic(badWork) 39 } 40 k := min(m, n) 41 if len(tau) < k { 42 panic(badTau) 43 } 44 if k == 0 { 45 work[0] = float64(lworkopt) 46 return 47 } 48 nbmin := 2 // Minimal block size. 49 var nx int // Use unblocked (unless changed in the next for loop) 50 iws := n 51 ldwork := nb 52 // Only consider blocked if the suggested block size is > 1 and the 53 // number of rows or columns is sufficiently large. 54 if 1 < nb && nb < k { 55 // nx is the block size at which the code switches from blocked 56 // to unblocked. 57 nx = max(0, impl.Ilaenv(3, "DGEQRF", " ", m, n, -1, -1)) 58 if k > nx { 59 iws = ldwork * n 60 if lwork < iws { 61 // Not enough workspace to use the optimal block 62 // size. Get the minimum block size instead. 63 nb = lwork / n 64 nbmin = max(2, impl.Ilaenv(2, "DGEQRF", " ", m, n, -1, -1)) 65 } 66 } 67 } 68 for i := range work { 69 work[i] = 0 70 } 71 // Compute QR using a blocked algorithm. 72 var i int 73 if nbmin <= nb && nb < k && nx < k { 74 for i = 0; i < k-nx; i += nb { 75 ib := min(k-i, nb) 76 // Compute the QR factorization of the current block. 77 impl.Dgeqr2(m-i, ib, a[i*lda+i:], lda, tau[i:], work) 78 if i+ib < n { 79 // Form the triangular factor of the block reflector and apply H^T 80 // In Dlarft, work becomes the T matrix. 81 impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib, 82 a[i*lda+i:], lda, 83 tau[i:], 84 work, ldwork) 85 impl.Dlarfb(blas.Left, blas.Trans, lapack.Forward, lapack.ColumnWise, 86 m-i, n-i-ib, ib, 87 a[i*lda+i:], lda, 88 work, ldwork, 89 a[i*lda+i+ib:], lda, 90 work[ib*ldwork:], ldwork) 91 } 92 } 93 } 94 // Call unblocked code on the remaining columns. 95 if i < k { 96 impl.Dgeqr2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work) 97 } 98 work[0] = float64(lworkopt) 99 }