gonum.org/v1/gonum@v0.14.0/lapack/gonum/dorgbr.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 "gonum.org/v1/gonum/lapack"
     8  
     9  // Dorgbr generates one of the matrices Q or Pᵀ computed by Dgebrd
    10  // computed from the decomposition Dgebrd. See Dgebd2 for the description of
    11  // Q and Pᵀ.
    12  //
    13  // If vect == lapack.GenerateQ, then a is assumed to have been an m×k matrix and
    14  // Q is of order m. If m >= k, then Dorgbr returns the first n columns of Q
    15  // where m >= n >= k. If m < k, then Dorgbr returns Q as an m×m matrix.
    16  //
    17  // If vect == lapack.GeneratePT, then A is assumed to have been a k×n matrix, and
    18  // Pᵀ is of order n. If k < n, then Dorgbr returns the first m rows of Pᵀ,
    19  // where n >= m >= k. If k >= n, then Dorgbr returns Pᵀ as an n×n matrix.
    20  //
    21  // Dorgbr is an internal routine. It is exported for testing purposes.
    22  func (impl Implementation) Dorgbr(vect lapack.GenOrtho, m, n, k int, a []float64, lda int, tau, work []float64, lwork int) {
    23  	wantq := vect == lapack.GenerateQ
    24  	mn := min(m, n)
    25  	switch {
    26  	case vect != lapack.GenerateQ && vect != lapack.GeneratePT:
    27  		panic(badGenOrtho)
    28  	case m < 0:
    29  		panic(mLT0)
    30  	case n < 0:
    31  		panic(nLT0)
    32  	case k < 0:
    33  		panic(kLT0)
    34  	case wantq && n > m:
    35  		panic(nGTM)
    36  	case wantq && n < min(m, k):
    37  		panic("lapack: n < min(m,k)")
    38  	case !wantq && m > n:
    39  		panic(mGTN)
    40  	case !wantq && m < min(n, k):
    41  		panic("lapack: m < min(n,k)")
    42  	case lda < max(1, n) && lwork != -1:
    43  		// Normally, we follow the reference and require the leading
    44  		// dimension to be always valid, even in case of workspace
    45  		// queries. However, if a caller provided a placeholder value
    46  		// for lda (and a) when doing a workspace query that didn't
    47  		// fulfill the condition here, it would cause a panic. This is
    48  		// exactly what Dgesvd does.
    49  		panic(badLdA)
    50  	case lwork < max(1, mn) && lwork != -1:
    51  		panic(badLWork)
    52  	case len(work) < max(1, lwork):
    53  		panic(shortWork)
    54  	}
    55  
    56  	// Quick return if possible.
    57  	work[0] = 1
    58  	if m == 0 || n == 0 {
    59  		return
    60  	}
    61  
    62  	if wantq {
    63  		if m >= k {
    64  			impl.Dorgqr(m, n, k, a, lda, tau, work, -1)
    65  		} else if m > 1 {
    66  			impl.Dorgqr(m-1, m-1, m-1, a[lda+1:], lda, tau, work, -1)
    67  		}
    68  	} else {
    69  		if k < n {
    70  			impl.Dorglq(m, n, k, a, lda, tau, work, -1)
    71  		} else if n > 1 {
    72  			impl.Dorglq(n-1, n-1, n-1, a[lda+1:], lda, tau, work, -1)
    73  		}
    74  	}
    75  	lworkopt := int(work[0])
    76  	lworkopt = max(lworkopt, mn)
    77  	if lwork == -1 {
    78  		work[0] = float64(lworkopt)
    79  		return
    80  	}
    81  
    82  	switch {
    83  	case len(a) < (m-1)*lda+n:
    84  		panic(shortA)
    85  	case wantq && len(tau) < min(m, k):
    86  		panic(shortTau)
    87  	case !wantq && len(tau) < min(n, k):
    88  		panic(shortTau)
    89  	}
    90  
    91  	if wantq {
    92  		// Form Q, determined by a call to Dgebrd to reduce an m×k matrix.
    93  		if m >= k {
    94  			impl.Dorgqr(m, n, k, a, lda, tau, work, lwork)
    95  		} else {
    96  			// Shift the vectors which define the elementary reflectors one
    97  			// column to the right, and set the first row and column of Q to
    98  			// those of the unit matrix.
    99  			for j := m - 1; j >= 1; j-- {
   100  				a[j] = 0
   101  				for i := j + 1; i < m; i++ {
   102  					a[i*lda+j] = a[i*lda+j-1]
   103  				}
   104  			}
   105  			a[0] = 1
   106  			for i := 1; i < m; i++ {
   107  				a[i*lda] = 0
   108  			}
   109  			if m > 1 {
   110  				// Form Q[1:m-1, 1:m-1]
   111  				impl.Dorgqr(m-1, m-1, m-1, a[lda+1:], lda, tau, work, lwork)
   112  			}
   113  		}
   114  	} else {
   115  		// Form Pᵀ, determined by a call to Dgebrd to reduce a k×n matrix.
   116  		if k < n {
   117  			impl.Dorglq(m, n, k, a, lda, tau, work, lwork)
   118  		} else {
   119  			// Shift the vectors which define the elementary reflectors one
   120  			// row downward, and set the first row and column of Pᵀ to
   121  			// those of the unit matrix.
   122  			a[0] = 1
   123  			for i := 1; i < n; i++ {
   124  				a[i*lda] = 0
   125  			}
   126  			for j := 1; j < n; j++ {
   127  				for i := j - 1; i >= 1; i-- {
   128  					a[i*lda+j] = a[(i-1)*lda+j]
   129  				}
   130  				a[j] = 0
   131  			}
   132  			if n > 1 {
   133  				impl.Dorglq(n-1, n-1, n-1, a[lda+1:], lda, tau, work, lwork)
   134  			}
   135  		}
   136  	}
   137  	work[0] = float64(lworkopt)
   138  }