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  }