1*> \brief \b DLAMSWLQ
2*
3*  Definition:
4*  ===========
5*
6*      SUBROUTINE DLAMSWLQ( 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*      DOUBLE        A( LDA, * ), WORK( * ), C(LDC, * ),
16*     $                  T( LDT, * )
17*> \par Purpose:
18*  =============
19*>
20*> \verbatim
21*>
22*>    DLAMQRTS 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 = 'T':      Q**T * C       C * Q**T
28*>    where Q is a real orthogonal matrix defined as the product of blocked
29*>    elementary reflectors computed by short wide LQ
30*>    factorization (DLASWLQ)
31*> \endverbatim
32*
33*  Arguments:
34*  ==========
35*
36*> \param[in] SIDE
37*> \verbatim
38*>          SIDE is CHARACTER*1
39*>          = 'L': apply Q or Q**T from the Left;
40*>          = 'R': apply Q or Q**T from the Right.
41*> \endverbatim
42*>
43*> \param[in] TRANS
44*> \verbatim
45*>          TRANS is CHARACTER*1
46*>          = 'N':  No transpose, apply Q;
47*>          = 'T':  Transpose, apply Q**T.
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 DOUBLE PRECISION 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*>          DLASWLQ 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 DOUBLE PRECISION 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 DOUBLE PRECISION array, dimension (LDC,N)
120*>          On entry, the M-by-N matrix C.
121*>          On exit, C is overwritten by Q*C or Q**T*C or C*Q**T 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) DOUBLE PRECISION 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 DLAMSWLQ( 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      DOUBLE PRECISION 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, CTR, LW
217*     ..
218*     .. External Functions ..
219      LOGICAL            LSAME
220      EXTERNAL           LSAME
221*     .. External Subroutines ..
222      EXTERNAL           DTPMLQT, DGEMLQT, 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, 'T' )
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( 'DLAMSWLQ', -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 DGEMLQT( 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          IF (KK.GT.0) THEN
288            II=M-KK+1
289            CALL DTPMLQT('L','T',KK , N, K, 0, MB, A(1,II), LDA,
290     $        T(1,CTR*K+1), LDT, C(1,1), LDC,
291     $        C(II,1), LDC, WORK, INFO )
292          ELSE
293            II=M+1
294          END IF
295*
296          DO I=II-(NB-K),NB+1,-(NB-K)
297*
298*         Multiply Q to the current block of C (1:M,I:I+NB)
299*
300            CTR = CTR - 1
301            CALL DTPMLQT('L','T',NB-K , N, K, 0,MB, A(1,I), LDA,
302     $          T(1, CTR*K+1),LDT, C(1,1), LDC,
303     $          C(I,1), LDC, WORK, INFO )
304
305          END DO
306*
307*         Multiply Q to the first block of C (1:M,1:NB)
308*
309          CALL DGEMLQT('L','T',NB , N, K, MB, A(1,1), LDA, T
310     $              ,LDT ,C(1,1), LDC, WORK, INFO )
311*
312      ELSE IF (LEFT.AND.NOTRAN) THEN
313*
314*         Multiply Q to the first block of C
315*
316         KK = MOD((M-K),(NB-K))
317         II=M-KK+1
318         CTR = 1
319         CALL DGEMLQT('L','N',NB , N, K, MB, A(1,1), LDA, T
320     $              ,LDT ,C(1,1), LDC, WORK, INFO )
321*
322         DO I=NB+1,II-NB+K,(NB-K)
323*
324*         Multiply Q to the current block of C (I:I+NB,1:N)
325*
326          CALL DTPMLQT('L','N',NB-K , N, K, 0,MB, A(1,I), LDA,
327     $         T(1,CTR*K+1), LDT, C(1,1), LDC,
328     $         C(I,1), LDC, WORK, INFO )
329          CTR = CTR + 1
330*
331         END DO
332         IF(II.LE.M) THEN
333*
334*         Multiply Q to the last block of C
335*
336          CALL DTPMLQT('L','N',KK , N, K, 0, MB, A(1,II), LDA,
337     $        T(1,CTR*K+1), LDT, C(1,1), LDC,
338     $        C(II,1), LDC, WORK, INFO )
339*
340         END IF
341*
342      ELSE IF(RIGHT.AND.NOTRAN) THEN
343*
344*         Multiply Q to the last block of C
345*
346          KK = MOD((N-K),(NB-K))
347          CTR = (N-K)/(NB-K)
348          IF (KK.GT.0) THEN
349            II=N-KK+1
350            CALL DTPMLQT('R','N',M , KK, K, 0, MB, A(1, II), LDA,
351     $        T(1,CTR *K+1), LDT, C(1,1), LDC,
352     $        C(1,II), LDC, WORK, INFO )
353          ELSE
354            II=N+1
355          END IF
356*
357          DO I=II-(NB-K),NB+1,-(NB-K)
358*
359*         Multiply Q to the current block of C (1:M,I:I+MB)
360*
361             CTR = CTR - 1
362             CALL DTPMLQT('R','N', M, NB-K, K, 0, MB, A(1, I), LDA,
363     $        T(1,CTR*K+1), LDT, C(1,1), LDC,
364     $        C(1,I), LDC, WORK, INFO )
365*
366          END DO
367*
368*         Multiply Q to the first block of C (1:M,1:MB)
369*
370          CALL DGEMLQT('R','N',M , NB, K, MB, A(1,1), LDA, T
371     $            ,LDT ,C(1,1), LDC, WORK, INFO )
372*
373      ELSE IF (RIGHT.AND.TRAN) THEN
374*
375*       Multiply Q to the first block of C
376*
377         KK = MOD((N-K),(NB-K))
378         CTR = 1
379         II=N-KK+1
380         CALL DGEMLQT('R','T',M , NB, K, MB, A(1,1), LDA, T
381     $            ,LDT ,C(1,1), LDC, WORK, INFO )
382*
383         DO I=NB+1,II-NB+K,(NB-K)
384*
385*         Multiply Q to the current block of C (1:M,I:I+MB)
386*
387          CALL DTPMLQT('R','T',M , NB-K, K, 0,MB, A(1,I), LDA,
388     $       T(1,CTR*K+1), LDT, C(1,1), LDC,
389     $       C(1,I), LDC, WORK, INFO )
390          CTR = CTR + 1
391*
392         END DO
393         IF(II.LE.N) THEN
394*
395*       Multiply Q to the last block of C
396*
397          CALL DTPMLQT('R','T',M , KK, K, 0,MB, A(1,II), LDA,
398     $      T(1,CTR*K+1),LDT, C(1,1), LDC,
399     $      C(1,II), LDC, WORK, INFO )
400*
401         END IF
402*
403      END IF
404*
405      WORK(1) = LW
406      RETURN
407*
408*     End of DLAMSWLQ
409*
410      END
411