From 126c4076e6b796edd85064922bd2cad327981c61 Mon Sep 17 00:00:00 2001 From: Martin Kroeker Date: Tue, 20 Oct 2026 11:10:33 +0200 Subject: [PATCH 1/2] Add new branches in ?LARFT (Reference-LAPACK PR 1399) --- lapack-netlib/SRC/clarft.c | 425 ++++++++++++--- lapack-netlib/SRC/clarft.f | 508 +++++++++++++----- lapack-netlib/SRC/clarft_lvl2.c | 892 +++++++++++++++++++++++-------- lapack-netlib/SRC/clarft_lvl2.f | 738 ++++++++++++++++++++------ lapack-netlib/SRC/dlarft.c | 440 +++++++++++++--- lapack-netlib/SRC/dlarft.f | 509 +++++++++++++----- lapack-netlib/SRC/dlarft_lvl2.c | 784 +++++++++++++++++++++------- lapack-netlib/SRC/dlarft_lvl2.f | 716 +++++++++++++++++++------ lapack-netlib/SRC/slarft.c | 442 +++++++++++++--- lapack-netlib/SRC/slarft.f | 511 +++++++++++++----- lapack-netlib/SRC/slarft_lvl2.c | 823 +++++++++++++++++++++-------- lapack-netlib/SRC/slarft_lvl2.f | 720 +++++++++++++++++++------ lapack-netlib/SRC/zlarft.c | 425 ++++++++++++--- lapack-netlib/SRC/zlarft.f | 527 ++++++++++++++----- lapack-netlib/SRC/zlarft_lvl2.c | 895 ++++++++++++++++++++++++-------- lapack-netlib/SRC/zlarft_lvl2.f | 734 ++++++++++++++++++++------ 16 files changed, 7871 insertions(+), 2218 deletions(-) diff --git a/lapack-netlib/SRC/clarft.c b/lapack-netlib/SRC/clarft.c index be36bcec8a..e9b6fd3180 100644 --- a/lapack-netlib/SRC/clarft.c +++ b/lapack-netlib/SRC/clarft.c @@ -254,11 +254,10 @@ typedef struct Namelist Namelist; -lf2c -lm (in that order) */ - /* Table of constant values */ static complex c_b1 = {1.f,0.f}; -static complex c_b3 = {-1.f,0.f}; +static complex c_b2 = {-1.f,0.f}; static integer c__3 = 3; static integer c_n1 = -1; static integer c__2 = 2; @@ -312,6 +311,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**H * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -324,6 +326,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -331,8 +335,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -403,7 +409,7 @@ f"> */ /* > the H(i) is best illustrated by the following example with n = 5 and */ /* > k = 3. The elements equal to 1 are not stored. */ /* > */ -/* > DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': */ +/* > DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and (STOREV = 'R' or STOREV = 'T'): */ /* > */ /* > V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) */ /* > ( v1 1 ) ( 1 v2 v2 v2 ) */ @@ -411,13 +417,36 @@ f"> */ /* > ( v1 v2 v3 ) */ /* > ( v1 v2 v3 ) */ /* > */ -/* > DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': */ +/* > DIRECT = 'B' and STOREV = 'C': (DIRECT = 'B' or DIRECT = 'T') and STOREV = 'R': */ /* > */ /* > V = ( v1 v2 v3 ) V = ( v1 v1 1 ) */ /* > ( v1 v2 v3 ) ( v2 v2 v2 1 ) */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -432,11 +461,13 @@ f"> */ /* Local variables */ integer i__, j, l; - logical lq, ql, qr; + logical lq, ql, qr, rq; integer nx; extern /* Subroutine */ void clarft_lvl2__(char *, char *, integer *, integer *, complex *, integer *, complex *, complex *, integer *); - logical dirf, colv; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern /* Subroutine */ void cgemm_(char *, char *, integer *, integer *, integer *, complex *, complex *, integer *, complex *, integer *, complex *, complex *, integer *); @@ -444,9 +475,11 @@ f"> */ extern /* Subroutine */ void ctrmm_(char *, char *, char *, char *, integer *, integer *, complex *, complex *, integer *, complex *, integer *), clacpy_(char *, - integer *, integer *, complex *, integer *, complex *, integer *); + integer *, integer *, complex *, integer *, complex *, integer *), + xerbla_(char *, integer *, ftnlen); extern integer ilaenv_(integer *, char *, char *, integer *, integer *, integer *, integer *, ftnlen, ftnlen); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -471,7 +504,7 @@ f"> */ /* Based on the algorithm of Elmroth and Gustavson, */ /* IBM J. Res. Develop. Vol 44 No. 4 July 2000. */ -/* Quick return if possible */ +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -483,19 +516,102 @@ f"> */ t -= t_offset; /* Function Body */ + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("CLARFT", &info,(ftnlen)6); + return 0; + } + +/* Quick return if possible */ + if (*n == 0 || *k == 0) { - return; + return 0; } +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + /* Base case */ if (*n == 1 || *k == 1) { - i__1 = t_dim1 + 1; - t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; - return; + if (lqt || rqt) { + i__1 = t_dim1 + 1; + r_cnjg(&q__1, &tau[1]); + t[i__1].r = q__1.r, t[i__1].i = q__1.i; + } else { + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + } + return 0; } -/* Determine when to cross over into the level 2 based implementation */ +/* Determine crossover point from level 2 to level 3 BLAS implementation */ /* Writing concatenation */ i__2[0] = 1, a__1[0] = direct; @@ -504,41 +620,17 @@ f"> */ nx = ilaenv_(&c__3, "CLARFT", ch__1, n, k, &c_n1, &c_n1, (ftnlen)6, ( ftnlen)2); if (*k < nx) { + +/* Finish this component with a level 2 BLAS implementation */ + clarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return; + return 0; } -/* Beginning of executable statements */ +/* Beginning of executable statements for the recursive case */ l = *k / 2; - -/* Determine what kind of Q we need to compute */ -/* We assume that if the user doesn't provide 'F' for DIRECT, */ -/* then they meant to provide 'B' and if they don't provide */ -/* 'C' for STOREV, then they meant to provide 'R' */ - - dirf = lsame_(direct, "F"); - colv = lsame_(storev, "C"); - -/* QR happens when we have forward direction in column storage */ - - qr = dirf && colv; - -/* LQ happens when we have forward direction in row storage */ - - lq = dirf && ! colv; - -/* QL happens when we have backward direction in column storage */ - - ql = ! dirf && colv; - -/* The last case is RQ. Due to how we structured this, if the */ -/* above 3 are false, then RQ must be true, so we never store */ -/* this */ -/* RQ happens when we have backward direction in row storage */ -/* RQ = (.NOT.DIRF).AND.(.NOT.COLV) */ - if (qr) { /* Break V apart into 6 components */ @@ -577,7 +669,7 @@ f"> */ /* (I - V_1*T_{1,1}*V_1')*(I - V_2*T_{2,2}*V_2') */ /* = I - V_1*T_{1,1}*V_1' - V_2*T_{2,2}*V_2' + V_1*T_{1,1}*V_1'*V_2*T_{2,2}*V_2' */ -/* Define T{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} */ +/* Define T_{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} */ /* Then, we can define the matrix V as */ /* V = |-------| */ @@ -636,7 +728,7 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__1 = *k - l; - ctrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b3, + ctrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b2, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ @@ -679,8 +771,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ -/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ +/* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) */ +/* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 */ /* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ @@ -691,7 +783,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{1,2} */ @@ -736,7 +828,7 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__1 = *k - l; - ctrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b3, + ctrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b2, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ @@ -745,6 +837,111 @@ f"> */ ctrmm_("Right", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b1, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + 1], ldt); + } else if (lqt) { + +/* Break V apart into 6 components */ + +/* V = |----------------------| */ +/* |V_{1,1} V_{1,2} V{1,3}| */ +/* |0 V_{2,2} V{2,3}| */ +/* |----------------------| */ + +/* V_{1,1}\in\C^{l,l} unit upper triangular */ +/* V_{1,2}\in\C^{l,k-l} rectangular */ +/* V_{1,3}\in\C^{l,n-k} rectangular */ + +/* V_{2,2}\in\C^{k-l,k-l} unit upper triangular */ +/* V_{2,3}\in\C^{k-l,n-k} rectangular */ + +/* Where l = floor(k/2) */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} 0 | */ +/* |T_{2,1} T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\C^{l, l} lower triangular */ +/* T_{2,2}\in\C^{k-l, k-l} lower triangular */ +/* T_{2,1}\in\C^{k-l, l} rectangular */ + +/* Then, consider the product: */ + +/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ +/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ + +/* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{2,1} */ + +/* Compute T_{1,1} recursively */ + + clarft_(direct, storev, n, &l, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + i__1 = *n - l; + i__3 = *k - l; + clarft_(direct, storev, &i__1, &i__3, &v[l + 1 + (l + 1) * v_dim1], + ldv, &tau[l + 1], &t[l + 1 + (l + 1) * t_dim1], ldt); + +/* Compute T_{2,1} */ +/* T_{2,1} = V_{1,2}' */ + + i__1 = *k - l; + for (i__ = 1; i__ <= i__1; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + i__4 = l + i__ + j * t_dim1; + r_cnjg(&q__1, &v[j + (l + i__) * v_dim1]); + t[i__4].r = q__1.r, t[i__4].i = q__1.i; + } + } + +/* T_{2,1} = V_{2,2}*T_{2,1} */ + + i__1 = *k - l; + ctrmm_("Left", "Upper", "No Transpose", "Unit", &i__1, &l, &c_b1, &v[ + l + 1 + (l + 1) * v_dim1], ldv, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} */ +/* Note: We assume K <= N, and GEMM will do nothing if N=K */ + + i__1 = *k - l; + i__3 = *n - *k; + cgemm_("No Transpose", "Conjugate", &i__1, &l, &i__3, &c_b1, &v[l + 1 + + (*k + 1) * v_dim1], ldv, &v[(*k + 1) * v_dim1 + 1], ldv, & + c_b1, &t[l + 1 + t_dim1], ldt); + +/* At this point, we have that T_{2,1} = V_2*V_1' */ +/* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} */ +/* respectively. */ + +/* T_{2,1} = -T_{2,2}*T_{2,1} */ + + i__1 = *k - l; + ctrmm_("Left", "Lower", "No Transpose", "Non-unit", &i__1, &l, &c_b2, + &t[l + 1 + (l + 1) * t_dim1], ldt, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = T_{2,1}*T_{1,1} */ + + i__1 = *k - l; + ctrmm_("Right", "Lower", "No Transpose", "Non-unit", &i__1, &l, &c_b1, + &t[t_offset], ldt, &t[l + 1 + t_dim1], ldt); } else if (ql) { /* Break V apart into 6 components */ @@ -842,7 +1039,7 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__1 = *k - l; - ctrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b3, + ctrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b2, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); @@ -851,10 +1048,7 @@ f"> */ i__1 = *k - l; ctrmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b1, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); - } else { - -/* Else means RQ case */ - + } else if (rq) { /* Break V apart into 6 components */ /* V = |-----------------------| */ @@ -887,8 +1081,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ -/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ +/* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) */ +/* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 */ /* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ @@ -899,7 +1093,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{2,1} */ @@ -944,16 +1138,121 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__1 = *k - l; - ctrmm_("Left", "Lower", "No tranpose", "Non-unit", &l, &i__1, &c_b3, & - t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + + ctrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b2, + &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = T_{2,1}*T_{1,1} */ i__1 = *k - l; - ctrmm_("Right", "Lower", "No tranpose", "Non-unit", &l, &i__1, &c_b1, - &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + ctrmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b1, + &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + } else if (rqt) { +/* Break V apart into 6 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} V_{1,2} 0 | */ +/* |V_{2,1} V_{2,2} V_{2,3}| */ +/* |-----------------------| */ + +/* V_{1,1}\in\C^{k-l,n-k} rectangular */ +/* V_{1,2}\in\C^{k-l,k-l} unit lower triangular */ + +/* V_{2,1}\in\C^{l,n-k} rectangular */ +/* V_{2,2}\in\C^{l,k-l} rectangular */ +/* V_{2,3}\in\C^{l,l} unit lower triangular */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} T_{1,2}| */ +/* | 0 T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\C^{k-l, k-l} non-unit upper triangular */ +/* T_{2,2}\in\C^{l, l} non-unit upper triangular */ +/* T_{1,2}\in\C^{k-l, l} rectangular */ + +/* Where l = floor(k/2) */ + +/* Then, consider the product: */ + +/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ +/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ + +/* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{1,2} */ + +/* Compute T_{1,1} recursively */ + + i__1 = *n - l; + i__3 = *k - l; + clarft_(direct, storev, &i__1, &i__3, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + clarft_(direct, storev, n, &l, &v[*k - l + 1 + v_dim1], ldv, &tau[*k + - l + 1], &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt); + +/* Compute T_{1,2} */ +/* T_{1,2} = V_{2,2}' */ + + i__1 = *k - l; + for (i__ = 1; i__ <= i__1; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + i__4 = i__ + (*k - l + j) * t_dim1; + r_cnjg(&q__1, &v[*k - l + j + (*n - *k + i__) * v_dim1]); + t[i__4].r = q__1.r, t[i__4].i = q__1.i; + } + } + +/* T_{1,2} = V_{1,2}T_{1,2} */ + + i__1 = *k - l; + ctrmm_("Left", "Lower", "No Transpose", "Unit", &i__1, &l, &c_b1, &v[( + *n - *k + 1) * v_dim1 + 1], ldv, &t[(*k - l + 1) * t_dim1 + 1] + , ldt); + +/* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} */ + + i__1 = *k - l; + i__3 = *n - *k; + cgemm_("No Transpose", "Conjugate", &i__1, &l, &i__3, &c_b1, &v[ + v_offset], ldv, &v[*k - l + 1 + v_dim1], ldv, &c_b1, &t[(*k - + l + 1) * t_dim1 + 1], ldt); + +/* At this point, we have that T_{1,2} = V_1*V_2' */ +/* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} */ +/* respectively. */ + +/* T_{1,2} = -T_{1,1}*T_{1,2} */ + + i__1 = *k - l; + ctrmm_("Left", "Upper", "No Transpose", "Non-Unit", &i__1, &l, &c_b2, + &t[t_offset], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); + +/* T_{1,2} = T_{1,2}*T_{2,2} */ + + i__1 = *k - l; + ctrmm_("Right", "Upper", "No Transpose", "Non-Unit", &i__1, &l, &c_b1, + &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - l + 1) + * t_dim1 + 1], ldt); } - return; + return 0; } /* clarft_ */ diff --git a/lapack-netlib/SRC/clarft.f b/lapack-netlib/SRC/clarft.f index 3bf2448ba8..78c754db85 100644 --- a/lapack-netlib/SRC/clarft.f +++ b/lapack-netlib/SRC/clarft.f @@ -48,6 +48,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**H * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -60,6 +63,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -67,8 +72,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -139,7 +146,7 @@ *> the H(i) is best illustrated by the following example with n = 5 and *> k = 3. The elements equal to 1 are not stored. *> -*> DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': +*> DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and (STOREV = 'R' or STOREV = 'T'): *> *> V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) *> ( v1 1 ) ( 1 v2 v2 v2 ) @@ -147,13 +154,36 @@ *> ( v1 v2 v3 ) *> ( v1 v2 v3 ) *> -*> DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': +*> DIRECT = 'B' and STOREV = 'C': (DIRECT = 'B' or DIRECT = 'T') and STOREV = 'R': *> *> V = ( v1 v2 v3 ) V = ( v1 v1 1 ) *> ( v1 v2 v3 ) ( v2 v2 v2 1 ) *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -167,28 +197,30 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. Scalar Arguments * - CHARACTER DIRECT, STOREV - INTEGER K, LDT, LDV, N + CHARACTER DIRECT, STOREV + INTEGER K, LDT, LDV, N * .. * .. Array Arguments .. * - COMPLEX T( LDT, * ), TAU( * ), V( LDV, * ) + COMPLEX T( LDT, * ), TAU( * ), V( LDV, * ) * .. * * .. Parameters .. * - COMPLEX ONE, NEG_ONE, ZERO - PARAMETER(ONE=(1.0E+0,0.0E+0), ZERO = (0.0E+0,0.0E+0), - $ NEG_ONE=(-1.0E+0,0.0E+0)) + COMPLEX ONE, NEG_ONE + PARAMETER(ONE=(1.0E+0,0.0E+0), + $ NEG_ONE=(-1.0E+0,0.0E+0)) * * .. Local Scalars .. * - INTEGER I,J,L,NX - LOGICAL QR,LQ,QL,DIRF,COLV + INTEGER I,J,L,NX,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET * * .. External Subroutines .. * - EXTERNAL CTRMM,CGEMM,CLACPY + EXTERNAL CLARFT_LVL2, CTRMM, CGEMM, CLACPY, XERBLA * * .. External Functions.. * @@ -199,7 +231,7 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * .. Intrinsic Functions.. * INTRINSIC CONJG -* +* * The general scheme used is inspired by the approach inside DGEQRT3 * which was (at the time of writing this code): * Based on the algorithm of Elmroth and Gustavson, @@ -207,57 +239,115 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * .. * .. Executable Statements .. * -* Quick return if possible +* Convert our character flags to logical flags for later * - IF(N.EQ.0.OR.K.EQ.0) THEN - RETURN - END IF + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') * -* Base case +* Error handling for our character flags * - IF(N.EQ.1.OR.K.EQ.1) THEN - T(1,1) = TAU(1) + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('CLARFT', INFO) RETURN END IF * -* Determine when to cross over into the level 2 based implementation +* Quick return if possible * - NX = ILAENV(3, "CLARFT", DIRECT // STOREV, N, K, -1, -1) - IF(K.LT.NX) THEN - CALL CLARFT_LVL2(DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT) + IF(N.EQ.0.OR.K.EQ.0) THEN RETURN END IF * -* Beginning of executable statements -* - L = K / 2 +* Now we determine what factorization our flags are associated with * -* Determine what kind of Q we need to compute -* We assume that if the user doesn't provide 'F' for DIRECT, -* then they meant to provide 'B' and if they don't provide -* 'C' for STOREV, then they meant to provide 'R' +* QR happens when we have forward direction in column storage * - DIRF = LSAME(DIRECT,'F') - COLV = LSAME(STOREV,'C') + QR = DIRF.AND.STOREC * -* QR happens when we have forward direction in column storage +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute * - QR = DIRF.AND.COLV + LQT = DIRF.AND.STORET * -* LQ happens when we have forward direction in row storage +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute * - LQ = DIRF.AND.(.NOT.COLV) + LQ = DIRF.AND.STORER * * QL happens when we have backward direction in column storage * - QL = (.NOT.DIRF).AND.COLV + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute * -* The last case is RQ. Due to how we structured this, if the -* above 3 are false, then RQ must be true, so we never store -* this -* RQ happens when we have backward direction in row storage -* RQ = (.NOT.DIRF).AND.(.NOT.COLV) + RQT = DIRT.AND.STORER * +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER +* +* Base case +* + IF(N.EQ.1.OR.K.EQ.1) THEN + IF( LQT.OR.RQT ) THEN + T(1,1) = CONJG(TAU(1)) + ELSE + T(1,1) = TAU(1) + END IF + RETURN + END IF +* +* Determine crossover point from level 2 to level 3 BLAS implementation +* + NX = ILAENV(3, "CLARFT", DIRECT // STOREV, N, K, -1, -1) + IF(K.LT.NX) THEN +* +* Finish this component with a level 2 BLAS implementation +* + CALL CLARFT_LVL2(DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT) + RETURN + END IF +* +* Beginning of executable statements for the recursive case +* + L = K / 2 IF(QR) THEN * * Break V apart into 6 components @@ -271,17 +361,17 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\C^{l,l} unit lower triangular * V_{2,1}\in\C^{k-l,l} rectangular * V_{3,1}\in\C^{n-k,l} rectangular -* +* * V_{2,2}\in\C^{k-l,k-l} unit lower triangular * V_{3,2}\in\C^{n-k,k-l} rectangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -292,17 +382,17 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_1*T_{1,1}*V_1')*(I - V_2*T_{2,2}*V_2') * = I - V_1*T_{1,1}*V_1' - V_2*T_{2,2}*V_2' + V_1*T_{1,1}*V_1'*V_2*T_{2,2}*V_2' -* -* Define T{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} -* -* Then, we can define the matrix V as +* +* Define T_{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -314,15 +404,15 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL CLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL CLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * -* Compute T_{1,2} +* Compute T_{1,2} * T_{1,2} = V_{2,1}' * DO J = 1, L DO I = 1, K-L - T(J, L+I) = CONJG(V(L+I, J)) + T(J,L+I) = CONJG(V(L+I,J)) END DO END DO * @@ -335,9 +425,8 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = V_{3,1}'*V_{3,2} + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL CGEMM('Conjugate', 'No transpose', L, K-L, N-K, ONE, - $ V(K+1, 1), LDV, V(K+1, L+1), LDV, ONE, T(1, L+1), - $ LDT) + CALL CGEMM('Conjugate', 'No transpose', L, K-L, N-K, ONE, + $ V(K+1, 1), LDV, V(K+1,L+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1'*V_2 * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -350,8 +439,8 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * T_{1,2} = T_{1,2}*T_{2,2} * - CALL CTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + CALL CTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) ELSE IF(LQ) THEN * @@ -365,19 +454,19 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\C^{l,l} unit upper triangular * V_{1,2}\in\C^{l,k-l} rectangular * V_{1,3}\in\C^{l,n-k} rectangular -* +* * V_{2,2}\in\C^{k-l,k-l} unit upper triangular * V_{2,3}\in\C^{k-l,n-k} rectangular * * Where l = floor(k/2) * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -386,20 +475,20 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2}\in\C^{l, k-l} rectangular * * Then, consider the product: -* -* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) -* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 -* +* +* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) +* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 +* * Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{1,2} * @@ -409,14 +498,14 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL CLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL CLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * * Compute T_{1,2} * T_{1,2} = V_{1,2} * - CALL CLACPY('All', L, K-L, V(1, L+1), LDV, T(1, L+1), LDT) + CALL CLACPY('All', L, K - L, V(1,L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*V_{2,2}' * @@ -444,6 +533,99 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * CALL CTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) + ELSE IF(LQT) THEN +* +* Break V apart into 6 components +* +* V = |----------------------| +* |V_{1,1} V_{1,2} V{1,3}| +* |0 V_{2,2} V{2,3}| +* |----------------------| +* +* V_{1,1}\in\C^{l,l} unit upper triangular +* V_{1,2}\in\C^{l,k-l} rectangular +* V_{1,3}\in\C^{l,n-k} rectangular +* +* V_{2,2}\in\C^{k-l,k-l} unit upper triangular +* V_{2,3}\in\C^{k-l,n-k} rectangular +* +* Where l = floor(k/2) +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} 0 | +* |T_{2,1} T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\C^{l, l} lower triangular +* T_{2,2}\in\C^{k-l, k-l} lower triangular +* T_{2,1}\in\C^{k-l, l} rectangular +* +* Then, consider the product: +* +* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) +* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 +* +* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{2,1} +* +* Compute T_{1,1} recursively +* + CALL CLARFT(DIRECT, STOREV, N, L, V, LDV, TAU, T, LDT) +* +* Compute T_{2,2} recursively +* + CALL CLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) + +* +* Compute T_{2,1} +* T_{2,1} = V_{1,2}' +* + DO I = 1, K-L + DO J = 1, L + T(L+I,J) = CONJG(V(J,L+I)) + END DO + END DO +* +* T_{2,1} = V_{2,2}*T_{2,1} +* + CALL CTRMM('Left', 'Upper', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(L+1,L+1), LDV, T(L+1,1), LDT) +* +* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} +* Note: We assume K <= N, and GEMM will do nothing if N=K +* + CALL CGEMM('No Transpose', 'Conjugate', K-L, L, N-K, ONE, + $ V(L+1,K+1), LDV, V(1, K+1), LDV, ONE, T(L+1,1), LDT) +* +* At this point, we have that T_{2,1} = V_2*V_1' +* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} +* respectively. +* +* T_{2,1} = -T_{2,2}*T_{2,1} +* + CALL CTRMM('Left', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, NEG_ONE, T(L+1,L+1), LDT, T(L+1,1), LDT) +* +* T_{2,1} = T_{2,1}*T_{1,1} +* + CALL CTRMM('Right', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, ONE, T, LDT, T(L+1,1), LDT) ELSE IF(QL) THEN * * Break V apart into 6 components @@ -456,18 +638,18 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * V_{1,1}\in\C^{n-k,k-l} rectangular * V_{2,1}\in\C^{k-l,k-l} unit upper triangular -* +* * V_{1,2}\in\C^{n-k,l} rectangular * V_{2,2}\in\C^{k-l,l} rectangular * V_{3,2}\in\C^{l,l} unit upper triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -478,17 +660,17 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_2*T_{2,2}*V_2')*(I - V_1*T_{1,1}*V_1') * = I - V_2*T_{2,2}*V_2' - V_1*T_{1,1}*V_1' + V_2*T_{2,2}*V_2'*V_1*T_{1,1}*V_1' -* +* * Define T_{2,1} = -T_{2,2}*V_2'*V_1*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -496,34 +678,34 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{1,1} recursively * - CALL CLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL CLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * CALL CLARFT(DIRECT, STOREV, N, L, V(1, K-L+1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2}' * DO J = 1, K-L DO I = 1, L - T(K-L+I, J) = CONJG(V(N-K+J, K-L+I)) + T(K-L+I,J) = CONJG(V(N-K+J, K-L+I)) END DO END DO * * T_{2,1} = T_{2,1}*V_{2,1} * CALL CTRMM('Right', 'Upper', 'No transpose', 'Unit', L, - $ K-L, ONE, V(N-K+1, 1), LDV, T(K-L+1, 1), LDT) + $ K-L, ONE, V(N-K+1,1), LDV, T(K-L+1,1), LDT) * * T_{2,1} = V_{2,2}'*V_{2,1} + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL CGEMM('Conjugate', 'No transpose', L, K-L, N-K, ONE, - $ V(1, K-L+1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + $ V(1,K-L+1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2'*V_1 * All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} @@ -532,17 +714,13 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{2,1} = -T_{2,2}*T_{2,1} * CALL CTRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * CALL CTRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) - ELSE -* -* Else means RQ case -* + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQ) THEN * Break V apart into 6 components * * V = |-----------------------| @@ -557,13 +735,13 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{2,2}\in\C^{l,k-l} rectangular * V_{2,3}\in\C^{l,l} unit lower triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -574,51 +752,51 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* -* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) -* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 -* +* +* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) +* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 +* * Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{2,1} * * Compute T_{1,1} recursively * - CALL CLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL CLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * CALL CLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2} * - CALL CLACPY('All', L, K-L, V(K-L+1, N-K+1), LDV, - $ T(K-L+1, 1), LDT) + CALL CLACPY('All', L, K-L, V(K-L+1,N-K+1), LDV, T(K-L+1,1), + $ LDT) * * T_{2,1} = T_{2,1}*V_{1,2}' * CALL CTRMM('Right', 'Lower', 'Conjugate', 'Unit', L, K-L, - $ ONE, V(1, N-K+1), LDV, T(K-L+1,1), LDT) + $ ONE, V(1, N-K+1), LDV, T(K-L+1,1), LDT) * * T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL CGEMM('No transpose', 'Conjugate', L, K-L, N-K, ONE, - $ V(K-L+1, 1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + CALL CGEMM('No transpose', 'Conjugate', L, K-L, N-K, ONE, + $ V(K-L+1,1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2*V_1' @@ -627,14 +805,104 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * T_{2,1} = -T_{2,2}*T_{2,1} * - CALL CTRMM('Left', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + CALL CTRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * - CALL CTRMM('Right', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) + CALL CTRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQT) THEN +* Break V apart into 6 components +* +* V = |-----------------------| +* |V_{1,1} V_{1,2} 0 | +* |V_{2,1} V_{2,2} V_{2,3}| +* |-----------------------| +* +* V_{1,1}\in\C^{k-l,n-k} rectangular +* V_{1,2}\in\C^{k-l,k-l} unit lower triangular +* +* V_{2,1}\in\C^{l,n-k} rectangular +* V_{2,2}\in\C^{l,k-l} rectangular +* V_{2,3}\in\C^{l,l} unit lower triangular +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} T_{1,2}| +* | 0 T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\C^{k-l, k-l} non-unit upper triangular +* T_{2,2}\in\C^{l, l} non-unit upper triangular +* T_{1,2}\in\C^{k-l, l} rectangular +* +* Where l = floor(k/2) +* +* Then, consider the product: +* +* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) +* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 +* +* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{1,2} +* +* Compute T_{1,1} recursively +* + CALL CLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) +* +* Compute T_{2,2} recursively +* + CALL CLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) +* +* Compute T_{1,2} +* T_{1,2} = V_{2,2}' +* + DO I = 1, K-L + DO J = 1, L + T(I,K-L+J) = CONJG(V(K-L+J, N-K+I)) + END DO + END DO +* +* T_{1,2} = V_{1,2}T_{1,2} +* + CALL CTRMM('Left', 'Lower', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(1,N-K+1), LDV, T(1,K-L+1), LDT) +* +* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} +* + CALL CGEMM('No Transpose', 'Conjugate', K-L, L, N-K, ONE, V, + $ LDV, V(K-L+1,1), LDV, ONE, T(1, K-L+1), LDT) +* +* At this point, we have that T_{1,2} = V_1*V_2' +* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} +* respectively. +* +* T_{1,2} = -T_{1,1}*T_{1,2} +* + CALL CTRMM('Left', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, NEG_ONE, T, LDT, T(1, K-L+1), LDT) +* +* T_{1,2} = T_{1,2}*T_{2,2} +* + CALL CTRMM('Right', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, ONE, T(K-L+1,K-L+1), LDT, T(1, K-L+1), LDT) END IF END SUBROUTINE diff --git a/lapack-netlib/SRC/clarft_lvl2.c b/lapack-netlib/SRC/clarft_lvl2.c index 90ee71fdbb..4aa5b8f3d0 100644 --- a/lapack-netlib/SRC/clarft_lvl2.c +++ b/lapack-netlib/SRC/clarft_lvl2.c @@ -254,29 +254,17 @@ typedef struct Namelist Namelist; static complex c_b1 = {1.f,0.f}; static integer c__1 = 1; -/* > \brief \b CLARFT_LVL2: Level 2 BLAS version for terminating case of CLARFT */ +/* > \brief \b CLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH */ /* =========== DOCUMENTATION =========== */ /* Online html documentation available at */ /* http://www.netlib.org/lapack/explore-html/ */ -/* > Download CLARFT_LVL2 + dependencies */ -/* > */ -/* > [TGZ] */ -/* > */ -/* > [ZIP] */ -/* > */ -/* > [TXT] */ - /* Definition: */ /* =========== */ -/* SUBROUTINE CLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, */ -/* T, LDT ) */ +/* SUBROUTINE CLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT ) */ /* CHARACTER DIRECT, STOREV */ /* INTEGER K, LDT, LDV, N */ @@ -304,6 +292,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**H * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -316,6 +307,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -323,8 +316,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -410,6 +405,29 @@ f"> */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -422,16 +440,21 @@ f"> */ complex q__1, q__2, q__3; /* Local variables */ - integer i__, j, prevlastv; + integer i__, j; + logical lq, ql, qr, rq; + integer kmi, nmi; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern /* Subroutine */ void cgemm_(char *, char *, integer *, integer *, integer *, complex *, complex *, integer *, complex *, integer *, complex *, complex *, integer *), cgemv_(char *, integer *, integer *, complex *, complex *, integer *, complex *, integer *, complex *, complex *, integer *); extern logical lsame_(char *, char *); - integer lastv; extern /* Subroutine */ void ctrmv_(char *, char *, char *, integer *, - complex *, integer *, complex *, integer *), mecago_(); + complex *, integer *, complex *, integer *), xerbla_(char *, integer *, ftnlen); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -439,10 +462,18 @@ f"> */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ -/* ===================================================================== */ -/* Quick return if possible */ + + + + + + + + + +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -454,212 +485,635 @@ f"> */ t -= t_offset; /* Function Body */ - if (*n == 0) { - return; + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("CLARFT_LVL2", &info, (ftnlen)11); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *k == 0) { + return 0; + } + +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + if (*n == 1 || *k == 1) { + if (lqt || rqt) { + i__1 = t_dim1 + 1; + r_cnjg(&q__1, &tau[1]); + t[i__1].r = q__1.r, t[i__1].i = q__1.i; + } else { + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + } + return 0; } + if (qr) { + +/* Break V into 9 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} 0 0 | i-1 */ +/* |V_{2,1} V_{2,2} 0 | 1 */ +/* |V_{3,1} V_{3,2} V_{3,3}| n-i */ +/* |-----------------------| */ +/* i-1 1 k-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See clarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' */ +/* [0\\V_{2,2}\\V_{3,2}]T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' */ +/* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' */ +/* We must do this at copy time as otherwise gemv will do nothing */ +/* on the last column when n=k, but we neet to make sure we are */ +/* scaled by this value */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = j + i__ * t_dim1; + i__4 = i__; + q__2.r = -tau[i__4].r, q__2.i = -tau[i__4].i; + r_cnjg(&q__3, &v[i__ + j * v_dim1]); + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = q__2.r * + q__3.i + q__2.i * q__3.r; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; + } + +/* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} */ +/* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + i__4 = i__; + q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; + cgemv_("Conjugate Transpose", &i__2, &i__3, &q__1, &v[i__ + 1 + + v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, &c_b1, & + t[i__ * t_dim1 + 1], &c__1); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + ctrmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + } + } else if (lq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See clarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} */ +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -\tau_{i}V_{1,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = j + i__ * t_dim1; + i__4 = i__; + q__2.r = -tau[i__4].r, q__2.i = -tau[i__4].i; + i__5 = j + i__ * v_dim1; + q__1.r = q__2.r * v[i__5].r - q__2.i * v[i__5].i, q__1.i = + q__2.r * v[i__5].i + q__2.i * v[i__5].r; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; + } + +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + i__4 = i__; + q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; + cgemm_("No Transpose", "Conjugate Transpose", &i__2, &c__1, &i__3, + &q__1, &v[(i__ + 1) * v_dim1 + 1], ldv, &v[i__ + (i__ + + 1) * v_dim1], ldv, &c_b1, &t[i__ * t_dim1 + 1], ldt); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + ctrmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + } + } else if (lqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ - if (lsame_(direct, "F")) { - prevlastv = *n; +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | i-1 */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{2,1} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On */ +/* each iteration, T_{3,1:3} are not referenced. See clarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} */ + +/* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} */ + +/* This means we will do the following */ + +/* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' */ +/* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} */ +/* T_{2,1} = T_{1,1}'T_{2,1} */ +/* T_{2,2} = \tau{i} */ + + i__1 = t_dim1 + 1; + r_cnjg(&q__1, &tau[1]); + t[i__1].r = q__1.r, t[i__1].i = q__1.i; i__1 = *k; - for (i__ = 1; i__ <= i__1; ++i__) { - prevlastv = f2cmax(prevlastv,i__); - i__2 = i__; - if (tau[i__2].r == 0.f && tau[i__2].i == 0.f) { - -/* H(i) = I */ - - i__2 = i__; - for (j = 1; j <= i__2; ++j) { - i__3 = j + i__ * t_dim1; - t[i__3].r = 0.f, t[i__3].i = 0.f; - } - } else { - -/* general case */ - - if (lsame_(storev, "C")) { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - i__3 = lastv + i__ * v_dim1; - if (v[i__3].r != 0.f || v[i__3].i != 0.f) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - i__3 = j + i__ * t_dim1; - i__4 = i__; - q__2.r = -tau[i__4].r, q__2.i = -tau[i__4].i; - r_cnjg(&q__3, &v[i__ + j * v_dim1]); - q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = - q__2.r * q__3.i + q__2.i * q__3.r; - t[i__3].r = q__1.r, t[i__3].i = q__1.i; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**H * V(i:j,i) */ - - i__2 = j - i__; - i__3 = i__ - 1; - i__4 = i__; - q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; - cgemv_("Conjugate transpose", &i__2, &i__3, &q__1, &v[i__ - + 1 + v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], & - c__1, &c_b1, &t[i__ * t_dim1 + 1], &c__1); - } else { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - i__3 = i__ + lastv * v_dim1; - if (v[i__3].r != 0.f || v[i__3].i != 0.f) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - i__3 = j + i__ * t_dim1; - i__4 = i__; - q__2.r = -tau[i__4].r, q__2.i = -tau[i__4].i; - i__5 = j + i__ * v_dim1; - q__1.r = q__2.r * v[i__5].r - q__2.i * v[i__5].i, - q__1.i = q__2.r * v[i__5].i + q__2.i * v[i__5] - .r; - t[i__3].r = q__1.r, t[i__3].i = q__1.i; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**H */ - - i__2 = i__ - 1; - i__3 = j - i__; - i__4 = i__; - q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; - cgemm_("N", "C", &i__2, &c__1, &i__3, &q__1, &v[(i__ + 1) - * v_dim1 + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], - ldv, &c_b1, &t[i__ * t_dim1 + 1], ldt); - } - -/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ - - i__2 = i__ - 1; - ctrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ - t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); - i__2 = i__ + i__ * t_dim1; - i__3 = i__; - t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; - if (i__ > 1) { - prevlastv = f2cmax(prevlastv,lastv); - } else { - prevlastv = lastv; - } + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{2,1} = -\tau_{i}V_{1,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = i__ + j * t_dim1; + i__4 = i__; + i__5 = j + i__ * v_dim1; + q__3.r = tau[i__4].r * v[i__5].r - tau[i__4].i * v[i__5].i, + q__3.i = tau[i__4].r * v[i__5].i + tau[i__4].i * v[ + i__5].r; + r_cnjg(&q__2, &q__3); + q__1.r = -q__2.r, q__1.i = -q__2.i; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; } + +/* T_{2,1} = -\tau_{i}V_{2,3}V_{1,3}' + T_{2,1} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + r_cnjg(&q__2, &tau[i__]); + q__1.r = -q__2.r, q__1.i = -q__2.i; + cgemm_("No Transpose", "Conjugate Transpose", &c__1, &i__2, &i__3, + &q__1, &v[i__ + (i__ + 1) * v_dim1], ldv, &v[(i__ + 1) * + v_dim1 + 1], ldv, &c_b1, &t[i__ + t_dim1], ldt); + +/* T_{2,1} = T_{1,1}'T_{2,1} */ + + i__2 = i__ - 1; + ctrmv_("Lower", "Transpose", "Non-unit", &i__2, &t[t_offset], ldt, + &t[i__ + t_dim1], ldt); + i__2 = i__ + i__ * t_dim1; + r_cnjg(&q__1, &tau[i__]); + t[i__2].r = q__1.r, t[i__2].i = q__1.i; + } + } else if (ql) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | n-i */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See clarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' */ +/* [V_{1,2}\\V_{2,2}\\0]T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' */ +/* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__1 = *k + *k * t_dim1; + i__2 = *k; + t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau(k-i+1) */ + + i__2 = kmi + kmi * t_dim1; + i__3 = kmi; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + +/* T_{3,2} = -\tau(k-i+1)V_{2,3}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = kmi + j + kmi * t_dim1; + i__4 = kmi; + q__2.r = -tau[i__4].r, q__2.i = -tau[i__4].i; + r_cnjg(&q__3, &v[nmi + (kmi + j) * v_dim1]); + q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, q__1.i = q__2.r * + q__3.i + q__2.i * q__3.r; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; + } + +/* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + i__4 = kmi; + q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; + cgemv_("Conjugate Transpose", &i__2, &i__3, &q__1, &v[(kmi + 1) * + v_dim1 + 1], ldv, &v[kmi * v_dim1 + 1], &c__1, &c_b1, &t[ + kmi + 1 + kmi * t_dim1], &c__1); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + ctrmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); } - } else { - prevlastv = 1; - for (i__ = *k; i__ >= 1; --i__) { - i__1 = i__; - if (tau[i__1].r == 0.f && tau[i__1].i == 0.f) { - -/* H(i) = I */ - - i__1 = *k; - for (j = i__; j <= i__1; ++j) { - i__2 = j + i__ * t_dim1; - t[i__2].r = 0.f, t[i__2].i = 0.f; - } - } else { - -/* general case */ - - if (i__ < *k) { - if (lsame_(storev, "C")) { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - i__2 = lastv + i__ * v_dim1; - if (v[i__2].r != 0.f || v[i__2].i != 0.f) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - i__2 = j + i__ * t_dim1; - i__3 = i__; - q__2.r = -tau[i__3].r, q__2.i = -tau[i__3].i; - r_cnjg(&q__3, &v[*n - *k + i__ + j * v_dim1]); - q__1.r = q__2.r * q__3.r - q__2.i * q__3.i, - q__1.i = q__2.r * q__3.i + q__2.i * - q__3.r; - t[i__2].r = q__1.r, t[i__2].i = q__1.i; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**H * V(j:n-k+i,i) */ - - i__1 = *n - *k + i__ - j; - i__2 = *k - i__; - i__3 = i__; - q__1.r = -tau[i__3].r, q__1.i = -tau[i__3].i; - cgemv_("Conjugate transpose", &i__1, &i__2, &q__1, &v[ - j + (i__ + 1) * v_dim1], ldv, &v[j + i__ * - v_dim1], &c__1, &c_b1, &t[i__ + 1 + i__ * - t_dim1], &c__1); - } else { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - i__2 = i__ + lastv * v_dim1; - if (v[i__2].r != 0.f || v[i__2].i != 0.f) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - i__2 = j + i__ * t_dim1; - i__3 = i__; - q__2.r = -tau[i__3].r, q__2.i = -tau[i__3].i; - i__4 = j + (*n - *k + i__) * v_dim1; - q__1.r = q__2.r * v[i__4].r - q__2.i * v[i__4].i, - q__1.i = q__2.r * v[i__4].i + q__2.i * v[ - i__4].r; - t[i__2].r = q__1.r, t[i__2].i = q__1.i; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**H */ - - i__1 = *k - i__; - i__2 = *n - *k + i__ - j; - i__3 = i__; - q__1.r = -tau[i__3].r, q__1.i = -tau[i__3].i; - cgemm_("N", "C", &i__1, &c__1, &i__2, &q__1, &v[i__ + - 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], - ldv, &c_b1, &t[i__ + 1 + i__ * t_dim1], ldt); - } - -/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ - - i__1 = *k - i__; - ctrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ - + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * - t_dim1], &c__1) - ; - if (i__ > 1) { - prevlastv = f2cmin(prevlastv,lastv); - } else { - prevlastv = lastv; - } - } - i__1 = i__ + i__ * t_dim1; - i__2 = i__; - t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + } else if (rq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See clarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__1 = *k + *k * t_dim1; + i__2 = *k; + t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + i__2 = kmi + kmi * t_dim1; + i__3 = kmi; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = kmi + j + kmi * t_dim1; + i__4 = kmi; + q__2.r = -tau[i__4].r, q__2.i = -tau[i__4].i; + i__5 = kmi + j + nmi * v_dim1; + q__1.r = q__2.r * v[i__5].r - q__2.i * v[i__5].i, q__1.i = + q__2.r * v[i__5].i + q__2.i * v[i__5].r; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; } + +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + i__4 = kmi; + q__1.r = -tau[i__4].r, q__1.i = -tau[i__4].i; + cgemm_("No Transpose", "Conjugate Transpose", &i__2, &c__1, &i__3, + &q__1, &v[kmi + 1 + v_dim1], ldv, &v[kmi + v_dim1], ldv, + &c_b1, &t[kmi + 1 + kmi * t_dim1], ldt); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + ctrmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); } - } - return; + } else if (rqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | k-i */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{2,3} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On */ +/* each iteration, T_{1,1:3} are not referenced. See clarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} */ -/* End of CLARFT_LVL2 */ +/* T_{3,2} = -T_{2,2}(V_{2,1}V_{3,1}' + V_{3,2}')T_{3,3} */ +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ +/* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} */ +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + i__1 = *k + *k * t_dim1; + r_cnjg(&q__1, &tau[*k]); + t[i__1].r = q__1.r, t[i__1].i = q__1.i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + i__2 = kmi + kmi * t_dim1; + r_cnjg(&q__1, &tau[kmi]); + t[i__2].r = q__1.r, t[i__2].i = q__1.i; + +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = kmi + (kmi + j) * t_dim1; + i__4 = kmi; + i__5 = kmi + j + nmi * v_dim1; + q__3.r = tau[i__4].r * v[i__5].r - tau[i__4].i * v[i__5].i, + q__3.i = tau[i__4].r * v[i__5].i + tau[i__4].i * v[ + i__5].r; + r_cnjg(&q__2, &q__3); + q__1.r = -q__2.r, q__1.i = -q__2.i; + t[i__3].r = q__1.r, t[i__3].i = q__1.i; + } + +/* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + r_cnjg(&q__2, &tau[kmi]); + q__1.r = -q__2.r, q__1.i = -q__2.i; + cgemm_("No Transpose", "Conjugate Transpose", &c__1, &i__2, &i__3, + &q__1, &v[kmi + v_dim1], ldv, &v[kmi + 1 + v_dim1], ldv, + &c_b1, &t[kmi + (kmi + 1) * t_dim1], ldt); + +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + i__2 = i__ - 1; + ctrmv_("Upper", "Transpose", "Non-unit", &i__2, &t[kmi + 1 + (kmi + + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); + } + } + return 0; } /* clarft_lvl2__ */ diff --git a/lapack-netlib/SRC/clarft_lvl2.f b/lapack-netlib/SRC/clarft_lvl2.f index 3b0aea1132..0dca6c0dc5 100644 --- a/lapack-netlib/SRC/clarft_lvl2.f +++ b/lapack-netlib/SRC/clarft_lvl2.f @@ -1,23 +1,14 @@ -*> \brief \b CLARFT_LVL2: Level 2 BLAS version for terminating case of CLARFT +*> \brief \b CLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH * * =========== DOCUMENTATION =========== * * Online html documentation available at * http://www.netlib.org/lapack/explore-html/ * -*> Download CLARFT_LVL2 + dependencies -*> -*> [TGZ] -*> -*> [ZIP] -*> -*> [TXT] -* * Definition: * =========== * -* SUBROUTINE CLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, -* T, LDT ) +* SUBROUTINE CLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT ) * * .. Scalar Arguments .. * CHARACTER DIRECT, STOREV @@ -49,6 +40,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**H * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -61,6 +55,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -68,8 +64,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -155,6 +153,29 @@ *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -170,159 +191,568 @@ SUBROUTINE CLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, INTEGER K, LDT, LDV, N * .. * .. Array Arguments .. +* COMPLEX T( LDT, * ), TAU( * ), V( LDV, * ) * .. * -* ===================================================================== -* * .. Parameters .. - COMPLEX ONE, ZERO - PARAMETER ( ONE = ( 1.0E+0, 0.0E+0 ), - $ ZERO = ( 0.0E+0, 0.0E+0 ) ) -* .. +* + COMPLEX ONE + PARAMETER(ONE=(1.0E+0,0.0E+0)) +* * .. Local Scalars .. - INTEGER I, J, PREVLASTV, LASTV -* .. +* + INTEGER I,J,KMI,NMI,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET +* * .. External Subroutines .. - EXTERNAL CGEMM, CGEMV, CTRMV -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME +* + EXTERNAL CTRMV,CGEMV,CGEMM,XERBLA +* +* .. External Functions.. +* + LOGICAL LSAME + EXTERNAL LSAME +* +* .. Intrinsic Functions.. +* + INTRINSIC CONJG * .. * .. Executable Statements .. * +* Convert our character flags to logical flags for later +* + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') +* +* Error handling for our character flags +* + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('CLARFT_LVL2', INFO) + RETURN + END IF +* * Quick return if possible * - IF( N.EQ.0 ) - $ RETURN -* - IF( LSAME( DIRECT, 'F' ) ) THEN - PREVLASTV = N - DO I = 1, K - PREVLASTV = MAX( PREVLASTV, I ) - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = 1, I - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * CONJG( V( I , J ) ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**H * V(i:j,i) -* - CALL CGEMV( 'Conjugate transpose', J-I, I-1, - $ -TAU( I ), V( I+1, 1 ), LDV, - $ V( I+1, I ), 1, - $ ONE, T( 1, I ), 1 ) - ELSE -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * V( J , I ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**H -* - CALL CGEMM( 'N', 'C', I-1, 1, J-I, -TAU( I ), - $ V( 1, I+1 ), LDV, V( I, I+1 ), LDV, - $ ONE, T( 1, I ), LDT ) - END IF -* -* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) -* - CALL CTRMV( 'Upper', 'No transpose', 'Non-unit', I-1, - $ T, - $ LDT, T( 1, I ), 1 ) - T( I, I ) = TAU( I ) - IF( I.GT.1 ) THEN - PREVLASTV = MAX( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF + IF(N.EQ.0.OR.K.EQ.0) THEN + RETURN + END IF +* +* Now we determine what factorization our flags are associated with +* +* QR happens when we have forward direction in column storage +* + QR = DIRF.AND.STOREC +* +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute +* + LQT = DIRF.AND.STORET +* +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute +* + LQ = DIRF.AND.STORER +* +* QL happens when we have backward direction in column storage +* + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER + IF( N.EQ.1.OR.K.EQ.1) THEN + IF( LQT.OR.RQT ) THEN + T(1,1) = CONJG(TAU(1)) + ELSE + T(1,1) = TAU(1) + END IF + RETURN + END IF + IF (QR) THEN +* +* Break V into 9 components +* +* V = |-----------------------| +* |V_{1,1} 0 0 | i-1 +* |V_{2,1} V_{2,2} 0 | 1 +* |V_{3,1} V_{3,2} V_{3,3}| n-i +* |-----------------------| +* i-1 1 k-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See clarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' +* [0\\V_{2,2}\\V_{3,2}]T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' +* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + + DO I = 2, K +* +* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' +* We must do this at copy time as otherwise gemv will do nothing +* on the last column when n=k, but we neet to make sure we are +* scaled by this value +* + DO J = 1, I-1 + T(J,I) = -TAU(I)*CONJG(V(I,J)) + END DO + +* +* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} +* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} +* + CALL CGEMV('Conjugate Transpose', N-I, I-1, -TAU(I), + $ V(I+1,1), LDV, V(I+1,I), 1, ONE, T(1, I), 1) + + +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL CTRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) + +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - ELSE - PREVLASTV = 1 - DO I = K, 1, -1 - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = I, K - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( I.LT.K ) THEN - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * CONJG( V( N-K+I , J ) ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**H * V(j:n-k+i,i) -* - CALL CGEMV( 'Conjugate transpose', N-K+I-J, K-I, - $ -TAU( I ), V( J, I+1 ), LDV, V( J, I ), - $ 1, ONE, T( I+1, I ), 1 ) - ELSE -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * V( J, N-K+I ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**H -* - CALL CGEMM( 'N', 'C', K-I, 1, N-K+I-J, - $ -TAU( I ), - $ V( I+1, J ), LDV, V( I, J ), LDV, - $ ONE, T( I+1, I ), LDT ) - END IF -* -* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) -* - CALL CTRMV( 'Lower', 'No transpose', 'Non-unit', - $ K-I, - $ T( I+1, I+1 ), LDT, T( I+1, I ), 1 ) - IF( I.GT.1 ) THEN - PREVLASTV = MIN( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF - T( I, I ) = TAU( I ) - END IF + ELSE IF (LQ) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See clarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + + DO I = 2, K +* +* T_{1,2} = -\tau_{i}V_{1,2} +* + DO J = 1, I-1 + T(J, I) = -TAU(I)*V(J, I) + END DO + +* +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* + CALL CGEMM('No Transpose', 'Conjugate Transpose', I-1, + $ 1, N-I, -TAU(I), V(1,I+1), LDV, V(I, I+1), LDV, ONE, + $ T(1, I), LDT) +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL CTRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) + +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - END IF - RETURN + ELSE IF (LQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | i-1 +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{2,1} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On +* each iteration, T_{3,1:3} are not referenced. See clarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} +* +* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} +* +* This means we will do the following +* +* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' +* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} +* T_{2,1} = T_{1,1}'T_{2,1} +* T_{2,2} = \tau{i} +* + T(1,1) = CONJG(TAU(1)) + + DO I = 2, K +* +* T_{2,1} = -\tau_{i}V_{1,2}' +* + DO J = 1, I-1 + T(I,J) = -CONJG(TAU(I)*V(J,I)) + END DO +* +* T_{2,1} = -\tau_{i}V_{2,3}V_{1,3}' + T_{2,1} +* + CALL CGEMM('No Transpose', 'Conjugate Transpose', 1, + $ I-1, N-I, -CONJG(TAU(I)), V(I,I+1), LDV, V(1, I+1), + $ LDV, ONE, T(I, 1), LDT) +* +* T_{2,1} = T_{1,1}'T_{2,1} +* + CALL CTRMV('Lower', 'Transpose', 'Non-unit', + $ I-1, T, LDT, T(I,1), LDT) + + T(I,I) = CONJG(TAU(I)) + END DO + ELSE IF (QL) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | n-i +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See clarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' +* [V_{1,2}\\V_{2,2}\\0]T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' +* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau(k-i+1) +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau(k-i+1)V_{2,3}' +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*CONJG(V(NMI, KMI + J)) + END DO +* +* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} +* + CALL CGEMV('Conjugate Transpose', N-I, I-1, -TAU(KMI), + $ V(1, KMI + 1), LDV, V(1, KMI), 1, ONE, + $ T(KMI+1, KMI), 1) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL CTRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI + 1, KMI + 1), LDT, T(KMI + 1, KMI), 1) + + END DO + ELSE IF (RQ) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See clarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*V(KMI + J, NMI) + END DO +* +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* + CALL CGEMM('No Transpose', 'Conjugate Transpose', I-1, + $ 1, N-I, -TAU(KMI), V(KMI+1, 1), LDV, V(KMI, 1), LDV, + $ ONE, T(KMI+1, KMI), LDT) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL CTRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI+1, KMI), 1) + END DO + ELSE IF (RQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | k-i +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{2,3} at +* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On +* each iteration, T_{1,1:3} are not referenced. See clarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} +* +* T_{3,2} = -T_{2,2}(V_{2,1}V_{3,1}' + V_{3,2}')T_{3,3} * -* End of CLARFT_LVL2 +* Thus, we will compute * - END +* T_{2,2} = \tau_{k-i+1} +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} +* T_{2,3} = T_{3,3}'T_{2,3} +* + T(K,K) = CONJG(TAU(K)) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = CONJG(TAU(KMI)) +* +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* + DO J = 1, I-1 + T(KMI, KMI + J) = -CONJG(TAU(KMI)*V(KMI + J, NMI)) + END DO +* +* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} +* + CALL CGEMM('No Transpose', 'Conjugate Transpose', 1, + $ I-1, N-I, -CONJG(TAU(KMI)), V(KMI, 1), LDV, + $ V(KMI+1,1), LDV, ONE, T(KMI, KMI+1), LDT) +* +* T_{2,3} = T_{3,3}'T_{2,3} +* + CALL CTRMV('Upper', 'Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI, KMI+1), LDT) + END DO + END IF + END SUBROUTINE diff --git a/lapack-netlib/SRC/dlarft.c b/lapack-netlib/SRC/dlarft.c index d478b38ece..0eff3edb54 100644 --- a/lapack-netlib/SRC/dlarft.c +++ b/lapack-netlib/SRC/dlarft.c @@ -231,8 +231,8 @@ typedef struct Namelist Namelist; static integer c__3 = 3; static integer c_n1 = -1; static integer c__2 = 2; -static doublereal c_b13 = 1.; -static doublereal c_b22 = -1.; +static doublereal c_b18 = 1.; +static doublereal c_b27 = -1.; /* > \brief \b DLARFT forms the triangular factor T of a block reflector H = I - vtvH */ @@ -283,6 +283,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**T * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -295,6 +298,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -302,8 +307,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -374,7 +381,7 @@ f"> */ /* > the H(i) is best illustrated by the following example with n = 5 and */ /* > k = 3. The elements equal to 1 are not stored. */ /* > */ -/* > DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': */ +/* > DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and (STOREV = 'R' or STOREV = 'T'): */ /* > */ /* > V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) */ /* > ( v1 1 ) ( 1 v2 v2 v2 ) */ @@ -382,13 +389,36 @@ f"> */ /* > ( v1 v2 v3 ) */ /* > ( v1 v2 v3 ) */ /* > */ -/* > DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': */ +/* > DIRECT = 'B' and STOREV = 'C': (DIRECT = 'B' or DIRECT = 'T') and STOREV = 'R': */ /* > */ /* > V = ( v1 v2 v3 ) V = ( v1 v1 1 ) */ /* > ( v1 v2 v3 ) ( v2 v2 v2 1 ) */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -403,12 +433,14 @@ f"> */ /* Local variables */ integer i__, j, l; - logical lq, ql, qr; + logical lq, ql, qr, rq; integer nx; extern /* Subroutine */ void dlarft_lvl2__(char *, char *, integer *, integer *, doublereal *, integer *, doublereal *, doublereal *, integer *); - logical dirf, colv; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern /* Subroutine */ void dgemm_(char *, char *, integer *, integer *, integer *, doublereal *, doublereal *, integer *, doublereal *, integer *, doublereal *, doublereal *, integer *); @@ -417,9 +449,10 @@ f"> */ integer *, integer *, doublereal *, doublereal *, integer *, doublereal *, integer *), dlacpy_( char *, integer *, integer *, doublereal *, integer *, doublereal - *, integer *); + *, integer *), xerbla_(char *, integer *, ftnlen); extern integer ilaenv_(integer *, char *, char *, integer *, integer *, integer *, integer *, ftnlen, ftnlen); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -442,7 +475,7 @@ f"> */ /* Based on the algorithm of Elmroth and Gustavson, */ /* IBM J. Res. Develop. Vol 44 No. 4 July 2000. */ -/* Quick return if possible */ +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -454,18 +487,95 @@ f"> */ t -= t_offset; /* Function Body */ + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("DLARFT", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + if (*n == 0 || *k == 0) { - return; + return 0; } +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + /* Base case */ if (*n == 1 || *k == 1) { t[t_dim1 + 1] = tau[1]; - return; + return 0; } -/* Determine when to cross over into the level 2 based implementation */ +/* Determine crossover point from level 2 to level 3 BLAS implementation */ /* Writing concatenation */ i__1[0] = 1, a__1[0] = direct; @@ -474,41 +584,17 @@ f"> */ nx = ilaenv_(&c__3, "DLARFT", ch__1, n, k, &c_n1, &c_n1, (ftnlen)6, ( ftnlen)2); if (*k < nx) { + +/* Finish this component with a level 2 BLAS implementation */ + dlarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return; + return 0; } -/* Beginning of executable statements */ +/* Beginning of executable statements for the recursive case */ l = *k / 2; - -/* Determine what kind of Q we need to compute */ -/* We assume that if the user doesn't provide 'F' for DIRECT, */ -/* then they meant to provide 'B' and if they don't provide */ -/* 'C' for STOREV, then they meant to provide 'R' */ - - dirf = lsame_(direct, "F"); - colv = lsame_(storev, "C"); - -/* QR happens when we have forward direction in column storage */ - - qr = dirf && colv; - -/* LQ happens when we have forward direction in row storage */ - - lq = dirf && ! colv; - -/* QL happens when we have backward direction in column storage */ - - ql = ! dirf && colv; - -/* The last case is RQ. Due to how we structured this, if the */ -/* above 3 are false, then RQ must be true, so we never store */ -/* this */ -/* RQ happens when we have backward direction in row storage */ -/* RQ = (.NOT.DIRF).AND.(.NOT.COLV) */ - if (qr) { /* Break V apart into 6 components */ @@ -585,7 +671,7 @@ f"> */ /* T_{1,2} = T_{1,2}*V_{2,2} */ i__2 = *k - l; - dtrmm_("Right", "Lower", "No transpose", "Unit", &l, &i__2, &c_b13, & + dtrmm_("Right", "Lower", "No transpose", "Unit", &l, &i__2, &c_b18, & v[l + 1 + (l + 1) * v_dim1], ldv, &t[(l + 1) * t_dim1 + 1], ldt); @@ -594,8 +680,8 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - dgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b13, &v[*k + - 1 + v_dim1], ldv, &v[*k + 1 + (l + 1) * v_dim1], ldv, &c_b13, + dgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b18, &v[*k + + 1 + v_dim1], ldv, &v[*k + 1 + (l + 1) * v_dim1], ldv, &c_b18, &t[(l + 1) * t_dim1 + 1], ldt); /* At this point, we have that T_{1,2} = V_1'*V_2 */ @@ -605,14 +691,14 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__2 = *k - l; - dtrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b22, + dtrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b27, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ i__2 = *k - l; dtrmm_("Right", "Upper", "No transpose", "Non-unit", &l, &i__2, & - c_b13, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + c_b18, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + 1], ldt); } else if (lq) { @@ -648,8 +734,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ -/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ +/* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) */ +/* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 */ /* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ @@ -660,7 +746,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{1,2} */ @@ -686,7 +772,7 @@ f"> */ /* T_{1,2} = T_{1,2}*V_{2,2}' */ i__2 = *k - l; - dtrmm_("Right", "Upper", "Transpose", "Unit", &l, &i__2, &c_b13, &v[l + dtrmm_("Right", "Upper", "Transpose", "Unit", &l, &i__2, &c_b18, &v[l + 1 + (l + 1) * v_dim1], ldv, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = V_{1,3}*V_{2,3}' + T_{1,2} */ @@ -694,9 +780,9 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - dgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b13, &v[(*k + dgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b18, &v[(*k + 1) * v_dim1 + 1], ldv, &v[l + 1 + (*k + 1) * v_dim1], ldv, & - c_b13, &t[(l + 1) * t_dim1 + 1], ldt); + c_b18, &t[(l + 1) * t_dim1 + 1], ldt); /* At this point, we have that T_{1,2} = V_1*V_2' */ /* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} */ @@ -705,15 +791,118 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__2 = *k - l; - dtrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b22, + dtrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b27, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ i__2 = *k - l; dtrmm_("Right", "Upper", "No transpose", "Non-unit", &l, &i__2, & - c_b13, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + c_b18, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + 1], ldt); + } else if (lqt) { + +/* Break V apart into 6 components */ + +/* V = |----------------------| */ +/* |V_{1,1} V_{1,2} V{1,3}| */ +/* |0 V_{2,2} V{2,3}| */ +/* |----------------------| */ + +/* V_{1,1}\in\R^{l,l} unit upper triangular */ +/* V_{1,2}\in\R^{l,k-l} rectangular */ +/* V_{1,3}\in\R^{l,n-k} rectangular */ + +/* V_{2,2}\in\R^{k-l,k-l} unit upper triangular */ +/* V_{2,3}\in\R^{k-l,n-k} rectangular */ + +/* Where l = floor(k/2) */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} 0 | */ +/* |T_{2,1} T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\R^{l, l} lower triangular */ +/* T_{2,2}\in\R^{k-l, k-l} lower triangular */ +/* T_{2,1}\in\R^{k-l, l} rectangular */ + +/* Then, consider the product: */ + +/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ +/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ + +/* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{2,1} */ + +/* Compute T_{1,1} recursively */ + + dlarft_(direct, storev, n, &l, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + i__2 = *n - l; + i__3 = *k - l; + dlarft_(direct, storev, &i__2, &i__3, &v[l + 1 + (l + 1) * v_dim1], + ldv, &tau[l + 1], &t[l + 1 + (l + 1) * t_dim1], ldt); + +/* Compute T_{2,1} */ +/* T_{2,1} = V_{1,2}' */ + + i__2 = *k - l; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + t[l + i__ + j * t_dim1] = v[j + (l + i__) * v_dim1]; + } + } + +/* T_{2,1} = V_{2,2}*T_{2,1} */ + + i__2 = *k - l; + dtrmm_("Left", "Upper", "No Transpose", "Unit", &i__2, &l, &c_b18, &v[ + l + 1 + (l + 1) * v_dim1], ldv, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} */ +/* Note: We assume K <= N, and GEMM will do nothing if N=K */ + + i__2 = *k - l; + i__3 = *n - *k; + dgemm_("No Transpose", "Transpose", &i__2, &l, &i__3, &c_b18, &v[l + + 1 + (*k + 1) * v_dim1], ldv, &v[(*k + 1) * v_dim1 + 1], ldv, & + c_b18, &t[l + 1 + t_dim1], ldt); + +/* At this point, we have that T_{2,1} = V_2*V_1' */ +/* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} */ +/* respectively. */ + +/* T_{2,1} = -T_{2,2}*T_{2,1} */ + + i__2 = *k - l; + dtrmm_("Left", "Lower", "No Transpose", "Non-unit", &i__2, &l, &c_b27, + &t[l + 1 + (l + 1) * t_dim1], ldt, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = T_{2,1}*T_{1,1} */ + + i__2 = *k - l; + dtrmm_("Right", "Lower", "No Transpose", "Non-unit", &i__2, &l, & + c_b18, &t[t_offset], ldt, &t[l + 1 + t_dim1], ldt); } else if (ql) { /* Break V apart into 6 components */ @@ -791,7 +980,7 @@ f"> */ /* T_{2,1} = T_{2,1}*V_{2,1} */ i__2 = *k - l; - dtrmm_("Right", "Upper", "No transpose", "Unit", &l, &i__2, &c_b13, & + dtrmm_("Right", "Upper", "No transpose", "Unit", &l, &i__2, &c_b18, & v[*n - *k + 1 + v_dim1], ldv, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = V_{2,2}'*V_{2,1} + T_{2,1} */ @@ -799,8 +988,8 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - dgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b13, &v[(*k - - l + 1) * v_dim1 + 1], ldv, &v[v_offset], ldv, &c_b13, &t[*k + dgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b18, &v[(*k + - l + 1) * v_dim1 + 1], ldv, &v[v_offset], ldv, &c_b18, &t[*k - l + 1 + t_dim1], ldt); /* At this point, we have that T_{2,1} = V_2'*V_1 */ @@ -810,7 +999,7 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__2 = *k - l; - dtrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__2, &c_b22, + dtrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__2, &c_b27, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); @@ -818,11 +1007,8 @@ f"> */ i__2 = *k - l; dtrmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__2, & - c_b13, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); - } else { - -/* Else means RQ case */ - + c_b18, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + } else if (rq) { /* Break V apart into 6 components */ /* V = |-----------------------| */ @@ -855,8 +1041,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ -/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ +/* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) */ +/* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 */ /* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ @@ -867,7 +1053,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{2,1} */ @@ -893,7 +1079,7 @@ f"> */ /* T_{2,1} = T_{2,1}*V_{1,2}' */ i__2 = *k - l; - dtrmm_("Right", "Lower", "Transpose", "Unit", &l, &i__2, &c_b13, &v[(* + dtrmm_("Right", "Lower", "Transpose", "Unit", &l, &i__2, &c_b18, &v[(* n - *k + 1) * v_dim1 + 1], ldv, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} */ @@ -901,8 +1087,8 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - dgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b13, &v[*k - - l + 1 + v_dim1], ldv, &v[v_offset], ldv, &c_b13, &t[*k - l + + dgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b18, &v[*k - + l + 1 + v_dim1], ldv, &v[v_offset], ldv, &c_b18, &t[*k - l + 1 + t_dim1], ldt); /* At this point, we have that T_{2,1} = V_2*V_1' */ @@ -912,16 +1098,120 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__2 = *k - l; - dtrmm_("Left", "Lower", "No tranpose", "Non-unit", &l, &i__2, &c_b22, - &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + + dtrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__2, &c_b27, + &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = T_{2,1}*T_{1,1} */ i__2 = *k - l; - dtrmm_("Right", "Lower", "No tranpose", "Non-unit", &l, &i__2, &c_b13, - &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + dtrmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__2, & + c_b18, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + } else if (rqt) { +/* Break V apart into 6 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} V_{1,2} 0 | */ +/* |V_{2,1} V_{2,2} V_{2,3}| */ +/* |-----------------------| */ + +/* V_{1,1}\in\R^{k-l,n-k} rectangular */ +/* V_{1,2}\in\R^{k-l,k-l} unit lower triangular */ + +/* V_{2,1}\in\R^{l,n-k} rectangular */ +/* V_{2,2}\in\R^{l,k-l} rectangular */ +/* V_{2,3}\in\R^{l,l} unit lower triangular */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} T_{1,2}| */ +/* | 0 T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\R^{k-l, k-l} non-unit upper triangular */ +/* T_{2,2}\in\R^{l, l} non-unit upper triangular */ +/* T_{1,2}\in\R^{k-l, l} rectangular */ + +/* Where l = floor(k/2) */ + +/* Then, consider the product: */ + +/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ +/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ + +/* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{1,2} */ + +/* Compute T_{1,1} recursively */ + + i__2 = *n - l; + i__3 = *k - l; + dlarft_(direct, storev, &i__2, &i__3, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + dlarft_(direct, storev, n, &l, &v[*k - l + 1 + v_dim1], ldv, &tau[*k + - l + 1], &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt); + +/* Compute T_{1,2} */ +/* T_{1,2} = V_{2,2}' */ + + i__2 = *k - l; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + t[i__ + (*k - l + j) * t_dim1] = v[*k - l + j + (*n - *k + + i__) * v_dim1]; + } + } + +/* T_{1,2} = V_{1,2}T_{1,2} */ + + i__2 = *k - l; + dtrmm_("Left", "Lower", "No Transpose", "Unit", &i__2, &l, &c_b18, &v[ + (*n - *k + 1) * v_dim1 + 1], ldv, &t[(*k - l + 1) * t_dim1 + + 1], ldt); + +/* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} */ + + i__2 = *k - l; + i__3 = *n - *k; + dgemm_("No Transpose", "Transpose", &i__2, &l, &i__3, &c_b18, &v[ + v_offset], ldv, &v[*k - l + 1 + v_dim1], ldv, &c_b18, &t[(*k + - l + 1) * t_dim1 + 1], ldt); + +/* At this point, we have that T_{1,2} = V_1*V_2' */ +/* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} */ +/* respectively. */ + +/* T_{1,2} = -T_{1,1}*T_{1,2} */ + + i__2 = *k - l; + dtrmm_("Left", "Upper", "No Transpose", "Non-Unit", &i__2, &l, &c_b27, + &t[t_offset], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); + +/* T_{1,2} = T_{1,2}*T_{2,2} */ + + i__2 = *k - l; + dtrmm_("Right", "Upper", "No Transpose", "Non-Unit", &i__2, &l, & + c_b18, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - + l + 1) * t_dim1 + 1], ldt); } - return; + return 0; } /* dlarft_ */ diff --git a/lapack-netlib/SRC/dlarft.f b/lapack-netlib/SRC/dlarft.f index fa2ea0d134..154f7226d8 100644 --- a/lapack-netlib/SRC/dlarft.f +++ b/lapack-netlib/SRC/dlarft.f @@ -48,6 +48,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**T * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -60,6 +63,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -67,8 +72,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -139,7 +146,7 @@ *> the H(i) is best illustrated by the following example with n = 5 and *> k = 3. The elements equal to 1 are not stored. *> -*> DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': +*> DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and (STOREV = 'R' or STOREV = 'T'): *> *> V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) *> ( v1 1 ) ( 1 v2 v2 v2 ) @@ -147,13 +154,36 @@ *> ( v1 v2 v3 ) *> ( v1 v2 v3 ) *> -*> DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': +*> DIRECT = 'B' and STOREV = 'C': (DIRECT = 'B' or DIRECT = 'T') and STOREV = 'R': *> *> V = ( v1 v2 v3 ) V = ( v1 v1 1 ) *> ( v1 v2 v3 ) ( v2 v2 v2 1 ) *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -177,24 +207,26 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. Parameters .. * - DOUBLE PRECISION ONE, NEG_ONE, ZERO - PARAMETER(ONE=1.0D+0, ZERO = 0.0D+0, NEG_ONE=-1.0D+0) + DOUBLE PRECISION ONE, NEG_ONE + PARAMETER(ONE=1.0D+0, NEG_ONE=-1.0D+0) * * .. Local Scalars .. * - INTEGER I,J,L,NX - LOGICAL QR,LQ,QL,DIRF,COLV + INTEGER I,J,L,NX,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET * * .. External Subroutines .. * - EXTERNAL DTRMM,DGEMM,DLACPY + EXTERNAL DLARFT_LVL2, DTRMM, DGEMM, DLACPY, XERBLA * * .. External Functions.. * LOGICAL LSAME INTEGER ILAENV EXTERNAL LSAME, ILAENV -* +* * The general scheme used is inspired by the approach inside DGEQRT3 * which was (at the time of writing this code): * Based on the algorithm of Elmroth and Gustavson, @@ -202,12 +234,90 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * .. * .. Executable Statements .. * +* Convert our character flags to logical flags for later +* + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') +* +* Error handling for our character flags +* + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('DLARFT', INFO) + RETURN + END IF +* * Quick return if possible * IF(N.EQ.0.OR.K.EQ.0) THEN RETURN END IF * +* Now we determine what factorization our flags are associated with +* +* QR happens when we have forward direction in column storage +* + QR = DIRF.AND.STOREC +* +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute +* + LQT = DIRF.AND.STORET +* +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute +* + LQ = DIRF.AND.STORER +* +* QL happens when we have backward direction in column storage +* + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER +* * Base case * IF(N.EQ.1.OR.K.EQ.1) THEN @@ -215,44 +325,20 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, RETURN END IF * -* Determine when to cross over into the level 2 based implementation +* Determine crossover point from level 2 to level 3 BLAS implementation * NX = ILAENV(3, "DLARFT", DIRECT // STOREV, N, K, -1, -1) IF(K.LT.NX) THEN +* +* Finish this component with a level 2 BLAS implementation +* CALL DLARFT_LVL2(DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT) RETURN END IF * -* Beginning of executable statements +* Beginning of executable statements for the recursive case * L = K / 2 -* -* Determine what kind of Q we need to compute -* We assume that if the user doesn't provide 'F' for DIRECT, -* then they meant to provide 'B' and if they don't provide -* 'C' for STOREV, then they meant to provide 'R' -* - DIRF = LSAME(DIRECT,'F') - COLV = LSAME(STOREV,'C') -* -* QR happens when we have forward direction in column storage -* - QR = DIRF.AND.COLV -* -* LQ happens when we have forward direction in row storage -* - LQ = DIRF.AND.(.NOT.COLV) -* -* QL happens when we have backward direction in column storage -* - QL = (.NOT.DIRF).AND.COLV -* -* The last case is RQ. Due to how we structured this, if the -* above 3 are false, then RQ must be true, so we never store -* this -* RQ happens when we have backward direction in row storage -* RQ = (.NOT.DIRF).AND.(.NOT.COLV) -* IF(QR) THEN * * Break V apart into 6 components @@ -266,17 +352,17 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\R^{l,l} unit lower triangular * V_{2,1}\in\R^{k-l,l} rectangular * V_{3,1}\in\R^{n-k,l} rectangular -* +* * V_{2,2}\in\R^{k-l,k-l} unit lower triangular * V_{3,2}\in\R^{n-k,k-l} rectangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -287,17 +373,17 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_1*T_{1,1}*V_1')*(I - V_2*T_{2,2}*V_2') * = I - V_1*T_{1,1}*V_1' - V_2*T_{2,2}*V_2' + V_1*T_{1,1}*V_1'*V_2*T_{2,2}*V_2' -* +* * Define T_{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -309,30 +395,29 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL DLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL DLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * -* Compute T_{1,2} +* Compute T_{1,2} * T_{1,2} = V_{2,1}' * DO J = 1, L DO I = 1, K-L - T(J, L+I) = V(L+I, J) + T(J,L+I) = V(L+I,J) END DO END DO * * T_{1,2} = T_{1,2}*V_{2,2} * CALL DTRMM('Right', 'Lower', 'No transpose', 'Unit', L, - $ K-L, ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) + $ K-L, ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = V_{3,1}'*V_{3,2} + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL DGEMM('Transpose', 'No transpose', L, K-L, N-K, ONE, - $ V(K+1, 1), LDV, V(K+1, L+1), LDV, ONE, - $ T(1, L+1), LDT) + CALL DGEMM('Transpose', 'No transpose', L, K-L, N-K, ONE, + $ V(K+1, 1), LDV, V(K+1,L+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1'*V_2 * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -341,12 +426,12 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = -T_{1,1}*T_{1,2} * CALL DTRMM('Left', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) + $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*T_{2,2} * - CALL DTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + CALL DTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) ELSE IF(LQ) THEN * @@ -360,19 +445,19 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\R^{l,l} unit upper triangular * V_{1,2}\in\R^{l,k-l} rectangular * V_{1,3}\in\R^{l,n-k} rectangular -* +* * V_{2,2}\in\R^{k-l,k-l} unit upper triangular * V_{2,3}\in\R^{k-l,n-k} rectangular * * Where l = floor(k/2) * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -381,20 +466,20 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2}\in\R^{l, k-l} rectangular * * Then, consider the product: -* -* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) -* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 -* +* +* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) +* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 +* * Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{1,2} * @@ -404,27 +489,26 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL DLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL DLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * * Compute T_{1,2} * T_{1,2} = V_{1,2} * - CALL DLACPY('All', L, K-L, V(1, L+1), LDV, T(1, L+1), LDT) + CALL DLACPY('All', L, K - L, V(1,L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*V_{2,2}' * CALL DTRMM('Right', 'Upper', 'Transpose', 'Unit', L, K-L, - $ ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) + $ ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = V_{1,3}*V_{2,3}' + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL DGEMM('No transpose', 'Transpose', L, K-L, N-K, ONE, - $ V(1, K+1), LDV, V(L+1, K+1), LDV, ONE, - $ T(1, L+1), LDT) + $ V(1, K+1), LDV, V(L+1, K+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1*V_2' * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -433,13 +517,106 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = -T_{1,1}*T_{1,2} * CALL DTRMM('Left', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) + $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*T_{2,2} * CALL DTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) + ELSE IF(LQT) THEN +* +* Break V apart into 6 components +* +* V = |----------------------| +* |V_{1,1} V_{1,2} V{1,3}| +* |0 V_{2,2} V{2,3}| +* |----------------------| +* +* V_{1,1}\in\R^{l,l} unit upper triangular +* V_{1,2}\in\R^{l,k-l} rectangular +* V_{1,3}\in\R^{l,n-k} rectangular +* +* V_{2,2}\in\R^{k-l,k-l} unit upper triangular +* V_{2,3}\in\R^{k-l,n-k} rectangular +* +* Where l = floor(k/2) +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} 0 | +* |T_{2,1} T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\R^{l, l} lower triangular +* T_{2,2}\in\R^{k-l, k-l} lower triangular +* T_{2,1}\in\R^{k-l, l} rectangular +* +* Then, consider the product: +* +* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) +* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 +* +* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{2,1} +* +* Compute T_{1,1} recursively +* + CALL DLARFT(DIRECT, STOREV, N, L, V, LDV, TAU, T, LDT) +* +* Compute T_{2,2} recursively +* + CALL DLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) + +* +* Compute T_{2,1} +* T_{2,1} = V_{1,2}' +* + DO I = 1, K-L + DO J = 1, L + T(L+I,J) = V(J,L+I) + END DO + END DO +* +* T_{2,1} = V_{2,2}*T_{2,1} +* + CALL DTRMM('Left', 'Upper', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(L+1,L+1), LDV, T(L+1,1), LDT) +* +* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} +* Note: We assume K <= N, and GEMM will do nothing if N=K +* + CALL DGEMM('No Transpose', 'Transpose', K-L, L, N-K, ONE, + $ V(L+1,K+1), LDV, V(1, K+1), LDV, ONE, T(L+1,1), LDT) +* +* At this point, we have that T_{2,1} = V_2*V_1' +* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} +* respectively. +* +* T_{2,1} = -T_{2,2}*T_{2,1} +* + CALL DTRMM('Left', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, NEG_ONE, T(L+1,L+1), LDT, T(L+1,1), LDT) +* +* T_{2,1} = T_{2,1}*T_{1,1} +* + CALL DTRMM('Right', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, ONE, T, LDT, T(L+1,1), LDT) ELSE IF(QL) THEN * * Break V apart into 6 components @@ -452,18 +629,18 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * V_{1,1}\in\R^{n-k,k-l} rectangular * V_{2,1}\in\R^{k-l,k-l} unit upper triangular -* +* * V_{1,2}\in\R^{n-k,l} rectangular * V_{2,2}\in\R^{k-l,l} rectangular * V_{3,2}\in\R^{l,l} unit upper triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -474,17 +651,17 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_2*T_{2,2}*V_2')*(I - V_1*T_{1,1}*V_1') * = I - V_2*T_{2,2}*V_2' - V_1*T_{1,1}*V_1' + V_2*T_{2,2}*V_2'*V_1*T_{1,1}*V_1' -* +* * Define T_{2,1} = -T_{2,2}*V_2'*V_1*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -492,34 +669,34 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{1,1} recursively * - CALL DLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL DLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * CALL DLARFT(DIRECT, STOREV, N, L, V(1, K-L+1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2}' * DO J = 1, K-L DO I = 1, L - T(K-L+I, J) = V(N-K+J, K-L+I) + T(K-L+I,J) = V(N-K+J, K-L+I) END DO END DO * * T_{2,1} = T_{2,1}*V_{2,1} * CALL DTRMM('Right', 'Upper', 'No transpose', 'Unit', L, - $ K-L, ONE, V(N-K+1, 1), LDV, T(K-L+1, 1), LDT) + $ K-L, ONE, V(N-K+1,1), LDV, T(K-L+1,1), LDT) * * T_{2,1} = V_{2,2}'*V_{2,1} + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL DGEMM('Transpose', 'No transpose', L, K-L, N-K, ONE, - $ V(1, K-L+1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + $ V(1,K-L+1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2'*V_1 * All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} @@ -528,17 +705,13 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{2,1} = -T_{2,2}*T_{2,1} * CALL DTRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * CALL DTRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) - ELSE -* -* Else means RQ case -* + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQ) THEN * Break V apart into 6 components * * V = |-----------------------| @@ -553,13 +726,13 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{2,2}\in\R^{l,k-l} rectangular * V_{2,3}\in\R^{l,l} unit lower triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -570,51 +743,51 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* -* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) -* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 -* +* +* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) +* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 +* * Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{2,1} * * Compute T_{1,1} recursively * - CALL DLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL DLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * - CALL DLARFT(DIRECT, STOREV, N, L, V(K-L+1, 1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + CALL DLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2} * - CALL DLACPY('All', L, K-L, V(K-L+1, N-K+1), LDV, - $ T(K-L+1, 1), LDT) + CALL DLACPY('All', L, K-L, V(K-L+1,N-K+1), LDV, T(K-L+1,1), + $ LDT) * * T_{2,1} = T_{2,1}*V_{1,2}' * CALL DTRMM('Right', 'Lower', 'Transpose', 'Unit', L, K-L, - $ ONE, V(1, N-K+1), LDV, T(K-L+1, 1), LDT) + $ ONE, V(1, N-K+1), LDV, T(K-L+1,1), LDT) * -* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} +* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL DGEMM('No transpose', 'Transpose', L, K-L, N-K, ONE, - $ V(K-L+1, 1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + CALL DGEMM('No transpose', 'Transpose', L, K-L, N-K, ONE, + $ V(K-L+1,1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2*V_1' @@ -623,14 +796,104 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * T_{2,1} = -T_{2,2}*T_{2,1} * - CALL DTRMM('Left', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + CALL DTRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * - CALL DTRMM('Right', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) + CALL DTRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQT) THEN +* Break V apart into 6 components +* +* V = |-----------------------| +* |V_{1,1} V_{1,2} 0 | +* |V_{2,1} V_{2,2} V_{2,3}| +* |-----------------------| +* +* V_{1,1}\in\R^{k-l,n-k} rectangular +* V_{1,2}\in\R^{k-l,k-l} unit lower triangular +* +* V_{2,1}\in\R^{l,n-k} rectangular +* V_{2,2}\in\R^{l,k-l} rectangular +* V_{2,3}\in\R^{l,l} unit lower triangular +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} T_{1,2}| +* | 0 T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\R^{k-l, k-l} non-unit upper triangular +* T_{2,2}\in\R^{l, l} non-unit upper triangular +* T_{1,2}\in\R^{k-l, l} rectangular +* +* Where l = floor(k/2) +* +* Then, consider the product: +* +* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) +* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 +* +* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{1,2} +* +* Compute T_{1,1} recursively +* + CALL DLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) +* +* Compute T_{2,2} recursively +* + CALL DLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) +* +* Compute T_{1,2} +* T_{1,2} = V_{2,2}' +* + DO I = 1, K-L + DO J = 1, L + T(I,K-L+J) = V(K-L+J, N-K+I) + END DO + END DO +* +* T_{1,2} = V_{1,2}T_{1,2} +* + CALL DTRMM('Left', 'Lower', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(1,N-K+1), LDV, T(1,K-L+1), LDT) +* +* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} +* + CALL DGEMM('No Transpose', 'Transpose', K-L, L, N-K, ONE, V, + $ LDV, V(K-L+1,1), LDV, ONE, T(1, K-L+1), LDT) +* +* At this point, we have that T_{1,2} = V_1*V_2' +* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} +* respectively. +* +* T_{1,2} = -T_{1,1}*T_{1,2} +* + CALL DTRMM('Left', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, NEG_ONE, T, LDT, T(1, K-L+1), LDT) +* +* T_{1,2} = T_{1,2}*T_{2,2} +* + CALL DTRMM('Right', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, ONE, T(K-L+1,K-L+1), LDT, T(1, K-L+1), LDT) END IF END SUBROUTINE diff --git a/lapack-netlib/SRC/dlarft_lvl2.c b/lapack-netlib/SRC/dlarft_lvl2.c index ff17bca48a..da5efa9a06 100644 --- a/lapack-netlib/SRC/dlarft_lvl2.c +++ b/lapack-netlib/SRC/dlarft_lvl2.c @@ -223,31 +223,20 @@ typedef struct Namelist Namelist; /* Table of constant values */ static integer c__1 = 1; -static doublereal c_b6 = 1.; +static doublereal c_b11 = 1.; -/* > \brief \b DLARFT_LVL2: Level 2 BLAS version for terminating case of DLARFT. */ +/* > \brief \b DLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH */ /* =========== DOCUMENTATION =========== */ /* Online html documentation available at */ /* http://www.netlib.org/lapack/explore-html/ */ -/* > Download DLARFT_LVL2 + dependencies */ -/* > */ -/* > [TGZ] */ -/* > */ -/* > [ZIP] */ -/* > */ -/* > [TXT] */ - /* Definition: */ /* =========== */ /* SUBROUTINE DLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, */ -/* T, LDT ) */ +/* $ T, LDT ) */ /* CHARACTER DIRECT, STOREV */ /* INTEGER K, LDT, LDV, N */ @@ -275,6 +264,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**T * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -287,6 +279,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -294,8 +288,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -381,6 +377,29 @@ f"> */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -393,14 +412,19 @@ f"> */ doublereal d__1; /* Local variables */ - integer i__, j, prevlastv; + integer i__, j; + logical lq, ql, qr, rq; + integer kmi, nmi; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern logical lsame_(char *, char *); extern /* Subroutine */ void dgemv_(char *, integer *, integer *, doublereal *, doublereal *, integer *, doublereal *, integer *, - doublereal *, doublereal *, integer *); - integer lastv; - extern /* Subroutine */ void dtrmv_(char *, char *, char *, integer *, - doublereal *, integer *, doublereal *, integer *), mecago_(); + doublereal *, doublereal *, integer *), dtrmv_(char *, + char *, char *, integer *, doublereal *, integer *, doublereal *, + integer *), xerbla_(char *, integer *, ftnlen); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -408,10 +432,16 @@ f"> */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ -/* ===================================================================== */ -/* Quick return if possible */ + + + + + + + +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -423,171 +453,565 @@ f"> */ t -= t_offset; /* Function Body */ - if (*n == 0) { - return; + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("DLARFT_LVL2", &info, (ftnlen)11); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *k == 0) { + return 0; + } + +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + if (*n == 1 || *k == 1) { + t[t_dim1 + 1] = tau[1]; + return 0; } + if (qr) { - if (lsame_(direct, "F")) { - prevlastv = *n; +/* Break V into 9 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} 0 0 | i-1 */ +/* |V_{2,1} V_{2,2} 0 | 1 */ +/* |V_{3,1} V_{3,2} V_{3,3}| n-i */ +/* |-----------------------| */ +/* i-1 1 k-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See dlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' */ +/* [0\\V_{2,2}\\V_{3,2}]T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' */ +/* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + t[t_dim1 + 1] = tau[1]; i__1 = *k; - for (i__ = 1; i__ <= i__1; ++i__) { - prevlastv = f2cmax(i__,prevlastv); - if (tau[i__] == 0.) { - -/* H(i) = I */ - - i__2 = i__; - for (j = 1; j <= i__2; ++j) { - t[j + i__ * t_dim1] = 0.; - } - } else { - -/* general case */ - - if (lsame_(storev, "C")) { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - if (v[lastv + i__ * v_dim1] != 0.) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[i__ + j * v_dim1]; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**T * V(i:j,i) */ - - i__2 = j - i__; - i__3 = i__ - 1; - d__1 = -tau[i__]; - dgemv_("Transpose", &i__2, &i__3, &d__1, &v[i__ + 1 + - v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, & - c_b6, &t[i__ * t_dim1 + 1], &c__1); - } else { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - if (v[i__ + lastv * v_dim1] != 0.) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[j + i__ * v_dim1]; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**T */ - - i__2 = i__ - 1; - i__3 = j - i__; - d__1 = -tau[i__]; - dgemv_("No transpose", &i__2, &i__3, &d__1, &v[(i__ + 1) * - v_dim1 + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], - ldv, &c_b6, &t[i__ * t_dim1 + 1], &c__1); - } - -/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ - - i__2 = i__ - 1; - dtrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ - t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); - t[i__ + i__ * t_dim1] = tau[i__]; - if (i__ > 1) { - prevlastv = f2cmax(prevlastv,lastv); - } else { - prevlastv = lastv; - } + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' */ +/* We must do this at copy time as otherwise gemv will do nothing */ +/* on the last column when n=k, but we neet to make sure we are */ +/* scaled by this value */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[j + i__ * t_dim1] = -v[i__ + j * v_dim1] * tau[i__]; } + +/* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} */ +/* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + d__1 = -tau[i__]; + dgemv_("Transpose", &i__2, &i__3, &d__1, &v[i__ + 1 + v_dim1], + ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, &c_b11, &t[i__ * + t_dim1 + 1], &c__1); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + dtrmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + t[i__ + i__ * t_dim1] = tau[i__]; } - } else { - prevlastv = 1; - for (i__ = *k; i__ >= 1; --i__) { - if (tau[i__] == 0.) { - -/* H(i) = I */ - - i__1 = *k; - for (j = i__; j <= i__1; ++j) { - t[j + i__ * t_dim1] = 0.; - } - } else { - -/* general case */ - - if (i__ < *k) { - if (lsame_(storev, "C")) { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - if (v[lastv + i__ * v_dim1] != 0.) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[*n - *k + i__ - + j * v_dim1]; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**T * V(j:n-k+i,i) */ - - i__1 = *n - *k + i__ - j; - i__2 = *k - i__; - d__1 = -tau[i__]; - dgemv_("Transpose", &i__1, &i__2, &d__1, &v[j + (i__ - + 1) * v_dim1], ldv, &v[j + i__ * v_dim1], & - c__1, &c_b6, &t[i__ + 1 + i__ * t_dim1], & - c__1); - } else { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - if (v[i__ + lastv * v_dim1] != 0.) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[j + (*n - *k - + i__) * v_dim1]; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**T */ - - i__1 = *k - i__; - i__2 = *n - *k + i__ - j; - d__1 = -tau[i__]; - dgemv_("No transpose", &i__1, &i__2, &d__1, &v[i__ + - 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], - ldv, &c_b6, &t[i__ + 1 + i__ * t_dim1], &c__1); - } - -/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ - - i__1 = *k - i__; - dtrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ - + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * - t_dim1], &c__1) - ; - if (i__ > 1) { - prevlastv = f2cmin(prevlastv,lastv); - } else { - prevlastv = lastv; - } - } - t[i__ + i__ * t_dim1] = tau[i__]; + } else if (lq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See dlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} */ +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + t[t_dim1 + 1] = tau[1]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -\tau_{i}V_{1,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[j + i__ * t_dim1] = -tau[i__] * v[j + i__ * v_dim1]; } + +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + d__1 = -tau[i__]; + dgemv_("No Transpose", &i__2, &i__3, &d__1, &v[(i__ + 1) * v_dim1 + + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], ldv, &c_b11, &t[ + i__ * t_dim1 + 1], &c__1); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + dtrmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + t[i__ + i__ * t_dim1] = tau[i__]; } - } - return; + } else if (lqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ -/* End of DLARFT_LVL2 */ +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | i-1 */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{2,1} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On */ +/* each iteration, T_{3,1:3} are not referenced. See dlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} */ + +/* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} */ + +/* This means we will do the following */ + +/* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' */ +/* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} */ +/* T_{2,1} = T_{1,1}'T_{2,1} */ +/* T_{2,2} = \tau{i} */ + + t[t_dim1 + 1] = tau[1]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{2,1} = -\tau_{i}V_{1,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[i__ + j * t_dim1] = -tau[i__] * v[j + i__ * v_dim1]; + } + +/* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + d__1 = -tau[i__]; + dgemv_("No transpose", &i__2, &i__3, &d__1, &v[(i__ + 1) * v_dim1 + + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], ldv, &c_b11, &t[ + i__ + t_dim1], ldt); + +/* T_{2,1} = T_{1,1}'T_{2,1}' */ + + i__2 = i__ - 1; + dtrmv_("Lower", "Transpose", "Non-unit", &i__2, &t[t_offset], ldt, + &t[i__ + t_dim1], ldt); + t[i__ + i__ * t_dim1] = tau[i__]; + } + } else if (ql) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | n-i */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See dlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' */ +/* [V_{1,2}\\V_{2,2}\\0]T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' */ +/* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + t[*k + *k * t_dim1] = tau[*k]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau(k-i+1) */ + + t[kmi + kmi * t_dim1] = tau[kmi]; + +/* T_{3,2} = -\tau(k-i+1)V_{2,3}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[kmi + j + kmi * t_dim1] = -tau[kmi] * v[nmi + (kmi + j) * + v_dim1]; + } + +/* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + d__1 = -tau[kmi]; + dgemv_("Transpose", &i__2, &i__3, &d__1, &v[(kmi + 1) * v_dim1 + + 1], ldv, &v[kmi * v_dim1 + 1], &c__1, &c_b11, &t[kmi + 1 + + kmi * t_dim1], &c__1); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + dtrmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); + } + } else if (rq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See dlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + t[*k + *k * t_dim1] = tau[*k]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + t[kmi + kmi * t_dim1] = tau[kmi]; + +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[kmi + j + kmi * t_dim1] = -tau[kmi] * v[kmi + j + nmi * + v_dim1]; + } + +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + d__1 = -tau[kmi]; + dgemv_("No Transpose", &i__2, &i__3, &d__1, &v[kmi + 1 + v_dim1], + ldv, &v[kmi + v_dim1], ldv, &c_b11, &t[kmi + 1 + kmi * + t_dim1], &c__1); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + dtrmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); + } + } else if (rqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | k-i */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{2,3} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On */ +/* each iteration, T_{1,1:3} are not referenced. See dlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} */ + +/* After transposing when necessary to fit our blas routines' interface, */ +/* we get */ +/* T_{3,2} = -T_{2,2}(V_{3,1}V_{2,1} + V_{3,2})T_{3,3} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ +/* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} */ +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + t[*k + *k * t_dim1] = tau[*k]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + t[kmi + kmi * t_dim1] = tau[kmi]; + +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[kmi + (kmi + j) * t_dim1] = -tau[kmi] * v[kmi + j + nmi * + v_dim1]; + } + +/* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + d__1 = -tau[kmi]; + dgemv_("No Transpose", &i__2, &i__3, &d__1, &v[kmi + 1 + v_dim1], + ldv, &v[kmi + v_dim1], ldv, &c_b11, &t[kmi + (kmi + 1) * + t_dim1], ldt); + +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + i__2 = i__ - 1; + dtrmv_("Upper", "Transpose", "Non-unit", &i__2, &t[kmi + 1 + (kmi + + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); + } + } + return 0; } /* dlarft_lvl2__ */ diff --git a/lapack-netlib/SRC/dlarft_lvl2.f b/lapack-netlib/SRC/dlarft_lvl2.f index 9614df466d..df8b358d36 100644 --- a/lapack-netlib/SRC/dlarft_lvl2.f +++ b/lapack-netlib/SRC/dlarft_lvl2.f @@ -1,23 +1,15 @@ -*> \brief \b DLARFT_LVL2: Level 2 BLAS version for terminating case of DLARFT. +*> \brief \b DLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH * * =========== DOCUMENTATION =========== * * Online html documentation available at * http://www.netlib.org/lapack/explore-html/ * -*> Download DLARFT_LVL2 + dependencies -*> -*> [TGZ] -*> -*> [ZIP] -*> -*> [TXT] -* * Definition: * =========== * * SUBROUTINE DLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, -* T, LDT ) +* $ T, LDT ) * * .. Scalar Arguments .. * CHARACTER DIRECT, STOREV @@ -49,6 +41,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**T * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -61,6 +56,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -68,8 +65,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -155,6 +154,29 @@ *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -170,157 +192,549 @@ SUBROUTINE DLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, INTEGER K, LDT, LDV, N * .. * .. Array Arguments .. +* DOUBLE PRECISION T( LDT, * ), TAU( * ), V( LDV, * ) * .. * -* ===================================================================== -* * .. Parameters .. - DOUBLE PRECISION ONE, ZERO - PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) -* .. +* + DOUBLE PRECISION ONE + PARAMETER(ONE=1.0D+0) +* * .. Local Scalars .. - INTEGER I, J, PREVLASTV, LASTV -* .. +* + INTEGER I,J,KMI,NMI,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET +* * .. External Subroutines .. - EXTERNAL DGEMV, DTRMV -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME +* + EXTERNAL DTRMV,DGEMV,XERBLA +* +* .. External Functions.. +* + LOGICAL LSAME + EXTERNAL LSAME * .. * .. Executable Statements .. * +* Convert our character flags to logical flags for later +* + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') +* +* Error handling for our character flags +* + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('DLARFT_LVL2', INFO) + RETURN + END IF +* * Quick return if possible * - IF( N.EQ.0 ) - $ RETURN -* - IF( LSAME( DIRECT, 'F' ) ) THEN - PREVLASTV = N - DO I = 1, K - PREVLASTV = MAX( I, PREVLASTV ) - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = 1, I - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * V( I , J ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**T * V(i:j,i) -* - CALL DGEMV( 'Transpose', J-I, I-1, -TAU( I ), - $ V( I+1, 1 ), LDV, V( I+1, I ), 1, ONE, - $ T( 1, I ), 1 ) - ELSE -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * V( J , I ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**T -* - CALL DGEMV( 'No transpose', I-1, J-I, -TAU( I ), - $ V( 1, I+1 ), LDV, V( I, I+1 ), LDV, ONE, - $ T( 1, I ), 1 ) - END IF -* -* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) -* - CALL DTRMV( 'Upper', 'No transpose', 'Non-unit', I-1, - $ T, - $ LDT, T( 1, I ), 1 ) - T( I, I ) = TAU( I ) - IF( I.GT.1 ) THEN - PREVLASTV = MAX( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF + IF(N.EQ.0.OR.K.EQ.0) THEN + RETURN + END IF +* +* Now we determine what factorization our flags are associated with +* +* QR happens when we have forward direction in column storage +* + QR = DIRF.AND.STOREC +* +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute +* + LQT = DIRF.AND.STORET +* +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute +* + LQ = DIRF.AND.STORER +* +* QL happens when we have backward direction in column storage +* + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER + IF( N.EQ.1.OR.K.EQ.1) THEN + T(1,1) = TAU(1) + RETURN + END IF + IF (QR) THEN +* +* Break V into 9 components +* +* V = |-----------------------| +* |V_{1,1} 0 0 | i-1 +* |V_{2,1} V_{2,2} 0 | 1 +* |V_{3,1} V_{3,2} V_{3,3}| n-i +* |-----------------------| +* i-1 1 k-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See dlarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' +* [0\\V_{2,2}\\V_{3,2}]T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' +* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + DO I = 2, K +* +* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' +* We must do this at copy time as otherwise gemv will do nothing +* on the last column when n=k, but we neet to make sure we are +* scaled by this value +* + DO J = 1, I-1 + T(J,I) = -V(I,J)*TAU(I) + END DO +* +* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} +* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} +* + CALL DGEMV('Transpose', N-I, I-1, -TAU(I), V(I+1,1), + $ LDV, V(I+1,I), 1, ONE, T(1, I), 1) +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL DTRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - ELSE - PREVLASTV = 1 - DO I = K, 1, -1 - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = I, K - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( I.LT.K ) THEN - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * V( N-K+I , J ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**T * V(j:n-k+i,i) -* - CALL DGEMV( 'Transpose', N-K+I-J, K-I, - $ -TAU( I ), - $ V( J, I+1 ), LDV, V( J, I ), 1, ONE, - $ T( I+1, I ), 1 ) - ELSE -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * V( J, N-K+I ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**T -* - CALL DGEMV( 'No transpose', K-I, N-K+I-J, - $ -TAU( I ), V( I+1, J ), LDV, V( I, J ), LDV, - $ ONE, T( I+1, I ), 1 ) - END IF -* -* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) -* - CALL DTRMV( 'Lower', 'No transpose', 'Non-unit', - $ K-I, - $ T( I+1, I+1 ), LDT, T( I+1, I ), 1 ) - IF( I.GT.1 ) THEN - PREVLASTV = MIN( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF - T( I, I ) = TAU( I ) - END IF + ELSE IF (LQ) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See dlarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + DO I = 2, K +* +* T_{1,2} = -\tau_{i}V_{1,2} +* + DO J = 1, I-1 + T(J, I) = -TAU(I)*V(J, I) + END DO +* +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* + CALL DGEMV('No Transpose', I-1, N-I, -TAU(I), V(1, I+1), + $ LDV, V(I, I+1), LDV, ONE, T(1,I), 1) +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL DTRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - END IF - RETURN + ELSE IF (LQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | i-1 +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{2,1} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On +* each iteration, T_{3,1:3} are not referenced. See dlarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} +* +* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} +* +* This means we will do the following +* +* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' +* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} +* T_{2,1} = T_{1,1}'T_{2,1} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + DO I = 2, K +* +* T_{2,1} = -\tau_{i}V_{1,2}' +* + DO J = 1, I-1 + T(I,J) = -TAU(I)*V(J,I) + END DO +* +* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} +* + CALL DGEMV('No transpose', I-1, N-I, -TAU(I), V(1, I+1), + $ LDV, V(I, I+1), LDV, ONE, T(I, 1), LDT) +* +* T_{2,1} = T_{1,1}'T_{2,1}' +* + CALL DTRMV('Lower', 'Transpose', 'Non-unit', I-1, + $ T, LDT, T(I,1), LDT) + T(I,I) = TAU(I) + END DO + ELSE IF (QL) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | n-i +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See dlarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' +* [V_{1,2}\\V_{2,2}\\0]T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' +* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau(k-i+1) +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau(k-i+1)V_{2,3}' +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*V(NMI, KMI + J) + END DO +* +* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} +* + CALL DGEMV('Transpose', N-I, I-1, -TAU(KMI), + $ V(1, KMI + 1), LDV, V(1, KMI), 1, ONE, + $ T(KMI+1, KMI), 1) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL DTRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI + 1, KMI + 1), LDT, T(KMI + 1, KMI), 1) + END DO + ELSE IF (RQ) THEN * -* End of DLARFT_LVL2 +* Break V into 9 components * - END +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See dlarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*V(KMI + J, NMI) + END DO +* +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* + CALL DGEMV('No Transpose', I-1, N-I, -TAU(KMI), + $ V(KMI+1, 1), LDV, V(KMI, 1), LDV, ONE, T(KMI+1, KMI), + $ 1) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL DTRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI+1, KMI), 1) + END DO + ELSE IF (RQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | k-i +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{2,3} at +* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On +* each iteration, T_{1,1:3} are not referenced. See dlarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} +* +* After transposing when necessary to fit our blas routines' interface, +* we get +* T_{3,2} = -T_{2,2}(V_{3,1}V_{2,1} + V_{3,2})T_{3,3} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} +* T_{2,3} = T_{3,3}'T_{2,3} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = TAU(KMI) +* +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* + DO J = 1, I-1 + T(KMI, KMI + J) = -TAU(KMI)*V(KMI + J, NMI) + END DO +* +* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} +* + CALL DGEMV('No Transpose', I-1, N-I, -TAU(KMI), + $ V(KMI+1, 1), LDV, V(KMI, 1), LDV, ONE, T(KMI, KMI+1), + $ LDT) +* +* T_{2,3} = T_{3,3}'T_{2,3} +* + CALL DTRMV('Upper', 'Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI, KMI+1), LDT) + END DO + END IF + END SUBROUTINE diff --git a/lapack-netlib/SRC/slarft.c b/lapack-netlib/SRC/slarft.c index eb69a6163b..594b8a1ba9 100644 --- a/lapack-netlib/SRC/slarft.c +++ b/lapack-netlib/SRC/slarft.c @@ -296,8 +296,8 @@ static integer smaxloc_(float *w, integer s, integer e, integer *n) static integer c__3 = 3; static integer c_n1 = -1; static integer c__2 = 2; -static real c_b13 = 1.f; -static real c_b22 = -1.f; +static real c_b18 = 1.f; +static real c_b27 = -1.f; /* > \brief \b SLARFT forms the triangular factor T of a block reflector H = I - vtvH */ @@ -348,6 +348,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**T * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -360,6 +363,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -367,8 +372,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -425,7 +432,7 @@ f"> */ /* > \author Univ. of Tennessee */ /* > \author Univ. of California Berkeley */ -/* > \author Johnathan Rhyne, Univ. of Colorado Denver (original author, 2024) */ +/* > \author Univ. of Colorado Denver */ /* > \author NAG Ltd. */ /* > \ingroup larft */ @@ -439,7 +446,7 @@ f"> */ /* > the H(i) is best illustrated by the following example with n = 5 and */ /* > k = 3. The elements equal to 1 are not stored. */ /* > */ -/* > DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': */ +/* > DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and (STOREV = 'R' or STOREV = 'T'): */ /* > */ /* > V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) */ /* > ( v1 1 ) ( 1 v2 v2 v2 ) */ @@ -447,13 +454,36 @@ f"> */ /* > ( v1 v2 v3 ) */ /* > ( v1 v2 v3 ) */ /* > */ -/* > DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': */ +/* > DIRECT = 'B' and STOREV = 'C': (DIRECT = 'B' or DIRECT = 'T') and STOREV = 'R': */ /* > */ /* > V = ( v1 v2 v3 ) V = ( v1 v1 1 ) */ /* > ( v1 v2 v3 ) ( v2 v2 v2 1 ) */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -467,21 +497,24 @@ f"> */ /* Local variables */ integer i__, j, l; - logical lq, ql, qr; + logical lq, ql, qr, rq; integer nx; extern /* Subroutine */ void slarft_lvl2__(char *, char *, integer *, integer *, real *, integer *, real *, real *, integer *); - logical dirf, colv; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern logical lsame_(char *, char *); extern /* Subroutine */ void sgemm_(char *, char *, integer *, integer *, integer *, real *, real *, integer *, real *, integer *, real *, real *, integer *), strmm_(char *, char *, char *, char *, integer *, integer *, real *, real *, integer *, real *, - integer *); + integer *), xerbla_(char *, integer *, ftnlen); extern integer ilaenv_(integer *, char *, char *, integer *, integer *, integer *, integer *, ftnlen, ftnlen); extern /* Subroutine */ void slacpy_(char *, integer *, integer *, real *, integer *, real *, integer *); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -504,7 +537,7 @@ f"> */ /* Based on the algorithm of Elmroth and Gustavson, */ /* IBM J. Res. Develop. Vol 44 No. 4 July 2000. */ -/* Quick return if possible */ +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -516,18 +549,95 @@ f"> */ t -= t_offset; /* Function Body */ + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("SLARFT", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + if (*n == 0 || *k == 0) { - return; + return 0; } +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + /* Base case */ if (*n == 1 || *k == 1) { t[t_dim1 + 1] = tau[1]; - return; + return 0; } -/* Determine when to cross over into the level 2 based implementation */ +/* Determine crossover point from level 2 to level 3 BLAS implementation */ /* Writing concatenation */ i__1[0] = 1, a__1[0] = direct; @@ -536,41 +646,17 @@ f"> */ nx = ilaenv_(&c__3, "SLARFT", ch__1, n, k, &c_n1, &c_n1, (ftnlen)6, ( ftnlen)2); if (*k < nx) { + +/* Finish this component with a level 2 BLAS implementation */ + slarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return; + return 0; } -/* Beginning of executable statements */ +/* Beginning of executable statements for the recursive case */ l = *k / 2; - -/* Determine what kind of Q we need to compute */ -/* We assume that if the user doesn't provide 'F' for DIRECT, */ -/* then they meant to provide 'B' and if they don't provide */ -/* 'C' for STOREV, then they meant to provide 'R' */ - - dirf = lsame_(direct, "F"); - colv = lsame_(storev, "C"); - -/* QR happens when we have forward direction in column storage */ - - qr = dirf && colv; - -/* LQ happens when we have forward direction in row storage */ - - lq = dirf && ! colv; - -/* QL happens when we have backward direction in column storage */ - - ql = ! dirf && colv; - -/* The last case is RQ. Due to how we structured this, if the */ -/* above 3 are false, then RQ must be true, so we never store */ -/* this */ -/* RQ happens when we have backward direction in row storage */ -/* RQ = (.NOT.DIRF).AND.(.NOT.COLV) */ - if (qr) { /* Break V apart into 6 components */ @@ -647,7 +733,7 @@ f"> */ /* T_{1,2} = T_{1,2}*V_{2,2} */ i__2 = *k - l; - strmm_("Right", "Lower", "No transpose", "Unit", &l, &i__2, &c_b13, & + strmm_("Right", "Lower", "No transpose", "Unit", &l, &i__2, &c_b18, & v[l + 1 + (l + 1) * v_dim1], ldv, &t[(l + 1) * t_dim1 + 1], ldt); @@ -656,8 +742,8 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - sgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b13, &v[*k + - 1 + v_dim1], ldv, &v[*k + 1 + (l + 1) * v_dim1], ldv, &c_b13, + sgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b18, &v[*k + + 1 + v_dim1], ldv, &v[*k + 1 + (l + 1) * v_dim1], ldv, &c_b18, &t[(l + 1) * t_dim1 + 1], ldt); /* At this point, we have that T_{1,2} = V_1'*V_2 */ @@ -667,14 +753,14 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__2 = *k - l; - strmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b22, + strmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b27, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ i__2 = *k - l; strmm_("Right", "Upper", "No transpose", "Non-unit", &l, &i__2, & - c_b13, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + c_b18, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + 1], ldt); } else if (lq) { @@ -710,8 +796,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ -/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ +/* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) */ +/* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 */ /* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ @@ -722,7 +808,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{1,2} */ @@ -748,7 +834,7 @@ f"> */ /* T_{1,2} = T_{1,2}*V_{2,2}' */ i__2 = *k - l; - strmm_("Right", "Upper", "Transpose", "Unit", &l, &i__2, &c_b13, &v[l + strmm_("Right", "Upper", "Transpose", "Unit", &l, &i__2, &c_b18, &v[l + 1 + (l + 1) * v_dim1], ldv, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = V_{1,3}*V_{2,3}' + T_{1,2} */ @@ -756,9 +842,9 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - sgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b13, &v[(*k + sgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b18, &v[(*k + 1) * v_dim1 + 1], ldv, &v[l + 1 + (*k + 1) * v_dim1], ldv, & - c_b13, &t[(l + 1) * t_dim1 + 1], ldt); + c_b18, &t[(l + 1) * t_dim1 + 1], ldt); /* At this point, we have that T_{1,2} = V_1*V_2' */ /* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} */ @@ -767,15 +853,118 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__2 = *k - l; - strmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b22, + strmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__2, &c_b27, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ i__2 = *k - l; strmm_("Right", "Upper", "No transpose", "Non-unit", &l, &i__2, & - c_b13, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + c_b18, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + 1], ldt); + } else if (lqt) { + +/* Break V apart into 6 components */ + +/* V = |----------------------| */ +/* |V_{1,1} V_{1,2} V{1,3}| */ +/* |0 V_{2,2} V{2,3}| */ +/* |----------------------| */ + +/* V_{1,1}\in\R^{l,l} unit upper triangular */ +/* V_{1,2}\in\R^{l,k-l} rectangular */ +/* V_{1,3}\in\R^{l,n-k} rectangular */ + +/* V_{2,2}\in\R^{k-l,k-l} unit upper triangular */ +/* V_{2,3}\in\R^{k-l,n-k} rectangular */ + +/* Where l = floor(k/2) */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} 0 | */ +/* |T_{2,1} T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\R^{l, l} lower triangular */ +/* T_{2,2}\in\R^{k-l, k-l} lower triangular */ +/* T_{2,1}\in\R^{k-l, l} rectangular */ + +/* Then, consider the product: */ + +/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ +/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ + +/* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{2,1} */ + +/* Compute T_{1,1} recursively */ + + slarft_(direct, storev, n, &l, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + i__2 = *n - l; + i__3 = *k - l; + slarft_(direct, storev, &i__2, &i__3, &v[l + 1 + (l + 1) * v_dim1], + ldv, &tau[l + 1], &t[l + 1 + (l + 1) * t_dim1], ldt); + +/* Compute T_{2,1} */ +/* T_{2,1} = V_{1,2}' */ + + i__2 = *k - l; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + t[l + i__ + j * t_dim1] = v[j + (l + i__) * v_dim1]; + } + } + +/* T_{2,1} = V_{2,2}*T_{2,1} */ + + i__2 = *k - l; + strmm_("Left", "Upper", "No Transpose", "Unit", &i__2, &l, &c_b18, &v[ + l + 1 + (l + 1) * v_dim1], ldv, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} */ +/* Note: We assume K <= N, and GEMM will do nothing if N=K */ + + i__2 = *k - l; + i__3 = *n - *k; + sgemm_("No Transpose", "Transpose", &i__2, &l, &i__3, &c_b18, &v[l + + 1 + (*k + 1) * v_dim1], ldv, &v[(*k + 1) * v_dim1 + 1], ldv, & + c_b18, &t[l + 1 + t_dim1], ldt); + +/* At this point, we have that T_{2,1} = V_2*V_1' */ +/* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} */ +/* respectively. */ + +/* T_{2,1} = -T_{2,2}*T_{2,1} */ + + i__2 = *k - l; + strmm_("Left", "Lower", "No Transpose", "Non-unit", &i__2, &l, &c_b27, + &t[l + 1 + (l + 1) * t_dim1], ldt, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = T_{2,1}*T_{1,1} */ + + i__2 = *k - l; + strmm_("Right", "Lower", "No Transpose", "Non-unit", &i__2, &l, & + c_b18, &t[t_offset], ldt, &t[l + 1 + t_dim1], ldt); } else if (ql) { /* Break V apart into 6 components */ @@ -853,7 +1042,7 @@ f"> */ /* T_{2,1} = T_{2,1}*V_{2,1} */ i__2 = *k - l; - strmm_("Right", "Upper", "No transpose", "Unit", &l, &i__2, &c_b13, & + strmm_("Right", "Upper", "No transpose", "Unit", &l, &i__2, &c_b18, & v[*n - *k + 1 + v_dim1], ldv, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = V_{2,2}'*V_{2,1} + T_{2,1} */ @@ -861,8 +1050,8 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - sgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b13, &v[(*k - - l + 1) * v_dim1 + 1], ldv, &v[v_offset], ldv, &c_b13, &t[*k + sgemm_("Transpose", "No transpose", &l, &i__2, &i__3, &c_b18, &v[(*k + - l + 1) * v_dim1 + 1], ldv, &v[v_offset], ldv, &c_b18, &t[*k - l + 1 + t_dim1], ldt); /* At this point, we have that T_{2,1} = V_2'*V_1 */ @@ -872,7 +1061,7 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__2 = *k - l; - strmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__2, &c_b22, + strmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__2, &c_b27, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); @@ -880,11 +1069,8 @@ f"> */ i__2 = *k - l; strmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__2, & - c_b13, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); - } else { - -/* Else means RQ case */ - + c_b18, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + } else if (rq) { /* Break V apart into 6 components */ /* V = |-----------------------| */ @@ -917,8 +1103,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ -/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ +/* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) */ +/* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 */ /* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ @@ -929,7 +1115,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'TV */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{2,1} */ @@ -955,7 +1141,7 @@ f"> */ /* T_{2,1} = T_{2,1}*V_{1,2}' */ i__2 = *k - l; - strmm_("Right", "Lower", "Transpose", "Unit", &l, &i__2, &c_b13, &v[(* + strmm_("Right", "Lower", "Transpose", "Unit", &l, &i__2, &c_b18, &v[(* n - *k + 1) * v_dim1 + 1], ldv, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} */ @@ -963,8 +1149,8 @@ f"> */ i__2 = *k - l; i__3 = *n - *k; - sgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b13, &v[*k - - l + 1 + v_dim1], ldv, &v[v_offset], ldv, &c_b13, &t[*k - l + + sgemm_("No transpose", "Transpose", &l, &i__2, &i__3, &c_b18, &v[*k - + l + 1 + v_dim1], ldv, &v[v_offset], ldv, &c_b18, &t[*k - l + 1 + t_dim1], ldt); /* At this point, we have that T_{2,1} = V_2*V_1' */ @@ -974,16 +1160,120 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__2 = *k - l; - strmm_("Left", "Lower", "No tranpose", "Non-unit", &l, &i__2, &c_b22, - &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + + strmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__2, &c_b27, + &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = T_{2,1}*T_{1,1} */ i__2 = *k - l; - strmm_("Right", "Lower", "No tranpose", "Non-unit", &l, &i__2, &c_b13, - &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + strmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__2, & + c_b18, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + } else if (rqt) { +/* Break V apart into 6 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} V_{1,2} 0 | */ +/* |V_{2,1} V_{2,2} V_{2,3}| */ +/* |-----------------------| */ + +/* V_{1,1}\in\R^{k-l,n-k} rectangular */ +/* V_{1,2}\in\R^{k-l,k-l} unit lower triangular */ + +/* V_{2,1}\in\R^{l,n-k} rectangular */ +/* V_{2,2}\in\R^{l,k-l} rectangular */ +/* V_{2,3}\in\R^{l,l} unit lower triangular */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} T_{1,2}| */ +/* | 0 T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\R^{k-l, k-l} non-unit upper triangular */ +/* T_{2,2}\in\R^{l, l} non-unit upper triangular */ +/* T_{1,2}\in\R^{k-l, l} rectangular */ + +/* Where l = floor(k/2) */ + +/* Then, consider the product: */ + +/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ +/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ + +/* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{1,2} */ + +/* Compute T_{1,1} recursively */ + + i__2 = *n - l; + i__3 = *k - l; + slarft_(direct, storev, &i__2, &i__3, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + slarft_(direct, storev, n, &l, &v[*k - l + 1 + v_dim1], ldv, &tau[*k + - l + 1], &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt); + +/* Compute T_{1,2} */ +/* T_{1,2} = V_{2,2}' */ + + i__2 = *k - l; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + t[i__ + (*k - l + j) * t_dim1] = v[*k - l + j + (*n - *k + + i__) * v_dim1]; + } + } + +/* T_{1,2} = V_{1,2}T_{1,2} */ + + i__2 = *k - l; + strmm_("Left", "Lower", "No Transpose", "Unit", &i__2, &l, &c_b18, &v[ + (*n - *k + 1) * v_dim1 + 1], ldv, &t[(*k - l + 1) * t_dim1 + + 1], ldt); + +/* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} */ + + i__2 = *k - l; + i__3 = *n - *k; + sgemm_("No Transpose", "Transpose", &i__2, &l, &i__3, &c_b18, &v[ + v_offset], ldv, &v[*k - l + 1 + v_dim1], ldv, &c_b18, &t[(*k + - l + 1) * t_dim1 + 1], ldt); + +/* At this point, we have that T_{1,2} = V_1*V_2' */ +/* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} */ +/* respectively. */ + +/* T_{1,2} = -T_{1,1}*T_{1,2} */ + + i__2 = *k - l; + strmm_("Left", "Upper", "No Transpose", "Non-Unit", &i__2, &l, &c_b27, + &t[t_offset], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); + +/* T_{1,2} = T_{1,2}*T_{2,2} */ + + i__2 = *k - l; + strmm_("Right", "Upper", "No Transpose", "Non-Unit", &i__2, &l, & + c_b18, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - + l + 1) * t_dim1 + 1], ldt); } - return; + return 0; } /* slarft_ */ diff --git a/lapack-netlib/SRC/slarft.f b/lapack-netlib/SRC/slarft.f index 3e0eac751e..a994a92498 100644 --- a/lapack-netlib/SRC/slarft.f +++ b/lapack-netlib/SRC/slarft.f @@ -48,6 +48,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**T * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -60,6 +63,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -67,8 +72,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -125,7 +132,7 @@ * *> \author Univ. of Tennessee *> \author Univ. of California Berkeley -*> \author Johnathan Rhyne, Univ. of Colorado Denver (original author, 2024) +*> \author Univ. of Colorado Denver *> \author NAG Ltd. * *> \ingroup larft @@ -139,7 +146,7 @@ *> the H(i) is best illustrated by the following example with n = 5 and *> k = 3. The elements equal to 1 are not stored. *> -*> DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and STOREV = 'R': +*> DIRECT = 'F' and STOREV = 'C': DIRECT = 'F' and (STOREV = 'R' or STOREV = 'T'): *> *> V = ( 1 ) V = ( 1 v1 v1 v1 v1 ) *> ( v1 1 ) ( 1 v2 v2 v2 ) @@ -147,13 +154,36 @@ *> ( v1 v2 v3 ) *> ( v1 v2 v3 ) *> -*> DIRECT = 'B' and STOREV = 'C': DIRECT = 'B' and STOREV = 'R': +*> DIRECT = 'B' and STOREV = 'C': (DIRECT = 'B' or DIRECT = 'T') and STOREV = 'R': *> *> V = ( v1 v2 v3 ) V = ( v1 v1 1 ) *> ( v1 v2 v3 ) ( v2 v2 v2 1 ) *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -177,24 +207,26 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. Parameters .. * - REAL ONE, NEG_ONE, ZERO - PARAMETER(ONE=1.0E+0, ZERO = 0.0E+0, NEG_ONE=-1.0E+0) + REAL ONE, NEG_ONE + PARAMETER(ONE=1.0E+0, NEG_ONE=-1.0E+0) * * .. Local Scalars .. * - INTEGER I,J,L,NX - LOGICAL QR,LQ,QL,DIRF,COLV + INTEGER I,J,L,NX,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET * * .. External Subroutines .. * - EXTERNAL STRMM,SGEMM,SLACPY + EXTERNAL SLARFT_LVL2, STRMM, SGEMM, SLACPY, XERBLA * * .. External Functions.. * LOGICAL LSAME INTEGER ILAENV EXTERNAL LSAME, ILAENV -* +* * The general scheme used is inspired by the approach inside DGEQRT3 * which was (at the time of writing this code): * Based on the algorithm of Elmroth and Gustavson, @@ -202,12 +234,90 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * .. * .. Executable Statements .. * +* Convert our character flags to logical flags for later +* + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') +* +* Error handling for our character flags +* + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('SLARFT', INFO) + RETURN + END IF +* * Quick return if possible * IF(N.EQ.0.OR.K.EQ.0) THEN RETURN END IF * +* Now we determine what factorization our flags are associated with +* +* QR happens when we have forward direction in column storage +* + QR = DIRF.AND.STOREC +* +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute +* + LQT = DIRF.AND.STORET +* +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute +* + LQ = DIRF.AND.STORER +* +* QL happens when we have backward direction in column storage +* + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER +* * Base case * IF(N.EQ.1.OR.K.EQ.1) THEN @@ -215,44 +325,20 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, RETURN END IF * -* Determine when to cross over into the level 2 based implementation +* Determine crossover point from level 2 to level 3 BLAS implementation * NX = ILAENV(3, "SLARFT", DIRECT // STOREV, N, K, -1, -1) IF(K.LT.NX) THEN +* +* Finish this component with a level 2 BLAS implementation +* CALL SLARFT_LVL2(DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT) RETURN END IF * -* Beginning of executable statements +* Beginning of executable statements for the recursive case * L = K / 2 -* -* Determine what kind of Q we need to compute -* We assume that if the user doesn't provide 'F' for DIRECT, -* then they meant to provide 'B' and if they don't provide -* 'C' for STOREV, then they meant to provide 'R' -* - DIRF = LSAME(DIRECT,'F') - COLV = LSAME(STOREV,'C') -* -* QR happens when we have forward direction in column storage -* - QR = DIRF.AND.COLV -* -* LQ happens when we have forward direction in row storage -* - LQ = DIRF.AND.(.NOT.COLV) -* -* QL happens when we have backward direction in column storage -* - QL = (.NOT.DIRF).AND.COLV -* -* The last case is RQ. Due to how we structured this, if the -* above 3 are false, then RQ must be true, so we never store -* this -* RQ happens when we have backward direction in row storage -* RQ = (.NOT.DIRF).AND.(.NOT.COLV) -* IF(QR) THEN * * Break V apart into 6 components @@ -266,17 +352,17 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\R^{l,l} unit lower triangular * V_{2,1}\in\R^{k-l,l} rectangular * V_{3,1}\in\R^{n-k,l} rectangular -* +* * V_{2,2}\in\R^{k-l,k-l} unit lower triangular * V_{3,2}\in\R^{n-k,k-l} rectangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -287,17 +373,17 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_1*T_{1,1}*V_1')*(I - V_2*T_{2,2}*V_2') * = I - V_1*T_{1,1}*V_1' - V_2*T_{2,2}*V_2' + V_1*T_{1,1}*V_1'*V_2*T_{2,2}*V_2' -* +* * Define T_{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -309,30 +395,29 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL SLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL SLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * -* Compute T_{1,2} +* Compute T_{1,2} * T_{1,2} = V_{2,1}' * DO J = 1, L DO I = 1, K-L - T(J, L+I) = V(L+I, J) + T(J,L+I) = V(L+I,J) END DO END DO * * T_{1,2} = T_{1,2}*V_{2,2} * CALL STRMM('Right', 'Lower', 'No transpose', 'Unit', L, - $ K-L, ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) + $ K-L, ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = V_{3,1}'*V_{3,2} + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL SGEMM('Transpose', 'No transpose', L, K-L, N-K, ONE, - $ V(K+1, 1), LDV, V(K+1, L+1), LDV, ONE, - $ T(1, L+1), LDT) + CALL SGEMM('Transpose', 'No transpose', L, K-L, N-K, ONE, + $ V(K+1, 1), LDV, V(K+1,L+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1'*V_2 * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -341,12 +426,12 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = -T_{1,1}*T_{1,2} * CALL STRMM('Left', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) + $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*T_{2,2} * - CALL STRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + CALL STRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) ELSE IF(LQ) THEN * @@ -360,19 +445,19 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\R^{l,l} unit upper triangular * V_{1,2}\in\R^{l,k-l} rectangular * V_{1,3}\in\R^{l,n-k} rectangular -* +* * V_{2,2}\in\R^{k-l,k-l} unit upper triangular * V_{2,3}\in\R^{k-l,n-k} rectangular * * Where l = floor(k/2) * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -381,20 +466,20 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2}\in\R^{l, k-l} rectangular * * Then, consider the product: -* -* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) -* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 -* +* +* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) +* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 +* * Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{1,2} * @@ -404,27 +489,26 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL SLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL SLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * * Compute T_{1,2} * T_{1,2} = V_{1,2} * - CALL SLACPY('All', L, K-L, V(1, L+1), LDV, T(1, L+1), LDT) + CALL SLACPY('All', L, K - L, V(1,L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*V_{2,2}' * CALL STRMM('Right', 'Upper', 'Transpose', 'Unit', L, K-L, - $ ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) + $ ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = V_{1,3}*V_{2,3}' + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL SGEMM('No transpose', 'Transpose', L, K-L, N-K, ONE, - $ V(1, K+1), LDV, V(L+1, K+1), LDV, ONE, - $ T(1, L+1), LDT) + $ V(1, K+1), LDV, V(L+1, K+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1*V_2' * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -433,13 +517,106 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = -T_{1,1}*T_{1,2} * CALL STRMM('Left', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) + $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*T_{2,2} * CALL STRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) + ELSE IF(LQT) THEN +* +* Break V apart into 6 components +* +* V = |----------------------| +* |V_{1,1} V_{1,2} V{1,3}| +* |0 V_{2,2} V{2,3}| +* |----------------------| +* +* V_{1,1}\in\R^{l,l} unit upper triangular +* V_{1,2}\in\R^{l,k-l} rectangular +* V_{1,3}\in\R^{l,n-k} rectangular +* +* V_{2,2}\in\R^{k-l,k-l} unit upper triangular +* V_{2,3}\in\R^{k-l,n-k} rectangular +* +* Where l = floor(k/2) +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} 0 | +* |T_{2,1} T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\R^{l, l} lower triangular +* T_{2,2}\in\R^{k-l, k-l} lower triangular +* T_{2,1}\in\R^{k-l, l} rectangular +* +* Then, consider the product: +* +* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) +* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 +* +* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{2,1} +* +* Compute T_{1,1} recursively +* + CALL SLARFT(DIRECT, STOREV, N, L, V, LDV, TAU, T, LDT) +* +* Compute T_{2,2} recursively +* + CALL SLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) + +* +* Compute T_{2,1} +* T_{2,1} = V_{1,2}' +* + DO I = 1, K-L + DO J = 1, L + T(L+I,J) = V(J,L+I) + END DO + END DO +* +* T_{2,1} = V_{2,2}*T_{2,1} +* + CALL STRMM('Left', 'Upper', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(L+1,L+1), LDV, T(L+1,1), LDT) +* +* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} +* Note: We assume K <= N, and GEMM will do nothing if N=K +* + CALL SGEMM('No Transpose', 'Transpose', K-L, L, N-K, ONE, + $ V(L+1,K+1), LDV, V(1, K+1), LDV, ONE, T(L+1,1), LDT) +* +* At this point, we have that T_{2,1} = V_2*V_1' +* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} +* respectively. +* +* T_{2,1} = -T_{2,2}*T_{2,1} +* + CALL STRMM('Left', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, NEG_ONE, T(L+1,L+1), LDT, T(L+1,1), LDT) +* +* T_{2,1} = T_{2,1}*T_{1,1} +* + CALL STRMM('Right', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, ONE, T, LDT, T(L+1,1), LDT) ELSE IF(QL) THEN * * Break V apart into 6 components @@ -452,18 +629,18 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * V_{1,1}\in\R^{n-k,k-l} rectangular * V_{2,1}\in\R^{k-l,k-l} unit upper triangular -* +* * V_{1,2}\in\R^{n-k,l} rectangular * V_{2,2}\in\R^{k-l,l} rectangular * V_{3,2}\in\R^{l,l} unit upper triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -474,17 +651,17 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_2*T_{2,2}*V_2')*(I - V_1*T_{1,1}*V_1') * = I - V_2*T_{2,2}*V_2' - V_1*T_{1,1}*V_1' + V_2*T_{2,2}*V_2'*V_1*T_{1,1}*V_1' -* +* * Define T_{2,1} = -T_{2,2}*V_2'*V_1*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -492,34 +669,34 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{1,1} recursively * - CALL SLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL SLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * CALL SLARFT(DIRECT, STOREV, N, L, V(1, K-L+1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2}' * DO J = 1, K-L DO I = 1, L - T(K-L+I, J) = V(N-K+J, K-L+I) + T(K-L+I,J) = V(N-K+J, K-L+I) END DO END DO * * T_{2,1} = T_{2,1}*V_{2,1} * CALL STRMM('Right', 'Upper', 'No transpose', 'Unit', L, - $ K-L, ONE, V(N-K+1, 1), LDV, T(K-L+1, 1), LDT) + $ K-L, ONE, V(N-K+1,1), LDV, T(K-L+1,1), LDT) * * T_{2,1} = V_{2,2}'*V_{2,1} + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL SGEMM('Transpose', 'No transpose', L, K-L, N-K, ONE, - $ V(1, K-L+1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + $ V(1,K-L+1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2'*V_1 * All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} @@ -528,17 +705,13 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{2,1} = -T_{2,2}*T_{2,1} * CALL STRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * CALL STRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) - ELSE -* -* Else means RQ case -* + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQ) THEN * Break V apart into 6 components * * V = |-----------------------| @@ -553,13 +726,13 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{2,2}\in\R^{l,k-l} rectangular * V_{2,3}\in\R^{l,l} unit lower triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -570,51 +743,51 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* -* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) -* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 -* +* +* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) +* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 +* * Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'TV +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{2,1} * * Compute T_{1,1} recursively * - CALL SLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL SLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * - CALL SLARFT(DIRECT, STOREV, N, L, V(K-L+1, 1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + CALL SLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2} * - CALL SLACPY('All', L, K-L, V(K-L+1, N-K+1), LDV, - $ T(K-L+1, 1), LDT) + CALL SLACPY('All', L, K-L, V(K-L+1,N-K+1), LDV, T(K-L+1,1), + $ LDT) * * T_{2,1} = T_{2,1}*V_{1,2}' * CALL STRMM('Right', 'Lower', 'Transpose', 'Unit', L, K-L, - $ ONE, V(1, N-K+1), LDV, T(K-L+1, 1), LDT) + $ ONE, V(1, N-K+1), LDV, T(K-L+1,1), LDT) * -* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} +* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL SGEMM('No transpose', 'Transpose', L, K-L, N-K, ONE, - $ V(K-L+1, 1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + CALL SGEMM('No transpose', 'Transpose', L, K-L, N-K, ONE, + $ V(K-L+1,1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2*V_1' @@ -623,14 +796,104 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * T_{2,1} = -T_{2,2}*T_{2,1} * - CALL STRMM('Left', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + CALL STRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * - CALL STRMM('Right', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) + CALL STRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQT) THEN +* Break V apart into 6 components +* +* V = |-----------------------| +* |V_{1,1} V_{1,2} 0 | +* |V_{2,1} V_{2,2} V_{2,3}| +* |-----------------------| +* +* V_{1,1}\in\R^{k-l,n-k} rectangular +* V_{1,2}\in\R^{k-l,k-l} unit lower triangular +* +* V_{2,1}\in\R^{l,n-k} rectangular +* V_{2,2}\in\R^{l,k-l} rectangular +* V_{2,3}\in\R^{l,l} unit lower triangular +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} T_{1,2}| +* | 0 T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\R^{k-l, k-l} non-unit upper triangular +* T_{2,2}\in\R^{l, l} non-unit upper triangular +* T_{1,2}\in\R^{k-l, l} rectangular +* +* Where l = floor(k/2) +* +* Then, consider the product: +* +* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) +* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 +* +* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{1,2} +* +* Compute T_{1,1} recursively +* + CALL SLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) +* +* Compute T_{2,2} recursively +* + CALL SLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) +* +* Compute T_{1,2} +* T_{1,2} = V_{2,2}' +* + DO I = 1, K-L + DO J = 1, L + T(I,K-L+J) = V(K-L+J, N-K+I) + END DO + END DO +* +* T_{1,2} = V_{1,2}T_{1,2} +* + CALL STRMM('Left', 'Lower', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(1,N-K+1), LDV, T(1,K-L+1), LDT) +* +* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} +* + CALL SGEMM('No Transpose', 'Transpose', K-L, L, N-K, ONE, V, + $ LDV, V(K-L+1,1), LDV, ONE, T(1, K-L+1), LDT) +* +* At this point, we have that T_{1,2} = V_1*V_2' +* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} +* respectively. +* +* T_{1,2} = -T_{1,1}*T_{1,2} +* + CALL STRMM('Left', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, NEG_ONE, T, LDT, T(1, K-L+1), LDT) +* +* T_{1,2} = T_{1,2}*T_{2,2} +* + CALL STRMM('Right', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, ONE, T(K-L+1,K-L+1), LDT, T(1, K-L+1), LDT) END IF END SUBROUTINE diff --git a/lapack-netlib/SRC/slarft_lvl2.c b/lapack-netlib/SRC/slarft_lvl2.c index 4e6189793f..026ef83da1 100644 --- a/lapack-netlib/SRC/slarft_lvl2.c +++ b/lapack-netlib/SRC/slarft_lvl2.c @@ -220,69 +220,18 @@ typedef struct Namelist Namelist; //#define mymaxloc_(w,s,e,n) {if (sizeof(*(w)) == sizeof(double)) dmaxloc_((w),*(s),*(e),n); else dmaxloc_((w),*(s),*(e),n);} #define mymaxloc(w,s,e,n) {dmaxloc_(w,*(s),*(e),n)} -/* procedure parameter types for -A and -C++ */ - - -#ifdef __cplusplus -typedef logical (*L_fp)(...); -#else -typedef logical (*L_fp)(); -#endif -#if 0 -static float spow_ui(float x, integer n) { - float pow=1.0; unsigned long int u; - if(n != 0) { - if(n < 0) n = -n, x = 1/x; - for(u = n; ; ) { - if(u & 01) pow *= x; - if(u >>= 1) x *= x; - else break; - } - } - return pow; -} -static double dpow_ui(double x, integer n) { - double pow=1.0; unsigned long int u; - if(n != 0) { - if(n < 0) n = -n, x = 1/x; - for(u = n; ; ) { - if(u & 01) pow *= x; - if(u >>= 1) x *= x; - else break; - } - } - return pow; -} -#endif -/* -- translated by f2c (version 20000121). - You must link the resulting object file with the libraries: - -lf2c -lm (in that order) -*/ - - /* Table of constant values */ static integer c__1 = 1; -static real c_b6 = 1.f; +static real c_b11 = 1.f; -/* > \brief \b SLARFT_LVL2: Level 2 BLAS version for terminating case of SLARFT. */ +/* > \brief \b SLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH */ /* =========== DOCUMENTATION =========== */ /* Online html documentation available at */ /* http://www.netlib.org/lapack/explore-html/ */ -/* > Download SLARFT_LVL2 + dependencies */ -/* > */ -/* > [TGZ] */ -/* > */ -/* > [ZIP] */ -/* > */ -/* > [TXT] */ - /* Definition: */ /* =========== */ @@ -315,6 +264,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**T * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -327,6 +279,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -334,8 +288,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -421,6 +377,29 @@ f"> */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -432,14 +411,18 @@ f"> */ real r__1; /* Local variables */ - integer i__, j, prevlastv; + integer i__, j; + logical lq, ql, qr, rq; + integer kmi, nmi; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern logical lsame_(char *, char *); extern /* Subroutine */ void sgemv_(char *, integer *, integer *, real *, - real *, integer *, real *, integer *, real *, real *, integer *); - integer lastv; - extern /* Subroutine */ void strmv_(char *, char *, char *, integer *, - real *, integer *, real *, integer *), - mecago_(); + real *, integer *, real *, integer *, real *, real *, integer *), strmv_(char *, char *, char *, integer *, real *, + integer *, real *, integer *), xerbla_( + char *, integer *, ftnlen); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -447,10 +430,16 @@ f"> */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ -/* ===================================================================== */ -/* Quick return if possible */ + + + + + + + +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -462,171 +451,565 @@ f"> */ t -= t_offset; /* Function Body */ - if (*n == 0) { - return; + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("SLARFT_LVL2", &info, (ftnlen)11); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *k == 0) { + return 0; + } + +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + if (*n == 1 || *k == 1) { + t[t_dim1 + 1] = tau[1]; + return 0; } + if (qr) { + +/* Break V into 9 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} 0 0 | i-1 */ +/* |V_{2,1} V_{2,2} 0 | 1 */ +/* |V_{3,1} V_{3,2} V_{3,3}| n-i */ +/* |-----------------------| */ +/* i-1 1 k-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See slarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' */ +/* [0\\V_{2,2}\\V_{3,2}]T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' */ +/* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + t[t_dim1 + 1] = tau[1]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' */ +/* We must do this at copy time as otherwise gemv will do nothing */ +/* on the last column when n=k, but we neet to make sure we are */ +/* scaled by this value */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[j + i__ * t_dim1] = -v[i__ + j * v_dim1] * tau[i__]; + } + +/* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} */ +/* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + r__1 = -tau[i__]; + sgemv_("Transpose", &i__2, &i__3, &r__1, &v[i__ + 1 + v_dim1], + ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, &c_b11, &t[i__ * + t_dim1 + 1], &c__1); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + strmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + t[i__ + i__ * t_dim1] = tau[i__]; + } + } else if (lq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See slarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} */ +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + t[t_dim1 + 1] = tau[1]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -\tau_{i}V_{1,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[j + i__ * t_dim1] = -tau[i__] * v[j + i__ * v_dim1]; + } - if (lsame_(direct, "F")) { - prevlastv = *n; +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + r__1 = -tau[i__]; + sgemv_("No Transpose", &i__2, &i__3, &r__1, &v[(i__ + 1) * v_dim1 + + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], ldv, &c_b11, &t[ + i__ * t_dim1 + 1], &c__1); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + strmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + t[i__ + i__ * t_dim1] = tau[i__]; + } + } else if (lqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | i-1 */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{2,1} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On */ +/* each iteration, T_{3,1:3} are not referenced. See slarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} */ + +/* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} */ + +/* This means we will do the following */ + +/* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' */ +/* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} */ +/* T_{2,1} = T_{1,1}'T_{2,1} */ +/* T_{2,2} = \tau{i} */ + + t[t_dim1 + 1] = tau[1]; i__1 = *k; - for (i__ = 1; i__ <= i__1; ++i__) { - prevlastv = f2cmax(i__,prevlastv); - if (tau[i__] == 0.f) { - -/* H(i) = I */ - - i__2 = i__; - for (j = 1; j <= i__2; ++j) { - t[j + i__ * t_dim1] = 0.f; - } - } else { - -/* general case */ - - if (lsame_(storev, "C")) { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - if (v[lastv + i__ * v_dim1] != 0.f) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[i__ + j * v_dim1]; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**T * V(i:j,i) */ - - i__2 = j - i__; - i__3 = i__ - 1; - r__1 = -tau[i__]; - sgemv_("Transpose", &i__2, &i__3, &r__1, &v[i__ + 1 + - v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, & - c_b6, &t[i__ * t_dim1 + 1], &c__1); - } else { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - if (v[i__ + lastv * v_dim1] != 0.f) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[j + i__ * v_dim1]; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**T */ - - i__2 = i__ - 1; - i__3 = j - i__; - r__1 = -tau[i__]; - sgemv_("No transpose", &i__2, &i__3, &r__1, &v[(i__ + 1) * - v_dim1 + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], - ldv, &c_b6, &t[i__ * t_dim1 + 1], &c__1); - } - -/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ - - i__2 = i__ - 1; - strmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ - t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); - t[i__ + i__ * t_dim1] = tau[i__]; - if (i__ > 1) { - prevlastv = f2cmax(prevlastv,lastv); - } else { - prevlastv = lastv; - } + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{2,1} = -\tau_{i}V_{1,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[i__ + j * t_dim1] = -tau[i__] * v[j + i__ * v_dim1]; } + +/* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + r__1 = -tau[i__]; + sgemv_("No transpose", &i__2, &i__3, &r__1, &v[(i__ + 1) * v_dim1 + + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], ldv, &c_b11, &t[ + i__ + t_dim1], ldt); + +/* T_{2,1}' = T_{1,1}'T_{2,1}' */ + + i__2 = i__ - 1; + strmv_("Lower", "Transpose", "Non-unit", &i__2, &t[t_offset], ldt, + &t[i__ + t_dim1], ldt); + t[i__ + i__ * t_dim1] = tau[i__]; } - } else { - prevlastv = 1; - for (i__ = *k; i__ >= 1; --i__) { - if (tau[i__] == 0.f) { - -/* H(i) = I */ - - i__1 = *k; - for (j = i__; j <= i__1; ++j) { - t[j + i__ * t_dim1] = 0.f; - } - } else { - -/* general case */ - - if (i__ < *k) { - if (lsame_(storev, "C")) { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - if (v[lastv + i__ * v_dim1] != 0.f) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[*n - *k + i__ - + j * v_dim1]; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**T * V(j:n-k+i,i) */ - - i__1 = *n - *k + i__ - j; - i__2 = *k - i__; - r__1 = -tau[i__]; - sgemv_("Transpose", &i__1, &i__2, &r__1, &v[j + (i__ - + 1) * v_dim1], ldv, &v[j + i__ * v_dim1], & - c__1, &c_b6, &t[i__ + 1 + i__ * t_dim1], & - c__1); - } else { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - if (v[i__ + lastv * v_dim1] != 0.f) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - t[j + i__ * t_dim1] = -tau[i__] * v[j + (*n - *k - + i__) * v_dim1]; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**T */ - - i__1 = *k - i__; - i__2 = *n - *k + i__ - j; - r__1 = -tau[i__]; - sgemv_("No transpose", &i__1, &i__2, &r__1, &v[i__ + - 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], - ldv, &c_b6, &t[i__ + 1 + i__ * t_dim1], &c__1); - } - -/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ - - i__1 = *k - i__; - strmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ - + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * - t_dim1], &c__1) - ; - if (i__ > 1) { - prevlastv = f2cmin(prevlastv,lastv); - } else { - prevlastv = lastv; - } - } - t[i__ + i__ * t_dim1] = tau[i__]; + } else if (ql) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | n-i */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See slarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' */ +/* [V_{1,2}\\V_{2,2}\\0]T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' */ +/* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + t[*k + *k * t_dim1] = tau[*k]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau(k-i+1) */ + + t[kmi + kmi * t_dim1] = tau[kmi]; + +/* T_{3,2} = -\tau(k-i+1)V_{2,3}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[kmi + j + kmi * t_dim1] = -tau[kmi] * v[nmi + (kmi + j) * + v_dim1]; } + +/* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + r__1 = -tau[kmi]; + sgemv_("Transpose", &i__2, &i__3, &r__1, &v[(kmi + 1) * v_dim1 + + 1], ldv, &v[kmi * v_dim1 + 1], &c__1, &c_b11, &t[kmi + 1 + + kmi * t_dim1], &c__1); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + strmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); } - } - return; + } else if (rq) { -/* End of SLARFT_LVL2 */ +/* Break V into 9 components */ +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See slarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + t[*k + *k * t_dim1] = tau[*k]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + t[kmi + kmi * t_dim1] = tau[kmi]; + +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[kmi + j + kmi * t_dim1] = -tau[kmi] * v[kmi + j + nmi * + v_dim1]; + } + +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + r__1 = -tau[kmi]; + sgemv_("No Transpose", &i__2, &i__3, &r__1, &v[kmi + 1 + v_dim1], + ldv, &v[kmi + v_dim1], ldv, &c_b11, &t[kmi + 1 + kmi * + t_dim1], &c__1); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + strmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); + } + } else if (rqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | k-i */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{2,3} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On */ +/* each iteration, T_{1,1:3} are not referenced. See slarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} */ + +/* After transposing when necessary to fit our blas routines' interface, */ +/* we get */ +/* T_{3,2} = -T_{2,2}(V_{3,1}V_{2,1} + V_{3,2})T_{3,3} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ +/* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} */ +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + t[*k + *k * t_dim1] = tau[*k]; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + t[kmi + kmi * t_dim1] = tau[kmi]; + +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + t[kmi + (kmi + j) * t_dim1] = -tau[kmi] * v[kmi + j + nmi * + v_dim1]; + } + +/* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + r__1 = -tau[kmi]; + sgemv_("No Transpose", &i__2, &i__3, &r__1, &v[kmi + 1 + v_dim1], + ldv, &v[kmi + v_dim1], ldv, &c_b11, &t[kmi + (kmi + 1) * + t_dim1], ldt); + +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + i__2 = i__ - 1; + strmv_("Upper", "Transpose", "Non-unit", &i__2, &t[kmi + 1 + (kmi + + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); + } + } + return 0; } /* slarft_lvl2__ */ diff --git a/lapack-netlib/SRC/slarft_lvl2.f b/lapack-netlib/SRC/slarft_lvl2.f index 7107a91d5d..2a4f5bd8ee 100644 --- a/lapack-netlib/SRC/slarft_lvl2.f +++ b/lapack-netlib/SRC/slarft_lvl2.f @@ -1,18 +1,10 @@ -*> \brief \b SLARFT_LVL2: Level 2 BLAS version for terminating case of SLARFT. +*> \brief \b SLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH * * =========== DOCUMENTATION =========== * * Online html documentation available at * http://www.netlib.org/lapack/explore-html/ * -*> Download SLARFT_LVL2 + dependencies -*> -*> [TGZ] -*> -*> [ZIP] -*> -*> [TXT] -* * Definition: * =========== * @@ -49,6 +41,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**T * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -61,6 +56,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -68,8 +65,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -155,6 +154,29 @@ *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -170,157 +192,555 @@ SUBROUTINE SLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, INTEGER K, LDT, LDV, N * .. * .. Array Arguments .. +* REAL T( LDT, * ), TAU( * ), V( LDV, * ) * .. * -* ===================================================================== -* * .. Parameters .. - REAL ONE, ZERO - PARAMETER ( ONE = 1.0E+0, ZERO = 0.0E+0 ) -* .. +* + REAL ONE + PARAMETER(ONE=1.0E+0) +* * .. Local Scalars .. - INTEGER I, J, PREVLASTV, LASTV -* .. +* + INTEGER I,J,KMI,NMI,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET +* * .. External Subroutines .. - EXTERNAL SGEMV, STRMV -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME +* + EXTERNAL STRMV,SGEMV,XERBLA +* +* .. External Functions.. +* + LOGICAL LSAME + EXTERNAL LSAME * .. * .. Executable Statements .. * +* Convert our character flags to logical flags for later +* + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') +* +* Error handling for our character flags +* + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('SLARFT_LVL2', INFO) + RETURN + END IF +* * Quick return if possible * - IF( N.EQ.0 ) - $ RETURN -* - IF( LSAME( DIRECT, 'F' ) ) THEN - PREVLASTV = N - DO I = 1, K - PREVLASTV = MAX( I, PREVLASTV ) - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = 1, I - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * V( I , J ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**T * V(i:j,i) -* - CALL SGEMV( 'Transpose', J-I, I-1, -TAU( I ), - $ V( I+1, 1 ), LDV, V( I+1, I ), 1, ONE, - $ T( 1, I ), 1 ) - ELSE -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * V( J , I ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**T -* - CALL SGEMV( 'No transpose', I-1, J-I, -TAU( I ), - $ V( 1, I+1 ), LDV, V( I, I+1 ), LDV, - $ ONE, T( 1, I ), 1 ) - END IF -* -* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) -* - CALL STRMV( 'Upper', 'No transpose', 'Non-unit', I-1, - $ T, - $ LDT, T( 1, I ), 1 ) - T( I, I ) = TAU( I ) - IF( I.GT.1 ) THEN - PREVLASTV = MAX( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF + IF(N.EQ.0.OR.K.EQ.0) THEN + RETURN + END IF +* +* Now we determine what factorization our flags are associated with +* +* QR happens when we have forward direction in column storage +* + QR = DIRF.AND.STOREC +* +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute +* + LQT = DIRF.AND.STORET +* +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute +* + LQ = DIRF.AND.STORER +* +* QL happens when we have backward direction in column storage +* + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER + IF( N.EQ.1.OR.K.EQ.1) THEN + T(1,1) = TAU(1) + RETURN + END IF + IF (QR) THEN +* +* Break V into 9 components +* +* V = |-----------------------| +* |V_{1,1} 0 0 | i-1 +* |V_{2,1} V_{2,2} 0 | 1 +* |V_{3,1} V_{3,2} V_{3,3}| n-i +* |-----------------------| +* i-1 1 k-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See slarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' +* [0\\V_{2,2}\\V_{3,2}]T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' +* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + + DO I = 2, K +* +* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' +* We must do this at copy time as otherwise gemv will do nothing +* on the last column when n=k, but we neet to make sure we are +* scaled by this value +* + DO J = 1, I-1 + T(J,I) = -V(I,J)*TAU(I) + END DO + +* +* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} +* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} +* + CALL SGEMV('Transpose', N-I, I-1, -TAU(I), V(I+1,1), + $ LDV, V(I+1,I), 1, ONE, T(1, I), 1) + + +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL STRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) + +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - ELSE - PREVLASTV = 1 - DO I = K, 1, -1 - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = I, K - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( I.LT.K ) THEN - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * V( N-K+I , J ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**T * V(j:n-k+i,i) -* - CALL SGEMV( 'Transpose', N-K+I-J, K-I, - $ -TAU( I ), - $ V( J, I+1 ), LDV, V( J, I ), 1, ONE, - $ T( I+1, I ), 1 ) - ELSE -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * V( J, N-K+I ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**T -* - CALL SGEMV( 'No transpose', K-I, N-K+I-J, - $ -TAU( I ), V( I+1, J ), LDV, V( I, J ), LDV, - $ ONE, T( I+1, I ), 1 ) - END IF -* -* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) -* - CALL STRMV( 'Lower', 'No transpose', 'Non-unit', - $ K-I, - $ T( I+1, I+1 ), LDT, T( I+1, I ), 1 ) - IF( I.GT.1 ) THEN - PREVLASTV = MIN( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF - T( I, I ) = TAU( I ) - END IF + ELSE IF (LQ) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See slarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + DO I = 2, K +* +* T_{1,2} = -\tau_{i}V_{1,2} +* + DO J = 1, I-1 + T(J, I) = -TAU(I)*V(J, I) + END DO +* +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* + CALL SGEMV('No Transpose', I-1, N-I, -TAU(I), V(1, I+1), + $ LDV, V(I, I+1), LDV, ONE, T(1,I), 1) +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL STRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - END IF - RETURN + ELSE IF (LQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | i-1 +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{2,1} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On +* each iteration, T_{3,1:3} are not referenced. See slarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} +* +* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} +* +* This means we will do the following +* +* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' +* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} +* T_{2,1} = T_{1,1}'T_{2,1} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + DO I = 2, K +* +* T_{2,1} = -\tau_{i}V_{1,2}' +* + DO J = 1, I-1 + T(I,J) = -TAU(I)*V(J,I) + END DO +* +* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} +* + CALL SGEMV('No transpose', I-1, N-I, -TAU(I), V(1, I+1), + $ LDV, V(I, I+1), LDV, ONE, T(I, 1), LDT) + +* +* T_{2,1}' = T_{1,1}'T_{2,1}' +* + CALL STRMV('Lower', 'Transpose', 'Non-unit', I-1, + $ T, LDT, T(I,1), LDT) + T(I,I) = TAU(I) + END DO + ELSE IF (QL) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | n-i +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See slarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' +* [V_{1,2}\\V_{2,2}\\0]T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' +* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau(k-i+1) +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau(k-i+1)V_{2,3}' +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*V(NMI, KMI + J) + END DO +* +* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} +* + CALL SGEMV('Transpose', N-I, I-1, -TAU(KMI), + $ V(1, KMI + 1), LDV, V(1, KMI), 1, ONE, + $ T(KMI+1, KMI), 1) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL STRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI + 1, KMI + 1), LDT, T(KMI + 1, KMI), 1) + END DO + ELSE IF (RQ) THEN * -* End of SLARFT_LVL2 +* Break V into 9 components * - END +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See slarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*V(KMI + J, NMI) + END DO +* +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* + CALL SGEMV('No Transpose', I-1, N-I, -TAU(KMI), + $ V(KMI+1, 1), LDV, V(KMI, 1), LDV, ONE, T(KMI+1, KMI), + $ 1) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL STRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI+1, KMI), 1) + END DO + ELSE IF (RQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | k-i +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{2,3} at +* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On +* each iteration, T_{1,1:3} are not referenced. See slarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} +* +* After transposing when necessary to fit our blas routines' interface, +* we get +* T_{3,2} = -T_{2,2}(V_{3,1}V_{2,1} + V_{3,2})T_{3,3} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} +* T_{2,3} = T_{3,3}'T_{2,3} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = TAU(KMI) +* +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* + DO J = 1, I-1 + T(KMI, KMI + J) = -TAU(KMI)*V(KMI + J, NMI) + END DO +* +* T_{2,3} = -\tau_{k-i+1}V_{3,1}V_{2,1} + T_{2,3} +* + CALL SGEMV('No Transpose', I-1, N-I, -TAU(KMI), + $ V(KMI+1, 1), LDV, V(KMI, 1), LDV, ONE, T(KMI, KMI+1), + $ LDT) +* +* T_{2,3} = T_{3,3}'T_{2,3} +* + CALL STRMV('Upper', 'Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI, KMI+1), LDT) + END DO + END IF + END SUBROUTINE diff --git a/lapack-netlib/SRC/zlarft.c b/lapack-netlib/SRC/zlarft.c index af3740e31d..649b28967f 100644 --- a/lapack-netlib/SRC/zlarft.c +++ b/lapack-netlib/SRC/zlarft.c @@ -261,7 +261,7 @@ typedef struct Namelist Namelist; /* Table of constant values */ static doublecomplex c_b1 = {1.,0.}; -static doublecomplex c_b3 = {-1.,0.}; +static doublecomplex c_b2 = {-1.,0.}; static integer c__3 = 3; static integer c_n1 = -1; static integer c__2 = 2; @@ -315,6 +315,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**H * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -327,6 +330,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -334,8 +339,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -421,6 +428,29 @@ f"> */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -436,23 +466,28 @@ f"> */ /* Local variables */ integer i__, j, l; - logical lq, ql, qr; + logical lq, ql, qr, rq; integer nx; extern /* Subroutine */ void zlarft_lvl2__(char *, char *, integer *, integer *, doublecomplex *, integer *, doublecomplex *, doublecomplex *, integer *); - logical dirf, colv; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern logical lsame_(char *, char *); extern /* Subroutine */ void zgemm_(char *, char *, integer *, integer *, integer *, doublecomplex *, doublecomplex *, integer *, doublecomplex *, integer *, doublecomplex *, doublecomplex *, integer *), ztrmm_(char *, char *, char *, char *, integer *, integer *, doublecomplex *, doublecomplex *, integer * - , doublecomplex *, integer *); + , doublecomplex *, integer *), + xerbla_(char *, integer *, ftnlen); extern integer ilaenv_(integer *, char *, char *, integer *, integer *, integer *, integer *, ftnlen, ftnlen); + logical storec; extern /* Subroutine */ void zlacpy_(char *, integer *, integer *, doublecomplex *, integer *, doublecomplex *, integer *); + logical storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -477,7 +512,7 @@ f"> */ /* Based on the algorithm of Elmroth and Gustavson, */ /* IBM J. Res. Develop. Vol 44 No. 4 July 2000. */ -/* Quick return if possible */ +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -489,19 +524,102 @@ f"> */ t -= t_offset; /* Function Body */ + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("ZLARFT", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible */ + if (*n == 0 || *k == 0) { - return; + return 0; } +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + /* Base case */ if (*n == 1 || *k == 1) { - i__1 = t_dim1 + 1; - t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; - return; + if (lqt || rqt) { + i__1 = t_dim1 + 1; + d_cnjg(&z__1, &tau[1]); + t[i__1].r = z__1.r, t[i__1].i = z__1.i; + } else { + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + } + return 0; } -/* Determine when to cross over into the level 2 based implementation */ +/* Determine crossover point from level 2 to level 3 BLAS implementation */ /* Writing concatenation */ i__2[0] = 1, a__1[0] = direct; @@ -510,41 +628,17 @@ f"> */ nx = ilaenv_(&c__3, "ZLARFT", ch__1, n, k, &c_n1, &c_n1, (ftnlen)6, ( ftnlen)2); if (*k < nx) { + +/* Finish this component with a level 2 BLAS implementation */ + zlarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return; + return 0; } -/* Beginning of executable statements */ +/* Beginning of executable statements for the recursive case */ l = *k / 2; - -/* Determine what kind of Q we need to compute */ -/* We assume that if the user doesn't provide 'F' for DIRECT, */ -/* then they meant to provide 'B' and if they don't provide */ -/* 'C' for STOREV, then they meant to provide 'R' */ - - dirf = lsame_(direct, "F"); - colv = lsame_(storev, "C"); - -/* QR happens when we have forward direction in column storage */ - - qr = dirf && colv; - -/* LQ happens when we have forward direction in row storage */ - - lq = dirf && ! colv; - -/* QL happens when we have backward direction in column storage */ - - ql = ! dirf && colv; - -/* The last case is RQ. Due to how we structured this, if the */ -/* above 3 are false, then RQ must be true, so we never store */ -/* this */ -/* RQ happens when we have backward direction in row storage */ -/* RQ = (.NOT.DIRF).AND.(.NOT.COLV) */ - if (qr) { /* Break V apart into 6 components */ @@ -642,7 +736,7 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__1 = *k - l; - ztrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b3, + ztrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b2, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ @@ -679,14 +773,14 @@ f"> */ /* To motivate the structure, assume we have already computed T_{1,1} */ /* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ -/* T_{1,1}\in\C^{l, l} upper triangular */ -/* T_{2,2}\in\C^{k-l, k-l} upper triangular */ -/* T_{1,2}\in\C^{l, k-l} rectangular */ +/* T_{1,1}\in\C^{l, l} upper triangular */ +/* T_{2,2}\in\C^{k-l, k-l} upper triangular */ +/* T_{1,2}\in\C^{l, k-l} rectangular */ /* Then, consider the product: */ -/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ -/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ +/* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) */ +/* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 */ /* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ @@ -697,7 +791,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{1,2} */ @@ -742,7 +836,7 @@ f"> */ /* T_{1,2} = -T_{1,1}*T_{1,2} */ i__1 = *k - l; - ztrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b3, + ztrmm_("Left", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b2, &t[t_offset], ldt, &t[(l + 1) * t_dim1 + 1], ldt); /* T_{1,2} = T_{1,2}*T_{2,2} */ @@ -751,6 +845,111 @@ f"> */ ztrmm_("Right", "Upper", "No transpose", "Non-unit", &l, &i__1, &c_b1, &t[l + 1 + (l + 1) * t_dim1], ldt, &t[(l + 1) * t_dim1 + 1], ldt); + } else if (lqt) { + +/* Break V apart into 6 components */ + +/* V = |----------------------| */ +/* |V_{1,1} V_{1,2} V{1,3}| */ +/* |0 V_{2,2} V{2,3}| */ +/* |----------------------| */ + +/* V_{1,1}\in\C^{l,l} unit upper triangular */ +/* V_{1,2}\in\C^{l,k-l} rectangular */ +/* V_{1,3}\in\C^{l,n-k} rectangular */ + +/* V_{2,2}\in\C^{k-l,k-l} unit upper triangular */ +/* V_{2,3}\in\C^{k-l,n-k} rectangular */ + +/* Where l = floor(k/2) */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} 0 | */ +/* |T_{2,1} T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\C^{l, l} lower triangular */ +/* T_{2,2}\in\C^{k-l, k-l} lower triangular */ +/* T_{2,1}\in\C^{k-l, l} rectangular */ + +/* Then, consider the product: */ + +/* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) */ +/* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 */ + +/* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{2,1} */ + +/* Compute T_{1,1} recursively */ + + zlarft_(direct, storev, n, &l, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + i__1 = *n - l; + i__3 = *k - l; + zlarft_(direct, storev, &i__1, &i__3, &v[l + 1 + (l + 1) * v_dim1], + ldv, &tau[l + 1], &t[l + 1 + (l + 1) * t_dim1], ldt); + +/* Compute T_{2,1} */ +/* T_{2,1} = V_{1,2}' */ + + i__1 = *k - l; + for (i__ = 1; i__ <= i__1; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + i__4 = l + i__ + j * t_dim1; + d_cnjg(&z__1, &v[j + (l + i__) * v_dim1]); + t[i__4].r = z__1.r, t[i__4].i = z__1.i; + } + } + +/* T_{2,1} = V_{2,2}*T_{2,1} */ + + i__1 = *k - l; + ztrmm_("Left", "Upper", "No Transpose", "Unit", &i__1, &l, &c_b1, &v[ + l + 1 + (l + 1) * v_dim1], ldv, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} */ +/* Note: We assume K <= N, and GEMM will do nothing if N=K */ + + i__1 = *k - l; + i__3 = *n - *k; + zgemm_("No Transpose", "Conjugate", &i__1, &l, &i__3, &c_b1, &v[l + 1 + + (*k + 1) * v_dim1], ldv, &v[(*k + 1) * v_dim1 + 1], ldv, & + c_b1, &t[l + 1 + t_dim1], ldt); + +/* At this point, we have that T_{2,1} = V_2*V_1' */ +/* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} */ +/* respectively. */ + +/* T_{2,1} = -T_{2,2}*T_{2,1} */ + + i__1 = *k - l; + ztrmm_("Left", "Lower", "No Transpose", "Non-unit", &i__1, &l, &c_b2, + &t[l + 1 + (l + 1) * t_dim1], ldt, &t[l + 1 + t_dim1], ldt); + +/* T_{2,1} = T_{2,1}*T_{1,1} */ + + i__1 = *k - l; + ztrmm_("Right", "Lower", "No Transpose", "Non-unit", &i__1, &l, &c_b1, + &t[t_offset], ldt, &t[l + 1 + t_dim1], ldt); } else if (ql) { /* Break V apart into 6 components */ @@ -848,7 +1047,7 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__1 = *k - l; - ztrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b3, + ztrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b2, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); @@ -857,10 +1056,7 @@ f"> */ i__1 = *k - l; ztrmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b1, &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); - } else { - -/* Else means RQ case */ - + } else if (rq) { /* Break V apart into 6 components */ /* V = |-----------------------| */ @@ -893,8 +1089,8 @@ f"> */ /* Then, consider the product: */ -/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ -/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ +/* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) */ +/* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 */ /* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} */ @@ -905,7 +1101,7 @@ f"> */ /* |---| */ /* So, our product is equivalent to the matrix product */ -/* I - V'*T*V */ +/* I - V'*T'*V */ /* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ /* to compute T_{2,1} */ @@ -950,16 +1146,121 @@ f"> */ /* T_{2,1} = -T_{2,2}*T_{2,1} */ i__1 = *k - l; - ztrmm_("Left", "Lower", "No tranpose", "Non-unit", &l, &i__1, &c_b3, & - t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + + ztrmm_("Left", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b2, + &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[*k - l + 1 + t_dim1], ldt); /* T_{2,1} = T_{2,1}*T_{1,1} */ i__1 = *k - l; - ztrmm_("Right", "Lower", "No tranpose", "Non-unit", &l, &i__1, &c_b1, - &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + ztrmm_("Right", "Lower", "No transpose", "Non-unit", &l, &i__1, &c_b1, + &t[t_offset], ldt, &t[*k - l + 1 + t_dim1], ldt); + } else if (rqt) { +/* Break V apart into 6 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} V_{1,2} 0 | */ +/* |V_{2,1} V_{2,2} V_{2,3}| */ +/* |-----------------------| */ + +/* V_{1,1}\in\C^{k-l,n-k} rectangular */ +/* V_{1,2}\in\C^{k-l,k-l} unit lower triangular */ + +/* V_{2,1}\in\C^{l,n-k} rectangular */ +/* V_{2,2}\in\C^{l,k-l} rectangular */ +/* V_{2,3}\in\C^{l,l} unit lower triangular */ + +/* We will construct the T matrix */ +/* T = |---------------| */ +/* |T_{1,1} T_{1,2}| */ +/* | 0 T_{2,2}| */ +/* |---------------| */ + +/* T is the triangular factor obtained from block reflectors. */ +/* To motivate the structure, assume we have already computed T_{1,1} */ +/* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 */ + +/* T_{1,1}\in\C^{k-l, k-l} non-unit upper triangular */ +/* T_{2,2}\in\C^{l, l} non-unit upper triangular */ +/* T_{1,2}\in\C^{k-l, l} rectangular */ + +/* Where l = floor(k/2) */ + +/* Then, consider the product: */ + +/* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) */ +/* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 */ + +/* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} */ + +/* Then, we can define the matrix V as */ +/* V = |---| */ +/* |V_1| */ +/* |V_2| */ +/* |---| */ + +/* So, our product is equivalent to the matrix product */ +/* I - V'*T*V */ +/* This means, we can compute T_{1,1} and T_{2,2}, then use this information */ +/* to compute T_{1,2} */ + +/* Compute T_{1,1} recursively */ + + i__1 = *n - l; + i__3 = *k - l; + zlarft_(direct, storev, &i__1, &i__3, &v[v_offset], ldv, &tau[1], &t[ + t_offset], ldt); + +/* Compute T_{2,2} recursively */ + + zlarft_(direct, storev, n, &l, &v[*k - l + 1 + v_dim1], ldv, &tau[*k + - l + 1], &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt); + +/* Compute T_{1,2} */ +/* T_{1,2} = V_{2,2}' */ + + i__1 = *k - l; + for (i__ = 1; i__ <= i__1; ++i__) { + i__3 = l; + for (j = 1; j <= i__3; ++j) { + i__4 = i__ + (*k - l + j) * t_dim1; + d_cnjg(&z__1, &v[*k - l + j + (*n - *k + i__) * v_dim1]); + t[i__4].r = z__1.r, t[i__4].i = z__1.i; + } + } + +/* T_{1,2} = V_{1,2}T_{1,2} */ + + i__1 = *k - l; + ztrmm_("Left", "Lower", "No Transpose", "Unit", &i__1, &l, &c_b1, &v[( + *n - *k + 1) * v_dim1 + 1], ldv, &t[(*k - l + 1) * t_dim1 + 1] + , ldt); + +/* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} */ + + i__1 = *k - l; + i__3 = *n - *k; + zgemm_("No Transpose", "Conjugate", &i__1, &l, &i__3, &c_b1, &v[ + v_offset], ldv, &v[*k - l + 1 + v_dim1], ldv, &c_b1, &t[(*k - + l + 1) * t_dim1 + 1], ldt); + +/* At this point, we have that T_{1,2} = V_1*V_2' */ +/* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} */ +/* respectively. */ + +/* T_{1,2} = -T_{1,1}*T_{1,2} */ + + i__1 = *k - l; + ztrmm_("Left", "Upper", "No Transpose", "Non-Unit", &i__1, &l, &c_b2, + &t[t_offset], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); + +/* T_{1,2} = T_{1,2}*T_{2,2} */ + + i__1 = *k - l; + ztrmm_("Right", "Upper", "No Transpose", "Non-Unit", &i__1, &l, &c_b1, + &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - l + 1) + * t_dim1 + 1], ldt); } - return; + return 0; } /* zlarft_ */ diff --git a/lapack-netlib/SRC/zlarft.f b/lapack-netlib/SRC/zlarft.f index efd52037d3..8a0d3f0cf7 100644 --- a/lapack-netlib/SRC/zlarft.f +++ b/lapack-netlib/SRC/zlarft.f @@ -48,6 +48,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**H * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -60,6 +63,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -67,8 +72,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -154,6 +161,29 @@ *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -167,28 +197,30 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. Scalar Arguments * - CHARACTER DIRECT, STOREV - INTEGER K, LDT, LDV, N + CHARACTER DIRECT, STOREV + INTEGER K, LDT, LDV, N * .. * .. Array Arguments .. * - COMPLEX*16 T( LDT, * ), TAU( * ), V( LDV, * ) + COMPLEX*16 T( LDT, * ), TAU( * ), V( LDV, * ) * .. * * .. Parameters .. * - COMPLEX*16 ONE, NEG_ONE, ZERO - PARAMETER(ONE=(1.0D+0,0.0D+0), ZERO = (0.0D+0,0.0D+0), - $ NEG_ONE=(-1.0D+0,0.0D+0)) + COMPLEX*16 ONE, NEG_ONE + PARAMETER(ONE=(1.0D+0,0.0D+0), + $ NEG_ONE=(-1.0D+0,0.0D+0)) * * .. Local Scalars .. * - INTEGER I,J,L,NX - LOGICAL QR,LQ,QL,DIRF,COLV + INTEGER I,J,L,NX,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET * * .. External Subroutines .. * - EXTERNAL ZTRMM,ZGEMM,ZLACPY + EXTERNAL ZLARFT_LVL2, ZTRMM, ZGEMM, ZLACPY, XERBLA * * .. External Functions.. * @@ -198,8 +230,8 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. Intrinsic Functions.. * - INTRINSIC CONJG -* + INTRINSIC DCONJG +* * The general scheme used is inspired by the approach inside DGEQRT3 * which was (at the time of writing this code): * Based on the algorithm of Elmroth and Gustavson, @@ -207,57 +239,115 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * .. * .. Executable Statements .. * -* Quick return if possible +* Convert our character flags to logical flags for later * - IF(N.EQ.0.OR.K.EQ.0) THEN - RETURN - END IF + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') * -* Base case +* Error handling for our character flags * - IF(N.EQ.1.OR.K.EQ.1) THEN - T(1,1) = TAU(1) + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('ZLARFT', INFO) RETURN END IF * -* Determine when to cross over into the level 2 based implementation +* Quick return if possible * - NX = ILAENV(3, "ZLARFT", DIRECT // STOREV, N, K, -1, -1) - IF(K.LT.NX) THEN - CALL ZLARFT_LVL2(DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT) + IF(N.EQ.0.OR.K.EQ.0) THEN RETURN END IF * -* Beginning of executable statements -* - L = K / 2 +* Now we determine what factorization our flags are associated with * -* Determine what kind of Q we need to compute -* We assume that if the user doesn't provide 'F' for DIRECT, -* then they meant to provide 'B' and if they don't provide -* 'C' for STOREV, then they meant to provide 'R' +* QR happens when we have forward direction in column storage * - DIRF = LSAME(DIRECT,'F') - COLV = LSAME(STOREV,'C') + QR = DIRF.AND.STOREC * -* QR happens when we have forward direction in column storage +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute * - QR = DIRF.AND.COLV + LQT = DIRF.AND.STORET * -* LQ happens when we have forward direction in row storage +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute * - LQ = DIRF.AND.(.NOT.COLV) + LQ = DIRF.AND.STORER * * QL happens when we have backward direction in column storage * - QL = (.NOT.DIRF).AND.COLV + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER +* +* Base case +* + IF(N.EQ.1.OR.K.EQ.1) THEN + IF( LQT.OR.RQT ) THEN + T(1,1) = DCONJG(TAU(1)) + ELSE + T(1,1) = TAU(1) + END IF + RETURN + END IF +* +* Determine crossover point from level 2 to level 3 BLAS implementation +* + NX = ILAENV(3, "ZLARFT", DIRECT // STOREV, N, K, -1, -1) + IF(K.LT.NX) THEN * -* The last case is RQ. Due to how we structured this, if the -* above 3 are false, then RQ must be true, so we never store -* this -* RQ happens when we have backward direction in row storage -* RQ = (.NOT.DIRF).AND.(.NOT.COLV) +* Finish this component with a level 2 BLAS implementation * + CALL ZLARFT_LVL2(DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT) + RETURN + END IF +* +* Beginning of executable statements for the recursive case +* + L = K / 2 IF(QR) THEN * * Break V apart into 6 components @@ -271,17 +361,17 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\C^{l,l} unit lower triangular * V_{2,1}\in\C^{k-l,l} rectangular * V_{3,1}\in\C^{n-k,l} rectangular -* +* * V_{2,2}\in\C^{k-l,k-l} unit lower triangular * V_{3,2}\in\C^{n-k,k-l} rectangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -292,17 +382,17 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_1*T_{1,1}*V_1')*(I - V_2*T_{2,2}*V_2') * = I - V_1*T_{1,1}*V_1' - V_2*T_{2,2}*V_2' + V_1*T_{1,1}*V_1'*V_2*T_{2,2}*V_2' -* +* * Define T_{1,2} = -T_{1,1}*V_1'*V_2*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -314,30 +404,29 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * -* Compute T_{1,2} +* Compute T_{1,2} * T_{1,2} = V_{2,1}' * DO J = 1, L DO I = 1, K-L - T(J, L+I) = CONJG(V(L+I, J)) + T(J,L+I) = CONJG(V(L+I,J)) END DO END DO * * T_{1,2} = T_{1,2}*V_{2,2} * CALL ZTRMM('Right', 'Lower', 'No transpose', 'Unit', L, - $ K-L, ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) + $ K-L, ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = V_{3,1}'*V_{3,2} + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL ZGEMM('Conjugate', 'No transpose', L, K-L, N-K, ONE, - $ V(K+1, 1), LDV, V(K+1, L+1), LDV, ONE, - $ T(1, L+1), LDT) + CALL ZGEMM('Conjugate', 'No transpose', L, K-L, N-K, ONE, + $ V(K+1, 1), LDV, V(K+1,L+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1'*V_2 * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -346,12 +435,12 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = -T_{1,1}*T_{1,2} * CALL ZTRMM('Left', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) + $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*T_{2,2} * - CALL ZTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + CALL ZTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) ELSE IF(LQ) THEN * @@ -365,41 +454,41 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{1,1}\in\C^{l,l} unit upper triangular * V_{1,2}\in\C^{l,k-l} rectangular * V_{1,3}\in\C^{l,n-k} rectangular -* +* * V_{2,2}\in\C^{k-l,k-l} unit upper triangular * V_{2,3}\in\C^{k-l,n-k} rectangular * * Where l = floor(k/2) * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} T_{1,2}| * |0 T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * -* T_{1,1}\in\C^{l, l} upper triangular -* T_{2,2}\in\C^{k-l, k-l} upper triangular -* T_{1,2}\in\C^{l, k-l} rectangular +* T_{1,1}\in\C^{l, l} upper triangular +* T_{2,2}\in\C^{k-l, k-l} upper triangular +* T_{1,2}\in\C^{l, k-l} rectangular * * Then, consider the product: -* -* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) -* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 -* +* +* (I - V_1'*T_{1,1}'*V_1)*(I - V_2'*T_{2,2}'*V_2) +* = I - V_1'*T_{1,1}'*V_1 - V_2'*T_{2,2}'*V_2 + V_1'*T_{1,1}'*V_1*V_2'*T_{2,2}'*V_2 +* * Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{1,2} * @@ -409,27 +498,26 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{2,2} recursively * - CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V(L+1, L+1), LDV, - $ TAU(L+1), T(L+1, L+1), LDT) + CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) * * Compute T_{1,2} * T_{1,2} = V_{1,2} * - CALL ZLACPY('All', L, K-L, V(1, L+1), LDV, T(1, L+1), LDT) + CALL ZLACPY('All', L, K - L, V(1,L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*V_{2,2}' * CALL ZTRMM('Right', 'Upper', 'Conjugate', 'Unit', L, K-L, - $ ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) + $ ONE, V(L+1, L+1), LDV, T(1, L+1), LDT) * * T_{1,2} = V_{1,3}*V_{2,3}' + T_{1,2} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL ZGEMM('No transpose', 'Conjugate', L, K-L, N-K, ONE, - $ V(1, K+1), LDV, V(L+1, K+1), LDV, ONE, - $ T(1, L+1), LDT) + $ V(1, K+1), LDV, V(L+1, K+1), LDV, ONE, T(1, L+1), LDT) * * At this point, we have that T_{1,2} = V_1*V_2' * All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} @@ -438,13 +526,106 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{1,2} = -T_{1,1}*T_{1,2} * CALL ZTRMM('Left', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) + $ K-L, NEG_ONE, T, LDT, T(1, L+1), LDT) * * T_{1,2} = T_{1,2}*T_{2,2} * CALL ZTRMM('Right', 'Upper', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T(L+1, L+1), LDT, T(1, L+1), LDT) + $ K-L, ONE, T(L+1,L+1), LDT, T(1, L+1), LDT) + ELSE IF(LQT) THEN +* +* Break V apart into 6 components +* +* V = |----------------------| +* |V_{1,1} V_{1,2} V{1,3}| +* |0 V_{2,2} V{2,3}| +* |----------------------| +* +* V_{1,1}\in\C^{l,l} unit upper triangular +* V_{1,2}\in\C^{l,k-l} rectangular +* V_{1,3}\in\C^{l,n-k} rectangular +* +* V_{2,2}\in\C^{k-l,k-l} unit upper triangular +* V_{2,3}\in\C^{k-l,n-k} rectangular +* +* Where l = floor(k/2) +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} 0 | +* |T_{2,1} T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\C^{l, l} lower triangular +* T_{2,2}\in\C^{k-l, k-l} lower triangular +* T_{2,1}\in\C^{k-l, l} rectangular +* +* Then, consider the product: +* +* (I - V_1'*T_{1,1}*V_1)*(I - V_2'*T_{2,2}*V_2) +* = I - V_1'*T_{1,1}*V_1 - V_2'*T_{2,2}*V_2 + V_1'*T_{1,1}*V_1*V_2'*T_{2,2}*V_2 +* +* Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{2,1} +* +* Compute T_{1,1} recursively +* + CALL ZLARFT(DIRECT, STOREV, N, L, V, LDV, TAU, T, LDT) +* +* Compute T_{2,2} recursively +* + CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V(L+1,L+1), LDV, + $ TAU(L+1), T(L+1,L+1), LDT) + +* +* Compute T_{2,1} +* T_{2,1} = V_{1,2}' +* + DO I = 1, K-L + DO J = 1, L + T(L+I,J) = CONJG(V(J,L+I)) + END DO + END DO +* +* T_{2,1} = V_{2,2}*T_{2,1} +* + CALL ZTRMM('Left', 'Upper', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(L+1,L+1), LDV, T(L+1,1), LDT) +* +* T_{2,1} = V_{2,3}*V_{1,3}' + T_{2,1} +* Note: We assume K <= N, and GEMM will do nothing if N=K +* + CALL ZGEMM('No Transpose', 'Conjugate', K-L, L, N-K, ONE, + $ V(L+1,K+1), LDV, V(1, K+1), LDV, ONE, T(L+1,1), LDT) +* +* At this point, we have that T_{2,1} = V_2*V_1' +* All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} +* respectively. +* +* T_{2,1} = -T_{2,2}*T_{2,1} +* + CALL ZTRMM('Left', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, NEG_ONE, T(L+1,L+1), LDT, T(L+1,1), LDT) +* +* T_{2,1} = T_{2,1}*T_{1,1} +* + CALL ZTRMM('Right', 'Lower', 'No Transpose', 'Non-unit', + $ K-L, L, ONE, T, LDT, T(L+1,1), LDT) ELSE IF(QL) THEN * * Break V apart into 6 components @@ -457,18 +638,18 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * V_{1,1}\in\C^{n-k,k-l} rectangular * V_{2,1}\in\C^{k-l,k-l} unit upper triangular -* +* * V_{1,2}\in\C^{n-k,l} rectangular * V_{2,2}\in\C^{k-l,l} rectangular * V_{3,2}\in\C^{l,l} unit upper triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -479,17 +660,17 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* +* * (I - V_2*T_{2,2}*V_2')*(I - V_1*T_{1,1}*V_1') * = I - V_2*T_{2,2}*V_2' - V_1*T_{1,1}*V_1' + V_2*T_{2,2}*V_2'*V_1*T_{1,1}*V_1' -* +* * Define T_{2,1} = -T_{2,2}*V_2'*V_1*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |-------| * |V_1 V_2| * |-------| -* +* * So, our product is equivalent to the matrix product * I - V*T*V' * This means, we can compute T_{1,1} and T_{2,2}, then use this information @@ -497,34 +678,34 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * Compute T_{1,1} recursively * - CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * CALL ZLARFT(DIRECT, STOREV, N, L, V(1, K-L+1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2}' * DO J = 1, K-L DO I = 1, L - T(K-L+I, J) = CONJG(V(N-K+J, K-L+I)) + T(K-L+I,J) = CONJG(V(N-K+J, K-L+I)) END DO END DO * * T_{2,1} = T_{2,1}*V_{2,1} * CALL ZTRMM('Right', 'Upper', 'No transpose', 'Unit', L, - $ K-L, ONE, V(N-K+1, 1), LDV, T(K-L+1, 1), LDT) + $ K-L, ONE, V(N-K+1,1), LDV, T(K-L+1,1), LDT) * * T_{2,1} = V_{2,2}'*V_{2,1} + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * CALL ZGEMM('Conjugate', 'No transpose', L, K-L, N-K, ONE, - $ V(1, K-L+1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + $ V(1,K-L+1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2'*V_1 * All that is left is to pre and post multiply by -T_{2,2} and T_{1,1} @@ -533,17 +714,13 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * T_{2,1} = -T_{2,2}*T_{2,1} * CALL ZTRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * CALL ZTRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) - ELSE -* -* Else means RQ case -* + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQ) THEN * Break V apart into 6 components * * V = |-----------------------| @@ -558,13 +735,13 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * V_{2,2}\in\C^{l,k-l} rectangular * V_{2,3}\in\C^{l,l} unit lower triangular * -* We will construct the T matrix +* We will construct the T matrix * T = |---------------| * |T_{1,1} 0 | * |T_{2,1} T_{2,2}| * |---------------| * -* T is the triangular factor obtained from block reflectors. +* T is the triangular factor obtained from block reflectors. * To motivate the structure, assume we have already computed T_{1,1} * and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 * @@ -575,51 +752,51 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * Where l = floor(k/2) * * Then, consider the product: -* -* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) -* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 -* +* +* (I - V_2'*T_{2,2}'*V_2)*(I - V_1'*T_{1,1}'*V_1) +* = I - V_2'*T_{2,2}'*V_2 - V_1'*T_{1,1}'*V_1 + V_2'*T_{2,2}'*V_2*V_1'*T_{1,1}'*V_1 +* * Define T_{2,1} = -T_{2,2}*V_2*V_1'*T_{1,1} -* -* Then, we can define the matrix V as +* +* Then, we can define the matrix V as * V = |---| * |V_1| * |V_2| * |---| -* +* * So, our product is equivalent to the matrix product -* I - V'*T*V +* I - V'*T'*V * This means, we can compute T_{1,1} and T_{2,2}, then use this information * to compute T_{2,1} * * Compute T_{1,1} recursively * - CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, LDT) + CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) * * Compute T_{2,2} recursively * - CALL ZLARFT(DIRECT, STOREV, N, L, V(K-L+1, 1), LDV, - $ TAU(K-L+1), T(K-L+1, K-L+1), LDT) + CALL ZLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) * * Compute T_{2,1} * T_{2,1} = V_{2,2} * - CALL ZLACPY('All', L, K-L, V(K-L+1, N-K+1), LDV, - $ T(K-L+1, 1), LDT) + CALL ZLACPY('All', L, K-L, V(K-L+1,N-K+1), LDV, T(K-L+1,1), + $ LDT) * * T_{2,1} = T_{2,1}*V_{1,2}' * CALL ZTRMM('Right', 'Lower', 'Conjugate', 'Unit', L, K-L, - $ ONE, V(1, N-K+1), LDV, T(K-L+1, 1), LDT) + $ ONE, V(1, N-K+1), LDV, T(K-L+1,1), LDT) * -* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} +* T_{2,1} = V_{2,1}*V_{1,1}' + T_{2,1} * Note: We assume K <= N, and GEMM will do nothing if N=K * - CALL ZGEMM('No transpose', 'Conjugate', L, K-L, N-K, ONE, - $ V(K-L+1, 1), LDV, V, LDV, ONE, T(K-L+1, 1), - $ LDT) + CALL ZGEMM('No transpose', 'Conjugate', L, K-L, N-K, ONE, + $ V(K-L+1,1), LDV, V, LDV, ONE, T(K-L+1,1), LDT) * * At this point, we have that T_{2,1} = V_2*V_1' @@ -628,14 +805,104 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * T_{2,1} = -T_{2,2}*T_{2,1} * - CALL ZTRMM('Left', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, NEG_ONE, T(K-L+1, K-L+1), LDT, - $ T(K-L+1, 1), LDT) + CALL ZTRMM('Left', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, NEG_ONE, T(K-L+1,K-L+1), LDT, T(K-L+1,1), LDT) * * T_{2,1} = T_{2,1}*T_{1,1} * - CALL ZTRMM('Right', 'Lower', 'No tranpose', 'Non-unit', L, - $ K-L, ONE, T, LDT, T(K-L+1, 1), LDT) + CALL ZTRMM('Right', 'Lower', 'No transpose', 'Non-unit', L, + $ K-L, ONE, T, LDT, T(K-L+1,1), LDT) + ELSE IF(RQT) THEN +* Break V apart into 6 components +* +* V = |-----------------------| +* |V_{1,1} V_{1,2} 0 | +* |V_{2,1} V_{2,2} V_{2,3}| +* |-----------------------| +* +* V_{1,1}\in\C^{k-l,n-k} rectangular +* V_{1,2}\in\C^{k-l,k-l} unit lower triangular +* +* V_{2,1}\in\C^{l,n-k} rectangular +* V_{2,2}\in\C^{l,k-l} rectangular +* V_{2,3}\in\C^{l,l} unit lower triangular +* +* We will construct the T matrix +* T = |---------------| +* |T_{1,1} T_{1,2}| +* | 0 T_{2,2}| +* |---------------| +* +* T is the triangular factor obtained from block reflectors. +* To motivate the structure, assume we have already computed T_{1,1} +* and T_{2,2}. Then collect the associated reflectors in V_1 and V_2 +* +* T_{1,1}\in\C^{k-l, k-l} non-unit upper triangular +* T_{2,2}\in\C^{l, l} non-unit upper triangular +* T_{1,2}\in\C^{k-l, l} rectangular +* +* Where l = floor(k/2) +* +* Then, consider the product: +* +* (I - V_2'*T_{2,2}*V_2)*(I - V_1'*T_{1,1}*V_1) +* = I - V_2'*T_{2,2}*V_2 - V_1'*T_{1,1}*V_1 + V_2'*T_{2,2}*V_2*V_1'*T_{1,1}*V_1 +* +* Define T_{1,2} = -T_{1,1}*V_1*V_2'*T_{2,2} +* +* Then, we can define the matrix V as +* V = |---| +* |V_1| +* |V_2| +* |---| +* +* So, our product is equivalent to the matrix product +* I - V'*T*V +* This means, we can compute T_{1,1} and T_{2,2}, then use this information +* to compute T_{1,2} +* +* Compute T_{1,1} recursively +* + CALL ZLARFT(DIRECT, STOREV, N-L, K-L, V, LDV, TAU, T, + $ LDT) +* +* Compute T_{2,2} recursively +* + CALL ZLARFT(DIRECT, STOREV, N, L, V(K-L+1,1), LDV, + $ TAU(K-L+1), T(K-L+1,K-L+1), LDT) +* +* Compute T_{1,2} +* T_{1,2} = V_{2,2}' +* + DO I = 1, K-L + DO J = 1, L + T(I,K-L+J) = CONJG(V(K-L+J, N-K+I)) + END DO + END DO +* +* T_{1,2} = V_{1,2}T_{1,2} +* + CALL ZTRMM('Left', 'Lower', 'No Transpose', 'Unit', K-L, L, + $ ONE, V(1,N-K+1), LDV, T(1,K-L+1), LDT) +* +* T_{1,2} = V_{1,1}V_{2,1}' + T_{1,2} +* + CALL ZGEMM('No Transpose', 'Conjugate', K-L, L, N-K, ONE, V, + $ LDV, V(K-L+1,1), LDV, ONE, T(1, K-L+1), LDT) +* +* At this point, we have that T_{1,2} = V_1*V_2' +* All that is left is to pre and post multiply by -T_{1,1} and T_{2,2} +* respectively. +* +* T_{1,2} = -T_{1,1}*T_{1,2} +* + CALL ZTRMM('Left', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, NEG_ONE, T, LDT, T(1, K-L+1), LDT) +* +* T_{1,2} = T_{1,2}*T_{2,2} +* + CALL ZTRMM('Right', 'Upper', 'No Transpose', 'Non-Unit', + $ K-L, L, ONE, T(K-L+1,K-L+1), LDT, T(1, K-L+1), LDT) END IF END SUBROUTINE diff --git a/lapack-netlib/SRC/zlarft_lvl2.c b/lapack-netlib/SRC/zlarft_lvl2.c index 9958be2af5..820800d464 100644 --- a/lapack-netlib/SRC/zlarft_lvl2.c +++ b/lapack-netlib/SRC/zlarft_lvl2.c @@ -257,30 +257,18 @@ typedef struct Namelist Namelist; -lf2c -lm (in that order) */ - /* Table of constant values */ static doublecomplex c_b1 = {1.,0.}; static integer c__1 = 1; -/* > \brief \b ZLARFT_LVL2: Level 2 BLAS version for terminating case of ZLARFT. */ +/* > \brief \b ZLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH */ /* =========== DOCUMENTATION =========== */ /* Online html documentation available at */ /* http://www.netlib.org/lapack/explore-html/ */ -/* > Download ZLARFT_LVL2 + dependencies */ -/* > */ -/* > [TGZ] */ -/* > */ -/* > [ZIP] */ -/* > */ -/* > [TXT] */ - /* Definition: */ /* =========== */ @@ -313,6 +301,9 @@ f"> */ /* > H(i) is stored in the i-th row of the array V, and */ /* > */ /* > H = I - V**H * T * V */ +/* > */ +/* > If DIRECT or STOREV = 'T', see Further Details for the shape of T */ +/* > */ /* > \endverbatim */ /* Arguments: */ @@ -325,6 +316,8 @@ f"> */ /* > multiplied to form the block reflector: */ /* > = 'F': H = H(1) H(2) . . . H(k) (Forward) */ /* > = 'B': H = H(k) . . . H(2) H(1) (Backward) */ +/* > = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) */ +/* > but we return the T matrix that is already (conjugate) transposed */ /* > \endverbatim */ /* > */ /* > \param[in] STOREV */ @@ -332,8 +325,10 @@ f"> */ /* > STOREV is CHARACTER*1 */ /* > Specifies how the vectors which define the elementary */ /* > reflectors are stored (see also Further Details): */ -/* > = 'C': columnwise */ -/* > = 'R': rowwise */ +/* > = 'C': column-wise */ +/* > = 'R': row-wise */ +/* > = 'T': (With DIRECT='F') Row-wise, but we return the T */ +/* > matrix that is already (conjugate) transposed. */ /* > \endverbatim */ /* > */ /* > \param[in] N */ @@ -419,6 +414,29 @@ f"> */ /* > ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) */ /* > ( 1 v3 ) */ /* > ( 1 ) */ +/* > */ +/* > In addition, the shape of T is determined by these same flags as */ +/* > in the below table. */ +/* > 'U' denotes upper triangular */ +/* > 'L' denotes lower triangular */ +/* > 'X' denotes no current implementation */ +/* > We also provide the logical variable that represents the case */ +/* > in the code if it is implemented */ +/* > */ +/* > |-----------------------------------------------------------| */ +/* > | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | */ +/* > |--------------+--------------+--------------+--------------| */ +/* > | STOREV = 'C' | U (QR) | L (QL) | X | */ +/* > | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | */ +/* > | STOREV = 'T' | L (LQT) | X | X | */ +/* > |-----------------------------------------------------------| */ +/* > */ +/* > Finally, the relationship between the (conjugate) transposed T matrices */ +/* > are as follows: (Note that T_{FC} denotes the T associated with calling */ +/* > this routine with DIRECT = 'F' and STOREV = 'C') */ +/* > */ +/* > T_{TR} = (T_{BR})**H */ +/* > T_{FT} = (T_{FR})**H */ /* > \endverbatim */ /* > */ /* ===================================================================== */ @@ -431,17 +449,23 @@ f"> */ doublecomplex z__1, z__2, z__3; /* Local variables */ - integer i__, j, prevlastv; + integer i__, j; + logical lq, ql, qr, rq; + integer kmi, nmi; + logical lqt, rqt, dirb, dirf; + integer info; + logical dirt; extern logical lsame_(char *, char *); extern /* Subroutine */ void zgemm_(char *, char *, integer *, integer *, integer *, doublecomplex *, doublecomplex *, integer *, doublecomplex *, integer *, doublecomplex *, doublecomplex *, integer *), zgemv_(char *, integer *, integer *, doublecomplex *, doublecomplex *, integer *, doublecomplex *, - integer *, doublecomplex *, doublecomplex *, integer *); - integer lastv; - extern /* Subroutine */ void ztrmv_(char *, char *, char *, integer *, - doublecomplex *, integer *, doublecomplex *, integer *), mecago_(); + integer *, doublecomplex *, doublecomplex *, integer *), + ztrmv_(char *, char *, char *, integer *, doublecomplex *, + integer *, doublecomplex *, integer *), + xerbla_(char *, integer *, ftnlen); + logical storec, storer, storet; /* -- LAPACK auxiliary routine -- */ @@ -449,10 +473,18 @@ f"> */ /* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */ -/* ===================================================================== */ -/* Quick return if possible */ + + + + + + + + + +/* Convert our character flags to logical flags for later */ /* Parameter adjustments */ v_dim1 = *ldv; @@ -464,212 +496,635 @@ f"> */ t -= t_offset; /* Function Body */ - if (*n == 0) { - return; + dirf = lsame_(direct, "F"); + dirb = lsame_(direct, "B"); + dirt = lsame_(direct, "T"); + storec = lsame_(storev, "C"); + storer = lsame_(storev, "R"); + storet = lsame_(storev, "T"); + +/* Error handling for our character flags */ + + info = 0; + if (! (dirf || dirb || dirt)) { + +/* DIRECT holds an illegal value */ + + info = 1; + } else if (! (storec || storer || storet)) { + +/* STOREV holds an illegal value */ + + info = 2; + } else if (dirb && storet) { + +/* This case is purposefully not implemented, but any other value for */ +/* STOREV is valid, so we report STOREV as the invalid input */ + + info = 2; + } else if (dirt && storec) { + +/* This case is purposefully not implemented, but any other value for */ +/* DIRECT is valid, so we report DIRECT as the invalid input */ + + info = 1; + } else if (dirt && storet) { + +/* This case is purposefully not implemented, and is ambiguous what */ +/* the user wants to do, so we arbitrarily say DIRECT is the incorrect */ +/* character flag. */ + + info = 1; + } + if (info != 0) { + xerbla_("ZLARFT_LVL2", &info, (ftnlen)11); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *k == 0) { + return 0; } - if (lsame_(direct, "F")) { - prevlastv = *n; +/* Now we determine what factorization our flags are associated with */ + +/* QR happens when we have forward direction in column storage */ + + qr = dirf && storec; + +/* LQT happens when we have forward direction in row storage and want to compute the transpose of */ +/* the T we would normally compute */ + + lqt = dirf && storet; + +/* LQ happens when we have forward direction in row storage and want to compute the T we would */ +/* normally compute */ + + lq = dirf && storer; + +/* QL happens when we have backward direction in column storage */ + + ql = dirb && storec; + +/* RQT happens when we have backward direction in row storage and want to compute the transpose */ +/* of the T we would normally compute */ + + rqt = dirt && storer; + +/* RQ happens when we have backward direction in row storage and want to compute the T that we */ +/* would normally compute */ + + rq = dirb && storer; + if (*n == 1 || *k == 1) { + if (lqt || rqt) { + i__1 = t_dim1 + 1; + d_cnjg(&z__1, &tau[1]); + t[i__1].r = z__1.r, t[i__1].i = z__1.i; + } else { + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + } + return 0; + } + if (qr) { + +/* Break V into 9 components */ + +/* V = |-----------------------| */ +/* |V_{1,1} 0 0 | i-1 */ +/* |V_{2,1} V_{2,2} 0 | 1 */ +/* |V_{3,1} V_{3,2} V_{3,3}| n-i */ +/* |-----------------------| */ +/* i-1 1 k-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See zlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' */ +/* [0\\V_{2,2}\\V_{3,2}]T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' */ +/* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; i__1 = *k; - for (i__ = 1; i__ <= i__1; ++i__) { - prevlastv = f2cmax(prevlastv,i__); - i__2 = i__; - if (tau[i__2].r == 0. && tau[i__2].i == 0.) { - -/* H(i) = I */ - - i__2 = i__; - for (j = 1; j <= i__2; ++j) { - i__3 = j + i__ * t_dim1; - t[i__3].r = 0., t[i__3].i = 0.; - } - } else { - -/* general case */ - - if (lsame_(storev, "C")) { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - i__3 = lastv + i__ * v_dim1; - if (v[i__3].r != 0. || v[i__3].i != 0.) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - i__3 = j + i__ * t_dim1; - i__4 = i__; - z__2.r = -tau[i__4].r, z__2.i = -tau[i__4].i; - d_cnjg(&z__3, &v[i__ + j * v_dim1]); - z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = - z__2.r * z__3.i + z__2.i * z__3.r; - t[i__3].r = z__1.r, t[i__3].i = z__1.i; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**H * V(i:j,i) */ - - i__2 = j - i__; - i__3 = i__ - 1; - i__4 = i__; - z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; - zgemv_("Conjugate transpose", &i__2, &i__3, &z__1, &v[i__ - + 1 + v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], & - c__1, &c_b1, &t[i__ * t_dim1 + 1], &c__1); - } else { -/* Skip any trailing zeros. */ - i__2 = i__ + 1; - for (lastv = *n; lastv >= i__2; --lastv) { - i__3 = i__ + lastv * v_dim1; - if (v[i__3].r != 0. || v[i__3].i != 0.) { - myexit_(); - } - } - i__2 = i__ - 1; - for (j = 1; j <= i__2; ++j) { - i__3 = j + i__ * t_dim1; - i__4 = i__; - z__2.r = -tau[i__4].r, z__2.i = -tau[i__4].i; - i__5 = j + i__ * v_dim1; - z__1.r = z__2.r * v[i__5].r - z__2.i * v[i__5].i, - z__1.i = z__2.r * v[i__5].i + z__2.i * v[i__5] - .r; - t[i__3].r = z__1.r, t[i__3].i = z__1.i; - } - j = f2cmin(lastv,prevlastv); - -/* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**H */ - - i__2 = i__ - 1; - i__3 = j - i__; - i__4 = i__; - z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; - zgemm_("N", "C", &i__2, &c__1, &i__3, &z__1, &v[(i__ + 1) - * v_dim1 + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], - ldv, &c_b1, &t[i__ * t_dim1 + 1], ldt); - } - -/* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) */ - - i__2 = i__ - 1; - ztrmv_("Upper", "No transpose", "Non-unit", &i__2, &t[ - t_offset], ldt, &t[i__ * t_dim1 + 1], &c__1); - i__2 = i__ + i__ * t_dim1; - i__3 = i__; - t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; - if (i__ > 1) { - prevlastv = f2cmax(prevlastv,lastv); - } else { - prevlastv = lastv; - } + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' */ +/* We must do this at copy time as otherwise gemv will do nothing */ +/* on the last column when n=k, but we neet to make sure we are */ +/* scaled by this value */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = j + i__ * t_dim1; + i__4 = i__; + z__2.r = -tau[i__4].r, z__2.i = -tau[i__4].i; + d_cnjg(&z__3, &v[i__ + j * v_dim1]); + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = z__2.r * + z__3.i + z__2.i * z__3.r; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; } + +/* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} */ +/* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + i__4 = i__; + z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; + zgemv_("Conjugate Transpose", &i__2, &i__3, &z__1, &v[i__ + 1 + + v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, &c_b1, & + t[i__ * t_dim1 + 1], &c__1); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + ztrmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; } - } else { - prevlastv = 1; - for (i__ = *k; i__ >= 1; --i__) { - i__1 = i__; - if (tau[i__1].r == 0. && tau[i__1].i == 0.) { - -/* H(i) = I */ - - i__1 = *k; - for (j = i__; j <= i__1; ++j) { - i__2 = j + i__ * t_dim1; - t[i__2].r = 0., t[i__2].i = 0.; - } - } else { - -/* general case */ - - if (i__ < *k) { - if (lsame_(storev, "C")) { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - i__2 = lastv + i__ * v_dim1; - if (v[i__2].r != 0. || v[i__2].i != 0.) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - i__2 = j + i__ * t_dim1; - i__3 = i__; - z__2.r = -tau[i__3].r, z__2.i = -tau[i__3].i; - d_cnjg(&z__3, &v[*n - *k + i__ + j * v_dim1]); - z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, - z__1.i = z__2.r * z__3.i + z__2.i * - z__3.r; - t[i__2].r = z__1.r, t[i__2].i = z__1.i; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**H * V(j:n-k+i,i) */ - - i__1 = *n - *k + i__ - j; - i__2 = *k - i__; - i__3 = i__; - z__1.r = -tau[i__3].r, z__1.i = -tau[i__3].i; - zgemv_("Conjugate transpose", &i__1, &i__2, &z__1, &v[ - j + (i__ + 1) * v_dim1], ldv, &v[j + i__ * - v_dim1], &c__1, &c_b1, &t[i__ + 1 + i__ * - t_dim1], &c__1); - } else { -/* Skip any leading zeros. */ - i__1 = i__ - 1; - for (lastv = 1; lastv <= i__1; ++lastv) { - i__2 = i__ + lastv * v_dim1; - if (v[i__2].r != 0. || v[i__2].i != 0.) { - myexit_(); - } - } - i__1 = *k; - for (j = i__ + 1; j <= i__1; ++j) { - i__2 = j + i__ * t_dim1; - i__3 = i__; - z__2.r = -tau[i__3].r, z__2.i = -tau[i__3].i; - i__4 = j + (*n - *k + i__) * v_dim1; - z__1.r = z__2.r * v[i__4].r - z__2.i * v[i__4].i, - z__1.i = z__2.r * v[i__4].i + z__2.i * v[ - i__4].r; - t[i__2].r = z__1.r, t[i__2].i = z__1.i; - } - j = f2cmax(lastv,prevlastv); - -/* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**H */ - - i__1 = *k - i__; - i__2 = *n - *k + i__ - j; - i__3 = i__; - z__1.r = -tau[i__3].r, z__1.i = -tau[i__3].i; - zgemm_("N", "C", &i__1, &c__1, &i__2, &z__1, &v[i__ + - 1 + j * v_dim1], ldv, &v[i__ + j * v_dim1], - ldv, &c_b1, &t[i__ + 1 + i__ * t_dim1], ldt); - } - -/* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) */ - - i__1 = *k - i__; - ztrmv_("Lower", "No transpose", "Non-unit", &i__1, &t[i__ - + 1 + (i__ + 1) * t_dim1], ldt, &t[i__ + 1 + i__ * - t_dim1], &c__1) - ; - if (i__ > 1) { - prevlastv = f2cmin(prevlastv,lastv); - } else { - prevlastv = lastv; - } - } - i__1 = i__ + i__ * t_dim1; - i__2 = i__; - t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + } else if (lq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | i-1 */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{1,2} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On */ +/* each iteration, T_{1:3,3} are not referenced. See zlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} */ + +/* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} */ + +/* This means we will do the following */ + +/* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} */ +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ +/* T_{1,2} = T_{1,1}T_{1,2} */ +/* T_{2,2} = \tau{i} */ + + i__1 = t_dim1 + 1; + t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{1,2} = -\tau_{i}V_{1,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = j + i__ * t_dim1; + i__4 = i__; + z__2.r = -tau[i__4].r, z__2.i = -tau[i__4].i; + i__5 = j + i__ * v_dim1; + z__1.r = z__2.r * v[i__5].r - z__2.i * v[i__5].i, z__1.i = + z__2.r * v[i__5].i + z__2.i * v[i__5].r; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; } + +/* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + i__4 = i__; + z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; + zgemm_("No Transpose", "Conjugate Transpose", &i__2, &c__1, &i__3, + &z__1, &v[(i__ + 1) * v_dim1 + 1], ldv, &v[i__ + (i__ + + 1) * v_dim1], ldv, &c_b1, &t[i__ * t_dim1 + 1], ldt); + +/* T_{1,2} = T_{1,1}T_{1,2} */ + + i__2 = i__ - 1; + ztrmv_("Upper", "No Transpose", "Non-unit", &i__2, &t[t_offset], + ldt, &t[i__ * t_dim1 + 1], &c__1); + +/* T_{2,2} = \tau{i} */ + + i__2 = i__ + i__ * t_dim1; + i__3 = i__; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; } - } - return; + } else if (lqt) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | i-1 */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 n-i */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{3,3} and repeat until we */ +/* reach the end. On each iteration V_{3,3} is not referenced */ + +/* We will construct T one column at a time from left to right */ +/* after initializing T(1,1) = TAU(1) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | i-1 */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | k-i */ +/* |-------------------------| */ +/* i-1 1 k-i */ + +/* Similarly as above, we will construct T_{2,1} and T_{2,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On */ +/* each iteration, T_{3,1:3} are not referenced. See zlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We now get */ + +/* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} */ + +/* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} */ + +/* This means we will do the following */ + +/* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' */ +/* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} */ +/* T_{2,1} = T_{1,1}'T_{2,1} */ +/* T_{2,2} = \tau{i} */ + + i__1 = t_dim1 + 1; + d_cnjg(&z__1, &tau[1]); + t[i__1].r = z__1.r, t[i__1].i = z__1.i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + +/* T_{2,1} = -\tau_{i}V_{1,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = i__ + j * t_dim1; + i__4 = i__; + i__5 = j + i__ * v_dim1; + z__3.r = tau[i__4].r * v[i__5].r - tau[i__4].i * v[i__5].i, + z__3.i = tau[i__4].r * v[i__5].i + tau[i__4].i * v[ + i__5].r; + d_cnjg(&z__2, &z__3); + z__1.r = -z__2.r, z__1.i = -z__2.i; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; + } + +/* T_{2,1} = -\tau_{i}V_{2,3}V_{1,3}' + T_{2,1} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + d_cnjg(&z__2, &tau[i__]); + z__1.r = -z__2.r, z__1.i = -z__2.i; + zgemm_("No Transpose", "Conjugate Transpose", &c__1, &i__2, &i__3, + &z__1, &v[i__ + (i__ + 1) * v_dim1], ldv, &v[(i__ + 1) * + v_dim1 + 1], ldv, &c_b1, &t[i__ + t_dim1], ldt); + +/* T_{2,1} = T_{1,1}'T_{2,1} */ + + i__2 = i__ - 1; + ztrmv_("Lower", "Transpose", "Non-unit", &i__2, &t[t_offset], ldt, + &t[i__ + t_dim1], ldt); + i__2 = i__ + i__ * t_dim1; + d_cnjg(&z__1, &tau[i__]); + t[i__2].r = z__1.r, t[i__2].i = z__1.i; + } + } else if (ql) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} V_{1,2} V_{1,3} | n-i */ +/* | 0 V_{2,2} V_{2,3} | 1 */ +/* | 0 0 V_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See zlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' */ +/* [V_{1,2}\\V_{2,2}\\0]T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' */ +/* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__1 = *k + *k * t_dim1; + i__2 = *k; + t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau(k-i+1) */ + + i__2 = kmi + kmi * t_dim1; + i__3 = kmi; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + +/* T_{3,2} = -\tau(k-i+1)V_{2,3}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = kmi + j + kmi * t_dim1; + i__4 = kmi; + z__2.r = -tau[i__4].r, z__2.i = -tau[i__4].i; + d_cnjg(&z__3, &v[nmi + (kmi + j) * v_dim1]); + z__1.r = z__2.r * z__3.r - z__2.i * z__3.i, z__1.i = z__2.r * + z__3.i + z__2.i * z__3.r; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; + } + +/* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} */ + + i__2 = *n - i__; + i__3 = i__ - 1; + i__4 = kmi; + z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; + zgemv_("Conjugate Transpose", &i__2, &i__3, &z__1, &v[(kmi + 1) * + v_dim1 + 1], ldv, &v[kmi * v_dim1 + 1], &c__1, &c_b1, &t[ + kmi + 1 + kmi * t_dim1], &c__1); + +/* T_{3,2} = T_{3,3}T_{3,2} */ -/* End of ZLARFT_LVL2 */ + i__2 = i__ - 1; + ztrmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); + } + } else if (rq) { + +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} 0 0 | k-i */ +/* | T_{2,1} T_{2,2} 0 | 1 */ +/* | T_{3,1} T_{3,2} T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{3,2} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On */ +/* each iteration, T_{1:3,1} are not referenced. See zlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} */ + +/* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__1 = *k + *k * t_dim1; + i__2 = *k; + t[i__1].r = tau[i__2].r, t[i__1].i = tau[i__2].i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + i__2 = kmi + kmi * t_dim1; + i__3 = kmi; + t[i__2].r = tau[i__3].r, t[i__2].i = tau[i__3].i; + +/* T_{3,2} = -\tau_{k-i+1}V_{3,2} */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = kmi + j + kmi * t_dim1; + i__4 = kmi; + z__2.r = -tau[i__4].r, z__2.i = -tau[i__4].i; + i__5 = kmi + j + nmi * v_dim1; + z__1.r = z__2.r * v[i__5].r - z__2.i * v[i__5].i, z__1.i = + z__2.r * v[i__5].i + z__2.i * v[i__5].r; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; + } + +/* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + i__4 = kmi; + z__1.r = -tau[i__4].r, z__1.i = -tau[i__4].i; + zgemm_("No Transpose", "Conjugate Transpose", &i__2, &c__1, &i__3, + &z__1, &v[kmi + 1 + v_dim1], ldv, &v[kmi + v_dim1], ldv, + &c_b1, &t[kmi + 1 + kmi * t_dim1], ldt); + +/* T_{3,2} = T_{3,3}T_{3,2} */ + + i__2 = i__ - 1; + ztrmv_("Lower", "No Transpose", "Non-unit", &i__2, &t[kmi + 1 + ( + kmi + 1) * t_dim1], ldt, &t[kmi + 1 + kmi * t_dim1], & + c__1); + } + } else if (rqt) { +/* Break V into 9 components */ + +/* V = |-------------------------| */ +/* | V_{1,1} 0 0 | k-i */ +/* | V_{2,1} V_{2,2} 0 | 1 */ +/* | V_{3,1} V_{3,2} V_{3,3} | i-1 */ +/* |-------------------------| */ +/* n-i 1 i-1 */ + +/* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular */ + +/* This is how we are going to view the matrix V at each step */ +/* i=2,\dots,k, then we grow into V_{1,1} and repeat until we */ +/* reach the end. On each iteration V_{1,1} is not referenced */ + +/* We will construct T one column at a time from right to left */ +/* after initializing T(K,K) = TAU(K) */ + +/* T = |-------------------------| */ +/* | T_{1,1} T_{1,2} T_{1,3} | k-i */ +/* | 0 T_{2,2} T_{2,3} | 1 */ +/* | 0 0 T_{3,3} | i-1 */ +/* |-------------------------| */ +/* k-i 1 i-1 */ + +/* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular */ + +/* Similarly as above, we will construct T_{2,2} and T_{2,3} at */ +/* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On */ +/* each iteration, T_{1,1:3} are not referenced. See zlarft.f */ +/* for details on how these formulae were constructed. */ + +/* We get that */ + +/* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} */ + +/* T_{3,2} = -T_{2,2}(V_{2,1}V_{3,1}' + V_{3,2}')T_{3,3} */ + +/* Thus, we will compute */ + +/* T_{2,2} = \tau_{k-i+1} */ +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ +/* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} */ +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + i__1 = *k + *k * t_dim1; + d_cnjg(&z__1, &tau[*k]); + t[i__1].r = z__1.r, t[i__1].i = z__1.i; + i__1 = *k; + for (i__ = 2; i__ <= i__1; ++i__) { + kmi = *k - i__ + 1; + nmi = *n - i__ + 1; + +/* T_{2,2} = \tau_{k-i+1} */ + + i__2 = kmi + kmi * t_dim1; + d_cnjg(&z__1, &tau[kmi]); + t[i__2].r = z__1.r, t[i__2].i = z__1.i; + +/* T_{2,3} = -\tau_{k-i+1}V_{3,2}' */ + + i__2 = i__ - 1; + for (j = 1; j <= i__2; ++j) { + i__3 = kmi + (kmi + j) * t_dim1; + i__4 = kmi; + i__5 = kmi + j + nmi * v_dim1; + z__3.r = tau[i__4].r * v[i__5].r - tau[i__4].i * v[i__5].i, + z__3.i = tau[i__4].r * v[i__5].i + tau[i__4].i * v[ + i__5].r; + d_cnjg(&z__2, &z__3); + z__1.r = -z__2.r, z__1.i = -z__2.i; + t[i__3].r = z__1.r, t[i__3].i = z__1.i; + } + +/* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} */ + + i__2 = i__ - 1; + i__3 = *n - i__; + d_cnjg(&z__2, &tau[kmi]); + z__1.r = -z__2.r, z__1.i = -z__2.i; + zgemm_("No Transpose", "Conjugate Transpose", &c__1, &i__2, &i__3, + &z__1, &v[kmi + v_dim1], ldv, &v[kmi + 1 + v_dim1], ldv, + &c_b1, &t[kmi + (kmi + 1) * t_dim1], ldt); + +/* T_{2,3} = T_{3,3}'T_{2,3} */ + + i__2 = i__ - 1; + ztrmv_("Upper", "Transpose", "Non-unit", &i__2, &t[kmi + 1 + (kmi + + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); + } + } + return 0; } /* zlarft_lvl2__ */ diff --git a/lapack-netlib/SRC/zlarft_lvl2.f b/lapack-netlib/SRC/zlarft_lvl2.f index 808c7fdb25..b16350b61d 100644 --- a/lapack-netlib/SRC/zlarft_lvl2.f +++ b/lapack-netlib/SRC/zlarft_lvl2.f @@ -1,18 +1,10 @@ -*> \brief \b ZLARFT_LVL2: Level 2 BLAS version for terminating case of ZLARFT. +*> \brief \b ZLARFT_LVL2 forms the triangular factor T of a block reflector H = I - vtvH * * =========== DOCUMENTATION =========== * * Online html documentation available at * http://www.netlib.org/lapack/explore-html/ * -*> Download ZLARFT_LVL2 + dependencies -*> -*> [TGZ] -*> -*> [ZIP] -*> -*> [TXT] -* * Definition: * =========== * @@ -49,6 +41,9 @@ *> H(i) is stored in the i-th row of the array V, and *> *> H = I - V**H * T * V +*> +*> If DIRECT or STOREV = 'T', see Further Details for the shape of T +*> *> \endverbatim * * Arguments: @@ -61,6 +56,8 @@ *> multiplied to form the block reflector: *> = 'F': H = H(1) H(2) . . . H(k) (Forward) *> = 'B': H = H(k) . . . H(2) H(1) (Backward) +*> = 'T' (with STOREV='R'): H = H(k) . . . H(2) H(1) (backward) +*> but we return the T matrix that is already (conjugate) transposed *> \endverbatim *> *> \param[in] STOREV @@ -68,8 +65,10 @@ *> STOREV is CHARACTER*1 *> Specifies how the vectors which define the elementary *> reflectors are stored (see also Further Details): -*> = 'C': columnwise -*> = 'R': rowwise +*> = 'C': column-wise +*> = 'R': row-wise +*> = 'T': (With DIRECT='F') Row-wise, but we return the T +*> matrix that is already (conjugate) transposed. *> \endverbatim *> *> \param[in] N @@ -155,6 +154,29 @@ *> ( 1 v2 v3 ) ( v3 v3 v3 v3 1 ) *> ( 1 v3 ) *> ( 1 ) +*> +*> In addition, the shape of T is determined by these same flags as +*> in the below table. +*> 'U' denotes upper triangular +*> 'L' denotes lower triangular +*> 'X' denotes no current implementation +*> We also provide the logical variable that represents the case +*> in the code if it is implemented +*> +*> |-----------------------------------------------------------| +*> | | DIRECT = 'F' | DIRECT = 'B' | DIRECT = 'T' | +*> |--------------+--------------+--------------+--------------| +*> | STOREV = 'C' | U (QR) | L (QL) | X | +*> | STOREV = 'R' | U (LQ) | L (RQ) | U (RQT) | +*> | STOREV = 'T' | L (LQT) | X | X | +*> |-----------------------------------------------------------| +*> +*> Finally, the relationship between the (conjugate) transposed T matrices +*> are as follows: (Note that T_{FC} denotes the T associated with calling +*> this routine with DIRECT = 'F' and STOREV = 'C') +*> +*> T_{TR} = (T_{BR})**H +*> T_{FT} = (T_{FR})**H *> \endverbatim *> * ===================================================================== @@ -170,158 +192,568 @@ SUBROUTINE ZLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, INTEGER K, LDT, LDV, N * .. * .. Array Arguments .. +* COMPLEX*16 T( LDT, * ), TAU( * ), V( LDV, * ) * .. * -* ===================================================================== -* * .. Parameters .. - COMPLEX*16 ONE, ZERO - PARAMETER ( ONE = ( 1.0D+0, 0.0D+0 ), - $ ZERO = ( 0.0D+0, 0.0D+0 ) ) -* .. +* + COMPLEX*16 ONE + PARAMETER(ONE=(1.0D+0,0.0D+0)) +* * .. Local Scalars .. - INTEGER I, J, PREVLASTV, LASTV -* .. +* + INTEGER I,J,KMI,NMI,INFO + LOGICAL QR, LQ, QL, RQ, LQT, RQT, + $ DIRF, DIRB, DIRT, + $ STOREC, STORER, STORET +* * .. External Subroutines .. - EXTERNAL ZGEMV, ZTRMV, ZGEMM -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME +* + EXTERNAL ZTRMV,ZGEMV,ZGEMM,XERBLA +* +* .. External Functions.. +* + LOGICAL LSAME + EXTERNAL LSAME +* +* .. Intrinsic Functions.. +* + INTRINSIC CONJG * .. * .. Executable Statements .. * +* Convert our character flags to logical flags for later +* + DIRF = LSAME(DIRECT,'F') + DIRB = LSAME(DIRECT,'B') + DIRT = LSAME(DIRECT,'T') + STOREC = LSAME(STOREV,'C') + STORER = LSAME(STOREV,'R') + STORET = LSAME(STOREV,'T') +* +* Error handling for our character flags +* + INFO = 0 + IF( .NOT.(DIRF.OR.DIRB.OR.DIRT) ) THEN +* +* DIRECT holds an illegal value +* + INFO = 1 + ELSE IF( .NOT.(STOREC.OR.STORER.OR.STORET) ) THEN +* +* STOREV holds an illegal value +* + INFO = 2 + ELSE IF( DIRB.AND.STORET ) THEN +* +* This case is purposefully not implemented, but any other value for +* STOREV is valid, so we report STOREV as the invalid input +* + INFO = 2 + ELSE IF( DIRT.AND.STOREC ) THEN +* +* This case is purposefully not implemented, but any other value for +* DIRECT is valid, so we report DIRECT as the invalid input +* + INFO = 1 + ELSE IF( DIRT.AND.STORET ) THEN +* +* This case is purposefully not implemented, and is ambiguous what +* the user wants to do, so we arbitrarily say DIRECT is the incorrect +* character flag. +* + INFO = 1 + END IF + + IF( INFO.NE.0 ) THEN + CALL XERBLA('ZLARFT_LVL2', INFO) + RETURN + END IF +* * Quick return if possible * - IF( N.EQ.0 ) - $ RETURN -* - IF( LSAME( DIRECT, 'F' ) ) THEN - PREVLASTV = N - DO I = 1, K - PREVLASTV = MAX( PREVLASTV, I ) - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = 1, I - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * CONJG( V( I , J ) ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(i:j,1:i-1)**H * V(i:j,i) -* - CALL ZGEMV( 'Conjugate transpose', J-I, I-1, - $ -TAU( I ), V( I+1, 1 ), LDV, - $ V( I+1, I ), 1, ONE, T( 1, I ), 1 ) - ELSE -* Skip any trailing zeros. - DO LASTV = N, I+1, -1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = 1, I-1 - T( J, I ) = -TAU( I ) * V( J , I ) - END DO - J = MIN( LASTV, PREVLASTV ) -* -* T(1:i-1,i) := - tau(i) * V(1:i-1,i:j) * V(i,i:j)**H -* - CALL ZGEMM( 'N', 'C', I-1, 1, J-I, -TAU( I ), - $ V( 1, I+1 ), LDV, V( I, I+1 ), LDV, - $ ONE, T( 1, I ), LDT ) - END IF -* -* T(1:i-1,i) := T(1:i-1,1:i-1) * T(1:i-1,i) -* - CALL ZTRMV( 'Upper', 'No transpose', 'Non-unit', I-1, - $ T, - $ LDT, T( 1, I ), 1 ) - T( I, I ) = TAU( I ) - IF( I.GT.1 ) THEN - PREVLASTV = MAX( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF + IF(N.EQ.0.OR.K.EQ.0) THEN + RETURN + END IF +* +* Now we determine what factorization our flags are associated with +* +* QR happens when we have forward direction in column storage +* + QR = DIRF.AND.STOREC +* +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute +* + LQT = DIRF.AND.STORET +* +* LQ happens when we have forward direction in row storage and want to compute the T we would +* normally compute +* + LQ = DIRF.AND.STORER +* +* QL happens when we have backward direction in column storage +* + QL = DIRB.AND.STOREC +* +* RQT happens when we have backward direction in row storage and want to compute the transpose +* of the T we would normally compute +* + RQT = DIRT.AND.STORER +* +* RQ happens when we have backward direction in row storage and want to compute the T that we +* would normally compute +* + RQ = DIRB.AND.STORER + IF( N.EQ.1.OR.K.EQ.1) THEN + IF( LQT.OR.RQT ) THEN + T(1,1) = CONJG(TAU(1)) + ELSE + T(1,1) = TAU(1) + END IF + RETURN + END IF + IF (QR) THEN +* +* Break V into 9 components +* +* V = |-----------------------| +* |V_{1,1} 0 0 | i-1 +* |V_{2,1} V_{2,2} 0 | 1 +* |V_{3,1} V_{3,2} V_{3,3}| n-i +* |-----------------------| +* i-1 1 k-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See zlarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1}\\V_{2,1}\\V_{3,1}]' +* [0\\V_{2,2}\\V_{3,2}]T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{2,1}' + V_{3,1}'V_{3,2})T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{2,1}'T_{2,2} = -\tau_{i}V_{2,1}' +* T_{1,2} = -\tau_{i}V_{3,2}' V_{3,1} + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + + DO I = 2, K +* +* T_{1,2} = -V_{2,1}'V_{2,2}T_{2,2} = -\tau_i V_{2,1}' +* We must do this at copy time as otherwise gemv will do nothing +* on the last column when n=k, but we neet to make sure we are +* scaled by this value +* + DO J = 1, I-1 + T(J,I) = -TAU(I)*CONJG(V(I,J)) + END DO + +* +* T_{1,2} = -V_{3,1}'V_{3,2}T_{2,2} + T_{1,2} +* = -\tau{i} V_{3,2}'V_{3,1} + T_{1,2} +* + CALL ZGEMV('Conjugate Transpose', N-I, I-1, -TAU(I), + $ V(I+1,1), LDV, V(I+1,I), 1, ONE, T(1, I), 1) + + +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL ZTRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) + +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - ELSE - PREVLASTV = 1 - DO I = K, 1, -1 - IF( TAU( I ).EQ.ZERO ) THEN -* -* H(i) = I -* - DO J = I, K - T( J, I ) = ZERO - END DO - ELSE -* -* general case -* - IF( I.LT.K ) THEN - IF( LSAME( STOREV, 'C' ) ) THEN -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( LASTV, I ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * CONJG( V( N-K+I , J ) ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(j:n-k+i,i+1:k)**H * V(j:n-k+i,i) -* - CALL ZGEMV( 'Conjugate transpose', N-K+I-J, K-I, - $ -TAU( I ), V( J, I+1 ), LDV, V( J, I ), - $ 1, ONE, T( I+1, I ), 1 ) - ELSE -* Skip any leading zeros. - DO LASTV = 1, I-1 - IF( V( I, LASTV ).NE.ZERO ) EXIT - END DO - DO J = I+1, K - T( J, I ) = -TAU( I ) * V( J, N-K+I ) - END DO - J = MAX( LASTV, PREVLASTV ) -* -* T(i+1:k,i) = -tau(i) * V(i+1:k,j:n-k+i) * V(i,j:n-k+i)**H -* - CALL ZGEMM( 'N', 'C', K-I, 1, N-K+I-J, - $ -TAU( I ), - $ V( I+1, J ), LDV, V( I, J ), LDV, - $ ONE, T( I+1, I ), LDT ) - END IF -* -* T(i+1:k,i) := T(i+1:k,i+1:k) * T(i+1:k,i) -* - CALL ZTRMV( 'Lower', 'No transpose', 'Non-unit', - $ K-I, - $ T( I+1, I+1 ), LDT, T( I+1, I ), 1 ) - IF( I.GT.1 ) THEN - PREVLASTV = MIN( PREVLASTV, LASTV ) - ELSE - PREVLASTV = LASTV - END IF - END IF - T( I, I ) = TAU( I ) - END IF + ELSE IF (LQ) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | i-1 +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{1,2} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,3}. On +* each iteration, T_{1:3,3} are not referenced. See zlarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{1,2} = -T_{1,1}[V_{1,1} V_{1,2} V_{1,3}][ 0 V_{2,2} V_{2,3} ]'T_{2,2} +* +* T_{1,2} = -T_{1,1}(V_{1,2} + V_{1,3}V_{2,3}')T_{2,2} +* +* This means we will do the following +* +* T_{1,2} = -V_{1,2}T_{2,2} = -\tau_{i}V_{1,2} +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* T_{1,2} = T_{1,1}T_{1,2} +* T_{2,2} = \tau{i} +* + T(1,1) = TAU(1) + + DO I = 2, K +* +* T_{1,2} = -\tau_{i}V_{1,2} +* + DO J = 1, I-1 + T(J, I) = -TAU(I)*V(J, I) + END DO + +* +* T_{1,2} = -\tau_{i}V_{1,3}V_{2,3}' + T_{1,2} +* + CALL ZGEMM('No Transpose', 'Conjugate Transpose', I-1, + $ 1, N-I, -TAU(I), V(1,I+1), LDV, V(I, I+1), LDV, ONE, + $ T(1, I), LDT) +* +* T_{1,2} = T_{1,1}T_{1,2} +* + CALL ZTRMV('Upper', 'No Transpose', 'Non-unit', I-1, + $ T, LDT, T(1,I), 1) + +* +* T_{2,2} = \tau{i} +* + T(I,I) = TAU(I) END DO - END IF - RETURN + ELSE IF (LQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | i-1 +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | k-i +* |-------------------------| +* i-1 1 n-i +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{3,3} and repeat until we +* reach the end. On each iteration V_{3,3} is not referenced +* +* We will construct T one column at a time from left to right +* after initializing T(1,1) = TAU(1) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | i-1 +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | k-i +* |-------------------------| +* i-1 1 k-i +* +* Similarly as above, we will construct T_{2,1} and T_{2,2} at +* each iteration i = 2, \dots k, and then grow into T_{3,1:3}. On +* each iteration, T_{3,1:3} are not referenced. See zlarft.f +* for details on how these formulae were constructed. +* +* We now get +* +* T_{2,1} = -T_{2,2}[0 V_{2,2} V_{2,3}][V_{1,1} V_{1,2} V_{1,3}]'T_{1,1} +* +* T_{2,1} = -T_{2,2}(V_{1,2}' + V_{2,3}V_{1,3}')T_{1,1} +* +* This means we will do the following +* +* T_{2,1} = -T_{2,2}V_{1,2}' = -\tau_{i}V_{1,2}' +* T_{2,1} = -\tau_{i}V_{1,3}V_{2,3}' + T_{2,1} +* T_{2,1} = T_{1,1}'T_{2,1} +* T_{2,2} = \tau{i} +* + T(1,1) = CONJG(TAU(1)) + + DO I = 2, K +* +* T_{2,1} = -\tau_{i}V_{1,2}' +* + DO J = 1, I-1 + T(I,J) = -CONJG(TAU(I)*V(J,I)) + END DO +* +* T_{2,1} = -\tau_{i}V_{2,3}V_{1,3}' + T_{2,1} +* + CALL ZGEMM('No Transpose', 'Conjugate Transpose', 1, + $ I-1, N-I, -CONJG(TAU(I)), V(I,I+1), LDV, V(1, I+1), + $ LDV, ONE, T(I, 1), LDT) +* +* T_{2,1} = T_{1,1}'T_{2,1} +* + CALL ZTRMV('Lower', 'Transpose', 'Non-unit', + $ I-1, T, LDT, T(I,1), LDT) + + T(I,I) = CONJG(TAU(I)) + END DO + ELSE IF (QL) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} V_{1,2} V_{1,3} | n-i +* | 0 V_{2,2} V_{2,3} | 1 +* | 0 0 V_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit upper triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See zlarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{1,3}\\V_{2,3}\\V_{3,3}]' +* [V_{1,2}\\V_{2,2}\\0]T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{1,3}'V_{1,2} + V_{2,3}')T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -T_{3,3}V_{3,2}' = -\tau_{k-i+1}V_{3,2}' +* T_{3,2} = -\tau_{k-i+1}V_{1,3}'V_{1,2} + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau(k-i+1) +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau(k-i+1)V_{2,3}' +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*CONJG(V(NMI, KMI + J)) + END DO +* +* T_{3,2} = -\tau(k-i+1)V_{1,3}'V_{1,2} + T_{3,2} +* + CALL ZGEMV('Conjugate Transpose', N-I, I-1, -TAU(KMI), + $ V(1, KMI + 1), LDV, V(1, KMI), 1, ONE, + $ T(KMI+1, KMI), 1) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL ZTRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI + 1, KMI + 1), LDT, T(KMI + 1, KMI), 1) + + END DO + ELSE IF (RQ) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} 0 0 | k-i +* | T_{2,1} T_{2,2} 0 | 1 +* | T_{3,1} T_{3,2} T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{3,2} at +* each iteration i = 2, \dots k, and then grow into T_{1:3,1}. On +* each iteration, T_{1:3,1} are not referenced. See zlarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{3,2} = -T_{3,3}[V_{3,1} V_{3,2} V_{3,3}][V_{2,1} V_{2,2} 0]'T_{2,2} +* +* T_{3,2} = -T_{3,3}(V_{3,1}V_{2,1}' + V_{3,2})T_{2,2} +* +* Thus, we will compute +* +* T_{2,2} = \tau_{k-i+1} +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* T_{3,2} = T_{3,3}T_{3,2} +* + T(K,K) = TAU(K) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = TAU(KMI) +* +* T_{3,2} = -\tau_{k-i+1}V_{3,2} +* + DO J = 1, I-1 + T(KMI + J, KMI) = -TAU(KMI)*V(KMI + J, NMI) + END DO +* +* T_{3,2} = -\tau_{k-i+1}V_{3,1}V_{2,1}' + T_{3,2} +* + CALL ZGEMM('No Transpose', 'Conjugate Transpose', I-1, + $ 1, N-I, -TAU(KMI), V(KMI+1, 1), LDV, V(KMI, 1), LDV, + $ ONE, T(KMI+1, KMI), LDT) +* +* T_{3,2} = T_{3,3}T_{3,2} +* + CALL ZTRMV('Lower', 'No Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI+1, KMI), 1) + END DO + ELSE IF (RQT) THEN +* +* Break V into 9 components +* +* V = |-------------------------| +* | V_{1,1} 0 0 | k-i +* | V_{2,1} V_{2,2} 0 | 1 +* | V_{3,1} V_{3,2} V_{3,3} | i-1 +* |-------------------------| +* n-i 1 i-1 +* +* V_{1,1}, V_{2,2} and V_{3,3} are unit lower triangular +* +* This is how we are going to view the matrix V at each step +* i=2,\dots,k, then we grow into V_{1,1} and repeat until we +* reach the end. On each iteration V_{1,1} is not referenced +* +* We will construct T one column at a time from right to left +* after initializing T(K,K) = TAU(K) +* +* T = |-------------------------| +* | T_{1,1} T_{1,2} T_{1,3} | k-i +* | 0 T_{2,2} T_{2,3} | 1 +* | 0 0 T_{3,3} | i-1 +* |-------------------------| +* k-i 1 i-1 +* +* T_{1,1}, T_{2,2}, and T_{3,3} are non-unit lower triangular +* +* Similarly as above, we will construct T_{2,2} and T_{2,3} at +* each iteration i = 2, \dots k, and then grow into T_{1,1:3}. On +* each iteration, T_{1,1:3} are not referenced. See zlarft.f +* for details on how these formulae were constructed. +* +* We get that +* +* T_{2,3} = -T_{2,2}[V_{2,1} V_{2,2} 0][V_{3,1} V_{3,2} V_{3,3}]'T_{3,3} +* +* T_{3,2} = -T_{2,2}(V_{2,1}V_{3,1}' + V_{3,2}')T_{3,3} * -* End of ZLARFT_LVL2 +* Thus, we will compute * - END +* T_{2,2} = \tau_{k-i+1} +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} +* T_{2,3} = T_{3,3}'T_{2,3} +* + T(K,K) = CONJG(TAU(K)) + DO I = 2, K + KMI = K-I+1 + NMI = N-I+1 +* +* T_{2,2} = \tau_{k-i+1} +* + T(KMI,KMI) = CONJG(TAU(KMI)) +* +* T_{2,3} = -\tau_{k-i+1}V_{3,2}' +* + DO J = 1, I-1 + T(KMI, KMI + J) = -CONJG(TAU(KMI)*V(KMI + J, NMI)) + END DO +* +* T_{2,3} = -\tau_{k-i+1}V_{2,1}V_{3,1}' + T_{2,3} +* + CALL ZGEMM('No Transpose', 'Conjugate Transpose', 1, + $ I-1, N-I, -CONJG(TAU(KMI)), V(KMI, 1), LDV, + $ V(KMI+1,1), LDV, ONE, T(KMI, KMI+1), LDT) +* +* T_{2,3} = T_{3,3}'T_{2,3} +* + CALL ZTRMV('Upper', 'Transpose', 'Non-unit', I-1, + $ T(KMI+1, KMI+1), LDT, T(KMI, KMI+1), LDT) + END DO + END IF + END SUBROUTINE From 087745fd68fc99647c882089da262b89607b9921 Mon Sep 17 00:00:00 2001 From: Martin Kroeker Date: Tue, 20 Oct 2026 11:49:13 +0200 Subject: [PATCH 2/2] Remove spurious return values --- lapack-netlib/SRC/clarft.c | 10 +++++----- lapack-netlib/SRC/clarft_lvl2.c | 8 ++++---- lapack-netlib/SRC/dlarft.c | 10 +++++----- lapack-netlib/SRC/dlarft_lvl2.c | 8 ++++---- lapack-netlib/SRC/slarft.c | 10 +++++----- lapack-netlib/SRC/slarft_lvl2.c | 8 ++++---- lapack-netlib/SRC/zlarft.c | 10 +++++----- lapack-netlib/SRC/zlarft_lvl2.c | 8 ++++---- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/lapack-netlib/SRC/clarft.c b/lapack-netlib/SRC/clarft.c index e9b6fd3180..b392e9155b 100644 --- a/lapack-netlib/SRC/clarft.c +++ b/lapack-netlib/SRC/clarft.c @@ -558,13 +558,13 @@ f"> */ } if (info != 0) { xerbla_("CLARFT", &info,(ftnlen)6); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -608,7 +608,7 @@ f"> */ i__1 = t_dim1 + 1; t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; } - return 0; + return; } /* Determine crossover point from level 2 to level 3 BLAS implementation */ @@ -625,7 +625,7 @@ f"> */ clarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return 0; + return; } /* Beginning of executable statements for the recursive case */ @@ -1253,6 +1253,6 @@ f"> */ &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); } - return 0; + return; } /* clarft_ */ diff --git a/lapack-netlib/SRC/clarft_lvl2.c b/lapack-netlib/SRC/clarft_lvl2.c index 4aa5b8f3d0..7ec4875028 100644 --- a/lapack-netlib/SRC/clarft_lvl2.c +++ b/lapack-netlib/SRC/clarft_lvl2.c @@ -527,13 +527,13 @@ static integer c__1 = 1; } if (info != 0) { xerbla_("CLARFT_LVL2", &info, (ftnlen)11); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -574,7 +574,7 @@ static integer c__1 = 1; i__1 = t_dim1 + 1; t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; } - return 0; + return; } if (qr) { @@ -1114,6 +1114,6 @@ static integer c__1 = 1; + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); } } - return 0; + return; } /* clarft_lvl2__ */ diff --git a/lapack-netlib/SRC/dlarft.c b/lapack-netlib/SRC/dlarft.c index 0eff3edb54..bab6cd283a 100644 --- a/lapack-netlib/SRC/dlarft.c +++ b/lapack-netlib/SRC/dlarft.c @@ -529,13 +529,13 @@ f"> */ } if (info != 0) { xerbla_("DLARFT", &info, (ftnlen)6); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -572,7 +572,7 @@ f"> */ if (*n == 1 || *k == 1) { t[t_dim1 + 1] = tau[1]; - return 0; + return; } /* Determine crossover point from level 2 to level 3 BLAS implementation */ @@ -589,7 +589,7 @@ f"> */ dlarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return 0; + return; } /* Beginning of executable statements for the recursive case */ @@ -1212,6 +1212,6 @@ f"> */ c_b18, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); } - return 0; + return; } /* dlarft_ */ diff --git a/lapack-netlib/SRC/dlarft_lvl2.c b/lapack-netlib/SRC/dlarft_lvl2.c index da5efa9a06..20d0d79d22 100644 --- a/lapack-netlib/SRC/dlarft_lvl2.c +++ b/lapack-netlib/SRC/dlarft_lvl2.c @@ -495,13 +495,13 @@ static doublereal c_b11 = 1.; } if (info != 0) { xerbla_("DLARFT_LVL2", &info, (ftnlen)11); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -535,7 +535,7 @@ static doublereal c_b11 = 1.; rq = dirb && storer; if (*n == 1 || *k == 1) { t[t_dim1 + 1] = tau[1]; - return 0; + return; } if (qr) { @@ -1012,6 +1012,6 @@ static doublereal c_b11 = 1.; + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); } } - return 0; + return; } /* dlarft_lvl2__ */ diff --git a/lapack-netlib/SRC/slarft.c b/lapack-netlib/SRC/slarft.c index 594b8a1ba9..ba66893688 100644 --- a/lapack-netlib/SRC/slarft.c +++ b/lapack-netlib/SRC/slarft.c @@ -591,13 +591,13 @@ f"> */ } if (info != 0) { xerbla_("SLARFT", &info, (ftnlen)6); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -634,7 +634,7 @@ f"> */ if (*n == 1 || *k == 1) { t[t_dim1 + 1] = tau[1]; - return 0; + return; } /* Determine crossover point from level 2 to level 3 BLAS implementation */ @@ -651,7 +651,7 @@ f"> */ slarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return 0; + return; } /* Beginning of executable statements for the recursive case */ @@ -1274,6 +1274,6 @@ f"> */ c_b18, &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); } - return 0; + return; } /* slarft_ */ diff --git a/lapack-netlib/SRC/slarft_lvl2.c b/lapack-netlib/SRC/slarft_lvl2.c index 026ef83da1..28d837bbc1 100644 --- a/lapack-netlib/SRC/slarft_lvl2.c +++ b/lapack-netlib/SRC/slarft_lvl2.c @@ -493,13 +493,13 @@ static real c_b11 = 1.f; } if (info != 0) { xerbla_("SLARFT_LVL2", &info, (ftnlen)11); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -533,7 +533,7 @@ static real c_b11 = 1.f; rq = dirb && storer; if (*n == 1 || *k == 1) { t[t_dim1 + 1] = tau[1]; - return 0; + return; } if (qr) { @@ -1010,6 +1010,6 @@ static real c_b11 = 1.f; + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); } } - return 0; + return; } /* slarft_lvl2__ */ diff --git a/lapack-netlib/SRC/zlarft.c b/lapack-netlib/SRC/zlarft.c index 649b28967f..731d3f4616 100644 --- a/lapack-netlib/SRC/zlarft.c +++ b/lapack-netlib/SRC/zlarft.c @@ -566,13 +566,13 @@ f"> */ } if (info != 0) { xerbla_("ZLARFT", &info, (ftnlen)6); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -616,7 +616,7 @@ f"> */ i__1 = t_dim1 + 1; t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; } - return 0; + return; } /* Determine crossover point from level 2 to level 3 BLAS implementation */ @@ -633,7 +633,7 @@ f"> */ zlarft_lvl2__(direct, storev, n, k, &v[v_offset], ldv, &tau[1], &t[ t_offset], ldt); - return 0; + return; } /* Beginning of executable statements for the recursive case */ @@ -1261,6 +1261,6 @@ f"> */ &t[*k - l + 1 + (*k - l + 1) * t_dim1], ldt, &t[(*k - l + 1) * t_dim1 + 1], ldt); } - return 0; + return; } /* zlarft_ */ diff --git a/lapack-netlib/SRC/zlarft_lvl2.c b/lapack-netlib/SRC/zlarft_lvl2.c index 820800d464..9d54998021 100644 --- a/lapack-netlib/SRC/zlarft_lvl2.c +++ b/lapack-netlib/SRC/zlarft_lvl2.c @@ -538,13 +538,13 @@ static integer c__1 = 1; } if (info != 0) { xerbla_("ZLARFT_LVL2", &info, (ftnlen)11); - return 0; + return; } /* Quick return if possible */ if (*n == 0 || *k == 0) { - return 0; + return; } /* Now we determine what factorization our flags are associated with */ @@ -585,7 +585,7 @@ static integer c__1 = 1; i__1 = t_dim1 + 1; t[i__1].r = tau[1].r, t[i__1].i = tau[1].i; } - return 0; + return; } if (qr) { @@ -1125,6 +1125,6 @@ static integer c__1 = 1; + 1) * t_dim1], ldt, &t[kmi + (kmi + 1) * t_dim1], ldt); } } - return 0; + return; } /* zlarft_lvl2__ */