1 *> \brief \b DORM22 multiplies a general matrix by a banded orthogonal matrix.
3 * =========== DOCUMENTATION ===========
5 * Online html documentation available at
6 * http://www.netlib.org/lapack/explore-html/
9 *> Download DORM22 + dependencies
10 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dorm22.f">
12 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dorm22.f">
14 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dorm22.f">
21 * SUBROUTINE DORM22( SIDE, TRANS, M, N, N1, N2, Q, LDQ, C, LDC,
22 * $ WORK, LWORK, INFO )
24 * .. Scalar Arguments ..
25 * CHARACTER SIDE, TRANS
26 * INTEGER M, N, N1, N2, LDQ, LDC, LWORK, INFO
28 * .. Array Arguments ..
29 * DOUBLE PRECISION Q( LDQ, * ), C( LDC, * ), WORK( * )
38 *> DORM22 overwrites the general real M-by-N matrix C with
40 *> SIDE = 'L' SIDE = 'R'
41 *> TRANS = 'N': Q * C C * Q
42 *> TRANS = 'T': Q**T * C C * Q**T
44 *> where Q is a real orthogonal matrix of order NQ, with NQ = M if
45 *> SIDE = 'L' and NQ = N if SIDE = 'R'.
46 *> The orthogonal matrix Q processes a 2-by-2 block structure
52 *> where Q12 is an N1-by-N1 lower triangular matrix and Q21 is an
53 *> N2-by-N2 upper triangular matrix.
61 *> SIDE is CHARACTER*1
62 *> = 'L': apply Q or Q**T from the Left;
63 *> = 'R': apply Q or Q**T from the Right.
68 *> TRANS is CHARACTER*1
69 *> = 'N': apply Q (No transpose);
70 *> = 'C': apply Q**T (Conjugate transpose).
76 *> The number of rows of the matrix C. M >= 0.
82 *> The number of columns of the matrix C. N >= 0.
90 *> The dimension of Q12 and Q21, respectively. N1, N2 >= 0.
91 *> The following requirement must be satisfied:
92 *> N1 + N2 = M if SIDE = 'L' and N1 + N2 = N if SIDE = 'R'.
97 *> Q is DOUBLE PRECISION array, dimension
98 *> (LDQ,M) if SIDE = 'L'
99 *> (LDQ,N) if SIDE = 'R'
105 *> The leading dimension of the array Q.
106 *> LDQ >= max(1,M) if SIDE = 'L'; LDQ >= max(1,N) if SIDE = 'R'.
111 *> C is DOUBLE PRECISION array, dimension (LDC,N)
112 *> On entry, the M-by-N matrix C.
113 *> On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q.
119 *> The leading dimension of the array C. LDC >= max(1,M).
124 *> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))
125 *> On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
131 *> The dimension of the array WORK.
132 *> If SIDE = 'L', LWORK >= max(1,N);
133 *> if SIDE = 'R', LWORK >= max(1,M).
134 *> For optimum performance LWORK >= M*N.
136 *> If LWORK = -1, then a workspace query is assumed; the routine
137 *> only calculates the optimal size of the WORK array, returns
138 *> this value as the first entry of the WORK array, and no error
139 *> message related to LWORK is issued by XERBLA.
145 *> = 0: successful exit
146 *> < 0: if INFO = -i, the i-th argument had an illegal value
153 *> \author Univ. of Tennessee
154 *> \author Univ. of California Berkeley
155 *> \author Univ. of Colorado Denver
158 *> \date January 2015
160 *> \ingroup complexOTHERcomputational
162 * =====================================================================
163 SUBROUTINE DORM22( SIDE, TRANS, M, N, N1, N2, Q, LDQ, C, LDC,
164 $ WORK, LWORK, INFO )
166 * -- LAPACK computational routine (version 3.6.0) --
167 * -- LAPACK is a software package provided by Univ. of Tennessee, --
168 * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
173 * .. Scalar Arguments ..
174 CHARACTER SIDE, TRANS
175 INTEGER M, N, N1, N2, LDQ, LDC, LWORK, INFO
177 * .. Array Arguments ..
178 DOUBLE PRECISION Q( LDQ, * ), C( LDC, * ), WORK( * )
181 * =====================================================================
185 PARAMETER ( ONE = 1.0D+0 )
187 * .. Local Scalars ..
188 LOGICAL LEFT, LQUERY, NOTRAN
189 INTEGER I, LDWORK, LEN, LWKOPT, NB, NQ, NW
191 * .. External Functions ..
195 * .. External Subroutines ..
196 EXTERNAL DGEMM, DLACPY, DTRMM, XERBLA
198 * .. Intrinsic Functions ..
199 INTRINSIC DBLE, MAX, MIN
201 * .. Executable Statements ..
203 * Test the input arguments
206 LEFT = LSAME( SIDE, 'L' )
207 NOTRAN = LSAME( TRANS, 'N' )
208 LQUERY = ( LWORK.EQ.-1 )
210 * NQ is the order of Q;
211 * NW is the minimum dimension of WORK.
219 IF( N1.EQ.0 .OR. N2.EQ.0 ) NW = 1
220 IF( .NOT.LEFT .AND. .NOT.LSAME( SIDE, 'R' ) ) THEN
222 ELSE IF( .NOT.LSAME( TRANS, 'N' ) .AND. .NOT.LSAME( TRANS, 'T' ) )
225 ELSE IF( M.LT.0 ) THEN
227 ELSE IF( N.LT.0 ) THEN
229 ELSE IF( N1.LT.0 .OR. N1+N2.NE.NQ ) THEN
231 ELSE IF( N2.LT.0 ) THEN
233 ELSE IF( LDQ.LT.MAX( 1, NQ ) ) THEN
235 ELSE IF( LDC.LT.MAX( 1, M ) ) THEN
237 ELSE IF( LWORK.LT.NW .AND. .NOT.LQUERY ) THEN
243 WORK( 1 ) = DBLE( LWKOPT )
247 CALL XERBLA( 'DORM22', -INFO )
249 ELSE IF( LQUERY ) THEN
253 * Quick return if possible
255 IF( M.EQ.0 .OR. N.EQ.0 ) THEN
260 * Degenerate cases (N1 = 0 or N2 = 0) are handled using DTRMM.
263 CALL DTRMM( SIDE, 'Upper', TRANS, 'Non-Unit', M, N, ONE,
267 ELSE IF( N2.EQ.0 ) THEN
268 CALL DTRMM( SIDE, 'Lower', TRANS, 'Non-Unit', M, N, ONE,
274 * Compute the largest chunk size available from the workspace.
276 NB = MAX( 1, MIN( LWORK, LWKOPT ) / NQ )
281 LEN = MIN( NB, N-I+1 )
284 * Multiply bottom part of C by Q12.
286 CALL DLACPY( 'All', N1, LEN, C( N2+1, I ), LDC, WORK,
288 CALL DTRMM( 'Left', 'Lower', 'No Transpose', 'Non-Unit',
289 $ N1, LEN, ONE, Q( 1, N2+1 ), LDQ, WORK,
292 * Multiply top part of C by Q11.
294 CALL DGEMM( 'No Transpose', 'No Transpose', N1, LEN, N2,
295 $ ONE, Q, LDQ, C( 1, I ), LDC, ONE, WORK,
298 * Multiply top part of C by Q21.
300 CALL DLACPY( 'All', N2, LEN, C( 1, I ), LDC,
301 $ WORK( N1+1 ), LDWORK )
302 CALL DTRMM( 'Left', 'Upper', 'No Transpose', 'Non-Unit',
303 $ N2, LEN, ONE, Q( N1+1, 1 ), LDQ,
304 $ WORK( N1+1 ), LDWORK )
306 * Multiply bottom part of C by Q22.
308 CALL DGEMM( 'No Transpose', 'No Transpose', N2, LEN, N1,
309 $ ONE, Q( N1+1, N2+1 ), LDQ, C( N2+1, I ), LDC,
310 $ ONE, WORK( N1+1 ), LDWORK )
312 * Copy everything back.
314 CALL DLACPY( 'All', M, LEN, WORK, LDWORK, C( 1, I ),
319 LEN = MIN( NB, N-I+1 )
322 * Multiply bottom part of C by Q21**T.
324 CALL DLACPY( 'All', N2, LEN, C( N1+1, I ), LDC, WORK,
326 CALL DTRMM( 'Left', 'Upper', 'Transpose', 'Non-Unit',
327 $ N2, LEN, ONE, Q( N1+1, 1 ), LDQ, WORK,
330 * Multiply top part of C by Q11**T.
332 CALL DGEMM( 'Transpose', 'No Transpose', N2, LEN, N1,
333 $ ONE, Q, LDQ, C( 1, I ), LDC, ONE, WORK,
336 * Multiply top part of C by Q12**T.
338 CALL DLACPY( 'All', N1, LEN, C( 1, I ), LDC,
339 $ WORK( N2+1 ), LDWORK )
340 CALL DTRMM( 'Left', 'Lower', 'Transpose', 'Non-Unit',
341 $ N1, LEN, ONE, Q( 1, N2+1 ), LDQ,
342 $ WORK( N2+1 ), LDWORK )
344 * Multiply bottom part of C by Q22**T.
346 CALL DGEMM( 'Transpose', 'No Transpose', N1, LEN, N2,
347 $ ONE, Q( N1+1, N2+1 ), LDQ, C( N1+1, I ), LDC,
348 $ ONE, WORK( N2+1 ), LDWORK )
350 * Copy everything back.
352 CALL DLACPY( 'All', M, LEN, WORK, LDWORK, C( 1, I ),
359 LEN = MIN( NB, M-I+1 )
362 * Multiply right part of C by Q21.
364 CALL DLACPY( 'All', LEN, N2, C( I, N1+1 ), LDC, WORK,
366 CALL DTRMM( 'Right', 'Upper', 'No Transpose', 'Non-Unit',
367 $ LEN, N2, ONE, Q( N1+1, 1 ), LDQ, WORK,
370 * Multiply left part of C by Q11.
372 CALL DGEMM( 'No Transpose', 'No Transpose', LEN, N2, N1,
373 $ ONE, C( I, 1 ), LDC, Q, LDQ, ONE, WORK,
376 * Multiply left part of C by Q12.
378 CALL DLACPY( 'All', LEN, N1, C( I, 1 ), LDC,
379 $ WORK( 1 + N2*LDWORK ), LDWORK )
380 CALL DTRMM( 'Right', 'Lower', 'No Transpose', 'Non-Unit',
381 $ LEN, N1, ONE, Q( 1, N2+1 ), LDQ,
382 $ WORK( 1 + N2*LDWORK ), LDWORK )
384 * Multiply right part of C by Q22.
386 CALL DGEMM( 'No Transpose', 'No Transpose', LEN, N1, N2,
387 $ ONE, C( I, N1+1 ), LDC, Q( N1+1, N2+1 ), LDQ,
388 $ ONE, WORK( 1 + N2*LDWORK ), LDWORK )
390 * Copy everything back.
392 CALL DLACPY( 'All', LEN, N, WORK, LDWORK, C( I, 1 ),
397 LEN = MIN( NB, M-I+1 )
400 * Multiply right part of C by Q12**T.
402 CALL DLACPY( 'All', LEN, N1, C( I, N2+1 ), LDC, WORK,
404 CALL DTRMM( 'Right', 'Lower', 'Transpose', 'Non-Unit',
405 $ LEN, N1, ONE, Q( 1, N2+1 ), LDQ, WORK,
408 * Multiply left part of C by Q11**T.
410 CALL DGEMM( 'No Transpose', 'Transpose', LEN, N1, N2,
411 $ ONE, C( I, 1 ), LDC, Q, LDQ, ONE, WORK,
414 * Multiply left part of C by Q21**T.
416 CALL DLACPY( 'All', LEN, N2, C( I, 1 ), LDC,
417 $ WORK( 1 + N1*LDWORK ), LDWORK )
418 CALL DTRMM( 'Right', 'Upper', 'Transpose', 'Non-Unit',
419 $ LEN, N2, ONE, Q( N1+1, 1 ), LDQ,
420 $ WORK( 1 + N1*LDWORK ), LDWORK )
422 * Multiply right part of C by Q22**T.
424 CALL DGEMM( 'No Transpose', 'Transpose', LEN, N2, N1,
425 $ ONE, C( I, N2+1 ), LDC, Q( N1+1, N2+1 ), LDQ,
426 $ ONE, WORK( 1 + N1*LDWORK ), LDWORK )
428 * Copy everything back.
430 CALL DLACPY( 'All', LEN, N, WORK, LDWORK, C( I, 1 ),
436 WORK( 1 ) = DBLE( LWKOPT )