github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/dlaqps.go (about)

     1  // Copyright ©2017 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 native
     6  
     7  import (
     8  	"math"
     9  
    10  	"github.com/gonum/blas"
    11  	"github.com/gonum/blas/blas64"
    12  )
    13  
    14  // Dlaqps computes a step of QR factorization with column pivoting
    15  // of an m×n matrix A by using Blas-3. It tries to factorize nb
    16  // columns from A starting from the row offset, and updates all
    17  // of the matrix with Dgemm.
    18  //
    19  // In some cases, due to catastrophic cancellations, it cannot
    20  // factorize nb columns. Hence, the actual number of factorized
    21  // columns is returned in kb.
    22  //
    23  // Dlaqps computes a QR factorization with column pivoting of the
    24  // block A[offset:m, 0:nb] of the m×n matrix A. The block
    25  // A[0:offset, 0:n] is accordingly pivoted, but not factorized.
    26  //
    27  // On exit, the upper triangle of block A[offset:m, 0:kb] is the
    28  // triangular factor obtained. The elements in block A[offset:m, 0:n]
    29  // below the diagonal, together with tau, represent the orthogonal
    30  // matrix Q as a product of elementary reflectors.
    31  //
    32  // offset is number of rows of the matrix A that must be pivoted but
    33  // not factorized. offset must not be negative otherwise Dlaqps will panic.
    34  //
    35  // On exit, jpvt holds the permutation that was applied; the jth column
    36  // of A*P was the jpvt[j] column of A. jpvt must have length n,
    37  // otherwise Dlapqs will panic.
    38  //
    39  // On exit tau holds the scalar factors of the elementary reflectors.
    40  // It must have length nb, otherwise Dlapqs will panic.
    41  //
    42  // vn1 and vn2 hold the partial and complete column norms respectively.
    43  // They must have length n, otherwise Dlapqs will panic.
    44  //
    45  // auxv must have length nb, otherwise Dlaqps will panic.
    46  //
    47  // f and ldf represent an n×nb matrix F that is overwritten during the
    48  // call.
    49  //
    50  // Dlaqps is an internal routine. It is exported for testing purposes.
    51  func (impl Implementation) Dlaqps(m, n, offset, nb int, a []float64, lda int, jpvt []int, tau, vn1, vn2, auxv, f []float64, ldf int) (kb int) {
    52  	checkMatrix(m, n, a, lda)
    53  	checkMatrix(n, nb, f, ldf)
    54  	if offset > m {
    55  		panic(offsetGTM)
    56  	}
    57  	if n < 0 || nb > n {
    58  		panic(badNb)
    59  	}
    60  	if len(jpvt) != n {
    61  		panic(badIpiv)
    62  	}
    63  	if len(tau) < nb {
    64  		panic(badTau)
    65  	}
    66  	if len(vn1) < n {
    67  		panic(badVn1)
    68  	}
    69  	if len(vn2) < n {
    70  		panic(badVn2)
    71  	}
    72  	if len(auxv) < nb {
    73  		panic(badAuxv)
    74  	}
    75  
    76  	lastrk := min(m, n+offset)
    77  	lsticc := -1
    78  	tol3z := math.Sqrt(dlamchE)
    79  
    80  	bi := blas64.Implementation()
    81  
    82  	var k, rk int
    83  	for ; k < nb && lsticc == -1; k++ {
    84  		rk = offset + k
    85  
    86  		// Determine kth pivot column and swap if necessary.
    87  		p := k + bi.Idamax(n-k, vn1[k:], 1)
    88  		if p != k {
    89  			bi.Dswap(m, a[p:], lda, a[k:], lda)
    90  			bi.Dswap(k, f[p*ldf:], 1, f[k*ldf:], 1)
    91  			jpvt[p], jpvt[k] = jpvt[k], jpvt[p]
    92  			vn1[p] = vn1[k]
    93  			vn2[p] = vn2[k]
    94  		}
    95  
    96  		// Apply previous Householder reflectors to column K:
    97  		//
    98  		// A[rk:m, k] = A[rk:m, k] - A[rk:m, 0:k-1]*F[k, 0:k-1]^T.
    99  		if k > 0 {
   100  			bi.Dgemv(blas.NoTrans, m-rk, k, -1,
   101  				a[rk*lda:], lda,
   102  				f[k*ldf:], 1,
   103  				1,
   104  				a[rk*lda+k:], lda)
   105  		}
   106  
   107  		// Generate elementary reflector H_k.
   108  		if rk < m-1 {
   109  			a[rk*lda+k], tau[k] = impl.Dlarfg(m-rk, a[rk*lda+k], a[(rk+1)*lda+k:], lda)
   110  		} else {
   111  			tau[k] = 0
   112  		}
   113  
   114  		akk := a[rk*lda+k]
   115  		a[rk*lda+k] = 1
   116  
   117  		// Compute kth column of F:
   118  		//
   119  		// Compute F[k+1:n, k] = tau[k]*A[rk:m, k+1:n]^T*A[rk:m, k].
   120  		if k < n-1 {
   121  			bi.Dgemv(blas.Trans, m-rk, n-k-1, tau[k],
   122  				a[rk*lda+k+1:], lda,
   123  				a[rk*lda+k:], lda,
   124  				0,
   125  				f[(k+1)*ldf+k:], ldf)
   126  		}
   127  
   128  		// Padding F[0:k, k] with zeros.
   129  		for j := 0; j < k; j++ {
   130  			f[j*ldf+k] = 0
   131  		}
   132  
   133  		// Incremental updating of F:
   134  		//
   135  		// F[0:n, k] := F[0:n, k] - tau[k]*F[0:n, 0:k-1]*A[rk:m, 0:k-1]^T*A[rk:m,k].
   136  		if k > 0 {
   137  			bi.Dgemv(blas.Trans, m-rk, k, -tau[k],
   138  				a[rk*lda:], lda,
   139  				a[rk*lda+k:], lda,
   140  				0,
   141  				auxv, 1)
   142  			bi.Dgemv(blas.NoTrans, n, k, 1,
   143  				f, ldf,
   144  				auxv, 1,
   145  				1,
   146  				f[k:], ldf)
   147  		}
   148  
   149  		// Update the current row of A:
   150  		//
   151  		// A[rk, k+1:n] = A[rk, k+1:n] - A[rk, 0:k]*F[k+1:n, 0:k]^T.
   152  		if k < n-1 {
   153  			bi.Dgemv(blas.NoTrans, n-k-1, k+1, -1,
   154  				f[(k+1)*ldf:], ldf,
   155  				a[rk*lda:], 1,
   156  				1,
   157  				a[rk*lda+k+1:], 1)
   158  		}
   159  
   160  		// Update partial column norms.
   161  		if rk < lastrk-1 {
   162  			for j := k + 1; j < n; j++ {
   163  				if vn1[j] == 0 {
   164  					continue
   165  				}
   166  
   167  				// The following marked lines follow from the
   168  				// analysis in Lapack Working Note 176.
   169  				r := math.Abs(a[rk*lda+j]) / vn1[j] // *
   170  				temp := math.Max(0, 1-r*r)          // *
   171  				r = vn1[j] / vn2[j]                 // *
   172  				temp2 := temp * r * r               // *
   173  				if temp2 < tol3z {
   174  					// vn2 is used here as a collection of
   175  					// indices into vn2 and also a collection
   176  					// of column norms.
   177  					vn2[j] = float64(lsticc)
   178  					lsticc = j
   179  				} else {
   180  					vn1[j] *= math.Sqrt(temp) // *
   181  				}
   182  			}
   183  		}
   184  
   185  		a[rk*lda+k] = akk
   186  	}
   187  	kb = k
   188  	rk = offset + kb
   189  
   190  	// Apply the block reflector to the rest of the matrix:
   191  	//
   192  	// A[offset+kb+1:m, kb+1:n] := A[offset+kb+1:m, kb+1:n] - A[offset+kb+1:m, 1:kb]*F[kb+1:n, 1:kb]^T.
   193  	if kb < min(n, m-offset) {
   194  		bi.Dgemm(blas.NoTrans, blas.Trans,
   195  			m-rk, n-kb, kb, -1,
   196  			a[rk*lda:], lda,
   197  			f[kb*ldf:], ldf,
   198  			1,
   199  			a[rk*lda+kb:], lda)
   200  	}
   201  
   202  	// Recomputation of difficult columns.
   203  	for lsticc >= 0 {
   204  		itemp := int(vn2[lsticc])
   205  
   206  		// NOTE: The computation of vn1[lsticc] relies on the fact that
   207  		// Dnrm2 does not fail on vectors with norm below the value of
   208  		// sqrt(dlamchS)
   209  		v := bi.Dnrm2(m-rk, a[rk*lda+lsticc:], lda)
   210  		vn1[lsticc] = v
   211  		vn2[lsticc] = v
   212  
   213  		lsticc = itemp
   214  	}
   215  
   216  	return kb
   217  }