gonum.org/v1/gonum@v0.14.0/lapack/gonum/dlahr2.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 ) 11 12 // Dlahr2 reduces the first nb columns of a real general n×(n-k+1) matrix A so 13 // that elements below the k-th subdiagonal are zero. The reduction is performed 14 // by an orthogonal similarity transformation Qᵀ * A * Q. Dlahr2 returns the 15 // matrices V and T which determine Q as a block reflector I - V*T*Vᵀ, and 16 // also the matrix Y = A * V * T. 17 // 18 // The matrix Q is represented as a product of nb elementary reflectors 19 // 20 // Q = H_0 * H_1 * ... * H_{nb-1}. 21 // 22 // Each H_i has the form 23 // 24 // H_i = I - tau[i] * v * vᵀ, 25 // 26 // where v is a real vector with v[0:i+k-1] = 0 and v[i+k-1] = 1. v[i+k:n] is 27 // stored on exit in A[i+k+1:n,i]. 28 // 29 // The elements of the vectors v together form the (n-k+1)×nb matrix 30 // V which is needed, with T and Y, to apply the transformation to the 31 // unreduced part of the matrix, using an update of the form 32 // 33 // A = (I - V*T*Vᵀ) * (A - Y*Vᵀ). 34 // 35 // On entry, a contains the n×(n-k+1) general matrix A. On return, the elements 36 // on and above the k-th subdiagonal in the first nb columns are overwritten 37 // with the corresponding elements of the reduced matrix; the elements below the 38 // k-th subdiagonal, with the slice tau, represent the matrix Q as a product of 39 // elementary reflectors. The other columns of A are unchanged. 40 // 41 // The contents of A on exit are illustrated by the following example 42 // with n = 7, k = 3 and nb = 2: 43 // 44 // [ a a a a a ] 45 // [ a a a a a ] 46 // [ a a a a a ] 47 // [ h h a a a ] 48 // [ v0 h a a a ] 49 // [ v0 v1 a a a ] 50 // [ v0 v1 a a a ] 51 // 52 // where a denotes an element of the original matrix A, h denotes a 53 // modified element of the upper Hessenberg matrix H, and vi denotes an 54 // element of the vector defining H_i. 55 // 56 // k is the offset for the reduction. Elements below the k-th subdiagonal in the 57 // first nb columns are reduced to zero. 58 // 59 // nb is the number of columns to be reduced. 60 // 61 // On entry, a represents the n×(n-k+1) matrix A. On return, the elements on and 62 // above the k-th subdiagonal in the first nb columns are overwritten with the 63 // corresponding elements of the reduced matrix. The elements below the k-th 64 // subdiagonal, with the slice tau, represent the matrix Q as a product of 65 // elementary reflectors. The other columns of A are unchanged. 66 // 67 // tau will contain the scalar factors of the elementary reflectors. It must 68 // have length at least nb. 69 // 70 // t and ldt represent the nb×nb upper triangular matrix T, and y and ldy 71 // represent the n×nb matrix Y. 72 // 73 // Dlahr2 is an internal routine. It is exported for testing purposes. 74 func (impl Implementation) Dlahr2(n, k, nb int, a []float64, lda int, tau, t []float64, ldt int, y []float64, ldy int) { 75 switch { 76 case n < 0: 77 panic(nLT0) 78 case k < 0: 79 panic(kLT0) 80 case nb < 0: 81 panic(nbLT0) 82 case nb > n: 83 panic(nbGTN) 84 case lda < max(1, n-k+1): 85 panic(badLdA) 86 case ldt < max(1, nb): 87 panic(badLdT) 88 case ldy < max(1, nb): 89 panic(badLdY) 90 } 91 92 // Quick return if possible. 93 if n < 0 { 94 return 95 } 96 97 switch { 98 case len(a) < (n-1)*lda+n-k+1: 99 panic(shortA) 100 case len(tau) < nb: 101 panic(shortTau) 102 case len(t) < (nb-1)*ldt+nb: 103 panic(shortT) 104 case len(y) < (n-1)*ldy+nb: 105 panic(shortY) 106 } 107 108 // Quick return if possible. 109 if n == 1 { 110 return 111 } 112 113 bi := blas64.Implementation() 114 var ei float64 115 for i := 0; i < nb; i++ { 116 if i > 0 { 117 // Update A[k:n,i]. 118 119 // Update i-th column of A - Y * Vᵀ. 120 bi.Dgemv(blas.NoTrans, n-k, i, 121 -1, y[k*ldy:], ldy, 122 a[(k+i-1)*lda:], 1, 123 1, a[k*lda+i:], lda) 124 125 // Apply I - V * Tᵀ * Vᵀ to this column (call it b) 126 // from the left, using the last column of T as 127 // workspace. 128 // Let V = [ V1 ] and b = [ b1 ] (first i rows) 129 // [ V2 ] [ b2 ] 130 // where V1 is unit lower triangular. 131 // 132 // w := V1ᵀ * b1. 133 bi.Dcopy(i, a[k*lda+i:], lda, t[nb-1:], ldt) 134 bi.Dtrmv(blas.Lower, blas.Trans, blas.Unit, i, 135 a[k*lda:], lda, t[nb-1:], ldt) 136 137 // w := w + V2ᵀ * b2. 138 bi.Dgemv(blas.Trans, n-k-i, i, 139 1, a[(k+i)*lda:], lda, 140 a[(k+i)*lda+i:], lda, 141 1, t[nb-1:], ldt) 142 143 // w := Tᵀ * w. 144 bi.Dtrmv(blas.Upper, blas.Trans, blas.NonUnit, i, 145 t, ldt, t[nb-1:], ldt) 146 147 // b2 := b2 - V2*w. 148 bi.Dgemv(blas.NoTrans, n-k-i, i, 149 -1, a[(k+i)*lda:], lda, 150 t[nb-1:], ldt, 151 1, a[(k+i)*lda+i:], lda) 152 153 // b1 := b1 - V1*w. 154 bi.Dtrmv(blas.Lower, blas.NoTrans, blas.Unit, i, 155 a[k*lda:], lda, t[nb-1:], ldt) 156 bi.Daxpy(i, -1, t[nb-1:], ldt, a[k*lda+i:], lda) 157 158 a[(k+i-1)*lda+i-1] = ei 159 } 160 161 // Generate the elementary reflector H_i to annihilate 162 // A[k+i+1:n,i]. 163 ei, tau[i] = impl.Dlarfg(n-k-i, a[(k+i)*lda+i], a[min(k+i+1, n-1)*lda+i:], lda) 164 a[(k+i)*lda+i] = 1 165 166 // Compute Y[k:n,i]. 167 bi.Dgemv(blas.NoTrans, n-k, n-k-i, 168 1, a[k*lda+i+1:], lda, 169 a[(k+i)*lda+i:], lda, 170 0, y[k*ldy+i:], ldy) 171 bi.Dgemv(blas.Trans, n-k-i, i, 172 1, a[(k+i)*lda:], lda, 173 a[(k+i)*lda+i:], lda, 174 0, t[i:], ldt) 175 bi.Dgemv(blas.NoTrans, n-k, i, 176 -1, y[k*ldy:], ldy, 177 t[i:], ldt, 178 1, y[k*ldy+i:], ldy) 179 bi.Dscal(n-k, tau[i], y[k*ldy+i:], ldy) 180 181 // Compute T[0:i,i]. 182 bi.Dscal(i, -tau[i], t[i:], ldt) 183 bi.Dtrmv(blas.Upper, blas.NoTrans, blas.NonUnit, i, 184 t, ldt, t[i:], ldt) 185 186 t[i*ldt+i] = tau[i] 187 } 188 a[(k+nb-1)*lda+nb-1] = ei 189 190 // Compute Y[0:k,0:nb]. 191 impl.Dlacpy(blas.All, k, nb, a[1:], lda, y, ldy) 192 bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, k, nb, 193 1, a[k*lda:], lda, y, ldy) 194 if n > k+nb { 195 bi.Dgemm(blas.NoTrans, blas.NoTrans, k, nb, n-k-nb, 196 1, a[1+nb:], lda, 197 a[(k+nb)*lda:], lda, 198 1, y, ldy) 199 } 200 bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.NonUnit, k, nb, 201 1, t, ldt, y, ldy) 202 }