gonum.org/v1/gonum@v0.14.0/lapack/gonum/dgebrd.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 gonum
     6  
     7  import (
     8  	"gonum.org/v1/gonum/blas"
     9  	"gonum.org/v1/gonum/blas/blas64"
    10  )
    11  
    12  // Dgebrd reduces a general m×n matrix A to upper or lower bidiagonal form B by
    13  // an orthogonal transformation:
    14  //
    15  //	Qᵀ * A * P = B.
    16  //
    17  // The diagonal elements of B are stored in d and the off-diagonal elements are stored
    18  // in e. These are additionally stored along the diagonal of A and the off-diagonal
    19  // of A. If m >= n B is an upper-bidiagonal matrix, and if m < n B is a
    20  // lower-bidiagonal matrix.
    21  //
    22  // The remaining elements of A store the data needed to construct Q and P.
    23  // The matrices Q and P are products of elementary reflectors
    24  //
    25  //	if m >= n, Q = H_0 * H_1 * ... * H_{n-1},
    26  //	           P = G_0 * G_1 * ... * G_{n-2},
    27  //	if m < n,  Q = H_0 * H_1 * ... * H_{m-2},
    28  //	           P = G_0 * G_1 * ... * G_{m-1},
    29  //
    30  // where
    31  //
    32  //	H_i = I - tauQ[i] * v_i * v_iᵀ,
    33  //	G_i = I - tauP[i] * u_i * u_iᵀ.
    34  //
    35  // As an example, on exit the entries of A when m = 6, and n = 5
    36  //
    37  //	[ d   e  u1  u1  u1]
    38  //	[v1   d   e  u2  u2]
    39  //	[v1  v2   d   e  u3]
    40  //	[v1  v2  v3   d   e]
    41  //	[v1  v2  v3  v4   d]
    42  //	[v1  v2  v3  v4  v5]
    43  //
    44  // and when m = 5, n = 6
    45  //
    46  //	[ d  u1  u1  u1  u1  u1]
    47  //	[ e   d  u2  u2  u2  u2]
    48  //	[v1   e   d  u3  u3  u3]
    49  //	[v1  v2   e   d  u4  u4]
    50  //	[v1  v2  v3   e   d  u5]
    51  //
    52  // d, tauQ, and tauP must all have length at least min(m,n), and e must have
    53  // length min(m,n) - 1, unless lwork is -1 when there is no check except for
    54  // work which must have a length of at least one.
    55  //
    56  // work is temporary storage, and lwork specifies the usable memory length.
    57  // At minimum, lwork >= max(1,m,n) or be -1 and this function will panic otherwise.
    58  // Dgebrd is blocked decomposition, but the block size is limited
    59  // by the temporary space available. If lwork == -1, instead of performing Dgebrd,
    60  // the optimal work length will be stored into work[0].
    61  //
    62  // Dgebrd is an internal routine. It is exported for testing purposes.
    63  func (impl Implementation) Dgebrd(m, n int, a []float64, lda int, d, e, tauQ, tauP, work []float64, lwork int) {
    64  	switch {
    65  	case m < 0:
    66  		panic(mLT0)
    67  	case n < 0:
    68  		panic(nLT0)
    69  	case lda < max(1, n):
    70  		panic(badLdA)
    71  	case lwork < max(1, max(m, n)) && lwork != -1:
    72  		panic(badLWork)
    73  	case len(work) < max(1, lwork):
    74  		panic(shortWork)
    75  	}
    76  
    77  	// Quick return if possible.
    78  	minmn := min(m, n)
    79  	if minmn == 0 {
    80  		work[0] = 1
    81  		return
    82  	}
    83  
    84  	nb := impl.Ilaenv(1, "DGEBRD", " ", m, n, -1, -1)
    85  	lwkopt := (m + n) * nb
    86  	if lwork == -1 {
    87  		work[0] = float64(lwkopt)
    88  		return
    89  	}
    90  
    91  	switch {
    92  	case len(a) < (m-1)*lda+n:
    93  		panic(shortA)
    94  	case len(d) < minmn:
    95  		panic(shortD)
    96  	case len(e) < minmn-1:
    97  		panic(shortE)
    98  	case len(tauQ) < minmn:
    99  		panic(shortTauQ)
   100  	case len(tauP) < minmn:
   101  		panic(shortTauP)
   102  	}
   103  
   104  	nx := minmn
   105  	ws := max(m, n)
   106  	if 1 < nb && nb < minmn {
   107  		// At least one blocked operation can be done.
   108  		// Get the crossover point nx.
   109  		nx = max(nb, impl.Ilaenv(3, "DGEBRD", " ", m, n, -1, -1))
   110  		// Determine when to switch from blocked to unblocked code.
   111  		if nx < minmn {
   112  			// At least one blocked operation will be done.
   113  			ws = (m + n) * nb
   114  			if lwork < ws {
   115  				// Not enough work space for the optimal nb,
   116  				// consider using a smaller block size.
   117  				nbmin := impl.Ilaenv(2, "DGEBRD", " ", m, n, -1, -1)
   118  				if lwork >= (m+n)*nbmin {
   119  					// Enough work space for minimum block size.
   120  					nb = lwork / (m + n)
   121  				} else {
   122  					nb = minmn
   123  					nx = minmn
   124  				}
   125  			}
   126  		}
   127  	}
   128  	bi := blas64.Implementation()
   129  	ldworkx := nb
   130  	ldworky := nb
   131  	var i int
   132  	for i = 0; i < minmn-nx; i += nb {
   133  		// Reduce rows and columns i:i+nb to bidiagonal form and return
   134  		// the matrices X and Y which are needed to update the unreduced
   135  		// part of the matrix.
   136  		// X is stored in the first m rows of work, y in the next rows.
   137  		x := work[:m*ldworkx]
   138  		y := work[m*ldworkx:]
   139  		impl.Dlabrd(m-i, n-i, nb, a[i*lda+i:], lda,
   140  			d[i:], e[i:], tauQ[i:], tauP[i:],
   141  			x, ldworkx, y, ldworky)
   142  
   143  		// Update the trailing submatrix A[i+nb:m,i+nb:n], using an update
   144  		// of the form  A := A - V*Y**T - X*U**T
   145  		bi.Dgemm(blas.NoTrans, blas.Trans, m-i-nb, n-i-nb, nb,
   146  			-1, a[(i+nb)*lda+i:], lda, y[nb*ldworky:], ldworky,
   147  			1, a[(i+nb)*lda+i+nb:], lda)
   148  
   149  		bi.Dgemm(blas.NoTrans, blas.NoTrans, m-i-nb, n-i-nb, nb,
   150  			-1, x[nb*ldworkx:], ldworkx, a[i*lda+i+nb:], lda,
   151  			1, a[(i+nb)*lda+i+nb:], lda)
   152  
   153  		// Copy diagonal and off-diagonal elements of B back into A.
   154  		if m >= n {
   155  			for j := i; j < i+nb; j++ {
   156  				a[j*lda+j] = d[j]
   157  				a[j*lda+j+1] = e[j]
   158  			}
   159  		} else {
   160  			for j := i; j < i+nb; j++ {
   161  				a[j*lda+j] = d[j]
   162  				a[(j+1)*lda+j] = e[j]
   163  			}
   164  		}
   165  	}
   166  	// Use unblocked code to reduce the remainder of the matrix.
   167  	impl.Dgebd2(m-i, n-i, a[i*lda+i:], lda, d[i:], e[i:], tauQ[i:], tauP[i:], work)
   168  	work[0] = float64(ws)
   169  }