gonum.org/v1/gonum@v0.14.0/lapack/gonum/dgehrd.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/blas/blas64" 10 "gonum.org/v1/gonum/lapack" 11 ) 12 13 // Dgehrd reduces a block of a real n×n general matrix A to upper Hessenberg 14 // form H by an orthogonal similarity transformation Qᵀ * A * Q = H. 15 // 16 // The matrix Q is represented as a product of (ihi-ilo) elementary 17 // reflectors 18 // 19 // Q = H_{ilo} H_{ilo+1} ... H_{ihi-1}. 20 // 21 // Each H_i has the form 22 // 23 // H_i = I - tau[i] * v * vᵀ 24 // 25 // where v is a real vector with v[0:i+1] = 0, v[i+1] = 1 and v[ihi+1:n] = 0. 26 // v[i+2:ihi+1] is stored on exit in A[i+2:ihi+1,i]. 27 // 28 // On entry, a contains the n×n general matrix to be reduced. On return, the 29 // upper triangle and the first subdiagonal of A will be overwritten with the 30 // upper Hessenberg matrix H, and the elements below the first subdiagonal, with 31 // the slice tau, represent the orthogonal matrix Q as a product of elementary 32 // reflectors. 33 // 34 // The contents of a are illustrated by the following example, with n = 7, ilo = 35 // 1 and ihi = 5. 36 // On entry, 37 // 38 // [ a a a a a a a ] 39 // [ a a a a a a ] 40 // [ a a a a a a ] 41 // [ a a a a a a ] 42 // [ a a a a a a ] 43 // [ a a a a a a ] 44 // [ a ] 45 // 46 // on return, 47 // 48 // [ a a h h h h a ] 49 // [ a h h h h a ] 50 // [ h h h h h h ] 51 // [ v1 h h h h h ] 52 // [ v1 v2 h h h h ] 53 // [ v1 v2 v3 h h h ] 54 // [ a ] 55 // 56 // where a denotes an element of the original matrix A, h denotes a 57 // modified element of the upper Hessenberg matrix H, and vi denotes an 58 // element of the vector defining H_i. 59 // 60 // ilo and ihi determine the block of A that will be reduced to upper Hessenberg 61 // form. It must hold that 0 <= ilo <= ihi < n if n > 0, and ilo == 0 and ihi == 62 // -1 if n == 0, otherwise Dgehrd will panic. 63 // 64 // On return, tau will contain the scalar factors of the elementary reflectors. 65 // Elements tau[:ilo] and tau[ihi:] will be set to zero. tau must have length 66 // equal to n-1 if n > 0, otherwise Dgehrd will panic. 67 // 68 // work must have length at least lwork and lwork must be at least max(1,n), 69 // otherwise Dgehrd will panic. On return, work[0] contains the optimal value of 70 // lwork. 71 // 72 // If lwork == -1, instead of performing Dgehrd, only the optimal value of lwork 73 // will be stored in work[0]. 74 // 75 // Dgehrd is an internal routine. It is exported for testing purposes. 76 func (impl Implementation) Dgehrd(n, ilo, ihi int, a []float64, lda int, tau, work []float64, lwork int) { 77 switch { 78 case n < 0: 79 panic(nLT0) 80 case ilo < 0 || max(0, n-1) < ilo: 81 panic(badIlo) 82 case ihi < min(ilo, n-1) || n <= ihi: 83 panic(badIhi) 84 case lda < max(1, n): 85 panic(badLdA) 86 case lwork < max(1, n) && lwork != -1: 87 panic(badLWork) 88 case len(work) < lwork: 89 panic(shortWork) 90 } 91 92 // Quick return if possible. 93 if n == 0 { 94 work[0] = 1 95 return 96 } 97 98 const ( 99 nbmax = 64 100 ldt = nbmax + 1 101 tsize = ldt * nbmax 102 ) 103 // Compute the workspace requirements. 104 nb := min(nbmax, impl.Ilaenv(1, "DGEHRD", " ", n, ilo, ihi, -1)) 105 lwkopt := n*nb + tsize 106 if lwork == -1 { 107 work[0] = float64(lwkopt) 108 return 109 } 110 111 if len(a) < (n-1)*lda+n { 112 panic(shortA) 113 } 114 if len(tau) != n-1 { 115 panic(badLenTau) 116 } 117 118 // Set tau[:ilo] and tau[ihi:] to zero. 119 for i := 0; i < ilo; i++ { 120 tau[i] = 0 121 } 122 for i := ihi; i < n-1; i++ { 123 tau[i] = 0 124 } 125 126 // Quick return if possible. 127 nh := ihi - ilo + 1 128 if nh <= 1 { 129 work[0] = 1 130 return 131 } 132 133 // Determine the block size. 134 nbmin := 2 135 var nx int 136 if 1 < nb && nb < nh { 137 // Determine when to cross over from blocked to unblocked code 138 // (last block is always handled by unblocked code). 139 nx = max(nb, impl.Ilaenv(3, "DGEHRD", " ", n, ilo, ihi, -1)) 140 if nx < nh { 141 // Determine if workspace is large enough for blocked code. 142 if lwork < n*nb+tsize { 143 // Not enough workspace to use optimal nb: 144 // determine the minimum value of nb, and reduce 145 // nb or force use of unblocked code. 146 nbmin = max(2, impl.Ilaenv(2, "DGEHRD", " ", n, ilo, ihi, -1)) 147 if lwork >= n*nbmin+tsize { 148 nb = (lwork - tsize) / n 149 } else { 150 nb = 1 151 } 152 } 153 } 154 } 155 ldwork := nb // work is used as an n×nb matrix. 156 157 var i int 158 if nb < nbmin || nh <= nb { 159 // Use unblocked code below. 160 i = ilo 161 } else { 162 // Use blocked code. 163 bi := blas64.Implementation() 164 iwt := n * nb // Size of the matrix Y and index where the matrix T starts in work. 165 for i = ilo; i < ihi-nx; i += nb { 166 ib := min(nb, ihi-i) 167 168 // Reduce columns [i:i+ib] to Hessenberg form, returning the 169 // matrices V and T of the block reflector H = I - V*T*Vᵀ 170 // which performs the reduction, and also the matrix Y = A*V*T. 171 impl.Dlahr2(ihi+1, i+1, ib, a[i:], lda, tau[i:], work[iwt:], ldt, work, ldwork) 172 173 // Apply the block reflector H to A[:ihi+1,i+ib:ihi+1] from the 174 // right, computing A := A - Y * Vᵀ. V[i+ib,i+ib-1] must be set 175 // to 1. 176 ei := a[(i+ib)*lda+i+ib-1] 177 a[(i+ib)*lda+i+ib-1] = 1 178 bi.Dgemm(blas.NoTrans, blas.Trans, ihi+1, ihi-i-ib+1, ib, 179 -1, work, ldwork, 180 a[(i+ib)*lda+i:], lda, 181 1, a[i+ib:], lda) 182 a[(i+ib)*lda+i+ib-1] = ei 183 184 // Apply the block reflector H to A[0:i+1,i+1:i+ib-1] from the 185 // right. 186 bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, i+1, ib-1, 187 1, a[(i+1)*lda+i:], lda, work, ldwork) 188 for j := 0; j <= ib-2; j++ { 189 bi.Daxpy(i+1, -1, work[j:], ldwork, a[i+j+1:], lda) 190 } 191 192 // Apply the block reflector H to A[i+1:ihi+1,i+ib:n] from the 193 // left. 194 impl.Dlarfb(blas.Left, blas.Trans, lapack.Forward, lapack.ColumnWise, 195 ihi-i, n-i-ib, ib, 196 a[(i+1)*lda+i:], lda, work[iwt:], ldt, a[(i+1)*lda+i+ib:], lda, work, ldwork) 197 } 198 } 199 // Use unblocked code to reduce the rest of the matrix. 200 impl.Dgehd2(n, i, ihi, a, lda, tau, work) 201 work[0] = float64(lwkopt) 202 }