* Add CX factorization (expert) routines ?GECXX (Reference-LAPACK PR 1161)
1715 lines
63 KiB
FortranFixed
1715 lines
63 KiB
FortranFixed
*> \brief \b DGECXX computes a CX factorization of a real M-by-N matrix A using a truncated (rank k) Householder QR factorization with column pivoting.
|
|
*
|
|
* =========== DOCUMENTATION ===========
|
|
*
|
|
* Online html documentation available at
|
|
* http://www.netlib.org/lapack/explore-html/
|
|
*
|
|
*> \htmlonly
|
|
*> Download DGECXX + dependencies
|
|
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgecxx.f">
|
|
*> [TGZ]</a>
|
|
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgecxx.f">
|
|
*> [ZIP]</a>
|
|
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgecxx.f">
|
|
*> [TXT]</a>
|
|
*> \endhtmlonly
|
|
*
|
|
* Definition:
|
|
* ===========
|
|
*
|
|
* SUBROUTINE DGECXX( FACT, USESD, M, N,
|
|
* $ DESEL_ROWS, SEL_DESEL_COLS,
|
|
* $ KMAXFREE, ABSTOL, RELTOL, A, LDA,
|
|
* $ K, MAXC2NRMK, RELMAXC2NRMK, FNRMK,
|
|
* $ IPIV, JPIV, TAU, C, LDC, QRC, LDQRC,
|
|
* $ X, LDX, WORK, LWORK, IWORK, LIWORK, INFO )
|
|
* IMPLICIT NONE
|
|
*
|
|
* .. Scalar Arguments ..
|
|
* CHARACTER FACT, USESD
|
|
* INTEGER INFO, K, KMAXFREE, LDA, LDC, LDQRC,
|
|
* $ LDX, LIWORK, LWORK, M, N
|
|
* DOUBLE PRECISION ABSTOL, FNRMK, MAXC2NRMK,
|
|
* $ RELMAXC2NRMK, RELTOL
|
|
* ..
|
|
* .. Array Arguments ..
|
|
* INTEGER DESEL_ROWS( * ), IPIV( * ), IWORK( * ),
|
|
* $ JPIV( * ), SEL_DESEL_COLS( * )
|
|
* DOUBLE PRECISION A( LDA, * ), C( LDC, * ), QRC( LDQRC, * ),
|
|
* $ TAU( * ), WORK( * ), X( LDX, *)
|
|
* ..
|
|
*
|
|
*
|
|
*> \par Purpose:
|
|
* =============
|
|
*>
|
|
*> \verbatim
|
|
*>
|
|
*> DGECXX computes a CX factorization of a real M-by-N matrix A using
|
|
*> a truncated rank-K Householder QR factorization with a column
|
|
*> pivoting algorithm, which is implemented in the DGEQP3RK routine.
|
|
*>
|
|
*> A * P = C*X + A_resid, where
|
|
*>
|
|
*> C is an M-by-K matrix consisting of K columns selected
|
|
*> from the original matrix A,
|
|
*>
|
|
*> X is a K-by-N matrix that minimizes the Frobenius norm of the
|
|
*> residual matrix A_resid, X = pseudoinv(C) * A,
|
|
*>
|
|
*> P is an N-by-N permutation matrix chosen so that the first
|
|
*> K columns of A*P equal C,
|
|
*>
|
|
*> A_resid is an M-by-N residual matrix.
|
|
*>
|
|
*> The column selection for the matrix C has two stages.
|
|
*>
|
|
*> Column preselection stage 1 (optional).
|
|
*> =======================================
|
|
*>
|
|
*> The user can select N_sel columns and deselect N_desel columns
|
|
*> of the matrix A that MUST be included and excluded respectively
|
|
*> from the matrix C a priori, before running the column selection
|
|
*> algorithm. This is controlled by flags in the array
|
|
*> SEL_DESEL_COLS. The deselected columns are permuted to the right
|
|
*> side of the matrix A and selected columns are permuted to the left
|
|
*> side of the matrix A. The details of the column permutation
|
|
*> (i.e. the column permutation matrix P) are stored in the
|
|
*> array JPIV. This feature can be used when the goal is to approximate
|
|
*> the deselected columns by linear combinations of K selected columns,
|
|
*> where the K columns MUST include the N_sel preselected columns.
|
|
*>
|
|
*> Column selection stage 2.
|
|
*> =========================
|
|
*>
|
|
*> The routine runs a column selection algorithm that can
|
|
*> be controlled by three stopping criteria described below.
|
|
*> For column selection, the routine uses a truncated (rank-K)
|
|
*> Householder QR factorization with column pivoting algorithm using
|
|
*> the routine DGEQP3RK.
|
|
*>
|
|
*> Optionally, before running the column selection
|
|
*> algorithm, the user can deselect M_desel rows of the matrix A that
|
|
*> should NOT be considered by the column selection algorithm (i.e.
|
|
*> during the factorization). This is controlled by flags in
|
|
*> the array DESEL_ROWS. The deselected rows are permuted to the
|
|
*> bottom of the matrix A. The details of the row permutation (i.e. the
|
|
*> row permutation matrix) are stored in the array IPIV. This feature
|
|
*> can be used when the goal is to use the deselected rows as test data,
|
|
*> and the selected rows as training data.
|
|
*>
|
|
*> This means that the column selection factorization algorithm is
|
|
*> effectively running on the submatrix A_sub = A(1:M_sub,1:N_sub) of
|
|
*> the matrix A after the permutations described above. Here M_sub is
|
|
*> the number of rows of the matrix A minus the number of deselected
|
|
*> rows M_desel, i.e. M_sub = M - M_desel, and N_sub is the number
|
|
*> of columns of the matrix A minus the number of deselected columns
|
|
*> N_desel, i.e. N_sub = N - N_desel.
|
|
*>
|
|
*> The reported column selection error metrics MAXC2NRMK, RELMAXC2NRMK
|
|
*> and FNRMK described below are computed using only A_sub.
|
|
*>
|
|
*> Column selection criteria.
|
|
*> ==========================
|
|
*>
|
|
*> The column selection criteria (i.e. when to stop the factorization)
|
|
*> can be any of the following:
|
|
*>
|
|
*> 1) KMAXFREE: This input parameter specifies the maximum number of
|
|
*> columns to factorize in addition to the N_sel preselected
|
|
*> columns. The factorization rank is limited to N_sel + KMAXFREE.
|
|
*> If N_sel + KMAXFREE >= min(M_sub, N_sub), this criterion
|
|
*> is not used.
|
|
*>
|
|
*> 2) ABSTOL: This input parameter specifies the absolute tolerance
|
|
*> for the maximum column 2-norm of the submatrix residual
|
|
*> A_sub_resid(K) = A_sub(K)(K+1:M_sub, K+1:N_sub), where
|
|
*> A_sub(K) denotes the contents of the array
|
|
*> A_sub = A(1:M_sub, 1:N_sub) after K columns were factorized.
|
|
*> This means that the factorization stops if this norm is less
|
|
*> than or equal to ABSTOL. If ABSTOL < 0.0, this criterion is
|
|
*> not used.
|
|
*>
|
|
*> 3) RELTOL: This input parameter specifies the tolerance for
|
|
*> the maximum column 2-norm of the submatrix residual
|
|
*> A_sub_resid(K) = A_sub(K)(K+1:M_sub, K+1:N_sub) divided
|
|
*> by the maximum column 2-norm of the submatrix
|
|
*> A_sub = A(1:M_sub, 1:N_sub), where A_sub(K) denotes the contents
|
|
*> of the array A_sub after K columns were factorized.
|
|
*> This means that the factorization stops when the ratio of the
|
|
*> maximum column 2-norm of A_sub_resid(K) to the maximum column
|
|
*> 2-norm of A_sub is less than or equal to RELTOL.
|
|
*> If RELTOL < 0.0, this criterion is not used.
|
|
*>
|
|
*> The algorithm stops when any of these conditions is first
|
|
*> satisfied, otherwise the entire submatrix A_sub is factorized.
|
|
*>
|
|
*> To perform a full-rank factorization of the matrix A_sub, use
|
|
*> selection criteria that satisfy N_sel + KMAXFREE >= min(M_sub,N_sub)
|
|
*> and ABSTOL < 0.0 and RELTOL < 0.0.
|
|
*>
|
|
*> If the user wishes to verify that the columns of the matrix C are
|
|
*> sufficiently linearly independent for their intended use, the user
|
|
*> can compute the condition number of its R factor by calling DTRCON
|
|
*> on the upper-triangular part of QRC(1:K,1:K) in the output
|
|
*> array QRC.
|
|
*>
|
|
*> How N_sel affects the column selection algorithm.
|
|
*> =================================================
|
|
*>
|
|
*> As mentioned above, the N_sel preselected columns are permuted to the
|
|
*> left side of the matrix A, and will be included in the column
|
|
*> selection. Then the routine factorizes that block A(1:M_sub,1:N_sel),
|
|
*> and if any of the three stopping criteria is met immediately after
|
|
*> factoring the first N_sel columns the routine exits
|
|
*> (i.e. if the user does not want to select KMAXFREE > 0 extra columns,
|
|
*> or if the absolute or relative tolerance of the maximum column 2-norm
|
|
*> of the residual is satisfied). In this case, the number
|
|
*> of selected columns would be K = N_sel. Otherwise, the factorization
|
|
*> routine finds a new column to select with the maximum column 2-norm
|
|
*> in the residual A(N_sel+1:M_sub,N_sel+1:N_sub), and swaps that
|
|
*> column with the first column of A(1:M,N_sel+1:N_sub). Then the
|
|
*> routine checks if the stopping criteria are met in the next residual
|
|
*> A(N_sel+2:M_sub,N_sel+2:N_sub), and so on.
|
|
*>
|
|
*> Computation of the matrix factors.
|
|
*> ==================================
|
|
*>
|
|
*> When the columns are selected for the factor C, and:
|
|
*> (a) If the flag FACT = 'P', the routine returns only the indices of
|
|
*> the selected columns from the original matrix A, which are
|
|
*> stored in the first K elements of the JPIV array.
|
|
*> (b) If the flag FACT = 'C', then in addition to (a), the routine
|
|
*> explicitly returns the matrix C in the array C.
|
|
*> (c) If the flag FACT = 'X', then in addition to (a) and (b),
|
|
*> the routine explicitly computes and returns the factor
|
|
*> X = pseudoinv(C) * A in the array X, and it also returns
|
|
*> the factor R alongside the Householder vectors
|
|
*> of the QR factorization of the matrix C in the array QRC.
|
|
*>
|
|
*> \endverbatim
|
|
*
|
|
* Arguments:
|
|
* ==========
|
|
*
|
|
*> \param[in] FACT
|
|
*> \verbatim
|
|
*> FACT is CHARACTER*1
|
|
*> The flag specifies how the factors of a CX factorization
|
|
*> are returned.
|
|
*>
|
|
*> = 'P': the routine returns:
|
|
*> (1) only the column permutation matrix P in
|
|
*> the array JPIV.
|
|
*> (The first K elements of the array JPIV
|
|
*> contain indices of the columns that were
|
|
*> selected from the matrix A to form the
|
|
*> factor C.)
|
|
*> (fastest option, smallest memory space)
|
|
*>
|
|
*> = 'C': the routine returns:
|
|
*> (1) the column permutation matrix P
|
|
*> in the array JPIV. (The first K elements are
|
|
*> indices of the selected columns from
|
|
*> the matrix A.)
|
|
*> (2) the M-by-K factor C explicitly in the array C.
|
|
*> (slower option, more memory space)
|
|
*>
|
|
*> = 'X': the routine returns:
|
|
*> (1) the column permutation matrix P in
|
|
*> the array JPIV. (The first K elements are
|
|
*> indices of the selected columns from
|
|
*> the matrix A.)
|
|
*> (2) the M-by-K factor C explicitly in the array C.
|
|
*> (3) the K-by-N factor X explicitly in the array X.
|
|
*> (4) the K-by-K upper triangular factor R and
|
|
*> the Householder vectors of the QR factorization
|
|
*> of the factor C in the array QRC.
|
|
*> ( The factor R may be useful for checking
|
|
*> the factor C for singularity, in which case
|
|
*> R will have a zero on the diagonal, and
|
|
*> the factor X cannot be computed. )
|
|
*> (slowest option, largest memory space)
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] USESD
|
|
*> \verbatim
|
|
*> USESD is CHARACTER*1
|
|
*> The flag specifies whether the row deselection and column
|
|
*> preselection-deselection functionality is turned ON or OFF.
|
|
*>
|
|
*> = 'N': Both row deselection and column
|
|
*> preselection-deselection are OFF.
|
|
*> Both arrays DESEL_ROWS and SEL_DESEL_COLS
|
|
*> are not used.
|
|
*>
|
|
*> = 'R': Only row deselection is ON.
|
|
*> Column preselection-deselection is OFF.
|
|
*> The array SEL_DESEL_COLS is not used.
|
|
*>
|
|
*> = 'C': Only column preselection-deselection is ON.
|
|
*> Row deselection is OFF.
|
|
*> The array DESEL_ROWS is not used.
|
|
*>
|
|
*> = 'A': Means "All". Both row deselection and column
|
|
*> preselection-deselection are ON.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] M
|
|
*> \verbatim
|
|
*> M is INTEGER
|
|
*> The number of rows of the matrix A. M >= 0.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] N
|
|
*> \verbatim
|
|
*> N is INTEGER
|
|
*> The number of columns of the matrix A. N >= 0.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in,out] DESEL_ROWS
|
|
*> \verbatim
|
|
*> DESEL_ROWS is INTEGER array, dimension (M)
|
|
*> DESEL_ROWS is only accessed if USESD = 'R' or 'A'.
|
|
*> This is a row deselection mask array that separates
|
|
*> the rows of matrix A into 2 sets.
|
|
*>
|
|
*> On entry:
|
|
*> a) If DESEL_ROWS(i) = -1, the i-th row of the matrix A is
|
|
*> deselected by the user, i.e. chosen to be excluded from
|
|
*> the column selection algorithm (in both preselection and
|
|
*> selection stages) and will be permuted to the bottom
|
|
*> of the matrix A.
|
|
*> The number of deselected rows is denoted by M_desel.
|
|
*>
|
|
*> b) If DESEL_ROWS(i) is not equal -1,
|
|
*> the i-th row of A will be used in the column selection
|
|
*> algorithm (in both preselection and selection stages).
|
|
*> This defines a set of M_sub = M - M_desel rows that
|
|
*> the algorithm will use to select columns.
|
|
*> After the permutation, this set will be at the top
|
|
*> of the matrix A.
|
|
*>
|
|
*> On exit:
|
|
*> DESEL_ROWS will be permuted according to IPIV(i),
|
|
*> so that, if IPIV(i) = k, then the entry i of DESEL_ROWS
|
|
*> on exit was the entry k of DESEL_ROWS on entry.
|
|
*>
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in,out] SEL_DESEL_COLS
|
|
*> \verbatim
|
|
*> SEL_DESEL_COLS is INTEGER array, dimension (N)
|
|
*> SEL_DESEL_COLS is only accessed if USESD = 'C' or 'A'.
|
|
*> This is a column preselection-deselection mask array that
|
|
*> separates the columns of matrix A into 3 sets.
|
|
*>
|
|
*> On entry:
|
|
*> a) If SEL_DESEL_COLS(j) = +1, the j-th column of the matrix
|
|
*> A is preselected by the user to be included
|
|
*> in the factor C and will be permuted to the left side
|
|
*> of the array A. The number of selected columns is
|
|
*> denoted by N_sel.
|
|
*>
|
|
*> b) If SEL_DESEL_COLS(j) = -1, the j-th column of the matrix
|
|
*> A is deselected by the user, i.e. chosen to be excluded
|
|
*> from the factor C and will be permuted to the right side
|
|
*> of the array A. The number of deselected columns is
|
|
*> denoted by N_desel.
|
|
*>
|
|
*> c) If SEL_DESEL_COLS(j) is not equal to 1 and not equal
|
|
*> to -1, the j-th column of A is a free column and will be
|
|
*> used by the column selection algorithm to determine if
|
|
*> this column will be selected. This defines a set of
|
|
*> columns of size N_free = N - N_sel - N_desel.
|
|
*>
|
|
*> On exit:
|
|
*> SEL_DESEL_COLS will be permuted according to JPIV(j),
|
|
*> so that, if JPIV(j) = k, then the entry j
|
|
*> of SEL_DESEL_COLS on exit was the entry k
|
|
*> of SEL_DESEL_COLS on entry.
|
|
*>
|
|
*> NOTE: An error returned as INFO = -6 means that the number
|
|
*> of preselected N_sel columns is larger than M_sub.
|
|
*> Therefore, the QR factorization of all N_sel preselected
|
|
*> columns cannot be completed.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] KMAXFREE
|
|
*> \verbatim
|
|
*> KMAXFREE is INTEGER, KMAXFREE >= 0.
|
|
*>
|
|
*> The first column selection stopping criterion from
|
|
*> the N_free columns (N_sel+1:N_sub) of the submatrix
|
|
*> A_sub = A(1:M_sub, 1:N_sub) in the column selection stage 2.
|
|
*>
|
|
*> KMAXFREE is the maximum number of columns of the matrix
|
|
*> A_free = A(N_sel+1:M_sub, N_sel+1:N_sub) to select
|
|
*> during the column selection stage 2.
|
|
*>
|
|
*> KMAXFREE does not include the preselected N_sel columns.
|
|
*> N_sel + KMAXFREE is the maximum factorization rank of
|
|
*> the matrix A_sub.
|
|
*>
|
|
*> a) If N_sel + KMAXFREE >= min(M_sub, N_sub), then this
|
|
*> stopping criterion is not used, i.e. columns are
|
|
*> selected in the factorization stage 2 depending
|
|
*> on ABSTOL and RELTOL.
|
|
*>
|
|
*> b) If KMAXFREE = 0, then this stopping criterion is
|
|
*> satisfied on input and the routine exits without
|
|
*> performing column selection stage 2
|
|
*> on the submatrix A_sub. This means that the matrix
|
|
*> A_free = A(N_sel+1:M_sub, N_sel+1:N_sub) is not modified
|
|
*> in the column selection stage 2
|
|
*> and A_free is itself the residual for the factorization.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] ABSTOL
|
|
*> \verbatim
|
|
*> ABSTOL is DOUBLE PRECISION, cannot be NaN.
|
|
*>
|
|
*> The second column selection stopping criterion from
|
|
*> the N_free columns (N_sel+1:N_sub) of the submatrix
|
|
*> A_sub = A(1:M_sub, 1:N_sub) in the column selection stage 2.
|
|
*>
|
|
*> ABSTOL is the absolute tolerance (stopping threshold)
|
|
*> for maxcol2norm(A_sub_resid(K)), where K >= N_sel.
|
|
*>
|
|
*> maxcol2norm(A_sub_resid(K)) is the maximum column 2-norm
|
|
*> of the residual matrix
|
|
*> A_sub_resid(K) = A_sub(K)(K+1:M_sub, K+1:N_sub)
|
|
*> when K columns have been factorized.
|
|
*> The column selection algorithm converges
|
|
*> (stops the factorization) when
|
|
*> maxcol2norm(A_sub_resid(K)) <= ABSTOL, where K >= N_sel.
|
|
*>
|
|
*> In the following,
|
|
*> SAFMIN = DLAMCH('S'),
|
|
*> A_free = A(N_sel+1:M_sub, N_sel+1:N_sub),
|
|
*> maxcol2norm(A_free) is the maximum column 2-norm
|
|
*> of the matrix A_free.
|
|
*>
|
|
*> a) If ABSTOL is NaN, then no computation is performed
|
|
*> and an error message ( INFO = -8 ) is issued
|
|
*> by XERBLA.
|
|
*>
|
|
*> b) If ABSTOL < 0.0, then this stopping criterion is not
|
|
*> used, and the column selection algorithm stops
|
|
*> the factorization of A_free depending
|
|
*> on KMAXFREE and RELTOL.
|
|
*> This includes the case where ABSTOL = -Inf.
|
|
*>
|
|
*> c) If 0.0 <= ABSTOL < 2*SAFMIN, then ABSTOL = 2*SAFMIN
|
|
*> is used. This includes the case where ABSTOL = -0.0.
|
|
*>
|
|
*> d) If 2*SAFMIN <= ABSTOL then the input value
|
|
*> of ABSTOL is used.
|
|
*>
|
|
*> If ABSTOL chosen above is >= maxcol2norm(A_free), then
|
|
*> this stopping criterion is satisfied on input, and
|
|
*> the routine only preselects K = N_sel columns. The leftmost
|
|
*> preselected N_sel columns in the submatrix
|
|
*> A_sub = A(1:M_sub, 1:N_sub) are factorized. The routine
|
|
*> then computes maxcol2norm(A_free) and returns it
|
|
*> in MAXC2NORMK, computes and returns RELMAXC2NORMK of A_free,
|
|
*> and exits immediately.
|
|
*> This means that the factorization residual
|
|
*> A_sub_resid(N_sel) = A_free = A(N_sel+1:M_sub,N_sel+1:N_sub)
|
|
*> is not modified in the column selection stage 2.
|
|
*> This includes the case where ABSTOL = +Inf.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] RELTOL
|
|
*> \verbatim
|
|
*> RELTOL is DOUBLE PRECISION, cannot be NaN.
|
|
*>
|
|
*> The third column selection stopping criterion from
|
|
*> the N_free columns (N_sel+1:N_sub) of the submatrix
|
|
*> A_sub = A(1:M_sub, 1:N_sub) in the column selection stage 2.
|
|
*>
|
|
*> RELTOL is the tolerance (stopping threshold) for the ratio
|
|
*> relmaxcol2norm(A_sub_resid(K)) =
|
|
*> = maxcol2norm(A_sub_resid(K))/maxcol2norm(A_sub),
|
|
*> where K >= N_sel.
|
|
*>
|
|
*> maxcol2norm(A_sub_resid(K)) is the maximum column 2-norm
|
|
*> of the residual matrix
|
|
*> A_sub_resid(K) = A_sub(K)(K+1:M_sub, K+1:N_sub)
|
|
*> when K columns have been factorized.
|
|
*> maxcol2norm(A_sub) is the maximum column 2-norm
|
|
*> of the original submatrix A_sub = A(1:M_sub, 1:N_sub).
|
|
*> The column selection algorithm converges
|
|
*> (stops the factorization) when the ratio
|
|
*> relmaxcol2norm(A_sub_resid(K)) <= RELTOL, where K >= N_sel.
|
|
*>
|
|
*> In the following,
|
|
*> EPS = DLAMCH('E'),
|
|
*> A_free = A(N_sel+1:M_sub, N_sel+1:N_sub).
|
|
*>
|
|
*> a) If RELTOL is NaN, then no computation is performed
|
|
*> and an error message ( INFO = -9 ) is issued
|
|
*> by XERBLA.
|
|
*>
|
|
*> b) If RELTOL < 0.0, then this stopping criterion is not
|
|
*> used and the column selection algorithm stops
|
|
*> the factorization of A_free depending
|
|
*> on KMAXFREE and ABSTOL.
|
|
*> This includes the case RELTOL = -Inf.
|
|
*>
|
|
*> c) If 0.0 <= RELTOL < EPS, then RELTOL = EPS is used.
|
|
*> This includes the case RELTOL = -0.0.
|
|
*>
|
|
*> d) If EPS <= RELTOL then the input value of RELTOL
|
|
*> is used.
|
|
*>
|
|
*> If RELTOL chosen above is >= 1.0, then this stopping
|
|
*> criterion is satisfied on input, and the routine
|
|
*> only preselects K = N_sel columns. The leftmost
|
|
*> preselected N_sel columns in the submatrix
|
|
*> A_sub = A(1:M_sub, 1:N_sub) are factorized.
|
|
*> The routine then computes maxcol2norm(A_free) and returns
|
|
*> it in MAXC2NORMK, returns RELMAXC2NORMK as 1.0, and exits
|
|
*> immediately.
|
|
*> This means that the factorization residual
|
|
*> A_sub_resid(N_sel) = A_free = A(N_sel+1:M_sub,N_sel+1:N_sub)
|
|
*> is not modified.
|
|
*> This includes the case RELTOL = +Inf.
|
|
*>
|
|
*> NOTE: We recommend RELTOL to satisfy
|
|
*> min(max(M_sub,N_sub)*EPS, sqrt(EPS)) <= RELTOL
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in,out] A
|
|
*> \verbatim
|
|
*> A is DOUBLE PRECISION array, dimension (LDA,N)
|
|
*>
|
|
*> On entry:
|
|
*> the M-by-N matrix A.
|
|
*>
|
|
*> On exit:
|
|
*>
|
|
*> NOTE:
|
|
*> The output parameter K, the number of selected
|
|
*> columns, is described later.
|
|
*> A_sub = A(1:M_sub, 1:N_sub).
|
|
*>
|
|
*> 1) If K = 0, A(1:M,1:N) contains the original matrix A.
|
|
*>
|
|
*> 2) If K > 0, A(1:M,1:N) contains the following parts:
|
|
*>
|
|
*> (a) If M_sub < M (which is the same as M_desel > 0),
|
|
*> the subarray A(M_sub+1:M,1:N) contains the deselected
|
|
*> rows.
|
|
*>
|
|
*> (b) If N_sub < N ( which is the same as N_desel > 0 ),
|
|
*> the subarray A(1:M,N_sub+1:N) contains the
|
|
*> deselected columns.
|
|
*>
|
|
*> (c) If N_sel > 0,
|
|
*> the union of the subarray A(1:M_sub, 1:N_sel)
|
|
*> and the subarray A(1:N_sel, 1:N_sub) contains parts
|
|
*> of the factors obtained by computing Householder QR
|
|
*> factorization WITHOUT column pivoting of N_sel
|
|
*> preselected columns using the routine DGEQRF.
|
|
*>
|
|
*> (d) The subarray A(N_sel+1:M_sub, N_sel+1:N_sub)
|
|
*> contains parts of the factors obtained by computing
|
|
*> a truncated (rank K) Householder QR factorization with
|
|
*> column pivoting using the routine DGEQP3RK on
|
|
*> the matrix A_free = A(N_sel+1:M_sub, N_sel+1:N_sub),
|
|
*> which is the result of applying selection and
|
|
*> deselection of columns, applying deselection of rows
|
|
*> to the original matrix A, and applying orthogonal
|
|
*> transformation from the factorization of the first
|
|
*> N_sel columns as described in part (c).
|
|
*>
|
|
*> 1. The elements below the diagonal of the subarray
|
|
*> A_sub(1:M_sub,1:K) together with TAU(1:K)
|
|
*> represent the orthogonal matrix Q(K) as a
|
|
*> product of K Householder elementary reflectors.
|
|
*>
|
|
*> 2. The elements on and above the diagonal of
|
|
*> the subarray A_sub(1:K,1:N_sub) contain the
|
|
*> K-by-N_sub upper-trapezoidal matrix
|
|
*> R_sub_approx(K) = ( R_sub11(K), R_sub12(K) ).
|
|
*> NOTE: If K = min(M_sub,N_sub), i.e. full rank
|
|
*> factorization, then R_sub_approx(K) is the
|
|
*> full factor R which is upper-trapezoidal.
|
|
*> If, in addition, M_sub >= N_sub, then R is
|
|
*> upper-triangular.
|
|
*>
|
|
*> 3. The subarray A_sub(K+1:M_sub,K+1:N_sub) contains
|
|
*> the (M_sub-K)-by-(N_sub-K) rectangular matrix
|
|
*> A_sub_resid(K) = A_sub(K)(K+1:M_sub, K+1:N_sub).
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] LDA
|
|
*> \verbatim
|
|
*> LDA is INTEGER
|
|
*> The leading dimension of the array A. LDA >= max(1,M).
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] K
|
|
*> \verbatim
|
|
*> K is INTEGER
|
|
*> The number of columns that were selected
|
|
*> (K is the factorization rank).
|
|
*> 0 <= K <= min( M_sub, N_sel+KMAXFREE, N_sub ).
|
|
*>
|
|
*> NOTE: If K = 0, a) the arrays A is not, modified.
|
|
*> b) the array TAU(1,min(M_sub,N_sub))
|
|
*> is set to ZERO.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] MAXC2NRMK
|
|
*> \verbatim
|
|
*> MAXC2NRMK is DOUBLE PRECISION
|
|
*> The maximum column 2-norm of the residual matrix
|
|
*> A_sub_resid(K) = A_sub(K)(K+1:M_sub, K+1:N_sub),
|
|
*> when factorization stopped at rank K. MAXC2NRMK >= 0.
|
|
*>
|
|
*> a) If K = 0, i.e. the factorization was not performed, so
|
|
*> the matrix A_sub = A(1:M_sub, 1:N_sub) was not modified
|
|
*> and is itself a residual matrix, then MAXC2NRMK equals
|
|
*> the maximum column 2-norm of the original matrix A_sub.
|
|
*>
|
|
*> b) If 0 < K < min(M_sub, N_sub), then MAXC2NRMK is returned.
|
|
*>
|
|
*> c) If K = min(M_sub, N_sub), i.e. the whole matrix A_sub was
|
|
*> factorized and there is no residual matrix,
|
|
*> then MAXC2NRMK = 0.0.
|
|
*>
|
|
*> NOTE: MAXC2NRMK at the factorization step K is equal
|
|
*> to the diagonal element R_sub(K+1,K+1) of the factor
|
|
*> R_sub in the next factorization step K+1.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] RELMAXC2NRMK
|
|
*> \verbatim
|
|
*> RELMAXC2NRMK is DOUBLE PRECISION
|
|
*> The ratio MAXC2NRMK / MAXC2NRM
|
|
*> of the maximum column 2-norm MAXC2NRMK of the residual
|
|
*> matrix A_sub_resid(K) = A_sub(K+1:M_sub, K+1:N_sub) (when
|
|
*> factorization stopped at rank K) and maximum column 2-norm
|
|
*> MAXC2NRM of the matrix A_sub = A(1:M_sub, 1:N_sub).
|
|
*> RELMAXC2NRMK >= 0.
|
|
*>
|
|
*> a) If K = 0, i.e. the factorization was not performed,
|
|
*> the matrix A_sub was not modified
|
|
*> and is itself a residual matrix,
|
|
*> then RELMAXC2NRMK = 1.0.
|
|
*>
|
|
*> b) If 0 < K < min(M_sub,N_sub), then
|
|
*> RELMAXC2NRMK = MAXC2NRMK / MAXC2NRM is returned.
|
|
*>
|
|
*> c) If K = min(M_sub,N_sub), i.e. the whole matrix A_sub was
|
|
*> factorized and there is no residual matrix
|
|
*> A_sub_resid(K), then RELMAXC2NRMK = 0.0.
|
|
*>
|
|
*> NOTE: RELMAXC2NRMK at the factorization step K would equal
|
|
*> abs(R_sub(K+1,K+1))/MAXC2NRM in the next
|
|
*> factorization step K+1, where R_sub(K+1,K+1) is the
|
|
*> diagonal element of the factor R_sub in the next
|
|
*> factorization step K+1.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] FNRMK
|
|
*> \verbatim
|
|
*> FNRMK is DOUBLE PRECISION
|
|
*> Frobenius norm of the residual matrix
|
|
*> A_sub_resid(K) = A_sub(K+1:M_sub, K+1:N_sub).
|
|
*> FNRMK >= 0.0
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] IPIV
|
|
*> \verbatim
|
|
*> IPIV is INTEGER array, dimension (M)
|
|
*> Row permutation indices due to row deselection,
|
|
*> for 1 <= i <= M.
|
|
*> If IPIV(i) = k, then the row i of A was
|
|
*> the row k of A.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] JPIV
|
|
*> \verbatim
|
|
*> JPIV is INTEGER array, dimension (N)
|
|
*> Column permutation indices, for 1 <= j <= N.
|
|
*> If JPIV(j)= k, then the column j of A*P was
|
|
*> the column k of A.
|
|
*>
|
|
*> The first K elements of the array JPIV contain
|
|
*> indices of the columns of the factor C that were selected
|
|
*> from the matrix A.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] TAU
|
|
*> \verbatim
|
|
*> TAU is DOUBLE PRECISION array, dimension (min(M_sub,N_sub))
|
|
*> The scalar factors of the elementary reflectors.
|
|
*>
|
|
*> If K = 0, all elements TAU(1:min(M_sub,N_sub)) are set
|
|
*> to zero.
|
|
*> If 0 < K <= min(M_sub,N_sub):
|
|
*> only the elements TAU(1:K) may be modified,
|
|
*> the elements TAU(K+1:min(M_sub,N_sub)) are set to zero.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] C
|
|
*> \verbatim
|
|
*> C is DOUBLE PRECISION array.
|
|
*>
|
|
*> If FACT = 'P':
|
|
*> the array is not used, the array dimension >= (1,1).
|
|
*>
|
|
*> If FACT = 'C':
|
|
*> the array dimension is (LDC,N).
|
|
*> If K = 0:
|
|
*> the M-by-N array C contains a copy of
|
|
*> the original M-by-N matrix A.
|
|
*> If K > 0:
|
|
*> a) columns (1:K) of the array C contain
|
|
*> the M-by-K factor C (the selected columns
|
|
*> from the original matrix A).
|
|
*> b) columns (K+1:N) of the array C contain
|
|
*> the deselected columns from the original
|
|
*> matrix A.
|
|
*>
|
|
*> If FACT = 'X':
|
|
*> the array dimension is (LDC,N).
|
|
*> If K = 0:
|
|
*> the M-by-N array C is not used.
|
|
*> If K > 0:
|
|
*> a) columns (1:K) of the array C contain
|
|
*> the M-by-K factor C (the selected columns
|
|
*> from the original matrix A).
|
|
*> b) columns (K+1:N) of the array C are
|
|
*> not used.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] LDC
|
|
*> \verbatim
|
|
*> LDC is INTEGER
|
|
*> The leading dimension of the array C.
|
|
*> If FACT = 'P', LDC >= 1.
|
|
*> If FACT = 'C' or 'X', LDC >= max(1,M).
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] QRC
|
|
*> \verbatim
|
|
*> QRC is DOUBLE PRECISION array.
|
|
*>
|
|
*> If FACT = 'P' or 'C': The array is not used,
|
|
*> the array dimension is >= (1,1).
|
|
*>
|
|
*> If FACT = 'X': the array dimension is (LDQRC,min(M,N)).
|
|
*>
|
|
*> If K = 0, the array is not used.
|
|
*> If K > 0, QRC(1:M,1:K) stores two components from
|
|
*> the QR factorization of the factor C. The K-by-K
|
|
*> factor R is stored in the upper triangle.
|
|
*> The Householder vectors are stored in the lower
|
|
*> trapezoid below the diagonal.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] LDQRC
|
|
*> \verbatim
|
|
*> LDQRC is INTEGER
|
|
*> The leading dimension of the array QRC.
|
|
*> If FACT = 'P' or 'C', LDQRC >= 1.
|
|
*> If FACT = 'X', LDQRC >= max(1,M).
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] X
|
|
*> \verbatim
|
|
*> X is DOUBLE PRECISION array.
|
|
*> If FACT = 'P' or 'C': The array is not used,
|
|
*> the array dimension is >= (1,1).
|
|
*>
|
|
*> If FACT = 'X': The array dimension is (LDX,N).
|
|
*> 1) If K = 0:
|
|
*> the M-by-N array X contains a copy of
|
|
*> the original M-by-N matrix A.
|
|
*> 2) If K > 0:
|
|
*> a) rows (1:K) of the M-by-N array X contain
|
|
*> the K-by-N factor X, where K <= N.
|
|
*> b) rows (K+1:M) of the M-by-N array X.
|
|
*> Each column of these rows contains the elements
|
|
*> whose sum of squares is the residual sum of
|
|
*> squares for the solution in each column of
|
|
*> the least squares problem.
|
|
*> min|| A - C*X ||_F for the unknown X.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] LDX
|
|
*> \verbatim
|
|
*> LDX is INTEGER
|
|
*> The leading dimension of the array X.
|
|
*> If FACT = 'P' or 'C', LDX >= 1.
|
|
*> If FACT = 'X', LDX >= max(1,M).
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] WORK
|
|
*> \verbatim
|
|
*> WORK is DOUBLE PRECISION array, dimension (max(1,LWORK)).
|
|
*>
|
|
*> On exit, if INFO >= 0, WORK(1) returns the optimal LWORK.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] LWORK
|
|
*> \verbatim
|
|
*> LWORK is INTEGER
|
|
*> The dimension of the array WORK.
|
|
*>
|
|
*> Minimal LWORK workspace general requirement.
|
|
*> LWORK >= max( 1, 3*N - 1 ) would be sufficient for all
|
|
*> values of FACT and USESD flags.
|
|
*>
|
|
*> For good performance, LWORK should generally be larger, and
|
|
*> the user should query the routine for the optimal LWORK.
|
|
*>
|
|
*> If LWORK = -1 or LIWORK =-1 then a workspace query is
|
|
*> assumed. The routine only calculates the optimal size of
|
|
*> the WORK and IWORK arrays, returns these values as the
|
|
*> first entry of the WORK and IWORK arrays respectively, and
|
|
*> no error message related to LWORK is issued by XERBLA.
|
|
*>
|
|
*> Exact minimal workspace requirements.
|
|
*> For USESD = 'N' or 'R' and for all FACT:
|
|
*> LWORK >= max( 1, 3*N - 1 )
|
|
*> For USESD = 'C' or 'A':
|
|
*> a) If FACT = 'P' or 'C':
|
|
*> LWORK >= max( 1, N_sub, min(1,MINMNFREE)*(3*N_free-1) )
|
|
*> b) If FACT = 'X':
|
|
*> LWORK >= max( 1, min(M,N)+N,
|
|
*> min(1,MINMNFREE)*(3*N_free-1) )
|
|
*> where MINMNFREE = min( M_free, N_free ).
|
|
*>
|
|
*> NOTE: The decision, whether the routine uses unblocked
|
|
*> BLAS 2 or blocked BLAS 3 code is based not only on the
|
|
*> dimension LWORK of the available workspace WORK, but
|
|
*> also on:
|
|
*> 1a) column preselection stage using DGEQRF:
|
|
*> the optimal block size NB, the crossover point NX
|
|
*> returned by ILAENV for the routine DGEQRF
|
|
*> in comparison to N_sel. (For N_sel <= NX
|
|
*> or N_sel <= NB, unblocked code is used in DGEQRF.)
|
|
*> 1b) column preselection stage using DORMQR:
|
|
*> the optimal block size NB returned by ILAENV for
|
|
*> the routine DORMQR in comparison to N_sel. (For
|
|
*> N_sel <= NB, unblocked code is used in DORMQR.)
|
|
*> 2) column selection stage via criteria using DGEQRP3RK:
|
|
*> the optimal block size NB, the crossover point NX
|
|
*> returned by ILAENV for the routine DGEQRP3RK
|
|
*> in comparison to min(M,N_sel). (For
|
|
*> min(M_sub, N_free, KMAXFREE) <= NX
|
|
*> or min(M_sub, N_free, KMAXFREE) <= NB, unblocked code
|
|
*> is used in DGEQRP3RK.)
|
|
*> 3a) computation of the factor X using DGEQRF in DGELS:
|
|
*> the optimal block size NB, the crossover point NX
|
|
*> returned by ILAENV for the routine DGEQRF
|
|
*> in comparison to K. (For K <= NX or K <= NB,
|
|
*> unblocked code is used in DGEQRF inside DGELS.)
|
|
*> 3b) computation of the factor X using DORMQR in DGELS:
|
|
*> the optimal block size NB returned by ILAENV for
|
|
*> the routine DORMQR in comparison to N. (For
|
|
*> N <= NB, unblocked code is used in DORMQR
|
|
*> inside DGELS.)
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] IWORK
|
|
*> \verbatim
|
|
*> IWORK is INTEGER array, dimension (max(1,LIWORK)).
|
|
*>
|
|
*> On exit, if INFO >= 0, IWORK(1) returns the optimal LIWORK.
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[in] LIWORK
|
|
*> \verbatim
|
|
*> LIWORK is INTEGER
|
|
*> The dimension of the array IWORK.
|
|
*>
|
|
*> Minimal LIWORK workspace general requirement.
|
|
*> LIWORK >= max( 1, 2*N ) would be sufficient for all values
|
|
*> of FACT and USESD flags.
|
|
*>
|
|
*> The optimal LIWORK is the same as the minimal LIWORK.
|
|
*> The user can still query the routine for the optimal LIWORK.
|
|
*>
|
|
*> If LWORK = -1 or LIWORK =-1 then a workspace query is
|
|
*> assumed. The routine only calculates the optimal size of
|
|
*> the WORK and IWORK arrays, returns these values as the first
|
|
*> entry of the WORK and IWORK arrays respectively, and no
|
|
*> error message related to LIWORK is issued by XERBLA.
|
|
*>
|
|
*> Exact minimal workspace requirements.
|
|
*> For USESD = 'N' or 'R':
|
|
*> a) If FACT = 'P':
|
|
*> LIWORK >= max( 1, N-1 )
|
|
*> b) If FACT = 'C' or 'X':
|
|
*> LIWORK >= max( 1, 2*N )
|
|
*> For USESD = 'C' or 'A':
|
|
*> a) If FACT = 'P':
|
|
*> LIWORK >= max( 1, (N_free-1) + min(1,N_sel)*N_free )
|
|
*> b) If FACT = 'C' or 'X':
|
|
*> LIWORK >= max( 1, 2*N )
|
|
*> \endverbatim
|
|
*>
|
|
*> \param[out] INFO
|
|
*> \verbatim
|
|
*> INFO is INTEGER
|
|
*> = 0: successful exit.
|
|
*> < 0: if INFO = -i, the i-th argument had an illegal value.
|
|
*> > 0: if INFO = i, the i-th diagonal element of the
|
|
*> triangular R factor of the QR factorization of
|
|
*> the matrix C is zero. Consequently, C does not have
|
|
*> full rank, and X cannot be computed as the least
|
|
*> squares solution to the overdetermined system C*X = A.
|
|
*> (R is stored in the array QRC.)
|
|
*> \endverbatim
|
|
*
|
|
* Authors:
|
|
* ========
|
|
*
|
|
*> \author Univ. of Tennessee
|
|
*> \author Univ. of California Berkeley
|
|
*> \author Univ. of Colorado Denver
|
|
*> \author NAG Ltd.
|
|
*
|
|
*> \par Contributors:
|
|
* ==================
|
|
*>
|
|
*> \verbatim
|
|
*>
|
|
*> April 2026, Igor Kozachenko, James Demmel,
|
|
*> EECS Department,
|
|
*> University of California, Berkeley, USA.
|
|
*> \endverbatim
|
|
*
|
|
*> \ingroup gecxx
|
|
*
|
|
* =====================================================================
|
|
SUBROUTINE DGECXX( FACT, USESD, M, N,
|
|
$ DESEL_ROWS, SEL_DESEL_COLS,
|
|
$ KMAXFREE, ABSTOL, RELTOL, A, LDA,
|
|
$ K, MAXC2NRMK, RELMAXC2NRMK, FNRMK,
|
|
$ IPIV, JPIV, TAU, C, LDC, QRC, LDQRC,
|
|
$ X, LDX, WORK, LWORK, IWORK, LIWORK, INFO )
|
|
IMPLICIT NONE
|
|
*
|
|
* -- LAPACK computational routine --
|
|
* -- LAPACK is a software package provided by Univ. of Tennessee, --
|
|
* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
|
|
*
|
|
* .. Scalar Arguments ..
|
|
CHARACTER FACT, USESD
|
|
INTEGER INFO, K, KMAXFREE, LDA, LDC, LDQRC,
|
|
$ LDX, LIWORK, LWORK, M, N
|
|
DOUBLE PRECISION ABSTOL, FNRMK, MAXC2NRMK,
|
|
$ RELMAXC2NRMK, RELTOL
|
|
* ..
|
|
* .. Array Arguments ..
|
|
INTEGER DESEL_ROWS( * ), IPIV( * ), IWORK( * ),
|
|
$ JPIV( * ), SEL_DESEL_COLS( * )
|
|
DOUBLE PRECISION A( LDA, * ), C( LDC, * ), QRC( LDQRC, * ),
|
|
$ TAU( * ), WORK( * ), X( LDX, *)
|
|
* ..
|
|
*
|
|
* =====================================================================
|
|
*
|
|
* .. Parameters ..
|
|
DOUBLE PRECISION ZERO, TWO, MINUSONE
|
|
PARAMETER ( ZERO = 0.0D+0, TWO = 2.0D+0,
|
|
$ MINUSONE = -1.0D+0 )
|
|
* ..
|
|
* .. Local Scalars ..
|
|
LOGICAL LQUERY, RETURNC, RETURNX,
|
|
$ USE_DESEL_ROWS, USE_SEL_DESEL_COLS, USETOL
|
|
INTEGER I, IP, IINFO, ITEMP, J, JDESEL, JP, KFREE,
|
|
$ KMAXLS, KP0, LIWKMIN, LIWKOPT, LWKMIN,
|
|
$ LWKOPT, MFREE, MDESEL, MINMN, MINMNFREE,
|
|
$ MRESID, MSUB, NFREE, NDESEL, NRESID, NSEL,
|
|
$ NSUB
|
|
DOUBLE PRECISION ABSTOLFREE, EPS, MAXC2NRM, MAXC2NRMKFREE,
|
|
$ RELTOLFREE, RELMAXC2NRMKFREE, SAFMIN
|
|
|
|
* .. External Subroutines ..
|
|
EXTERNAL DCOPY, DGELS, DGEQP3RK, DGEQRF, DLACPY,
|
|
$ DORMQR, DSWAP, XERBLA
|
|
* ..
|
|
* .. External Functions ..
|
|
LOGICAL DISNAN, LSAME
|
|
INTEGER IDAMAX, ILAENV
|
|
DOUBLE PRECISION DLAMCH, DLANGE, DNRM2
|
|
EXTERNAL DISNAN, DLAMCH, DLANGE, DNRM2, IDAMAX,
|
|
$ ILAENV, LSAME
|
|
* ..
|
|
* .. Intrinsic Functions ..
|
|
INTRINSIC DBLE, MAX, MIN
|
|
* ..
|
|
* .. Executable Statements ..
|
|
*
|
|
* Test the input arguments
|
|
*
|
|
INFO = 0
|
|
MDESEL = 0
|
|
NSEL = 0
|
|
NDESEL = 0
|
|
MSUB = M
|
|
NSUB = N
|
|
MFREE = MSUB
|
|
NFREE = NSUB
|
|
MINMN = MIN( M, N )
|
|
*
|
|
LQUERY = ( LWORK.EQ.-1 .OR. LIWORK.EQ.-1 )
|
|
*
|
|
RETURNX = LSAME( FACT, 'X' )
|
|
RETURNC = LSAME( FACT, 'C' ) .OR. RETURNX
|
|
*
|
|
USE_DESEL_ROWS = LSAME( USESD, 'R' )
|
|
$ .OR. LSAME( USESD, 'A' )
|
|
USE_SEL_DESEL_COLS = LSAME( USESD, 'C' )
|
|
$ .OR. LSAME( USESD, 'A' )
|
|
*
|
|
IF( .NOT.( RETURNC .OR. LSAME( FACT, 'P') ) ) THEN
|
|
INFO = -1
|
|
ELSE IF( .NOT.( USE_DESEL_ROWS .OR. USE_SEL_DESEL_COLS
|
|
$ .OR. LSAME( USESD, 'N' ) ) ) THEN
|
|
INFO = -2
|
|
ELSE IF( M.LT.0 ) THEN
|
|
INFO = -3
|
|
ELSE IF( N.LT.0 ) THEN
|
|
INFO = -4
|
|
ELSE
|
|
*
|
|
* This is to check that the number of preselected columns NSEL
|
|
* cannot be larger than MSUB, which is the number of rows
|
|
* without MDESEL deselected rows. When the number of
|
|
* preselected columns NSEL is larger than MSUB,
|
|
* the factorization of all preselected NSEL columns cannot be
|
|
* completed. MSUB also will be used for LDX argument check
|
|
* later.
|
|
*
|
|
IF( USE_DESEL_ROWS ) THEN
|
|
*
|
|
* Count the number of free rows MSUB.
|
|
*
|
|
DO I = 1, M
|
|
IF( DESEL_ROWS( I ).EQ.-1 ) MDESEL = MDESEL + 1
|
|
END DO
|
|
MSUB = M - MDESEL
|
|
MFREE = MSUB
|
|
END IF
|
|
*
|
|
IF( USE_SEL_DESEL_COLS ) THEN
|
|
*
|
|
* Count the number of preselected columns NSEL and the
|
|
* number of preselected and free columns NSUB = N - NDESEL.
|
|
*
|
|
DO J = 1, N
|
|
IF( SEL_DESEL_COLS( J ).EQ.1 ) NSEL = NSEL + 1
|
|
IF( SEL_DESEL_COLS( J ).EQ.-1 ) NDESEL = NDESEL + 1
|
|
END DO
|
|
NSUB = N - NDESEL
|
|
MFREE = MSUB - NSEL
|
|
NFREE = NSUB - NSEL
|
|
*
|
|
END IF
|
|
MINMNFREE = MIN( MFREE, NFREE )
|
|
*
|
|
IF( NSEL.GT.MSUB ) THEN
|
|
INFO = -6
|
|
ELSE IF( KMAXFREE.LT.0 ) THEN
|
|
INFO = -7
|
|
ELSE IF( DISNAN( ABSTOL ) ) THEN
|
|
INFO = -8
|
|
ELSE IF( DISNAN( RELTOL ) ) THEN
|
|
INFO = -9
|
|
ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
|
|
INFO = -11
|
|
* This is a check for LDC
|
|
ELSE IF( ( RETURNC .AND. LDC.LT.MAX( 1, M ) )
|
|
$ .OR. ( .NOT.RETURNC .AND. LDC.LT.1 ) ) THEN
|
|
INFO = -20
|
|
* This is a check for LDQRC
|
|
ELSE IF( ( RETURNX .AND. LDQRC.LT.MAX( 1, M ) )
|
|
$ .OR. ( .NOT.RETURNX .AND. LDQRC.LT.1 ) ) THEN
|
|
INFO = -22
|
|
* This is a check for LDX
|
|
ELSE IF( ( RETURNX .AND. LDX.LT.MAX( 1, M ) )
|
|
$ .OR. ( .NOT.RETURNX .AND. LDX.LT.1 ) ) THEN
|
|
INFO = -24
|
|
END IF
|
|
*
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
* a) Test the input workspace size LWORK and LIWORK for the
|
|
* minimum size requirement LWKMIN and LIWKMIN respectively.
|
|
* b) Determine the optimal workspace sizes LWKOPT and LIWKOPT to
|
|
* be returned in WORK( 1 ) and IWORK( 1 ) respectively,
|
|
* if INFO >= 0 in cases:
|
|
* (1) LQUERY = .TRUE.,
|
|
* (2) when the routine exits.
|
|
* Here, LWKMIN and LIWKMIN are the minimum workspaces required for
|
|
* unblocked code.
|
|
*
|
|
IF( INFO.EQ.0 ) THEN
|
|
IF( MINMN.EQ.0 ) THEN
|
|
LWKMIN = 1
|
|
LWKOPT = 1
|
|
LIWKMIN = 1
|
|
LIWKOPT = 1
|
|
ELSE
|
|
*
|
|
* (Real_wk_part_1) Real minimum and optimal workspace
|
|
* computation.
|
|
* LWKMIN = MAX(1, NSUB) for column 2-norm computation
|
|
*
|
|
LWKMIN = MAX( 1, NSUB )
|
|
LWKOPT = LWKMIN
|
|
*
|
|
* (Int_wk_part_1) Integer minimum workspace computation.
|
|
*
|
|
LIWKMIN = 1
|
|
*
|
|
* Call of DGEQRF.
|
|
*
|
|
IF( NSEL.GT.0 ) THEN
|
|
*
|
|
* (Real_wk_part_2) Real minimum workspace computation.
|
|
* LWKMIN = MAX(1, NSEL) for the call of DGEQRF.
|
|
* We can skip counting this workspace as
|
|
* LWKMIN = MAX( LWKMIN, NSEL ), since NSEL <= NSUB.
|
|
*
|
|
* Query for optimal workspace size for DGEQRF.
|
|
*
|
|
CALL DGEQRF( MSUB, NSEL, A, LDA, TAU, WORK,
|
|
$ -1, IINFO )
|
|
LWKOPT = MAX( LWKOPT, INT( WORK( 1 ) ) )
|
|
*
|
|
* Call of DORMQR.
|
|
*
|
|
IF( NFREE.GT.0 ) THEN
|
|
*
|
|
* (Real_wk_part_3) Real minimum workspace computation.
|
|
* NOTE: minimum workspace requirement for DORMQR
|
|
* LWKMIN = MAX(1, NFREE) is smaller than NSUB
|
|
* and it is smaller than LWKMIN = 3*NFREE-1 for
|
|
* DGEQP3RK. We can skip counting this workspace as
|
|
* as LWKMIN = MAX( LWKMIN, NFREE ).
|
|
*
|
|
* Query for optimal workspace size for DORMQR.
|
|
*
|
|
CALL DORMQR( 'L', 'T', MSUB, NFREE,
|
|
$ NSEL, A, LDA, TAU, A( 1, NSEL+1 ), LDA, WORK,
|
|
$ -1, IINFO )
|
|
LWKOPT = MAX( LWKOPT, INT( WORK( 1 ) ) )
|
|
END IF
|
|
*
|
|
END IF
|
|
*
|
|
* Call of DGEQP3RK.
|
|
*
|
|
IF ( MINMNFREE.NE.0 ) THEN
|
|
*
|
|
* (Real_wk_part_4) Real minimum workspace computation.
|
|
* LWKMIN = MAX(1, 3*NFREE-1) for the call of DGEQP3RK.
|
|
*
|
|
LWKMIN = MAX( LWKMIN, 3*NFREE - 1 )
|
|
*
|
|
* Query for optimal workspace size for DGEQP3RK.
|
|
*
|
|
CALL DGEQP3RK( MFREE, NFREE, 0, NFREE,
|
|
$ MINUSONE, MINUSONE,
|
|
$ A( 1, 1 ), LDA, KFREE, MAXC2NRMKFREE,
|
|
$ RELMAXC2NRMKFREE, JPIV( 1 ), TAU( 1 ),
|
|
$ WORK, -1, IWORK, IINFO )
|
|
LWKOPT = MAX( LWKOPT, INT( WORK( 1 ) ) )
|
|
*
|
|
* (Int_wk_part_2) Integer minimum workspace computation.
|
|
* LIWKMIN = NFREE-1 for the call of DGEQP3RK.
|
|
*
|
|
LIWKMIN = MAX( LIWKMIN, NFREE-1 )
|
|
*
|
|
IF( NSEL.NE.0 ) THEN
|
|
*
|
|
* (Int_wk_part_3) Integer minimum workspace computation.
|
|
* NFREE is for DGEQP3RK and NFREE-1 for JPIV adjustment.
|
|
*
|
|
LIWKMIN = MAX( LIWKMIN, NFREE + NFREE-1 )
|
|
END IF
|
|
*
|
|
END IF
|
|
*
|
|
IF( RETURNC ) THEN
|
|
*
|
|
* Integer minimum workspace computation.
|
|
* (Int_wk_part_4) LIWKMIN = 2*N for applying the
|
|
* interchanges for the columns in the matrix C.
|
|
*
|
|
LIWKMIN = MAX( LIWKMIN, 2*N )
|
|
END IF
|
|
*
|
|
* Integer optimal workspace computation.
|
|
*
|
|
LIWKOPT = LIWKMIN
|
|
*
|
|
* Call of DGELS.
|
|
*
|
|
IF( RETURNX ) THEN
|
|
*
|
|
* (Real_wk_part_5) Real minimum workspace computation.
|
|
* LWKMIN = max( 1, MINMN + max( MINMN, N ) ) =
|
|
* = max( 1, MINMN + N ) for the call of DGELS.
|
|
*
|
|
LWKMIN = MAX( LWKMIN, MINMN + N )
|
|
*
|
|
* Query for optimal workspace size for DGELS.
|
|
*
|
|
KMAXLS = MINMN
|
|
*
|
|
CALL DGELS( 'N', M, KMAXLS, N, QRC, LDQRC, X, LDX,
|
|
$ WORK, -1, IINFO )
|
|
LWKOPT = MAX( LWKOPT, INT( WORK(1) ) )
|
|
*
|
|
END IF
|
|
*
|
|
* End of ELSE for IF( MINMN.EQ.0 )
|
|
*
|
|
END IF
|
|
*
|
|
IF( ( LWORK.LT.LWKMIN ) .AND. .NOT.LQUERY ) THEN
|
|
INFO = -26
|
|
ELSE IF( ( LIWORK.LT.LIWKMIN ) .AND. .NOT.LQUERY ) THEN
|
|
INFO = -28
|
|
END IF
|
|
END IF
|
|
*
|
|
IF( INFO.EQ.0 ) THEN
|
|
WORK( 1 ) = DBLE( LWKOPT )
|
|
IWORK( 1 ) = LIWKOPT
|
|
END IF
|
|
*
|
|
IF( INFO.NE.0 ) THEN
|
|
CALL XERBLA( 'DGECXX', -INFO )
|
|
RETURN
|
|
ELSE IF( LQUERY ) THEN
|
|
RETURN
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
* Quick return if possible for:
|
|
* a) M = 0 or N = 0. There is no matrix A(1:M,1:N).
|
|
* b) MSUB = 0 or NSUB = 0. There is no matrix A_sub(1:MSUB,1:NSUB).
|
|
* NOTE: min( M, N) = 0 implies min( MSUB, NSUB) = 0.
|
|
* We need to return correct values for all scalar output parameters,
|
|
* (including WORK(1) and IWORK(1), which are set above).
|
|
*
|
|
IF( MIN( MSUB, NSUB ).EQ.0 ) THEN
|
|
K = 0
|
|
MAXC2NRMK = ZERO
|
|
RELMAXC2NRMK = ZERO
|
|
FNRMK = ZERO
|
|
RETURN
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
K = 0
|
|
*
|
|
* If we need to return factor X, copy the original untouched matrix
|
|
* A into the array X.
|
|
*
|
|
IF( RETURNX ) THEN
|
|
CALL DLACPY( 'F', M, N, A, LDA, X, LDX )
|
|
END IF
|
|
*
|
|
* If we need to return the factor C, copy the original matrix A
|
|
* into the array C, only if do not return the factor X. In this
|
|
* case, we need to choose the columns of the matrix A in the array C
|
|
* in place, otherwise we can copy the columns of the matrix A from
|
|
* the array X.
|
|
*
|
|
IF( RETURNC .AND. .NOT. RETURNX ) THEN
|
|
CALL DLACPY( 'F', M, N, A, LDA, C, LDC )
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
* Permute the deselected rows to the bottom of the matrix A.
|
|
* 1) The initial order of included rows in their block is preserved.
|
|
* 2) The initial order of deselected rows in their block is not
|
|
* preserved.
|
|
* ==================================================================
|
|
*
|
|
* I is an index of DESEL_ROWS array and a row index of
|
|
* the matrix A. MSUB is the number of processed included rows, which
|
|
* is also an index pointer to the last included row in the matrix A.
|
|
* We can think of I as a row source index, and MSUB as a destination
|
|
* index for moving an included row in the matrix A.
|
|
*
|
|
* ( We start with MSUB = 0. We loop over index I in (1:M), and
|
|
* for each position I in DESEL_ROWS array, we check if the row at
|
|
* the position I in the matrix A is an included row (not -1 value).
|
|
* If it is an included row, we increment MSUB pointer, otherwise
|
|
* we do not change MSUB index pointer. Then, we bring this included
|
|
* row from the index I in the matrix A into smaller (or same)
|
|
* MSUB index in the matrix A. If I = MSUB, then the included row
|
|
* is already in place. Due to row swap, the deselected row
|
|
* at MSUB index will move into I index in the matrix A. In this way,
|
|
* we move all the included rows to the top matrix block preserving
|
|
* their initial order within the included block. The initial order
|
|
* of deselected rows will not be preserved within their block.
|
|
*
|
|
IF( USE_DESEL_ROWS ) THEN
|
|
*
|
|
MSUB = 0
|
|
DO I = 1, M, 1
|
|
*
|
|
* Initialize the row pivot array IPIV.
|
|
IPIV( I ) = I
|
|
*
|
|
* The row at the index I is an included row and should be
|
|
* moved to the top of the matrix A.
|
|
*
|
|
IF( DESEL_ROWS( I ).NE.-1 ) THEN
|
|
MSUB = MSUB + 1
|
|
*
|
|
* This is a check whether the included row is
|
|
* on the included place already.
|
|
*
|
|
IF( I.NE.MSUB ) THEN
|
|
*
|
|
* Here, we swap A(I,1:N) into A(MSUB,1:N).
|
|
*
|
|
CALL DSWAP( N, A( I, 1 ), LDA, A( MSUB, 1 ), LDA )
|
|
*
|
|
* Save the interchange.
|
|
*
|
|
IPIV( I ) = IPIV( MSUB )
|
|
IPIV( MSUB ) = I
|
|
DESEL_ROWS( MSUB ) = DESEL_ROWS( I )
|
|
DESEL_ROWS( I ) = -1
|
|
END IF
|
|
END IF
|
|
*
|
|
END DO
|
|
*
|
|
ELSE
|
|
*
|
|
* We do not use the row deselection DESEL_ROWS array.
|
|
* Initialize the row pivot array IPIV.
|
|
* NOTE: MSUB=M has default value,
|
|
* which is set at the beginning of the routine, before argument
|
|
* checks.
|
|
*
|
|
DO I = 1, M, 1
|
|
IPIV( I ) = I
|
|
END DO
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
* Permute the preselected columns to the left and deselected
|
|
* columns to the right of the matrix A.
|
|
* 1) The order of preselected columns is preserved.
|
|
* 2) The order of free columns is not preserved.
|
|
* 3) The order of deselected columns is not preserved.
|
|
* ==================================================================
|
|
*
|
|
* J is the index of SEL_DESEL_COLS array and column J
|
|
* of the matrix A.
|
|
*
|
|
IF( USE_SEL_DESEL_COLS ) THEN
|
|
*
|
|
* Column selection.
|
|
* NSEL is the number of selected columns, also the pointer to
|
|
* the last selected column.
|
|
*
|
|
NSEL = 0
|
|
DO J = 1, N, 1
|
|
*
|
|
* Initialize column pivot array JPIV.
|
|
JPIV( J ) = J
|
|
*
|
|
IF( SEL_DESEL_COLS( J ).EQ.1 ) THEN
|
|
NSEL = NSEL + 1
|
|
*
|
|
* This is the check whether the selected column is
|
|
* on the selected place already.
|
|
*
|
|
IF( J.NE.NSEL ) THEN
|
|
*
|
|
* Here, we swap the column A(1:M,J) into A(1:M,NSEL)
|
|
*
|
|
CALL DSWAP( M, A( 1, J ), 1, A( 1, NSEL ), 1 )
|
|
JPIV( J ) = JPIV( NSEL )
|
|
JPIV( NSEL ) = J
|
|
SEL_DESEL_COLS( J ) = SEL_DESEL_COLS( NSEL )
|
|
SEL_DESEL_COLS( NSEL ) = 1
|
|
END IF
|
|
END IF
|
|
END DO
|
|
*
|
|
* Column deselection.
|
|
* JDESEL the pointer to the last
|
|
* deselected column counting right-to-left.
|
|
*
|
|
JDESEL = N+1
|
|
DO J = N, NSEL+1, -1
|
|
IF( SEL_DESEL_COLS( J ).EQ.-1 ) THEN
|
|
JDESEL = JDESEL - 1
|
|
*
|
|
* This is the check whether the deselected column is
|
|
* on the deselected place already.
|
|
*
|
|
IF( J.NE.JDESEL ) THEN
|
|
*
|
|
* Here, we swap the column A(1:M,J) into A(1:M,JDESEL)
|
|
*
|
|
CALL DSWAP( M, A( 1, J ), 1, A( 1, JDESEL ), 1 )
|
|
ITEMP = JPIV( J )
|
|
JPIV( J ) = JPIV( JDESEL )
|
|
JPIV( JDESEL ) = ITEMP
|
|
SEL_DESEL_COLS( J ) = SEL_DESEL_COLS( JDESEL )
|
|
SEL_DESEL_COLS( JDESEL ) = -1
|
|
END IF
|
|
END IF
|
|
END DO
|
|
*
|
|
NSUB = JDESEL - 1
|
|
*
|
|
ELSE
|
|
*
|
|
* We do not use the column selection deselection
|
|
* SEL_DESEL_COLS array.
|
|
* Initialize column pivot array JPIV.
|
|
* NOTE: NSUB=N has default value,
|
|
* which is set at the beginning of the routine, before argument
|
|
* checks.
|
|
*
|
|
DO J = 1, N, 1
|
|
JPIV( J ) = J
|
|
END DO
|
|
*
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
* Compute the complete column 2-norms of the submatrix
|
|
* A_sub = A(1:MSUB, 1:NSUB) and store them in WORK(1:NSUB).
|
|
*
|
|
DO J = 1, NSUB
|
|
WORK( J ) = DNRM2( MSUB, A( 1, J ), 1 )
|
|
END DO
|
|
*
|
|
* Compute the column index of the maximum column 2-norm and
|
|
* the maximum column 2-norm itself for the submatrix
|
|
* A_sub = A(1:MSUB, 1:NSUB).
|
|
*
|
|
KP0 = IDAMAX( NSUB, WORK( 1 ), 1 )
|
|
MAXC2NRM = WORK( KP0 )
|
|
*
|
|
* ==================================================================
|
|
* Process preselected columns
|
|
*
|
|
* Compute the QR factorization of NSEL preselected columns (1:NSEL)
|
|
* in the submatrix A_sub = A(1:MSUB, 1:NSUB) and update
|
|
* remaining NFREE free columns (NSEL+1:NSUB).
|
|
* NSUB = NSEL + NFREE
|
|
*
|
|
IF( NSEL.GT.0 ) THEN
|
|
*
|
|
* Case (a): MSUB < NSEL.
|
|
*
|
|
* This is handled at the argument check stage in the
|
|
* beginning of the routine. When the number of preselected
|
|
* columns is larger than MSUB, hence the factorization of
|
|
* all NSEL columns cannot be completed. Return from the
|
|
* routine with the error of COL_SEL_DESEL parameter.
|
|
*
|
|
* Case (b): MSUB = NSEL.
|
|
* Case (c-1): MSUB > NSEL and NSEL = NSUB.
|
|
*
|
|
* For cases (b) and (c-1), there will be no residual
|
|
* submatrix after factorization of NSEL columns
|
|
* at step K = NSEL:
|
|
* A_sub_resid(NSEL) = A(NSEL+1:MSUB, NSEL+1:NSUB).
|
|
*
|
|
* Case (c-2): MSUB > NSEL and NSEL < NSUB.
|
|
*
|
|
* For Case (c-2) is a submatrix residual at step K=NSEL
|
|
* A_sub_resid(NSEL) = A(NSEL+1:MSUB, NSEL+1:NSUB)
|
|
*
|
|
CALL DGEQRF( MSUB, NSEL, A, LDA, TAU, WORK, LWORK, IINFO )
|
|
*
|
|
* Apply Q**T from the left to A(NSEL+1:MSUB, NSEL+1:NSUB)
|
|
*
|
|
IF( NFREE.GT.0 ) THEN
|
|
*
|
|
* This is only for case (c-2) ('L' = Left, 'T' = Transpose)
|
|
*
|
|
CALL DORMQR( 'L', 'T', MSUB, NFREE, NSEL,
|
|
$ A, LDA, TAU, A( 1, NSEL+1 ), LDA, WORK,
|
|
$ LWORK, IINFO )
|
|
END IF
|
|
*
|
|
K = K + NSEL
|
|
*
|
|
* End of IF(NSEL.GT.0)
|
|
*
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
KFREE = 0
|
|
*
|
|
IF( MINMNFREE.NE.0 ) THEN
|
|
*
|
|
* Factorize NFREE free columns of
|
|
* A_free = A_sub_resid(NSEL) = A(NSEL+1:MSUB, NSEL+1:NSUB),
|
|
* KFREE is the number of columns that were actually factorized
|
|
* among NFREE columns.
|
|
*
|
|
* ==================================================================
|
|
*
|
|
EPS = DLAMCH('Epsilon')
|
|
*
|
|
USETOL = .FALSE.
|
|
*
|
|
* Adjust ABSTOL only if nonnegative. Negative value means disabled.
|
|
* We need to keep negative value for later use in criterion
|
|
* check.
|
|
*
|
|
IF( ABSTOL.GE.ZERO ) THEN
|
|
SAFMIN = DLAMCH('Safe minimum')
|
|
ABSTOL = MAX( ABSTOL, TWO*SAFMIN )
|
|
USETOL = .TRUE.
|
|
END IF
|
|
*
|
|
* Adjust RELTOL only if nonnegative. Negative value means disabled.
|
|
* We need to keep negative value for later use in criterion
|
|
* check.
|
|
*
|
|
IF( RELTOL.GE.ZERO ) THEN
|
|
RELTOL = MAX( RELTOL, EPS )
|
|
USETOL = .TRUE.
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
* Disable RELTOLFREE when calling DGEQP3RK for free columns
|
|
* factorization, since DGEQP3RK expects RELTOLFREE with respect
|
|
* to the residual matrix A_sub_resid(NSEL), not the whole
|
|
* original matrix A. We can use RELTOL criterion by passing it
|
|
* to ABSTOLFREE as RELTOL*MAXC2NRM. We need to make sure that
|
|
* the negative values of ABSTOL and RELTOL are propagated
|
|
* to ABSTOLFREE and RELTOLFREE, since negative values means
|
|
* that the criterion is disabled.
|
|
*
|
|
IF( USETOL ) THEN
|
|
ABSTOLFREE = MAX( ABSTOL, RELTOL * MAXC2NRM )
|
|
ELSE
|
|
ABSTOLFREE = MINUSONE
|
|
END IF
|
|
RELTOLFREE = MINUSONE
|
|
*
|
|
* Save JPIV(NSEL+1:NSUB) into WORK(NFREE+1:2*NFREE-1)
|
|
*
|
|
IF( NSEL.NE.0 ) THEN
|
|
DO J = 1, NFREE, 1
|
|
IWORK( NFREE + J ) = JPIV( NSEL+J )
|
|
END DO
|
|
END IF
|
|
*
|
|
CALL DGEQP3RK( MFREE, NFREE, 0, KMAXFREE,
|
|
$ ABSTOLFREE, RELTOLFREE,
|
|
$ A( NSEL+1, NSEL+1 ), LDA, KFREE, MAXC2NRMKFREE,
|
|
$ RELMAXC2NRMKFREE, JPIV( NSEL+1 ),
|
|
$ TAU( NSEL+1 ), WORK, LWORK, IWORK, IINFO )
|
|
*
|
|
* Adjust JPIV
|
|
*
|
|
IF( NSEL.NE.0 ) THEN
|
|
DO J = 1, NFREE, 1
|
|
JPIV( NSEL+J ) = IWORK( NFREE + JPIV( NSEL+J ) )
|
|
END DO
|
|
END IF
|
|
*
|
|
* 1) Adjust the return value for the number of factorized
|
|
* columns K for the whole submatrix A_sub.
|
|
* 2) MAXC2NRMK is returned transparently without change
|
|
* as MAXC2NRMKFREE is returned from DGEQP3RK.
|
|
* 3) Adjust the return value RELMAXC2NRMK for the whole
|
|
* submatrix A_sub. We do not use RELMAXC2NRMKFREE
|
|
* returned from DGEQP3RK.
|
|
*
|
|
K = K + KFREE
|
|
MAXC2NRMK = MAXC2NRMKFREE
|
|
RELMAXC2NRMK = MAXC2NRMK / MAXC2NRM
|
|
*
|
|
ELSE
|
|
*
|
|
* Set norms to zero
|
|
*
|
|
MAXC2NRMK = ZERO
|
|
RELMAXC2NRMK = ZERO
|
|
*
|
|
END IF
|
|
*
|
|
* Now, MRESID and NRESID is the number of rows and columns
|
|
* respectively in A_free_resid = A(K+1:MSUB,K+1:NSUB).
|
|
*
|
|
MRESID = MFREE-KFREE
|
|
NRESID = NFREE-KFREE
|
|
*
|
|
IF( MIN( MRESID, NRESID ).NE.0 ) THEN
|
|
FNRMK = DLANGE( 'F', MRESID, NRESID, A( K+1, K+1 ),
|
|
$ LDA, WORK )
|
|
ELSE
|
|
FNRMK = ZERO
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
* Return the matrix C.
|
|
*
|
|
IF( RETURNC .AND. K.GT.0 ) THEN
|
|
*
|
|
IF( RETURNX ) THEN
|
|
*
|
|
* Copy the selected K columns of the original matrix A (that was
|
|
* saved into the array X) into the array C according to
|
|
* the pivot array JPIV. If we return X, then the matrix A is
|
|
* saved in the array X, and it is faster to copy into C than
|
|
* doing column permutation in place, as it is the ELSE case.
|
|
*
|
|
DO J = 1, K, 1
|
|
CALL DCOPY( M, X( 1, JPIV( J ) ), 1, C( 1, J ), 1 )
|
|
END DO
|
|
*
|
|
ELSE
|
|
*
|
|
* Swap the columns of the original matrix A copied into
|
|
* the array C in place.
|
|
*
|
|
* The original M-by-N matrix A was copied into the array C at
|
|
* the beginning of the routine, if RETURNC = .TRUE..
|
|
|
|
* Apply the column permutation matrix P stored in JPIV(1:K)
|
|
* to the columns 1:K in the M-by-N array C in place.
|
|
* After column interchanges, the first K columns of C should
|
|
* be the same as the first K columns of A*P, i.e.
|
|
* (A*P)(1:M,1:K) = C(1:M,1:K). The complexity of this algorithm
|
|
* is min(K,N-1).
|
|
*
|
|
* Index I is the original column index in the
|
|
* array C before interchanges.
|
|
* J is the current column index of the original column I at
|
|
* each step of interchanges.
|
|
*
|
|
* Auxiliary array IWORK(1:N) stores the inverse P_inv(J)
|
|
* of the current column permutation matrix P(J) at each
|
|
* column interchange step J only for the array
|
|
* values >= J:N.
|
|
* C_prev = P_inv(J) * C_next.
|
|
* Each IWORK(I) contains JJ corresponding to I
|
|
* Initialize IWORK(1:N) as (1:N).
|
|
*
|
|
DO I = 1, N, 1
|
|
IWORK( I ) = I
|
|
END DO
|
|
*
|
|
* Auxiliary array IWORK(N+1:2N) stores the current column
|
|
* permutation matrix P_(J) at each column interchange step J
|
|
* only for the array index >= J:N.
|
|
* C_prev * P_(J) = C_next.
|
|
* Each IWORK(N+JJ) contains I corresponding to JJ.
|
|
* Initialize IWORK(N+1:2*N) as (1:N).
|
|
*
|
|
DO J = 1, N, 1
|
|
IWORK( N + J ) = J
|
|
END DO
|
|
*
|
|
* Loop over the columns J = ( 1:min( K, N-1 ) ) in C.
|
|
*
|
|
DO J = 1, MIN( K, N-1 ), 1
|
|
*
|
|
* IP is the original pivot column, i.e. is the original
|
|
* column that should be placed in the current column index
|
|
* J in the array C.
|
|
*
|
|
IP = JPIV( J )
|
|
*
|
|
* I is the original column that is
|
|
* currently in the column index J in the array C after
|
|
* previous column interchanges.
|
|
*
|
|
I = IWORK( N+J )
|
|
*
|
|
IF( I.NE.IP ) THEN
|
|
*
|
|
* JP is the current index of the original pivot
|
|
* column IP in the array C after previous column
|
|
* interchanges.
|
|
*
|
|
JP = IWORK( IP )
|
|
|
|
* Swap the original pivot column IP = JPIV( J ),
|
|
* at the current pivot index JP = IWORK( IP ) into
|
|
* index J.
|
|
*
|
|
CALL DSWAP( M, C( 1, J ), 1, C( 1, JP ), 1 )
|
|
*
|
|
* Update the array IWORK(1:N) for the original column
|
|
* I that was swapped with IP.
|
|
*
|
|
IWORK( I ) = IWORK( IP )
|
|
*
|
|
* Update the array IWORK(N+1:2*N) for the current column
|
|
* index JP that was swapped with the current column
|
|
* index J.
|
|
*
|
|
IWORK( N + JP ) = IWORK( N + J )
|
|
*
|
|
END IF
|
|
*
|
|
END DO
|
|
*
|
|
* End of ELSE( RETURNX )
|
|
*
|
|
END IF
|
|
*
|
|
* End of IF( RETURNC .AND. K.GT.0 )
|
|
*
|
|
END IF
|
|
*
|
|
* ==================================================================
|
|
*
|
|
* Return the matrix X.
|
|
*
|
|
IF( RETURNX .AND. K.GT.0 ) THEN
|
|
*
|
|
* We need to use C and A to compute X = pseudoinv(C) * A, as
|
|
* the linear least squares solution to the overdetermined system
|
|
* C*X = A. We use LLS routine that uses the QR factorization. For
|
|
* that purpose, we store the matrix C into the array QRC.
|
|
* The matrix A was copied into the array X at the beginning
|
|
* of the routine.
|
|
*
|
|
CALL DLACPY( 'F', M, K, C, LDC, QRC, LDQRC )
|
|
*
|
|
CALL DGELS( 'N', M, K, N, QRC, LDQRC, X, LDX,
|
|
$ WORK, LWORK, IINFO )
|
|
INFO = IINFO
|
|
*
|
|
END IF
|
|
*
|
|
WORK( 1 ) = DBLE( LWKOPT )
|
|
IWORK( 1 ) = LIWKOPT
|
|
*
|
|
* End of DGECXX
|
|
*
|
|
END
|