1*> \brief \b ZLAMSWLQ
2*
3*  Definition:
4*  ===========
5*
6*      SUBROUTINE ZLAMSWLQ( SIDE, TRANS, M, N, K, MB, NB, A, LDA, T,
7*     $                LDT, C, LDC, WORK, LWORK, INFO )
8*
9*
10*     .. Scalar Arguments ..
11*      CHARACTER         SIDE, TRANS
12*      INTEGER           INFO, LDA, M, N, K, MB, NB, LDT, LWORK, LDC
13*     ..
14*     .. Array Arguments ..
15*      COMPLEX*16        A( LDA, * ), WORK( * ), C(LDC, * ),
16*     $                  T( LDT, * )
17*> \par Purpose:
18*  =============
19*>
20*> \verbatim
21*>
22*>    ZLAMQRTS overwrites the general real M-by-N matrix C with
23*>
24*>
25*>                    SIDE = 'L'     SIDE = 'R'
26*>    TRANS = 'N':      Q * C          C * Q
27*>    TRANS = 'C':      Q**H * C       C * Q**H
28*>    where Q is a real orthogonal matrix defined as the product of blocked
29*>    elementary reflectors computed by short wide LQ
30*>    factorization (ZLASWLQ)
31*> \endverbatim
32*
33*  Arguments:
34*  ==========
35*
36*> \param[in] SIDE
37*> \verbatim
38*>          SIDE is CHARACTER*1
39*>          = 'L': apply Q or Q**H from the Left;
40*>          = 'R': apply Q or Q**H from the Right.
41*> \endverbatim
42*>
43*> \param[in] TRANS
44*> \verbatim
45*>          TRANS is CHARACTER*1
46*>          = 'N':  No transpose, apply Q;
47*>          = 'C':  Conjugate Transpose, apply Q**H.
48*> \endverbatim
49*>
50*> \param[in] M
51*> \verbatim
52*>          M is INTEGER
53*>          The number of rows of the matrix C.  M >=0.
54*> \endverbatim
55*>
56*> \param[in] N
57*> \verbatim
58*>          N is INTEGER
59*>          The number of columns of the matrix C. N >= M.
60*> \endverbatim
61*>
62*> \param[in] K
63*> \verbatim
64*>          K is INTEGER
65*>          The number of elementary reflectors whose product defines
66*>          the matrix Q.
67*>          M >= K >= 0;
68*>
69*> \endverbatim
70*> \param[in] MB
71*> \verbatim
72*>          MB is INTEGER
73*>          The row block size to be used in the blocked QR.
74*>          M >= MB >= 1
75*> \endverbatim
76*>
77*> \param[in] NB
78*> \verbatim
79*>          NB is INTEGER
80*>          The column block size to be used in the blocked QR.
81*>          NB > M.
82*> \endverbatim
83*>
84*> \param[in] A
85*> \verbatim
86*>          A is COMPLEX*16 array, dimension
87*>                               (LDA,M) if SIDE = 'L',
88*>                               (LDA,N) if SIDE = 'R'
89*>          The i-th row must contain the vector which defines the blocked
90*>          elementary reflector H(i), for i = 1,2,...,k, as returned by
91*>          ZLASWLQ in the first k rows of its array argument A.
92*> \endverbatim
93*>
94*> \param[in] LDA
95*> \verbatim
96*>          LDA is INTEGER
97*>          The leading dimension of the array A.
98*>          If SIDE = 'L', LDA >= max(1,M);
99*>          if SIDE = 'R', LDA >= max(1,N).
100*> \endverbatim
101*>
102*> \param[in] T
103*> \verbatim
104*>          T is COMPLEX*16 array, dimension
105*>          ( M * Number of blocks(CEIL(N-K/NB-K)),
106*>          The blocked upper triangular block reflectors stored in compact form
107*>          as a sequence of upper triangular blocks.  See below
108*>          for further details.
109*> \endverbatim
110*>
111*> \param[in] LDT
112*> \verbatim
113*>          LDT is INTEGER
114*>          The leading dimension of the array T.  LDT >= MB.
115*> \endverbatim
116*>
117*> \param[in,out] C
118*> \verbatim
119*>          C is COMPLEX*16 array, dimension (LDC,N)
120*>          On entry, the M-by-N matrix C.
121*>          On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q.
122*> \endverbatim
123*>
124*> \param[in] LDC
125*> \verbatim
126*>          LDC is INTEGER
127*>          The leading dimension of the array C. LDC >= max(1,M).
128*> \endverbatim
129*>
130*> \param[out] WORK
131*> \verbatim
132*>         (workspace) COMPLEX*16 array, dimension (MAX(1,LWORK))
133*> \endverbatim
134*>
135*> \param[in] LWORK
136*> \verbatim
137*>          LWORK is INTEGER
138*>          The dimension of the array WORK.
139*>          If SIDE = 'L', LWORK >= max(1,NB) * MB;
140*>          if SIDE = 'R', LWORK >= max(1,M) * MB.
141*>          If LWORK = -1, then a workspace query is assumed; the routine
142*>          only calculates the optimal size of the WORK array, returns
143*>          this value as the first entry of the WORK array, and no error
144*>          message related to LWORK is issued by XERBLA.
145*> \endverbatim
146*>
147*> \param[out] INFO
148*> \verbatim
149*>          INFO is INTEGER
150*>          = 0:  successful exit
151*>          < 0:  if INFO = -i, the i-th argument had an illegal value
152*> \endverbatim
153*
154*  Authors:
155*  ========
156*
157*> \author Univ. of Tennessee
158*> \author Univ. of California Berkeley
159*> \author Univ. of Colorado Denver
160*> \author NAG Ltd.
161*
162*> \par Further Details:
163*  =====================
164*>
165*> \verbatim
166*> Short-Wide LQ (SWLQ) performs LQ by a sequence of orthogonal transformations,
167*> representing Q as a product of other orthogonal matrices
168*>   Q = Q(1) * Q(2) * . . . * Q(k)
169*> where each Q(i) zeros out upper diagonal entries of a block of NB rows of A:
170*>   Q(1) zeros out the upper diagonal entries of rows 1:NB of A
171*>   Q(2) zeros out the bottom MB-N rows of rows [1:M,NB+1:2*NB-M] of A
172*>   Q(3) zeros out the bottom MB-N rows of rows [1:M,2*NB-M+1:3*NB-2*M] of A
173*>   . . .
174*>
175*> Q(1) is computed by GELQT, which represents Q(1) by Householder vectors
176*> stored under the diagonal of rows 1:MB of A, and by upper triangular
177*> block reflectors, stored in array T(1:LDT,1:N).
178*> For more information see Further Details in GELQT.
179*>
180*> Q(i) for i>1 is computed by TPLQT, which represents Q(i) by Householder vectors
181*> stored in columns [(i-1)*(NB-M)+M+1:i*(NB-M)+M] of A, and by upper triangular
182*> block reflectors, stored in array T(1:LDT,(i-1)*M+1:i*M).
183*> The last Q(k) may use fewer rows.
184*> For more information see Further Details in TPQRT.
185*>
186*> For more details of the overall algorithm, see the description of
187*> Sequential TSQR in Section 2.2 of [1].
188*>
189*> [1] “Communication-Optimal Parallel and Sequential QR and LU Factorizations,”
190*>     J. Demmel, L. Grigori, M. Hoemmen, J. Langou,
191*>     SIAM J. Sci. Comput, vol. 34, no. 1, 2012
192*> \endverbatim
193*>
194*  =====================================================================
195      SUBROUTINE ZLAMSWLQ( SIDE, TRANS, M, N, K, MB, NB, A, LDA, T,
196     $    LDT, C, LDC, WORK, LWORK, INFO )
197*
198*  -- LAPACK computational routine --
199*  -- LAPACK is a software package provided by Univ. of Tennessee,    --
200*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
201*
202*     .. Scalar Arguments ..
203      CHARACTER         SIDE, TRANS
204      INTEGER           INFO, LDA, M, N, K, MB, NB, LDT, LWORK, LDC
205*     ..
206*     .. Array Arguments ..
207      COMPLEX*16        A( LDA, * ), WORK( * ), C(LDC, * ),
208     $      T( LDT, * )
209*     ..
210*
211* =====================================================================
212*
213*     ..
214*     .. Local Scalars ..
215      LOGICAL    LEFT, RIGHT, TRAN, NOTRAN, LQUERY
216      INTEGER    I, II, KK, LW, CTR
217*     ..
218*     .. External Functions ..
219      LOGICAL            LSAME
220      EXTERNAL           LSAME
221*     .. External Subroutines ..
222      EXTERNAL    ZTPMLQT, ZGEMLQT, XERBLA
223*     ..
224*     .. Executable Statements ..
225*
226*     Test the input arguments
227*
228      LQUERY  = LWORK.LT.0
229      NOTRAN  = LSAME( TRANS, 'N' )
230      TRAN    = LSAME( TRANS, 'C' )
231      LEFT    = LSAME( SIDE, 'L' )
232      RIGHT   = LSAME( SIDE, 'R' )
233      IF (LEFT) THEN
234        LW = N * MB
235      ELSE
236        LW = M * MB
237      END IF
238*
239      INFO = 0
240      IF( .NOT.LEFT .AND. .NOT.RIGHT ) THEN
241         INFO = -1
242      ELSE IF( .NOT.TRAN .AND. .NOT.NOTRAN ) THEN
243         INFO = -2
244      ELSE IF( M.LT.0 ) THEN
245        INFO = -3
246      ELSE IF( N.LT.0 ) THEN
247        INFO = -4
248      ELSE IF( K.LT.0 ) THEN
249        INFO = -5
250      ELSE IF( LDA.LT.MAX( 1, K ) ) THEN
251        INFO = -9
252      ELSE IF( LDT.LT.MAX( 1, MB) ) THEN
253        INFO = -11
254      ELSE IF( LDC.LT.MAX( 1, M ) ) THEN
255         INFO = -13
256      ELSE IF(( LWORK.LT.MAX(1,LW)).AND.(.NOT.LQUERY)) THEN
257        INFO = -15
258      END IF
259*
260      IF( INFO.NE.0 ) THEN
261        CALL XERBLA( 'ZLAMSWLQ', -INFO )
262        WORK(1) = LW
263        RETURN
264      ELSE IF (LQUERY) THEN
265        WORK(1) = LW
266        RETURN
267      END IF
268*
269*     Quick return if possible
270*
271      IF( MIN(M,N,K).EQ.0 ) THEN
272        RETURN
273      END IF
274*
275      IF((NB.LE.K).OR.(NB.GE.MAX(M,N,K))) THEN
276        CALL ZGEMLQT( SIDE, TRANS, M, N, K, MB, A, LDA,
277     $        T, LDT, C, LDC, WORK, INFO)
278        RETURN
279      END IF
280*
281      IF(LEFT.AND.TRAN) THEN
282*
283*         Multiply Q to the last block of C
284*
285          KK = MOD((M-K),(NB-K))
286          CTR = (M-K)/(NB-K)
287*
288          IF (KK.GT.0) THEN
289            II=M-KK+1
290            CALL ZTPMLQT('L','C',KK , N, K, 0, MB, A(1,II), LDA,
291     $        T(1,CTR*K+1), LDT, C(1,1), LDC,
292     $        C(II,1), LDC, WORK, INFO )
293          ELSE
294            II=M+1
295          END IF
296*
297          DO I=II-(NB-K),NB+1,-(NB-K)
298*
299*         Multiply Q to the current block of C (1:M,I:I+NB)
300*
301            CTR = CTR - 1
302            CALL ZTPMLQT('L','C',NB-K , N, K, 0,MB, A(1,I), LDA,
303     $          T(1,CTR*K+1),LDT, C(1,1), LDC,
304     $          C(I,1), LDC, WORK, INFO )
305
306          END DO
307*
308*         Multiply Q to the first block of C (1:M,1:NB)
309*
310          CALL ZGEMLQT('L','C',NB , N, K, MB, A(1,1), LDA, T
311     $              ,LDT ,C(1,1), LDC, WORK, INFO )
312*
313      ELSE IF (LEFT.AND.NOTRAN) THEN
314*
315*         Multiply Q to the first block of C
316*
317         KK = MOD((M-K),(NB-K))
318         II=M-KK+1
319         CTR = 1
320         CALL ZGEMLQT('L','N',NB , N, K, MB, A(1,1), LDA, T
321     $              ,LDT ,C(1,1), LDC, WORK, INFO )
322*
323         DO I=NB+1,II-NB+K,(NB-K)
324*
325*         Multiply Q to the current block of C (I:I+NB,1:N)
326*
327          CALL ZTPMLQT('L','N',NB-K , N, K, 0,MB, A(1,I), LDA,
328     $         T(1, CTR * K + 1), LDT, C(1,1), LDC,
329     $         C(I,1), LDC, WORK, INFO )
330          CTR = CTR + 1
331*
332         END DO
333         IF(II.LE.M) THEN
334*
335*         Multiply Q to the last block of C
336*
337          CALL ZTPMLQT('L','N',KK , N, K, 0, MB, A(1,II), LDA,
338     $        T(1, CTR * K + 1), LDT, C(1,1), LDC,
339     $        C(II,1), LDC, WORK, INFO )
340*
341         END IF
342*
343      ELSE IF(RIGHT.AND.NOTRAN) THEN
344*
345*         Multiply Q to the last block of C
346*
347          KK = MOD((N-K),(NB-K))
348          CTR = (N-K)/(NB-K)
349          IF (KK.GT.0) THEN
350            II=N-KK+1
351            CALL ZTPMLQT('R','N',M , KK, K, 0, MB, A(1, II), LDA,
352     $        T(1, CTR * K + 1), LDT, C(1,1), LDC,
353     $        C(1,II), LDC, WORK, INFO )
354          ELSE
355            II=N+1
356          END IF
357*
358          DO I=II-(NB-K),NB+1,-(NB-K)
359*
360*         Multiply Q to the current block of C (1:M,I:I+MB)
361*
362          CTR = CTR - 1
363          CALL ZTPMLQT('R','N', M, NB-K, K, 0, MB, A(1, I), LDA,
364     $        T(1, CTR * K + 1), LDT, C(1,1), LDC,
365     $        C(1,I), LDC, WORK, INFO )
366
367          END DO
368*
369*         Multiply Q to the first block of C (1:M,1:MB)
370*
371          CALL ZGEMLQT('R','N',M , NB, K, MB, A(1,1), LDA, T
372     $            ,LDT ,C(1,1), LDC, WORK, INFO )
373*
374      ELSE IF (RIGHT.AND.TRAN) THEN
375*
376*       Multiply Q to the first block of C
377*
378         KK = MOD((N-K),(NB-K))
379         II=N-KK+1
380         CALL ZGEMLQT('R','C',M , NB, K, MB, A(1,1), LDA, T
381     $            ,LDT ,C(1,1), LDC, WORK, INFO )
382         CTR = 1
383*
384         DO I=NB+1,II-NB+K,(NB-K)
385*
386*         Multiply Q to the current block of C (1:M,I:I+MB)
387*
388          CALL ZTPMLQT('R','C',M , NB-K, K, 0,MB, A(1,I), LDA,
389     $       T(1,CTR *K+1), LDT, C(1,1), LDC,
390     $       C(1,I), LDC, WORK, INFO )
391          CTR = CTR + 1
392*
393         END DO
394         IF(II.LE.N) THEN
395*
396*       Multiply Q to the last block of C
397*
398          CALL ZTPMLQT('R','C',M , KK, K, 0,MB, A(1,II), LDA,
399     $      T(1, CTR * K + 1),LDT, C(1,1), LDC,
400     $      C(1,II), LDC, WORK, INFO )
401*
402         END IF
403*
404      END IF
405*
406      WORK(1) = LW
407      RETURN
408*
409*     End of ZLAMSWLQ
410*
411      END
412