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