Annotation of rpl/lapack/lapack/zunm22.f, revision 1.5
1.1 bertrand 1: *> \brief \b ZUNM22 multiplies a general matrix by a banded unitary matrix.
2: *
3: * =========== DOCUMENTATION ===========
4: *
5: * Online html documentation available at
6: * http://www.netlib.org/lapack/explore-html/
7: *
8: *> \htmlonly
9: *> Download ZUNM22 + dependencies
10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/zunm22.f">
11: *> [TGZ]</a>
12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/zunm22.f">
13: *> [ZIP]</a>
14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/zunm22.f">
15: *> [TXT]</a>
16: *> \endhtmlonly
17: *
18: * Definition:
19: * ===========
20: *
21: * SUBROUTINE ZUNM22( SIDE, TRANS, M, N, N1, N2, Q, LDQ, C, LDC,
22: * $ WORK, LWORK, INFO )
23: *
24: * .. Scalar Arguments ..
25: * CHARACTER SIDE, TRANS
26: * INTEGER M, N, N1, N2, LDQ, LDC, LWORK, INFO
27: * ..
28: * .. Array Arguments ..
29: * COMPLEX*16 Q( LDQ, * ), C( LDC, * ), WORK( * )
30: * ..
31: *
32: *> \par Purpose
33: * ============
34: *>
35: *> \verbatim
36: *>
37: *> ZUNM22 overwrites the general complex M-by-N matrix C with
38: *>
39: *> SIDE = 'L' SIDE = 'R'
40: *> TRANS = 'N': Q * C C * Q
41: *> TRANS = 'C': Q**H * C C * Q**H
42: *>
43: *> where Q is a complex unitary matrix of order NQ, with NQ = M if
44: *> SIDE = 'L' and NQ = N if SIDE = 'R'.
45: *> The unitary matrix Q processes a 2-by-2 block structure
46: *>
47: *> [ Q11 Q12 ]
48: *> Q = [ ]
49: *> [ Q21 Q22 ],
50: *>
51: *> where Q12 is an N1-by-N1 lower triangular matrix and Q21 is an
52: *> N2-by-N2 upper triangular matrix.
53: *> \endverbatim
54: *
1.4 bertrand 55: * Arguments:
56: * ==========
1.1 bertrand 57: *
58: *> \param[in] SIDE
59: *> \verbatim
60: *> SIDE is CHARACTER*1
61: *> = 'L': apply Q or Q**H from the Left;
62: *> = 'R': apply Q or Q**H from the Right.
63: *> \endverbatim
64: *>
65: *> \param[in] TRANS
66: *> \verbatim
67: *> TRANS is CHARACTER*1
68: *> = 'N': apply Q (No transpose);
69: *> = 'C': apply Q**H (Conjugate transpose).
70: *> \endverbatim
71: *>
72: *> \param[in] M
73: *> \verbatim
74: *> M is INTEGER
75: *> The number of rows of the matrix C. M >= 0.
76: *> \endverbatim
77: *>
78: *> \param[in] N
79: *> \verbatim
80: *> N is INTEGER
81: *> The number of columns of the matrix C. N >= 0.
82: *> \endverbatim
83: *>
84: *> \param[in] N1
85: *> \param[in] N2
86: *> \verbatim
87: *> N1 is INTEGER
88: *> N2 is INTEGER
89: *> The dimension of Q12 and Q21, respectively. N1, N2 >= 0.
90: *> The following requirement must be satisfied:
91: *> N1 + N2 = M if SIDE = 'L' and N1 + N2 = N if SIDE = 'R'.
92: *> \endverbatim
93: *>
94: *> \param[in] Q
95: *> \verbatim
96: *> Q is COMPLEX*16 array, dimension
97: *> (LDQ,M) if SIDE = 'L'
98: *> (LDQ,N) if SIDE = 'R'
99: *> \endverbatim
100: *>
101: *> \param[in] LDQ
102: *> \verbatim
103: *> LDQ is INTEGER
104: *> The leading dimension of the array Q.
105: *> LDQ >= max(1,M) if SIDE = 'L'; LDQ >= max(1,N) if SIDE = 'R'.
106: *> \endverbatim
107: *>
108: *> \param[in,out] C
109: *> \verbatim
110: *> C is COMPLEX*16 array, dimension (LDC,N)
111: *> On entry, the M-by-N matrix C.
112: *> On exit, C is overwritten by Q*C or Q**H*C or C*Q**H or C*Q.
113: *> \endverbatim
114: *>
115: *> \param[in] LDC
116: *> \verbatim
117: *> LDC is INTEGER
118: *> The leading dimension of the array C. LDC >= max(1,M).
119: *> \endverbatim
120: *>
121: *> \param[out] WORK
122: *> \verbatim
123: *> WORK is COMPLEX*16 array, dimension (MAX(1,LWORK))
124: *> On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
125: *> \endverbatim
126: *>
127: *> \param[in] LWORK
128: *> \verbatim
129: *> LWORK is INTEGER
130: *> The dimension of the array WORK.
131: *> If SIDE = 'L', LWORK >= max(1,N);
132: *> if SIDE = 'R', LWORK >= max(1,M).
133: *> For optimum performance LWORK >= M*N.
134: *>
135: *> If LWORK = -1, then a workspace query is assumed; the routine
136: *> only calculates the optimal size of the WORK array, returns
137: *> this value as the first entry of the WORK array, and no error
138: *> message related to LWORK is issued by XERBLA.
139: *> \endverbatim
140: *>
141: *> \param[out] INFO
142: *> \verbatim
143: *> INFO is INTEGER
144: *> = 0: successful exit
145: *> < 0: if INFO = -i, the i-th argument had an illegal value
146: *> \endverbatim
147: *
148: *
149: * Authors:
150: * ========
151: *
152: *> \author Univ. of Tennessee
153: *> \author Univ. of California Berkeley
154: *> \author Univ. of Colorado Denver
155: *> \author NAG Ltd.
156: *
157: *> \date January 2015
158: *
159: *> \ingroup complexOTHERcomputational
160: *
161: * =====================================================================
162: SUBROUTINE ZUNM22( SIDE, TRANS, M, N, N1, N2, Q, LDQ, C, LDC,
163: $ WORK, LWORK, INFO )
164: *
1.4 bertrand 165: * -- LAPACK computational routine (version 3.7.1) --
1.1 bertrand 166: * -- LAPACK is a software package provided by Univ. of Tennessee, --
167: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
168: * January 2015
169: *
170: IMPLICIT NONE
171: *
172: * .. Scalar Arguments ..
173: CHARACTER SIDE, TRANS
174: INTEGER M, N, N1, N2, LDQ, LDC, LWORK, INFO
175: * ..
176: * .. Array Arguments ..
177: COMPLEX*16 Q( LDQ, * ), C( LDC, * ), WORK( * )
178: * ..
179: *
180: * =====================================================================
181: *
182: * .. Parameters ..
183: COMPLEX*16 ONE
184: PARAMETER ( ONE = ( 1.0D+0, 0.0D+0 ) )
185: *
186: * .. Local Scalars ..
187: LOGICAL LEFT, LQUERY, NOTRAN
188: INTEGER I, LDWORK, LEN, LWKOPT, NB, NQ, NW
189: * ..
190: * .. External Functions ..
191: LOGICAL LSAME
192: EXTERNAL LSAME
193: * ..
194: * .. External Subroutines ..
195: EXTERNAL ZGEMM, ZLACPY, ZTRMM, XERBLA
196: * ..
197: * .. Intrinsic Functions ..
198: INTRINSIC DCMPLX, MAX, MIN
199: * ..
200: * .. Executable Statements ..
201: *
202: * Test the input arguments
203: *
204: INFO = 0
205: LEFT = LSAME( SIDE, 'L' )
206: NOTRAN = LSAME( TRANS, 'N' )
207: LQUERY = ( LWORK.EQ.-1 )
208: *
209: * NQ is the order of Q;
210: * NW is the minimum dimension of WORK.
211: *
212: IF( LEFT ) THEN
213: NQ = M
214: ELSE
215: NQ = N
216: END IF
217: NW = NQ
218: IF( N1.EQ.0 .OR. N2.EQ.0 ) NW = 1
219: IF( .NOT.LEFT .AND. .NOT.LSAME( SIDE, 'R' ) ) THEN
220: INFO = -1
221: ELSE IF( .NOT.LSAME( TRANS, 'N' ) .AND. .NOT.LSAME( TRANS, 'C' ) )
222: $ THEN
223: INFO = -2
224: ELSE IF( M.LT.0 ) THEN
225: INFO = -3
226: ELSE IF( N.LT.0 ) THEN
227: INFO = -4
228: ELSE IF( N1.LT.0 .OR. N1+N2.NE.NQ ) THEN
229: INFO = -5
230: ELSE IF( N2.LT.0 ) THEN
231: INFO = -6
232: ELSE IF( LDQ.LT.MAX( 1, NQ ) ) THEN
233: INFO = -8
234: ELSE IF( LDC.LT.MAX( 1, M ) ) THEN
235: INFO = -10
236: ELSE IF( LWORK.LT.NW .AND. .NOT.LQUERY ) THEN
237: INFO = -12
238: END IF
239: *
240: IF( INFO.EQ.0 ) THEN
241: LWKOPT = M*N
242: WORK( 1 ) = DCMPLX( LWKOPT )
243: END IF
244: *
245: IF( INFO.NE.0 ) THEN
246: CALL XERBLA( 'ZUNM22', -INFO )
247: RETURN
248: ELSE IF( LQUERY ) THEN
249: RETURN
250: END IF
251: *
252: * Quick return if possible
253: *
254: IF( M.EQ.0 .OR. N.EQ.0 ) THEN
255: WORK( 1 ) = 1
256: RETURN
257: END IF
258: *
259: * Degenerate cases (N1 = 0 or N2 = 0) are handled using ZTRMM.
260: *
261: IF( N1.EQ.0 ) THEN
262: CALL ZTRMM( SIDE, 'Upper', TRANS, 'Non-Unit', M, N, ONE,
263: $ Q, LDQ, C, LDC )
264: WORK( 1 ) = ONE
265: RETURN
266: ELSE IF( N2.EQ.0 ) THEN
267: CALL ZTRMM( SIDE, 'Lower', TRANS, 'Non-Unit', M, N, ONE,
268: $ Q, LDQ, C, LDC )
269: WORK( 1 ) = ONE
270: RETURN
271: END IF
272: *
273: * Compute the largest chunk size available from the workspace.
274: *
275: NB = MAX( 1, MIN( LWORK, LWKOPT ) / NQ )
276: *
277: IF( LEFT ) THEN
278: IF( NOTRAN ) THEN
279: DO I = 1, N, NB
280: LEN = MIN( NB, N-I+1 )
281: LDWORK = M
282: *
283: * Multiply bottom part of C by Q12.
284: *
285: CALL ZLACPY( 'All', N1, LEN, C( N2+1, I ), LDC, WORK,
286: $ LDWORK )
287: CALL ZTRMM( 'Left', 'Lower', 'No Transpose', 'Non-Unit',
288: $ N1, LEN, ONE, Q( 1, N2+1 ), LDQ, WORK,
289: $ LDWORK )
290: *
291: * Multiply top part of C by Q11.
292: *
293: CALL ZGEMM( 'No Transpose', 'No Transpose', N1, LEN, N2,
294: $ ONE, Q, LDQ, C( 1, I ), LDC, ONE, WORK,
295: $ LDWORK )
296: *
297: * Multiply top part of C by Q21.
298: *
299: CALL ZLACPY( 'All', N2, LEN, C( 1, I ), LDC,
300: $ WORK( N1+1 ), LDWORK )
301: CALL ZTRMM( 'Left', 'Upper', 'No Transpose', 'Non-Unit',
302: $ N2, LEN, ONE, Q( N1+1, 1 ), LDQ,
303: $ WORK( N1+1 ), LDWORK )
304: *
305: * Multiply bottom part of C by Q22.
306: *
307: CALL ZGEMM( 'No Transpose', 'No Transpose', N2, LEN, N1,
308: $ ONE, Q( N1+1, N2+1 ), LDQ, C( N2+1, I ), LDC,
309: $ ONE, WORK( N1+1 ), LDWORK )
310: *
311: * Copy everything back.
312: *
313: CALL ZLACPY( 'All', M, LEN, WORK, LDWORK, C( 1, I ),
314: $ LDC )
315: END DO
316: ELSE
317: DO I = 1, N, NB
318: LEN = MIN( NB, N-I+1 )
319: LDWORK = M
320: *
321: * Multiply bottom part of C by Q21**H.
322: *
323: CALL ZLACPY( 'All', N2, LEN, C( N1+1, I ), LDC, WORK,
324: $ LDWORK )
325: CALL ZTRMM( 'Left', 'Upper', 'Conjugate', 'Non-Unit',
326: $ N2, LEN, ONE, Q( N1+1, 1 ), LDQ, WORK,
327: $ LDWORK )
328: *
329: * Multiply top part of C by Q11**H.
330: *
331: CALL ZGEMM( 'Conjugate', 'No Transpose', N2, LEN, N1,
332: $ ONE, Q, LDQ, C( 1, I ), LDC, ONE, WORK,
333: $ LDWORK )
334: *
335: * Multiply top part of C by Q12**H.
336: *
337: CALL ZLACPY( 'All', N1, LEN, C( 1, I ), LDC,
338: $ WORK( N2+1 ), LDWORK )
339: CALL ZTRMM( 'Left', 'Lower', 'Conjugate', 'Non-Unit',
340: $ N1, LEN, ONE, Q( 1, N2+1 ), LDQ,
341: $ WORK( N2+1 ), LDWORK )
342: *
343: * Multiply bottom part of C by Q22**H.
344: *
345: CALL ZGEMM( 'Conjugate', 'No Transpose', N1, LEN, N2,
346: $ ONE, Q( N1+1, N2+1 ), LDQ, C( N1+1, I ), LDC,
347: $ ONE, WORK( N2+1 ), LDWORK )
348: *
349: * Copy everything back.
350: *
351: CALL ZLACPY( 'All', M, LEN, WORK, LDWORK, C( 1, I ),
352: $ LDC )
353: END DO
354: END IF
355: ELSE
356: IF( NOTRAN ) THEN
357: DO I = 1, M, NB
358: LEN = MIN( NB, M-I+1 )
359: LDWORK = LEN
360: *
361: * Multiply right part of C by Q21.
362: *
363: CALL ZLACPY( 'All', LEN, N2, C( I, N1+1 ), LDC, WORK,
364: $ LDWORK )
365: CALL ZTRMM( 'Right', 'Upper', 'No Transpose', 'Non-Unit',
366: $ LEN, N2, ONE, Q( N1+1, 1 ), LDQ, WORK,
367: $ LDWORK )
368: *
369: * Multiply left part of C by Q11.
370: *
371: CALL ZGEMM( 'No Transpose', 'No Transpose', LEN, N2, N1,
372: $ ONE, C( I, 1 ), LDC, Q, LDQ, ONE, WORK,
373: $ LDWORK )
374: *
375: * Multiply left part of C by Q12.
376: *
377: CALL ZLACPY( 'All', LEN, N1, C( I, 1 ), LDC,
378: $ WORK( 1 + N2*LDWORK ), LDWORK )
379: CALL ZTRMM( 'Right', 'Lower', 'No Transpose', 'Non-Unit',
380: $ LEN, N1, ONE, Q( 1, N2+1 ), LDQ,
381: $ WORK( 1 + N2*LDWORK ), LDWORK )
382: *
383: * Multiply right part of C by Q22.
384: *
385: CALL ZGEMM( 'No Transpose', 'No Transpose', LEN, N1, N2,
386: $ ONE, C( I, N1+1 ), LDC, Q( N1+1, N2+1 ), LDQ,
387: $ ONE, WORK( 1 + N2*LDWORK ), LDWORK )
388: *
389: * Copy everything back.
390: *
391: CALL ZLACPY( 'All', LEN, N, WORK, LDWORK, C( I, 1 ),
392: $ LDC )
393: END DO
394: ELSE
395: DO I = 1, M, NB
396: LEN = MIN( NB, M-I+1 )
397: LDWORK = LEN
398: *
399: * Multiply right part of C by Q12**H.
400: *
401: CALL ZLACPY( 'All', LEN, N1, C( I, N2+1 ), LDC, WORK,
402: $ LDWORK )
403: CALL ZTRMM( 'Right', 'Lower', 'Conjugate', 'Non-Unit',
404: $ LEN, N1, ONE, Q( 1, N2+1 ), LDQ, WORK,
405: $ LDWORK )
406: *
407: * Multiply left part of C by Q11**H.
408: *
409: CALL ZGEMM( 'No Transpose', 'Conjugate', LEN, N1, N2,
410: $ ONE, C( I, 1 ), LDC, Q, LDQ, ONE, WORK,
411: $ LDWORK )
412: *
413: * Multiply left part of C by Q21**H.
414: *
415: CALL ZLACPY( 'All', LEN, N2, C( I, 1 ), LDC,
416: $ WORK( 1 + N1*LDWORK ), LDWORK )
417: CALL ZTRMM( 'Right', 'Upper', 'Conjugate', 'Non-Unit',
418: $ LEN, N2, ONE, Q( N1+1, 1 ), LDQ,
419: $ WORK( 1 + N1*LDWORK ), LDWORK )
420: *
421: * Multiply right part of C by Q22**H.
422: *
423: CALL ZGEMM( 'No Transpose', 'Conjugate', LEN, N2, N1,
424: $ ONE, C( I, N2+1 ), LDC, Q( N1+1, N2+1 ), LDQ,
425: $ ONE, WORK( 1 + N1*LDWORK ), LDWORK )
426: *
427: * Copy everything back.
428: *
429: CALL ZLACPY( 'All', LEN, N, WORK, LDWORK, C( I, 1 ),
430: $ LDC )
431: END DO
432: END IF
433: END IF
434: *
435: WORK( 1 ) = DCMPLX( LWKOPT )
436: RETURN
437: *
438: * End of ZUNM22
439: *
440: END
CVSweb interface <joel.bertrand@systella.fr>