All files dorgqr.js

71.59% Statements 126/176
61.53% Branches 8/13
100% Functions 1/1
71.59% Lines 126/176

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 1772x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 5x 5x 2x 2x 7x       2x 2x 2x 2x 2x 7x                             2x 7x                     7x 2x 2x 2x 2x 2x 2x 2x 2x 7x                                               2x 2x 2x 7x 2x 2x 2x 2x 2x  
/**
* @license Apache-2.0
*
* Copyright (c) 2026 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
'use strict';
 
/* eslint-disable max-len, max-params */
 
// MODULES //
 
var max = require( '@stdlib/math/base/special/max' );
var min = require( '@stdlib/math/base/special/min' );
var dorg2r = require( './dorg2r.js' );
var dlarfb = require( './dlarfb.js' );
var dlarft = require( './dlarft.js' );
 
 
// MAIN //
 
/**
* Generates an `M-by-N` real matrix `Q` with orthonormal columns, which is defined as the first `N` columns of a product of `K` elementary reflectors of order `M`.
*
* ## Notes
*
* -   On entry, the i-th column of A must contain the reflector vector for `H(i)`, as returned by DGEQRF.
* -   On exit, A contains the M-by-N orthogonal matrix Q.
* -   For optimum performance `LWORK >= N*NB`, where `NB` is the optimal blocksize.
* -   If `LWORK = -1`, then a workspace query is assumed.
* -   The routine only calculates the optimal size of the `WORK` array, returns this value as the first entry of the `WORK` array.
*
* @private
* @param {NonNegativeInteger} M - number of rows of `Q`
* @param {NonNegativeInteger} N - number of columns of `Q`
* @param {NonNegativeInteger} K - number of elementary reflectors whose product defines the matrix `Q`
* @param {Float64Array} A - input/output matrix
* @param {integer} strideA1 - stride length for the first dimension of `A`
* @param {integer} strideA2 - stride length for the second dimension of `A`
* @param {NonNegativeInteger} offsetA - starting index of `A`
* @param {Float64Array} TAU - scalar factors of reflectors
* @param {integer} strideTAU - stride length for `TAU`
* @param {NonNegativeInteger} offsetTAU - starting index of `TAU`
* @param {Float64Array} WORK - workspace array
* @param {integer} strideWORK - stride length for `WORK`
* @param {NonNegativeInteger} offsetWORK - starting index of `WORK`
* @param {NonNegativeInteger} LWORK - dimension of the array `WORK`
* @returns {integer} status code
*
* @example
* var Float64Array = require( '@stdlib/array/float64' );
*
* var A = new Float64Array( [ 1, 0, 0, 0, 1, 0 ] );
* var TAU = new Float64Array( [ 2, 2 ] );
* var WORK = new Float64Array( 10 );
*
* var info = dorgqr( 3, 2, 2, A, 1, 3, 0, TAU, 1, 0, WORK, 1, 0, 10 );
* // A => <Float64Array>[ -1, 0, 0, 0, -1, 0 ]
* // info => 0
* // WORK[ 0 ] => 2
*/
function dorgqr( M, N, K, A, strideA1, strideA2, offsetA, TAU, strideTAU, offsetTAU, WORK, strideWORK, offsetWORK, LWORK ) {
	var ldwork;
	var lwkopt;
	var lquery;
	var nbmin;
	var iws;
	var nb;
	var nx;
	var kk;
	var ki;
	var ib;
	var i;
	var j;
	var l;
 
	nb = 32; // The optimal blocksize derived from the Fortran LAPACK call `ilaenv( 1, 'DORGQR', ' ', m, n, k, -1 )`
	lwkopt = max( 1, N ) * nb;
	WORK[ offsetWORK ] = lwkopt;
	lquery = ( LWORK === -1 );
 
	if ( lquery ) {
		return 0;
	}
 
	// Quick return if possible
	if ( N === 0 ) {
		WORK[ offsetWORK ] = 1;
		return 0;
	}
 
	nbmin = 2;
	nx = 0;
	iws = N;
 
	if ( nb > 1 && nb < K ) {
		// Determine when to cross over from blocked to unblocked code.
		nx = 128; // The cross-over point derived from the Fortran LAPACK call `ilaenv( 3, 'DORGQR', ' ', m, n, k, -1 )`

		if ( nx < K ) {
			// Determine if workspace is large enough for blocked code
			ldwork = N;
			iws = ldwork * nb;
			if ( LWORK < iws ) {
				// Not enough workspace to use optimal NB: reduce NB and determine the minimum value of NB.
				nb = LWORK / ldwork;
				nbmin = 2; // The minimum block size derived from the Fortran LAPACK call `ilaenv( 2, 'DORGQR', ' ', m, n, k, -1 )`
			}
		}
	}
 
	if ( nb >= nbmin && nb < K && nx < K ) {
		// Use blocked code after the last block. The first kk columns are handled by the block method.
		ki = ( ( K - nx - 1 ) / nb ) * nb;
		kk = min( K, ki + nb );

		// Set A(1:kk,kk+1:n) to zero
		for ( j = kk; j < N; j++ ) {
			for ( i = 0; i < kk; i++ ) {
				A[ offsetA + ( i * strideA1 ) + ( j * strideA2 ) ] = 0;
			}
		}
	} else {
		kk = 0;
	}
 
	// Use unblocked code for the last or only block
	if ( kk < N ) {
		dorg2r( M - kk, N - kk, K - kk, A, strideA1, strideA2, offsetA + ( kk * strideA1 ) + ( kk * strideA2 ), TAU, strideTAU, offsetTAU + ( kk * strideTAU ), WORK, strideWORK, offsetWORK );
	}
 
	if ( kk > 0 ) {
		// Use blocked code
		for ( i = ki; i >= 0; i -= nb ) {
			ib = min( nb, K - i );

			if ( i + ib < N ) {
				// Form the triangular factor T of the block reflector H = H(i) H(i+1) . . . H(i+ib-1)
				dlarft( 'forward', 'columns', M - i, ib, A, strideA1, strideA2, offsetA + ( i * ( strideA1 + strideA2 ) ), TAU, strideTAU, offsetTAU + ( i * strideTAU ), WORK, 1, ldwork, offsetWORK );

				// Apply H to A(i:M-1, i+ib:N-1) from the left
				dlarfb( 'left', 'no-transpose', 'forward', 'columns', M - i, N - i - ib, ib, A, strideA1, strideA2, offsetA + ( i * ( strideA1 + strideA2 ) ), WORK, 1, ldwork, offsetWORK, A, strideA1, strideA2, offsetA + ( i * strideA1 ) + ( ( i + ib ) * strideA2 ), WORK, 1, ldwork, offsetWORK + ( ib * strideWORK ) );
			}

			// Apply H to rows i:m of current block
			dorg2r( M - i, ib, ib, A, strideA1, strideA2, offsetA + ( i * ( strideA1 + strideA2 ) ), TAU, strideTAU, offsetTAU + ( i * strideTAU ), WORK, 1, offsetWORK );

			// Set rows 1:i-1 of current block to zero
			for ( j = i; j < i + ib; j++ ) {
				for ( l = 0; l < i; l++ ) {
					A[ offsetA + ( l * strideA1 ) + ( j * strideA2 ) ] = 0;
				}
			}
		}
	}
 
	WORK[ offsetWORK ] = iws;
	return 0;
}
 
 
// EXPORTS //
 
module.exports = dorgqr;