From 1f262000d485363b7efc059496aac182b8ebefa0 Mon Sep 17 00:00:00 2001 From: Johnathan Rhyne Date: Tue, 8 Sep 2026 18:17:39 -0600 Subject: [PATCH 1/4] new paths for larft, fixing inconsistent documentation, standardizing the character flag parsing, and added error messages for unimplemented cases. TODO: add LVL2 and failing tests --- SRC/clarft.f | 486 ++++++++++++++++++++++++++++++++++++++----------- SRC/dlarft.f | 487 +++++++++++++++++++++++++++++++++++++------------ SRC/slarft.f | 487 +++++++++++++++++++++++++++++++++++++------------ SRC/zlarft.f | 505 +++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 1513 insertions(+), 452 deletions(-) diff --git a/SRC/clarft.f b/SRC/clarft.f index dbd2e49a2..e6d7ffe97 100644 --- a/SRC/clarft.f +++ b/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, CLARFT_LVL2 + EXTERNAL CLARFT_LVL2, CTRMM, CGEMM, CLACPY * * .. 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,6 +239,54 @@ RECURSIVE SUBROUTINE CLARFT( 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('CLARFT', INFO) + RETURN + END IF +* * Quick return if possible * IF(N.EQ.0.OR.K.EQ.0) THEN @@ -216,48 +296,58 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * Base case * IF(N.EQ.1.OR.K.EQ.1) THEN - T(1,1) = TAU(1) + IF( LQT.OR.RQT ) THEN + T(1,1) = CONJG(TAU(1)) + ELSE + T(1,1) = TAU(1) + END IF 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, "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 +* 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') +* Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage * - QR = DIRF.AND.COLV + QR = DIRF.AND.STOREC * -* LQ happens when we have forward direction in row storage +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute * - LQ = DIRF.AND.(.NOT.COLV) + 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 = (.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 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/SRC/dlarft.f b/SRC/dlarft.f index 567b1e52e..d18d24edc 100644 --- a/SRC/dlarft.f +++ b/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, DLARFT_LVL2 + EXTERNAL DLARFT_LVL2, DTRMM, DGEMM, DLACPY * * .. 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,6 +234,54 @@ 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 @@ -215,44 +295,50 @@ 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') +* Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage * - QR = DIRF.AND.COLV + QR = DIRF.AND.STOREC * -* LQ happens when we have forward direction in row storage +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute * - LQ = DIRF.AND.(.NOT.COLV) + 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 = (.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 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/SRC/slarft.f b/SRC/slarft.f index ba13c068b..044e0e6a4 100644 --- a/SRC/slarft.f +++ b/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 @@ -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, SLARFT_LVL2 + EXTERNAL SLARFT_LVL2, STRMM, SGEMM, SLACPY * * .. 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,6 +234,54 @@ 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 @@ -215,44 +295,50 @@ 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') +* Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage * - QR = DIRF.AND.COLV + QR = DIRF.AND.STOREC * -* LQ happens when we have forward direction in row storage +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute * - LQ = DIRF.AND.(.NOT.COLV) + 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 = (.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 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/SRC/zlarft.f b/SRC/zlarft.f index 626a3c4b9..6cb830388 100644 --- a/SRC/zlarft.f +++ b/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, ZLARFT_LVL2 + EXTERNAL ZLARFT_LVL2, ZTRMM, ZGEMM, ZLACPY * * .. 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,6 +239,54 @@ RECURSIVE SUBROUTINE ZLARFT( 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('ZLARFT', INFO) + RETURN + END IF +* * Quick return if possible * IF(N.EQ.0.OR.K.EQ.0) THEN @@ -216,48 +296,58 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * Base case * IF(N.EQ.1.OR.K.EQ.1) THEN - T(1,1) = TAU(1) + IF( LQT.OR.RQT ) THEN + T(1,1) = DCONJG(TAU(1)) + ELSE + T(1,1) = TAU(1) + END IF 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, "ZLARFT", DIRECT // STOREV, N, K, -1, -1) IF(K.LT.NX) THEN +* +* 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 +* 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') +* Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage * - QR = DIRF.AND.COLV + QR = DIRF.AND.STOREC * -* LQ happens when we have forward direction in row storage +* LQT happens when we have forward direction in row storage and want to compute the transpose of +* the T we would normally compute * - LQ = DIRF.AND.(.NOT.COLV) + 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 = (.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 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 From 7a9cf9a88db20893ab8b50e724cffbe51f1cf447 Mon Sep 17 00:00:00 2001 From: Johnathan Rhyne Date: Wed, 9 Sep 2026 11:21:28 -0600 Subject: [PATCH 2/4] fixed complex test failures by moving the case selection to before the base case --- SRC/clarft.f | 52 ++++++++++++++++++++++++++-------------------------- SRC/dlarft.f | 44 ++++++++++++++++++++++---------------------- SRC/slarft.f | 44 ++++++++++++++++++++++---------------------- SRC/zlarft.f | 52 ++++++++++++++++++++++++++-------------------------- 4 files changed, 96 insertions(+), 96 deletions(-) diff --git a/SRC/clarft.f b/SRC/clarft.f index e6d7ffe97..782852d18 100644 --- a/SRC/clarft.f +++ b/SRC/clarft.f @@ -293,32 +293,6 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, RETURN END IF * -* 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 -* * Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage @@ -348,6 +322,32 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * 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 diff --git a/SRC/dlarft.f b/SRC/dlarft.f index d18d24edc..0a371fafa 100644 --- a/SRC/dlarft.f +++ b/SRC/dlarft.f @@ -288,28 +288,6 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, RETURN END IF * -* Base case -* - IF(N.EQ.1.OR.K.EQ.1) THEN - T(1,1) = TAU(1) - RETURN - END IF -* -* 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 for the recursive case -* - L = K / 2 -* * Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage @@ -339,6 +317,28 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * would normally compute * RQ = DIRB.AND.STORER +* +* Base case +* + IF(N.EQ.1.OR.K.EQ.1) THEN + T(1,1) = TAU(1) + RETURN + END IF +* +* 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 for the recursive case +* + L = K / 2 IF(QR) THEN * * Break V apart into 6 components diff --git a/SRC/slarft.f b/SRC/slarft.f index 044e0e6a4..a407cb93d 100644 --- a/SRC/slarft.f +++ b/SRC/slarft.f @@ -288,28 +288,6 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, RETURN END IF * -* Base case -* - IF(N.EQ.1.OR.K.EQ.1) THEN - T(1,1) = TAU(1) - RETURN - END IF -* -* 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 for the recursive case -* - L = K / 2 -* * Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage @@ -339,6 +317,28 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * would normally compute * RQ = DIRB.AND.STORER +* +* Base case +* + IF(N.EQ.1.OR.K.EQ.1) THEN + T(1,1) = TAU(1) + RETURN + END IF +* +* 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 for the recursive case +* + L = K / 2 IF(QR) THEN * * Break V apart into 6 components diff --git a/SRC/zlarft.f b/SRC/zlarft.f index 6cb830388..ffc11dae7 100644 --- a/SRC/zlarft.f +++ b/SRC/zlarft.f @@ -293,32 +293,6 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, RETURN END IF * -* 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 -* -* 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 -* * Now we determine what factorization our flags are associated with * * QR happens when we have forward direction in column storage @@ -348,6 +322,32 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * 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 +* +* 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 From 8841a56c64ee2bec84234b0590142caead676913 Mon Sep 17 00:00:00 2001 From: Johnathan Rhyne Date: Wed, 9 Sep 2026 16:29:24 -0600 Subject: [PATCH 3/4] fixed errors and added the new branches to level2 implementation --- SRC/clarft_lvl2.f | 738 ++++++++++++++++++++++++++++++++++++---------- SRC/dlarft_lvl2.f | 716 ++++++++++++++++++++++++++++++++++---------- SRC/slarft.f | 2 +- SRC/slarft_lvl2.f | 720 ++++++++++++++++++++++++++++++++++---------- SRC/zlarft_lvl2.f | 734 +++++++++++++++++++++++++++++++++++---------- 5 files changed, 2303 insertions(+), 607 deletions(-) diff --git a/SRC/clarft_lvl2.f b/SRC/clarft_lvl2.f index 3b0aea113..32f1dcea3 100644 --- a/SRC/clarft_lvl2.f +++ b/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 +* +* .. 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/SRC/dlarft_lvl2.f b/SRC/dlarft_lvl2.f index 9614df466..1f890e3a0 100644 --- a/SRC/dlarft_lvl2.f +++ b/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 +* +* .. 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/SRC/slarft.f b/SRC/slarft.f index a407cb93d..6e019a3c3 100644 --- a/SRC/slarft.f +++ b/SRC/slarft.f @@ -132,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 diff --git a/SRC/slarft_lvl2.f b/SRC/slarft_lvl2.f index 7107a91d5..763457a8e 100644 --- a/SRC/slarft_lvl2.f +++ b/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 +* +* .. 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/SRC/zlarft_lvl2.f b/SRC/zlarft_lvl2.f index 808c7fdb2..cec8ea5ba 100644 --- a/SRC/zlarft_lvl2.f +++ b/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 +* +* .. 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 bc00df832a32bab310be6e081cc529bb46c29175 Mon Sep 17 00:00:00 2001 From: Johnathan Rhyne Date: Wed, 9 Sep 2026 16:57:01 -0600 Subject: [PATCH 4/4] added XERBLA to external subroutine declaration so extended API tests can run --- SRC/clarft.f | 2 +- SRC/clarft_lvl2.f | 2 +- SRC/dlarft.f | 2 +- SRC/dlarft_lvl2.f | 2 +- SRC/slarft.f | 2 +- SRC/slarft_lvl2.f | 2 +- SRC/zlarft.f | 2 +- SRC/zlarft_lvl2.f | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SRC/clarft.f b/SRC/clarft.f index 782852d18..78c754db8 100644 --- a/SRC/clarft.f +++ b/SRC/clarft.f @@ -220,7 +220,7 @@ RECURSIVE SUBROUTINE CLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. External Subroutines .. * - EXTERNAL CLARFT_LVL2, CTRMM, CGEMM, CLACPY + EXTERNAL CLARFT_LVL2, CTRMM, CGEMM, CLACPY, XERBLA * * .. External Functions.. * diff --git a/SRC/clarft_lvl2.f b/SRC/clarft_lvl2.f index 32f1dcea3..0dca6c0dc 100644 --- a/SRC/clarft_lvl2.f +++ b/SRC/clarft_lvl2.f @@ -209,7 +209,7 @@ SUBROUTINE CLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, * * .. External Subroutines .. * - EXTERNAL CTRMV,CGEMV,CGEMM + EXTERNAL CTRMV,CGEMV,CGEMM,XERBLA * * .. External Functions.. * diff --git a/SRC/dlarft.f b/SRC/dlarft.f index 0a371fafa..154f7226d 100644 --- a/SRC/dlarft.f +++ b/SRC/dlarft.f @@ -219,7 +219,7 @@ RECURSIVE SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. External Subroutines .. * - EXTERNAL DLARFT_LVL2, DTRMM, DGEMM, DLACPY + EXTERNAL DLARFT_LVL2, DTRMM, DGEMM, DLACPY, XERBLA * * .. External Functions.. * diff --git a/SRC/dlarft_lvl2.f b/SRC/dlarft_lvl2.f index 1f890e3a0..df8b358d3 100644 --- a/SRC/dlarft_lvl2.f +++ b/SRC/dlarft_lvl2.f @@ -210,7 +210,7 @@ SUBROUTINE DLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, * * .. External Subroutines .. * - EXTERNAL DTRMV,DGEMV + EXTERNAL DTRMV,DGEMV,XERBLA * * .. External Functions.. * diff --git a/SRC/slarft.f b/SRC/slarft.f index 6e019a3c3..a994a9249 100644 --- a/SRC/slarft.f +++ b/SRC/slarft.f @@ -219,7 +219,7 @@ RECURSIVE SUBROUTINE SLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. External Subroutines .. * - EXTERNAL SLARFT_LVL2, STRMM, SGEMM, SLACPY + EXTERNAL SLARFT_LVL2, STRMM, SGEMM, SLACPY, XERBLA * * .. External Functions.. * diff --git a/SRC/slarft_lvl2.f b/SRC/slarft_lvl2.f index 763457a8e..2a4f5bd8e 100644 --- a/SRC/slarft_lvl2.f +++ b/SRC/slarft_lvl2.f @@ -210,7 +210,7 @@ SUBROUTINE SLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, * * .. External Subroutines .. * - EXTERNAL STRMV,SGEMV + EXTERNAL STRMV,SGEMV,XERBLA * * .. External Functions.. * diff --git a/SRC/zlarft.f b/SRC/zlarft.f index ffc11dae7..8a0d3f0cf 100644 --- a/SRC/zlarft.f +++ b/SRC/zlarft.f @@ -220,7 +220,7 @@ RECURSIVE SUBROUTINE ZLARFT( DIRECT, STOREV, N, K, V, LDV, * * .. External Subroutines .. * - EXTERNAL ZLARFT_LVL2, ZTRMM, ZGEMM, ZLACPY + EXTERNAL ZLARFT_LVL2, ZTRMM, ZGEMM, ZLACPY, XERBLA * * .. External Functions.. * diff --git a/SRC/zlarft_lvl2.f b/SRC/zlarft_lvl2.f index cec8ea5ba..b16350b61 100644 --- a/SRC/zlarft_lvl2.f +++ b/SRC/zlarft_lvl2.f @@ -210,7 +210,7 @@ SUBROUTINE ZLARFT_LVL2( DIRECT, STOREV, N, K, V, LDV, TAU, * * .. External Subroutines .. * - EXTERNAL ZTRMV,ZGEMV,ZGEMM + EXTERNAL ZTRMV,ZGEMV,ZGEMM,XERBLA * * .. External Functions.. *