1*> \brief \b ZLARFB_GETT
2*
3*  =========== DOCUMENTATION ===========
4*
5* Online html documentation available at
6*            http://www.netlib.org/lapack/explore-html/
7*
8*> \htmlonly
9*> Download ZLARFB_GETT + dependencies
10*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/zlarfb_gett.f">
11*> [TGZ]</a>
12*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/zlarfb_gett.f">
13*> [ZIP]</a>
14*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/zlarfb_gett.f">
15*> [TXT]</a>
16*> \endhtmlonly
17*
18*  Definition:
19*  ===========
20*
21*       SUBROUTINE ZLARFB_GETT( IDENT, M, N, K, T, LDT, A, LDA, B, LDB,
22*      $                        WORK, LDWORK )
23*       IMPLICIT NONE
24*
25*       .. Scalar Arguments ..
26*       CHARACTER          IDENT
27*       INTEGER            K, LDA, LDB, LDT, LDWORK, M, N
28*       ..
29*       .. Array Arguments ..
30*       COMPLEX*16         A( LDA, * ), B( LDB, * ), T( LDT, * ),
31*      $                   WORK( LDWORK, * )
32*       ..
33*
34*> \par Purpose:
35*  =============
36*>
37*> \verbatim
38*>
39*> ZLARFB_GETT applies a complex Householder block reflector H from the
40*> left to a complex (K+M)-by-N  "triangular-pentagonal" matrix
41*> composed of two block matrices: an upper trapezoidal K-by-N matrix A
42*> stored in the array A, and a rectangular M-by-(N-K) matrix B, stored
43*> in the array B. The block reflector H is stored in a compact
44*> WY-representation, where the elementary reflectors are in the
45*> arrays A, B and T. See Further Details section.
46*> \endverbatim
47*
48*  Arguments:
49*  ==========
50*
51*> \param[in] IDENT
52*> \verbatim
53*>          IDENT is CHARACTER*1
54*>          If IDENT = not 'I', or not 'i', then V1 is unit
55*>             lower-triangular and stored in the left K-by-K block of
56*>             the input matrix A,
57*>          If IDENT = 'I' or 'i', then  V1 is an identity matrix and
58*>             not stored.
59*>          See Further Details section.
60*> \endverbatim
61*>
62*> \param[in] M
63*> \verbatim
64*>          M is INTEGER
65*>          The number of rows of the matrix B.
66*>          M >= 0.
67*> \endverbatim
68*>
69*> \param[in] N
70*> \verbatim
71*>          N is INTEGER
72*>          The number of columns of the matrices A and B.
73*>          N >= 0.
74*> \endverbatim
75*>
76*> \param[in] K
77*> \verbatim
78*>          K is INTEGER
79*>          The number or rows of the matrix A.
80*>          K is also order of the matrix T, i.e. the number of
81*>          elementary reflectors whose product defines the block
82*>          reflector. 0 <= K <= N.
83*> \endverbatim
84*>
85*> \param[in] T
86*> \verbatim
87*>          T is COMPLEX*16 array, dimension (LDT,K)
88*>          The upper-triangular K-by-K matrix T in the representation
89*>          of the block reflector.
90*> \endverbatim
91*>
92*> \param[in] LDT
93*> \verbatim
94*>          LDT is INTEGER
95*>          The leading dimension of the array T. LDT >= K.
96*> \endverbatim
97*>
98*> \param[in,out] A
99*> \verbatim
100*>          A is COMPLEX*16 array, dimension (LDA,N)
101*>
102*>          On entry:
103*>           a) In the K-by-N upper-trapezoidal part A: input matrix A.
104*>           b) In the columns below the diagonal: columns of V1
105*>              (ones are not stored on the diagonal).
106*>
107*>          On exit:
108*>            A is overwritten by rectangular K-by-N product H*A.
109*>
110*>          See Further Details section.
111*> \endverbatim
112*>
113*> \param[in] LDA
114*> \verbatim
115*>          LDB is INTEGER
116*>          The leading dimension of the array A. LDA >= max(1,K).
117*> \endverbatim
118*>
119*> \param[in,out] B
120*> \verbatim
121*>          B is COMPLEX*16 array, dimension (LDB,N)
122*>
123*>          On entry:
124*>            a) In the M-by-(N-K) right block: input matrix B.
125*>            b) In the M-by-N left block: columns of V2.
126*>
127*>          On exit:
128*>            B is overwritten by rectangular M-by-N product H*B.
129*>
130*>          See Further Details section.
131*> \endverbatim
132*>
133*> \param[in] LDB
134*> \verbatim
135*>          LDB is INTEGER
136*>          The leading dimension of the array B. LDB >= max(1,M).
137*> \endverbatim
138*>
139*> \param[out] WORK
140*> \verbatim
141*>          WORK is COMPLEX*16 array,
142*>          dimension (LDWORK,max(K,N-K))
143*> \endverbatim
144*>
145*> \param[in] LDWORK
146*> \verbatim
147*>          LDWORK is INTEGER
148*>          The leading dimension of the array WORK. LDWORK>=max(1,K).
149*>
150*> \endverbatim
151*
152*  Authors:
153*  ========
154*
155*> \author Univ. of Tennessee
156*> \author Univ. of California Berkeley
157*> \author Univ. of Colorado Denver
158*> \author NAG Ltd.
159*
160*> \ingroup complex16OTHERauxiliary
161*
162*> \par Contributors:
163*  ==================
164*>
165*> \verbatim
166*>
167*> November 2020, Igor Kozachenko,
168*>                Computer Science Division,
169*>                University of California, Berkeley
170*>
171*> \endverbatim
172*
173*> \par Further Details:
174*  =====================
175*>
176*> \verbatim
177*>
178*>    (1) Description of the Algebraic Operation.
179*>
180*>    The matrix A is a K-by-N matrix composed of two column block
181*>    matrices, A1, which is K-by-K, and A2, which is K-by-(N-K):
182*>    A = ( A1, A2 ).
183*>    The matrix B is an M-by-N matrix composed of two column block
184*>    matrices, B1, which is M-by-K, and B2, which is M-by-(N-K):
185*>    B = ( B1, B2 ).
186*>
187*>    Perform the operation:
188*>
189*>       ( A_out ) := H * ( A_in ) = ( I - V * T * V**H ) * ( A_in ) =
190*>       ( B_out )        ( B_in )                          ( B_in )
191*>                  = ( I - ( V1 ) * T * ( V1**H, V2**H ) ) * ( A_in )
192*>                          ( V2 )                            ( B_in )
193*>     On input:
194*>
195*>    a) ( A_in )  consists of two block columns:
196*>       ( B_in )
197*>
198*>       ( A_in ) = (( A1_in ) ( A2_in )) = (( A1_in ) ( A2_in ))
199*>       ( B_in )   (( B1_in ) ( B2_in ))   ((     0 ) ( B2_in )),
200*>
201*>       where the column blocks are:
202*>
203*>       (  A1_in )  is a K-by-K upper-triangular matrix stored in the
204*>                   upper triangular part of the array A(1:K,1:K).
205*>       (  B1_in )  is an M-by-K rectangular ZERO matrix and not stored.
206*>
207*>       ( A2_in )  is a K-by-(N-K) rectangular matrix stored
208*>                  in the array A(1:K,K+1:N).
209*>       ( B2_in )  is an M-by-(N-K) rectangular matrix stored
210*>                  in the array B(1:M,K+1:N).
211*>
212*>    b) V = ( V1 )
213*>           ( V2 )
214*>
215*>       where:
216*>       1) if IDENT == 'I',V1 is a K-by-K identity matrix, not stored;
217*>       2) if IDENT != 'I',V1 is a K-by-K unit lower-triangular matrix,
218*>          stored in the lower-triangular part of the array
219*>          A(1:K,1:K) (ones are not stored),
220*>       and V2 is an M-by-K rectangular stored the array B(1:M,1:K),
221*>                 (because on input B1_in is a rectangular zero
222*>                  matrix that is not stored and the space is
223*>                  used to store V2).
224*>
225*>    c) T is a K-by-K upper-triangular matrix stored
226*>       in the array T(1:K,1:K).
227*>
228*>    On output:
229*>
230*>    a) ( A_out ) consists of two  block columns:
231*>       ( B_out )
232*>
233*>       ( A_out ) = (( A1_out ) ( A2_out ))
234*>       ( B_out )   (( B1_out ) ( B2_out )),
235*>
236*>       where the column blocks are:
237*>
238*>       ( A1_out )  is a K-by-K square matrix, or a K-by-K
239*>                   upper-triangular matrix, if V1 is an
240*>                   identity matrix. AiOut is stored in
241*>                   the array A(1:K,1:K).
242*>       ( B1_out )  is an M-by-K rectangular matrix stored
243*>                   in the array B(1:M,K:N).
244*>
245*>       ( A2_out )  is a K-by-(N-K) rectangular matrix stored
246*>                   in the array A(1:K,K+1:N).
247*>       ( B2_out )  is an M-by-(N-K) rectangular matrix stored
248*>                   in the array B(1:M,K+1:N).
249*>
250*>
251*>    The operation above can be represented as the same operation
252*>    on each block column:
253*>
254*>       ( A1_out ) := H * ( A1_in ) = ( I - V * T * V**H ) * ( A1_in )
255*>       ( B1_out )        (     0 )                          (     0 )
256*>
257*>       ( A2_out ) := H * ( A2_in ) = ( I - V * T * V**H ) * ( A2_in )
258*>       ( B2_out )        ( B2_in )                          ( B2_in )
259*>
260*>    If IDENT != 'I':
261*>
262*>       The computation for column block 1:
263*>
264*>       A1_out: = A1_in - V1*T*(V1**H)*A1_in
265*>
266*>       B1_out: = - V2*T*(V1**H)*A1_in
267*>
268*>       The computation for column block 2, which exists if N > K:
269*>
270*>       A2_out: = A2_in - V1*T*( (V1**H)*A2_in + (V2**H)*B2_in )
271*>
272*>       B2_out: = B2_in - V2*T*( (V1**H)*A2_in + (V2**H)*B2_in )
273*>
274*>    If IDENT == 'I':
275*>
276*>       The operation for column block 1:
277*>
278*>       A1_out: = A1_in - V1*T*A1_in
279*>
280*>       B1_out: = - V2*T*A1_in
281*>
282*>       The computation for column block 2, which exists if N > K:
283*>
284*>       A2_out: = A2_in - T*( A2_in + (V2**H)*B2_in )
285*>
286*>       B2_out: = B2_in - V2*T*( A2_in + (V2**H)*B2_in )
287*>
288*>    (2) Description of the Algorithmic Computation.
289*>
290*>    In the first step, we compute column block 2, i.e. A2 and B2.
291*>    Here, we need to use the K-by-(N-K) rectangular workspace
292*>    matrix W2 that is of the same size as the matrix A2.
293*>    W2 is stored in the array WORK(1:K,1:(N-K)).
294*>
295*>    In the second step, we compute column block 1, i.e. A1 and B1.
296*>    Here, we need to use the K-by-K square workspace matrix W1
297*>    that is of the same size as the as the matrix A1.
298*>    W1 is stored in the array WORK(1:K,1:K).
299*>
300*>    NOTE: Hence, in this routine, we need the workspace array WORK
301*>    only of size WORK(1:K,1:max(K,N-K)) so it can hold both W2 from
302*>    the first step and W1 from the second step.
303*>
304*>    Case (A), when V1 is unit lower-triangular, i.e. IDENT != 'I',
305*>    more computations than in the Case (B).
306*>
307*>    if( IDENT != 'I' ) then
308*>     if ( N > K ) then
309*>       (First Step - column block 2)
310*>       col2_(1) W2: = A2
311*>       col2_(2) W2: = (V1**H) * W2 = (unit_lower_tr_of_(A1)**H) * W2
312*>       col2_(3) W2: = W2 + (V2**H) * B2 = W2 + (B1**H) * B2
313*>       col2_(4) W2: = T * W2
314*>       col2_(5) B2: = B2 - V2 * W2 = B2 - B1 * W2
315*>       col2_(6) W2: = V1 * W2 = unit_lower_tr_of_(A1) * W2
316*>       col2_(7) A2: = A2 - W2
317*>     else
318*>       (Second Step - column block 1)
319*>       col1_(1) W1: = A1
320*>       col1_(2) W1: = (V1**H) * W1 = (unit_lower_tr_of_(A1)**H) * W1
321*>       col1_(3) W1: = T * W1
322*>       col1_(4) B1: = - V2 * W1 = - B1 * W1
323*>       col1_(5) square W1: = V1 * W1 = unit_lower_tr_of_(A1) * W1
324*>       col1_(6) square A1: = A1 - W1
325*>     end if
326*>    end if
327*>
328*>    Case (B), when V1 is an identity matrix, i.e. IDENT == 'I',
329*>    less computations than in the Case (A)
330*>
331*>    if( IDENT == 'I' ) then
332*>     if ( N > K ) then
333*>       (First Step - column block 2)
334*>       col2_(1) W2: = A2
335*>       col2_(3) W2: = W2 + (V2**H) * B2 = W2 + (B1**H) * B2
336*>       col2_(4) W2: = T * W2
337*>       col2_(5) B2: = B2 - V2 * W2 = B2 - B1 * W2
338*>       col2_(7) A2: = A2 - W2
339*>     else
340*>       (Second Step - column block 1)
341*>       col1_(1) W1: = A1
342*>       col1_(3) W1: = T * W1
343*>       col1_(4) B1: = - V2 * W1 = - B1 * W1
344*>       col1_(6) upper-triangular_of_(A1): = A1 - W1
345*>     end if
346*>    end if
347*>
348*>    Combine these cases (A) and (B) together, this is the resulting
349*>    algorithm:
350*>
351*>    if ( N > K ) then
352*>
353*>      (First Step - column block 2)
354*>
355*>      col2_(1)  W2: = A2
356*>      if( IDENT != 'I' ) then
357*>        col2_(2)  W2: = (V1**H) * W2
358*>                      = (unit_lower_tr_of_(A1)**H) * W2
359*>      end if
360*>      col2_(3)  W2: = W2 + (V2**H) * B2 = W2 + (B1**H) * B2]
361*>      col2_(4)  W2: = T * W2
362*>      col2_(5)  B2: = B2 - V2 * W2 = B2 - B1 * W2
363*>      if( IDENT != 'I' ) then
364*>        col2_(6)    W2: = V1 * W2 = unit_lower_tr_of_(A1) * W2
365*>      end if
366*>      col2_(7) A2: = A2 - W2
367*>
368*>    else
369*>
370*>    (Second Step - column block 1)
371*>
372*>      col1_(1) W1: = A1
373*>      if( IDENT != 'I' ) then
374*>        col1_(2) W1: = (V1**H) * W1
375*>                    = (unit_lower_tr_of_(A1)**H) * W1
376*>      end if
377*>      col1_(3) W1: = T * W1
378*>      col1_(4) B1: = - V2 * W1 = - B1 * W1
379*>      if( IDENT != 'I' ) then
380*>        col1_(5) square W1: = V1 * W1 = unit_lower_tr_of_(A1) * W1
381*>        col1_(6_a) below_diag_of_(A1): =  - below_diag_of_(W1)
382*>      end if
383*>      col1_(6_b) up_tr_of_(A1): = up_tr_of_(A1) - up_tr_of_(W1)
384*>
385*>    end if
386*>
387*> \endverbatim
388*>
389*  =====================================================================
390      SUBROUTINE ZLARFB_GETT( IDENT, M, N, K, T, LDT, A, LDA, B, LDB,
391     $                        WORK, LDWORK )
392      IMPLICIT NONE
393*
394*  -- LAPACK auxiliary routine --
395*  -- LAPACK is a software package provided by Univ. of Tennessee,    --
396*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
397*
398*     .. Scalar Arguments ..
399      CHARACTER          IDENT
400      INTEGER            K, LDA, LDB, LDT, LDWORK, M, N
401*     ..
402*     .. Array Arguments ..
403      COMPLEX*16         A( LDA, * ), B( LDB, * ), T( LDT, * ),
404     $                   WORK( LDWORK, * )
405*     ..
406*
407*  =====================================================================
408*
409*     .. Parameters ..
410      COMPLEX*16         CONE, CZERO
411      PARAMETER          ( CONE = ( 1.0D+0, 0.0D+0 ),
412     $                     CZERO = ( 0.0D+0, 0.0D+0 ) )
413*     ..
414*     .. Local Scalars ..
415      LOGICAL            LNOTIDENT
416      INTEGER            I, J
417*     ..
418*     .. EXTERNAL FUNCTIONS ..
419      LOGICAL            LSAME
420      EXTERNAL           LSAME
421*     ..
422*     .. External Subroutines ..
423      EXTERNAL           ZCOPY, ZGEMM, ZTRMM
424*     ..
425*     .. Executable Statements ..
426*
427*     Quick return if possible
428*
429      IF( M.LT.0 .OR. N.LE.0 .OR. K.EQ.0 .OR. K.GT.N )
430     $   RETURN
431*
432      LNOTIDENT = .NOT.LSAME( IDENT, 'I' )
433*
434*     ------------------------------------------------------------------
435*
436*     First Step. Computation of the Column Block 2:
437*
438*        ( A2 ) := H * ( A2 )
439*        ( B2 )        ( B2 )
440*
441*     ------------------------------------------------------------------
442*
443      IF( N.GT.K ) THEN
444*
445*        col2_(1) Compute W2: = A2. Therefore, copy A2 = A(1:K, K+1:N)
446*        into W2=WORK(1:K, 1:N-K) column-by-column.
447*
448         DO J = 1, N-K
449            CALL ZCOPY( K, A( 1, K+J ), 1, WORK( 1, J ), 1 )
450         END DO
451
452         IF( LNOTIDENT ) THEN
453*
454*           col2_(2) Compute W2: = (V1**H) * W2 = (A1**H) * W2,
455*           V1 is not an identy matrix, but unit lower-triangular
456*           V1 stored in A1 (diagonal ones are not stored).
457*
458*
459            CALL ZTRMM( 'L', 'L', 'C', 'U', K, N-K, CONE, A, LDA,
460     $                  WORK, LDWORK )
461         END IF
462*
463*        col2_(3) Compute W2: = W2 + (V2**H) * B2 = W2 + (B1**H) * B2
464*        V2 stored in B1.
465*
466         IF( M.GT.0 ) THEN
467            CALL ZGEMM( 'C', 'N', K, N-K, M, CONE, B, LDB,
468     $                  B( 1, K+1 ), LDB, CONE, WORK, LDWORK )
469         END IF
470*
471*        col2_(4) Compute W2: = T * W2,
472*        T is upper-triangular.
473*
474         CALL ZTRMM( 'L', 'U', 'N', 'N', K, N-K, CONE, T, LDT,
475     $               WORK, LDWORK )
476*
477*        col2_(5) Compute B2: = B2 - V2 * W2 = B2 - B1 * W2,
478*        V2 stored in B1.
479*
480         IF( M.GT.0 ) THEN
481            CALL ZGEMM( 'N', 'N', M, N-K, K, -CONE, B, LDB,
482     $                   WORK, LDWORK, CONE, B( 1, K+1 ), LDB )
483         END IF
484*
485         IF( LNOTIDENT ) THEN
486*
487*           col2_(6) Compute W2: = V1 * W2 = A1 * W2,
488*           V1 is not an identity matrix, but unit lower-triangular,
489*           V1 stored in A1 (diagonal ones are not stored).
490*
491            CALL ZTRMM( 'L', 'L', 'N', 'U', K, N-K, CONE, A, LDA,
492     $                  WORK, LDWORK )
493         END IF
494*
495*        col2_(7) Compute A2: = A2 - W2 =
496*                             = A(1:K, K+1:N-K) - WORK(1:K, 1:N-K),
497*        column-by-column.
498*
499         DO J = 1, N-K
500            DO I = 1, K
501               A( I, K+J ) = A( I, K+J ) - WORK( I, J )
502            END DO
503         END DO
504*
505      END IF
506*
507*     ------------------------------------------------------------------
508*
509*     Second Step. Computation of the Column Block 1:
510*
511*        ( A1 ) := H * ( A1 )
512*        ( B1 )        (  0 )
513*
514*     ------------------------------------------------------------------
515*
516*     col1_(1) Compute W1: = A1. Copy the upper-triangular
517*     A1 = A(1:K, 1:K) into the upper-triangular
518*     W1 = WORK(1:K, 1:K) column-by-column.
519*
520      DO J = 1, K
521         CALL ZCOPY( J, A( 1, J ), 1, WORK( 1, J ), 1 )
522      END DO
523*
524*     Set the subdiagonal elements of W1 to zero column-by-column.
525*
526      DO J = 1, K - 1
527         DO I = J + 1, K
528            WORK( I, J ) = CZERO
529         END DO
530      END DO
531*
532      IF( LNOTIDENT ) THEN
533*
534*        col1_(2) Compute W1: = (V1**H) * W1 = (A1**H) * W1,
535*        V1 is not an identity matrix, but unit lower-triangular
536*        V1 stored in A1 (diagonal ones are not stored),
537*        W1 is upper-triangular with zeroes below the diagonal.
538*
539         CALL ZTRMM( 'L', 'L', 'C', 'U', K, K, CONE, A, LDA,
540     $               WORK, LDWORK )
541      END IF
542*
543*     col1_(3) Compute W1: = T * W1,
544*     T is upper-triangular,
545*     W1 is upper-triangular with zeroes below the diagonal.
546*
547      CALL ZTRMM( 'L', 'U', 'N', 'N', K, K, CONE, T, LDT,
548     $            WORK, LDWORK )
549*
550*     col1_(4) Compute B1: = - V2 * W1 = - B1 * W1,
551*     V2 = B1, W1 is upper-triangular with zeroes below the diagonal.
552*
553      IF( M.GT.0 ) THEN
554         CALL ZTRMM( 'R', 'U', 'N', 'N', M, K, -CONE, WORK, LDWORK,
555     $               B, LDB )
556      END IF
557*
558      IF( LNOTIDENT ) THEN
559*
560*        col1_(5) Compute W1: = V1 * W1 = A1 * W1,
561*        V1 is not an identity matrix, but unit lower-triangular
562*        V1 stored in A1 (diagonal ones are not stored),
563*        W1 is upper-triangular on input with zeroes below the diagonal,
564*        and square on output.
565*
566         CALL ZTRMM( 'L', 'L', 'N', 'U', K, K, CONE, A, LDA,
567     $               WORK, LDWORK )
568*
569*        col1_(6) Compute A1: = A1 - W1 = A(1:K, 1:K) - WORK(1:K, 1:K)
570*        column-by-column. A1 is upper-triangular on input.
571*        If IDENT, A1 is square on output, and W1 is square,
572*        if NOT IDENT, A1 is upper-triangular on output,
573*        W1 is upper-triangular.
574*
575*        col1_(6)_a Compute elements of A1 below the diagonal.
576*
577         DO J = 1, K - 1
578            DO I = J + 1, K
579               A( I, J ) = - WORK( I, J )
580            END DO
581         END DO
582*
583      END IF
584*
585*     col1_(6)_b Compute elements of A1 on and above the diagonal.
586*
587      DO J = 1, K
588         DO I = 1, J
589            A( I, J ) = A( I, J ) - WORK( I, J )
590         END DO
591      END DO
592*
593      RETURN
594*
595*     End of ZLARFB_GETT
596*
597      END
598