1: *> \brief \b DTRSYL
2: *
3: * =========== DOCUMENTATION ===========
4: *
5: * Online html documentation available at
6: * http://www.netlib.org/lapack/explore-html/
7: *
8: *> \htmlonly
9: *> Download DTRSYL + dependencies
10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrsyl.f">
11: *> [TGZ]</a>
12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrsyl.f">
13: *> [ZIP]</a>
14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrsyl.f">
15: *> [TXT]</a>
16: *> \endhtmlonly
17: *
18: * Definition:
19: * ===========
20: *
21: * SUBROUTINE DTRSYL( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB, C,
22: * LDC, SCALE, INFO )
23: *
24: * .. Scalar Arguments ..
25: * CHARACTER TRANA, TRANB
26: * INTEGER INFO, ISGN, LDA, LDB, LDC, M, N
27: * DOUBLE PRECISION SCALE
28: * ..
29: * .. Array Arguments ..
30: * DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * )
31: * ..
32: *
33: *
34: *> \par Purpose:
35: * =============
36: *>
37: *> \verbatim
38: *>
39: *> DTRSYL solves the real Sylvester matrix equation:
40: *>
41: *> op(A)*X + X*op(B) = scale*C or
42: *> op(A)*X - X*op(B) = scale*C,
43: *>
44: *> where op(A) = A or A**T, and A and B are both upper quasi-
45: *> triangular. A is M-by-M and B is N-by-N; the right hand side C and
46: *> the solution X are M-by-N; and scale is an output scale factor, set
47: *> <= 1 to avoid overflow in X.
48: *>
49: *> A and B must be in Schur canonical form (as returned by DHSEQR), that
50: *> is, block upper triangular with 1-by-1 and 2-by-2 diagonal blocks;
51: *> each 2-by-2 diagonal block has its diagonal elements equal and its
52: *> off-diagonal elements of opposite sign.
53: *> \endverbatim
54: *
55: * Arguments:
56: * ==========
57: *
58: *> \param[in] TRANA
59: *> \verbatim
60: *> TRANA is CHARACTER*1
61: *> Specifies the option op(A):
62: *> = 'N': op(A) = A (No transpose)
63: *> = 'T': op(A) = A**T (Transpose)
64: *> = 'C': op(A) = A**H (Conjugate transpose = Transpose)
65: *> \endverbatim
66: *>
67: *> \param[in] TRANB
68: *> \verbatim
69: *> TRANB is CHARACTER*1
70: *> Specifies the option op(B):
71: *> = 'N': op(B) = B (No transpose)
72: *> = 'T': op(B) = B**T (Transpose)
73: *> = 'C': op(B) = B**H (Conjugate transpose = Transpose)
74: *> \endverbatim
75: *>
76: *> \param[in] ISGN
77: *> \verbatim
78: *> ISGN is INTEGER
79: *> Specifies the sign in the equation:
80: *> = +1: solve op(A)*X + X*op(B) = scale*C
81: *> = -1: solve op(A)*X - X*op(B) = scale*C
82: *> \endverbatim
83: *>
84: *> \param[in] M
85: *> \verbatim
86: *> M is INTEGER
87: *> The order of the matrix A, and the number of rows in the
88: *> matrices X and C. M >= 0.
89: *> \endverbatim
90: *>
91: *> \param[in] N
92: *> \verbatim
93: *> N is INTEGER
94: *> The order of the matrix B, and the number of columns in the
95: *> matrices X and C. N >= 0.
96: *> \endverbatim
97: *>
98: *> \param[in] A
99: *> \verbatim
100: *> A is DOUBLE PRECISION array, dimension (LDA,M)
101: *> The upper quasi-triangular matrix A, in Schur canonical form.
102: *> \endverbatim
103: *>
104: *> \param[in] LDA
105: *> \verbatim
106: *> LDA is INTEGER
107: *> The leading dimension of the array A. LDA >= max(1,M).
108: *> \endverbatim
109: *>
110: *> \param[in] B
111: *> \verbatim
112: *> B is DOUBLE PRECISION array, dimension (LDB,N)
113: *> The upper quasi-triangular matrix B, in Schur canonical form.
114: *> \endverbatim
115: *>
116: *> \param[in] LDB
117: *> \verbatim
118: *> LDB is INTEGER
119: *> The leading dimension of the array B. LDB >= max(1,N).
120: *> \endverbatim
121: *>
122: *> \param[in,out] C
123: *> \verbatim
124: *> C is DOUBLE PRECISION array, dimension (LDC,N)
125: *> On entry, the M-by-N right hand side matrix C.
126: *> On exit, C is overwritten by the solution matrix X.
127: *> \endverbatim
128: *>
129: *> \param[in] LDC
130: *> \verbatim
131: *> LDC is INTEGER
132: *> The leading dimension of the array C. LDC >= max(1,M)
133: *> \endverbatim
134: *>
135: *> \param[out] SCALE
136: *> \verbatim
137: *> SCALE is DOUBLE PRECISION
138: *> The scale factor, scale, set <= 1 to avoid overflow in X.
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: *> = 1: A and B have common or very close eigenvalues; perturbed
147: *> values were used to solve the equation (but the matrices
148: *> A and B are unchanged).
149: *> \endverbatim
150: *
151: * Authors:
152: * ========
153: *
154: *> \author Univ. of Tennessee
155: *> \author Univ. of California Berkeley
156: *> \author Univ. of Colorado Denver
157: *> \author NAG Ltd.
158: *
159: *> \date November 2011
160: *
161: *> \ingroup doubleSYcomputational
162: *
163: * =====================================================================
164: SUBROUTINE DTRSYL( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB, C,
165: $ LDC, SCALE, INFO )
166: *
167: * -- LAPACK computational routine (version 3.4.0) --
168: * -- LAPACK is a software package provided by Univ. of Tennessee, --
169: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
170: * November 2011
171: *
172: * .. Scalar Arguments ..
173: CHARACTER TRANA, TRANB
174: INTEGER INFO, ISGN, LDA, LDB, LDC, M, N
175: DOUBLE PRECISION SCALE
176: * ..
177: * .. Array Arguments ..
178: DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * )
179: * ..
180: *
181: * =====================================================================
182: *
183: * .. Parameters ..
184: DOUBLE PRECISION ZERO, ONE
185: PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
186: * ..
187: * .. Local Scalars ..
188: LOGICAL NOTRNA, NOTRNB
189: INTEGER IERR, J, K, K1, K2, KNEXT, L, L1, L2, LNEXT
190: DOUBLE PRECISION A11, BIGNUM, DA11, DB, EPS, SCALOC, SGN, SMIN,
191: $ SMLNUM, SUML, SUMR, XNORM
192: * ..
193: * .. Local Arrays ..
194: DOUBLE PRECISION DUM( 1 ), VEC( 2, 2 ), X( 2, 2 )
195: * ..
196: * .. External Functions ..
197: LOGICAL LSAME
198: DOUBLE PRECISION DDOT, DLAMCH, DLANGE
199: EXTERNAL LSAME, DDOT, DLAMCH, DLANGE
200: * ..
201: * .. External Subroutines ..
202: EXTERNAL DLABAD, DLALN2, DLASY2, DSCAL, XERBLA
203: * ..
204: * .. Intrinsic Functions ..
205: INTRINSIC ABS, DBLE, MAX, MIN
206: * ..
207: * .. Executable Statements ..
208: *
209: * Decode and Test input parameters
210: *
211: NOTRNA = LSAME( TRANA, 'N' )
212: NOTRNB = LSAME( TRANB, 'N' )
213: *
214: INFO = 0
215: IF( .NOT.NOTRNA .AND. .NOT.LSAME( TRANA, 'T' ) .AND. .NOT.
216: $ LSAME( TRANA, 'C' ) ) THEN
217: INFO = -1
218: ELSE IF( .NOT.NOTRNB .AND. .NOT.LSAME( TRANB, 'T' ) .AND. .NOT.
219: $ LSAME( TRANB, 'C' ) ) THEN
220: INFO = -2
221: ELSE IF( ISGN.NE.1 .AND. ISGN.NE.-1 ) THEN
222: INFO = -3
223: ELSE IF( M.LT.0 ) THEN
224: INFO = -4
225: ELSE IF( N.LT.0 ) THEN
226: INFO = -5
227: ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
228: INFO = -7
229: ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
230: INFO = -9
231: ELSE IF( LDC.LT.MAX( 1, M ) ) THEN
232: INFO = -11
233: END IF
234: IF( INFO.NE.0 ) THEN
235: CALL XERBLA( 'DTRSYL', -INFO )
236: RETURN
237: END IF
238: *
239: * Quick return if possible
240: *
241: SCALE = ONE
242: IF( M.EQ.0 .OR. N.EQ.0 )
243: $ RETURN
244: *
245: * Set constants to control overflow
246: *
247: EPS = DLAMCH( 'P' )
248: SMLNUM = DLAMCH( 'S' )
249: BIGNUM = ONE / SMLNUM
250: CALL DLABAD( SMLNUM, BIGNUM )
251: SMLNUM = SMLNUM*DBLE( M*N ) / EPS
252: BIGNUM = ONE / SMLNUM
253: *
254: SMIN = MAX( SMLNUM, EPS*DLANGE( 'M', M, M, A, LDA, DUM ),
255: $ EPS*DLANGE( 'M', N, N, B, LDB, DUM ) )
256: *
257: SGN = ISGN
258: *
259: IF( NOTRNA .AND. NOTRNB ) THEN
260: *
261: * Solve A*X + ISGN*X*B = scale*C.
262: *
263: * The (K,L)th block of X is determined starting from
264: * bottom-left corner column by column by
265: *
266: * A(K,K)*X(K,L) + ISGN*X(K,L)*B(L,L) = C(K,L) - R(K,L)
267: *
268: * Where
269: * M L-1
270: * R(K,L) = SUM [A(K,I)*X(I,L)] + ISGN*SUM [X(K,J)*B(J,L)].
271: * I=K+1 J=1
272: *
273: * Start column loop (index = L)
274: * L1 (L2) : column index of the first (first) row of X(K,L).
275: *
276: LNEXT = 1
277: DO 60 L = 1, N
278: IF( L.LT.LNEXT )
279: $ GO TO 60
280: IF( L.EQ.N ) THEN
281: L1 = L
282: L2 = L
283: ELSE
284: IF( B( L+1, L ).NE.ZERO ) THEN
285: L1 = L
286: L2 = L + 1
287: LNEXT = L + 2
288: ELSE
289: L1 = L
290: L2 = L
291: LNEXT = L + 1
292: END IF
293: END IF
294: *
295: * Start row loop (index = K)
296: * K1 (K2): row index of the first (last) row of X(K,L).
297: *
298: KNEXT = M
299: DO 50 K = M, 1, -1
300: IF( K.GT.KNEXT )
301: $ GO TO 50
302: IF( K.EQ.1 ) THEN
303: K1 = K
304: K2 = K
305: ELSE
306: IF( A( K, K-1 ).NE.ZERO ) THEN
307: K1 = K - 1
308: K2 = K
309: KNEXT = K - 2
310: ELSE
311: K1 = K
312: K2 = K
313: KNEXT = K - 1
314: END IF
315: END IF
316: *
317: IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
318: SUML = DDOT( M-K1, A( K1, MIN( K1+1, M ) ), LDA,
319: $ C( MIN( K1+1, M ), L1 ), 1 )
320: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
321: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
322: SCALOC = ONE
323: *
324: A11 = A( K1, K1 ) + SGN*B( L1, L1 )
325: DA11 = ABS( A11 )
326: IF( DA11.LE.SMIN ) THEN
327: A11 = SMIN
328: DA11 = SMIN
329: INFO = 1
330: END IF
331: DB = ABS( VEC( 1, 1 ) )
332: IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
333: IF( DB.GT.BIGNUM*DA11 )
334: $ SCALOC = ONE / DB
335: END IF
336: X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
337: *
338: IF( SCALOC.NE.ONE ) THEN
339: DO 10 J = 1, N
340: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
341: 10 CONTINUE
342: SCALE = SCALE*SCALOC
343: END IF
344: C( K1, L1 ) = X( 1, 1 )
345: *
346: ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
347: *
348: SUML = DDOT( M-K2, A( K1, MIN( K2+1, M ) ), LDA,
349: $ C( MIN( K2+1, M ), L1 ), 1 )
350: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
351: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
352: *
353: SUML = DDOT( M-K2, A( K2, MIN( K2+1, M ) ), LDA,
354: $ C( MIN( K2+1, M ), L1 ), 1 )
355: SUMR = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L1 ), 1 )
356: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
357: *
358: CALL DLALN2( .FALSE., 2, 1, SMIN, ONE, A( K1, K1 ),
359: $ LDA, ONE, ONE, VEC, 2, -SGN*B( L1, L1 ),
360: $ ZERO, X, 2, SCALOC, XNORM, IERR )
361: IF( IERR.NE.0 )
362: $ INFO = 1
363: *
364: IF( SCALOC.NE.ONE ) THEN
365: DO 20 J = 1, N
366: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
367: 20 CONTINUE
368: SCALE = SCALE*SCALOC
369: END IF
370: C( K1, L1 ) = X( 1, 1 )
371: C( K2, L1 ) = X( 2, 1 )
372: *
373: ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
374: *
375: SUML = DDOT( M-K1, A( K1, MIN( K1+1, M ) ), LDA,
376: $ C( MIN( K1+1, M ), L1 ), 1 )
377: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
378: VEC( 1, 1 ) = SGN*( C( K1, L1 )-( SUML+SGN*SUMR ) )
379: *
380: SUML = DDOT( M-K1, A( K1, MIN( K1+1, M ) ), LDA,
381: $ C( MIN( K1+1, M ), L2 ), 1 )
382: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L2 ), 1 )
383: VEC( 2, 1 ) = SGN*( C( K1, L2 )-( SUML+SGN*SUMR ) )
384: *
385: CALL DLALN2( .TRUE., 2, 1, SMIN, ONE, B( L1, L1 ),
386: $ LDB, ONE, ONE, VEC, 2, -SGN*A( K1, K1 ),
387: $ ZERO, X, 2, SCALOC, XNORM, IERR )
388: IF( IERR.NE.0 )
389: $ INFO = 1
390: *
391: IF( SCALOC.NE.ONE ) THEN
392: DO 30 J = 1, N
393: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
394: 30 CONTINUE
395: SCALE = SCALE*SCALOC
396: END IF
397: C( K1, L1 ) = X( 1, 1 )
398: C( K1, L2 ) = X( 2, 1 )
399: *
400: ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
401: *
402: SUML = DDOT( M-K2, A( K1, MIN( K2+1, M ) ), LDA,
403: $ C( MIN( K2+1, M ), L1 ), 1 )
404: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
405: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
406: *
407: SUML = DDOT( M-K2, A( K1, MIN( K2+1, M ) ), LDA,
408: $ C( MIN( K2+1, M ), L2 ), 1 )
409: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L2 ), 1 )
410: VEC( 1, 2 ) = C( K1, L2 ) - ( SUML+SGN*SUMR )
411: *
412: SUML = DDOT( M-K2, A( K2, MIN( K2+1, M ) ), LDA,
413: $ C( MIN( K2+1, M ), L1 ), 1 )
414: SUMR = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L1 ), 1 )
415: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
416: *
417: SUML = DDOT( M-K2, A( K2, MIN( K2+1, M ) ), LDA,
418: $ C( MIN( K2+1, M ), L2 ), 1 )
419: SUMR = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L2 ), 1 )
420: VEC( 2, 2 ) = C( K2, L2 ) - ( SUML+SGN*SUMR )
421: *
422: CALL DLASY2( .FALSE., .FALSE., ISGN, 2, 2,
423: $ A( K1, K1 ), LDA, B( L1, L1 ), LDB, VEC,
424: $ 2, SCALOC, X, 2, XNORM, IERR )
425: IF( IERR.NE.0 )
426: $ INFO = 1
427: *
428: IF( SCALOC.NE.ONE ) THEN
429: DO 40 J = 1, N
430: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
431: 40 CONTINUE
432: SCALE = SCALE*SCALOC
433: END IF
434: C( K1, L1 ) = X( 1, 1 )
435: C( K1, L2 ) = X( 1, 2 )
436: C( K2, L1 ) = X( 2, 1 )
437: C( K2, L2 ) = X( 2, 2 )
438: END IF
439: *
440: 50 CONTINUE
441: *
442: 60 CONTINUE
443: *
444: ELSE IF( .NOT.NOTRNA .AND. NOTRNB ) THEN
445: *
446: * Solve A**T *X + ISGN*X*B = scale*C.
447: *
448: * The (K,L)th block of X is determined starting from
449: * upper-left corner column by column by
450: *
451: * A(K,K)**T*X(K,L) + ISGN*X(K,L)*B(L,L) = C(K,L) - R(K,L)
452: *
453: * Where
454: * K-1 T L-1
455: * R(K,L) = SUM [A(I,K)**T*X(I,L)] +ISGN*SUM [X(K,J)*B(J,L)]
456: * I=1 J=1
457: *
458: * Start column loop (index = L)
459: * L1 (L2): column index of the first (last) row of X(K,L)
460: *
461: LNEXT = 1
462: DO 120 L = 1, N
463: IF( L.LT.LNEXT )
464: $ GO TO 120
465: IF( L.EQ.N ) THEN
466: L1 = L
467: L2 = L
468: ELSE
469: IF( B( L+1, L ).NE.ZERO ) THEN
470: L1 = L
471: L2 = L + 1
472: LNEXT = L + 2
473: ELSE
474: L1 = L
475: L2 = L
476: LNEXT = L + 1
477: END IF
478: END IF
479: *
480: * Start row loop (index = K)
481: * K1 (K2): row index of the first (last) row of X(K,L)
482: *
483: KNEXT = 1
484: DO 110 K = 1, M
485: IF( K.LT.KNEXT )
486: $ GO TO 110
487: IF( K.EQ.M ) THEN
488: K1 = K
489: K2 = K
490: ELSE
491: IF( A( K+1, K ).NE.ZERO ) THEN
492: K1 = K
493: K2 = K + 1
494: KNEXT = K + 2
495: ELSE
496: K1 = K
497: K2 = K
498: KNEXT = K + 1
499: END IF
500: END IF
501: *
502: IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
503: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
504: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
505: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
506: SCALOC = ONE
507: *
508: A11 = A( K1, K1 ) + SGN*B( L1, L1 )
509: DA11 = ABS( A11 )
510: IF( DA11.LE.SMIN ) THEN
511: A11 = SMIN
512: DA11 = SMIN
513: INFO = 1
514: END IF
515: DB = ABS( VEC( 1, 1 ) )
516: IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
517: IF( DB.GT.BIGNUM*DA11 )
518: $ SCALOC = ONE / DB
519: END IF
520: X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
521: *
522: IF( SCALOC.NE.ONE ) THEN
523: DO 70 J = 1, N
524: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
525: 70 CONTINUE
526: SCALE = SCALE*SCALOC
527: END IF
528: C( K1, L1 ) = X( 1, 1 )
529: *
530: ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
531: *
532: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
533: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
534: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
535: *
536: SUML = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
537: SUMR = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L1 ), 1 )
538: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
539: *
540: CALL DLALN2( .TRUE., 2, 1, SMIN, ONE, A( K1, K1 ),
541: $ LDA, ONE, ONE, VEC, 2, -SGN*B( L1, L1 ),
542: $ ZERO, X, 2, SCALOC, XNORM, IERR )
543: IF( IERR.NE.0 )
544: $ INFO = 1
545: *
546: IF( SCALOC.NE.ONE ) THEN
547: DO 80 J = 1, N
548: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
549: 80 CONTINUE
550: SCALE = SCALE*SCALOC
551: END IF
552: C( K1, L1 ) = X( 1, 1 )
553: C( K2, L1 ) = X( 2, 1 )
554: *
555: ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
556: *
557: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
558: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
559: VEC( 1, 1 ) = SGN*( C( K1, L1 )-( SUML+SGN*SUMR ) )
560: *
561: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
562: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L2 ), 1 )
563: VEC( 2, 1 ) = SGN*( C( K1, L2 )-( SUML+SGN*SUMR ) )
564: *
565: CALL DLALN2( .TRUE., 2, 1, SMIN, ONE, B( L1, L1 ),
566: $ LDB, ONE, ONE, VEC, 2, -SGN*A( K1, K1 ),
567: $ ZERO, X, 2, SCALOC, XNORM, IERR )
568: IF( IERR.NE.0 )
569: $ INFO = 1
570: *
571: IF( SCALOC.NE.ONE ) THEN
572: DO 90 J = 1, N
573: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
574: 90 CONTINUE
575: SCALE = SCALE*SCALOC
576: END IF
577: C( K1, L1 ) = X( 1, 1 )
578: C( K1, L2 ) = X( 2, 1 )
579: *
580: ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
581: *
582: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
583: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L1 ), 1 )
584: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
585: *
586: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
587: SUMR = DDOT( L1-1, C( K1, 1 ), LDC, B( 1, L2 ), 1 )
588: VEC( 1, 2 ) = C( K1, L2 ) - ( SUML+SGN*SUMR )
589: *
590: SUML = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
591: SUMR = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L1 ), 1 )
592: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
593: *
594: SUML = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L2 ), 1 )
595: SUMR = DDOT( L1-1, C( K2, 1 ), LDC, B( 1, L2 ), 1 )
596: VEC( 2, 2 ) = C( K2, L2 ) - ( SUML+SGN*SUMR )
597: *
598: CALL DLASY2( .TRUE., .FALSE., ISGN, 2, 2, A( K1, K1 ),
599: $ LDA, B( L1, L1 ), LDB, VEC, 2, SCALOC, X,
600: $ 2, XNORM, IERR )
601: IF( IERR.NE.0 )
602: $ INFO = 1
603: *
604: IF( SCALOC.NE.ONE ) THEN
605: DO 100 J = 1, N
606: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
607: 100 CONTINUE
608: SCALE = SCALE*SCALOC
609: END IF
610: C( K1, L1 ) = X( 1, 1 )
611: C( K1, L2 ) = X( 1, 2 )
612: C( K2, L1 ) = X( 2, 1 )
613: C( K2, L2 ) = X( 2, 2 )
614: END IF
615: *
616: 110 CONTINUE
617: 120 CONTINUE
618: *
619: ELSE IF( .NOT.NOTRNA .AND. .NOT.NOTRNB ) THEN
620: *
621: * Solve A**T*X + ISGN*X*B**T = scale*C.
622: *
623: * The (K,L)th block of X is determined starting from
624: * top-right corner column by column by
625: *
626: * A(K,K)**T*X(K,L) + ISGN*X(K,L)*B(L,L)**T = C(K,L) - R(K,L)
627: *
628: * Where
629: * K-1 N
630: * R(K,L) = SUM [A(I,K)**T*X(I,L)] + ISGN*SUM [X(K,J)*B(L,J)**T].
631: * I=1 J=L+1
632: *
633: * Start column loop (index = L)
634: * L1 (L2): column index of the first (last) row of X(K,L)
635: *
636: LNEXT = N
637: DO 180 L = N, 1, -1
638: IF( L.GT.LNEXT )
639: $ GO TO 180
640: IF( L.EQ.1 ) THEN
641: L1 = L
642: L2 = L
643: ELSE
644: IF( B( L, L-1 ).NE.ZERO ) THEN
645: L1 = L - 1
646: L2 = L
647: LNEXT = L - 2
648: ELSE
649: L1 = L
650: L2 = L
651: LNEXT = L - 1
652: END IF
653: END IF
654: *
655: * Start row loop (index = K)
656: * K1 (K2): row index of the first (last) row of X(K,L)
657: *
658: KNEXT = 1
659: DO 170 K = 1, M
660: IF( K.LT.KNEXT )
661: $ GO TO 170
662: IF( K.EQ.M ) THEN
663: K1 = K
664: K2 = K
665: ELSE
666: IF( A( K+1, K ).NE.ZERO ) THEN
667: K1 = K
668: K2 = K + 1
669: KNEXT = K + 2
670: ELSE
671: K1 = K
672: K2 = K
673: KNEXT = K + 1
674: END IF
675: END IF
676: *
677: IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
678: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
679: SUMR = DDOT( N-L1, C( K1, MIN( L1+1, N ) ), LDC,
680: $ B( L1, MIN( L1+1, N ) ), LDB )
681: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
682: SCALOC = ONE
683: *
684: A11 = A( K1, K1 ) + SGN*B( L1, L1 )
685: DA11 = ABS( A11 )
686: IF( DA11.LE.SMIN ) THEN
687: A11 = SMIN
688: DA11 = SMIN
689: INFO = 1
690: END IF
691: DB = ABS( VEC( 1, 1 ) )
692: IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
693: IF( DB.GT.BIGNUM*DA11 )
694: $ SCALOC = ONE / DB
695: END IF
696: X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
697: *
698: IF( SCALOC.NE.ONE ) THEN
699: DO 130 J = 1, N
700: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
701: 130 CONTINUE
702: SCALE = SCALE*SCALOC
703: END IF
704: C( K1, L1 ) = X( 1, 1 )
705: *
706: ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
707: *
708: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
709: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
710: $ B( L1, MIN( L2+1, N ) ), LDB )
711: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
712: *
713: SUML = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
714: SUMR = DDOT( N-L2, C( K2, MIN( L2+1, N ) ), LDC,
715: $ B( L1, MIN( L2+1, N ) ), LDB )
716: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
717: *
718: CALL DLALN2( .TRUE., 2, 1, SMIN, ONE, A( K1, K1 ),
719: $ LDA, ONE, ONE, VEC, 2, -SGN*B( L1, L1 ),
720: $ ZERO, X, 2, SCALOC, XNORM, IERR )
721: IF( IERR.NE.0 )
722: $ INFO = 1
723: *
724: IF( SCALOC.NE.ONE ) THEN
725: DO 140 J = 1, N
726: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
727: 140 CONTINUE
728: SCALE = SCALE*SCALOC
729: END IF
730: C( K1, L1 ) = X( 1, 1 )
731: C( K2, L1 ) = X( 2, 1 )
732: *
733: ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
734: *
735: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
736: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
737: $ B( L1, MIN( L2+1, N ) ), LDB )
738: VEC( 1, 1 ) = SGN*( C( K1, L1 )-( SUML+SGN*SUMR ) )
739: *
740: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
741: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
742: $ B( L2, MIN( L2+1, N ) ), LDB )
743: VEC( 2, 1 ) = SGN*( C( K1, L2 )-( SUML+SGN*SUMR ) )
744: *
745: CALL DLALN2( .FALSE., 2, 1, SMIN, ONE, B( L1, L1 ),
746: $ LDB, ONE, ONE, VEC, 2, -SGN*A( K1, K1 ),
747: $ ZERO, X, 2, SCALOC, XNORM, IERR )
748: IF( IERR.NE.0 )
749: $ INFO = 1
750: *
751: IF( SCALOC.NE.ONE ) THEN
752: DO 150 J = 1, N
753: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
754: 150 CONTINUE
755: SCALE = SCALE*SCALOC
756: END IF
757: C( K1, L1 ) = X( 1, 1 )
758: C( K1, L2 ) = X( 2, 1 )
759: *
760: ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
761: *
762: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L1 ), 1 )
763: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
764: $ B( L1, MIN( L2+1, N ) ), LDB )
765: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
766: *
767: SUML = DDOT( K1-1, A( 1, K1 ), 1, C( 1, L2 ), 1 )
768: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
769: $ B( L2, MIN( L2+1, N ) ), LDB )
770: VEC( 1, 2 ) = C( K1, L2 ) - ( SUML+SGN*SUMR )
771: *
772: SUML = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L1 ), 1 )
773: SUMR = DDOT( N-L2, C( K2, MIN( L2+1, N ) ), LDC,
774: $ B( L1, MIN( L2+1, N ) ), LDB )
775: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
776: *
777: SUML = DDOT( K1-1, A( 1, K2 ), 1, C( 1, L2 ), 1 )
778: SUMR = DDOT( N-L2, C( K2, MIN( L2+1, N ) ), LDC,
779: $ B( L2, MIN( L2+1, N ) ), LDB )
780: VEC( 2, 2 ) = C( K2, L2 ) - ( SUML+SGN*SUMR )
781: *
782: CALL DLASY2( .TRUE., .TRUE., ISGN, 2, 2, A( K1, K1 ),
783: $ LDA, B( L1, L1 ), LDB, VEC, 2, SCALOC, X,
784: $ 2, XNORM, IERR )
785: IF( IERR.NE.0 )
786: $ INFO = 1
787: *
788: IF( SCALOC.NE.ONE ) THEN
789: DO 160 J = 1, N
790: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
791: 160 CONTINUE
792: SCALE = SCALE*SCALOC
793: END IF
794: C( K1, L1 ) = X( 1, 1 )
795: C( K1, L2 ) = X( 1, 2 )
796: C( K2, L1 ) = X( 2, 1 )
797: C( K2, L2 ) = X( 2, 2 )
798: END IF
799: *
800: 170 CONTINUE
801: 180 CONTINUE
802: *
803: ELSE IF( NOTRNA .AND. .NOT.NOTRNB ) THEN
804: *
805: * Solve A*X + ISGN*X*B**T = scale*C.
806: *
807: * The (K,L)th block of X is determined starting from
808: * bottom-right corner column by column by
809: *
810: * A(K,K)*X(K,L) + ISGN*X(K,L)*B(L,L)**T = C(K,L) - R(K,L)
811: *
812: * Where
813: * M N
814: * R(K,L) = SUM [A(K,I)*X(I,L)] + ISGN*SUM [X(K,J)*B(L,J)**T].
815: * I=K+1 J=L+1
816: *
817: * Start column loop (index = L)
818: * L1 (L2): column index of the first (last) row of X(K,L)
819: *
820: LNEXT = N
821: DO 240 L = N, 1, -1
822: IF( L.GT.LNEXT )
823: $ GO TO 240
824: IF( L.EQ.1 ) THEN
825: L1 = L
826: L2 = L
827: ELSE
828: IF( B( L, L-1 ).NE.ZERO ) THEN
829: L1 = L - 1
830: L2 = L
831: LNEXT = L - 2
832: ELSE
833: L1 = L
834: L2 = L
835: LNEXT = L - 1
836: END IF
837: END IF
838: *
839: * Start row loop (index = K)
840: * K1 (K2): row index of the first (last) row of X(K,L)
841: *
842: KNEXT = M
843: DO 230 K = M, 1, -1
844: IF( K.GT.KNEXT )
845: $ GO TO 230
846: IF( K.EQ.1 ) THEN
847: K1 = K
848: K2 = K
849: ELSE
850: IF( A( K, K-1 ).NE.ZERO ) THEN
851: K1 = K - 1
852: K2 = K
853: KNEXT = K - 2
854: ELSE
855: K1 = K
856: K2 = K
857: KNEXT = K - 1
858: END IF
859: END IF
860: *
861: IF( L1.EQ.L2 .AND. K1.EQ.K2 ) THEN
862: SUML = DDOT( M-K1, A( K1, MIN( K1+1, M ) ), LDA,
863: $ C( MIN( K1+1, M ), L1 ), 1 )
864: SUMR = DDOT( N-L1, C( K1, MIN( L1+1, N ) ), LDC,
865: $ B( L1, MIN( L1+1, N ) ), LDB )
866: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
867: SCALOC = ONE
868: *
869: A11 = A( K1, K1 ) + SGN*B( L1, L1 )
870: DA11 = ABS( A11 )
871: IF( DA11.LE.SMIN ) THEN
872: A11 = SMIN
873: DA11 = SMIN
874: INFO = 1
875: END IF
876: DB = ABS( VEC( 1, 1 ) )
877: IF( DA11.LT.ONE .AND. DB.GT.ONE ) THEN
878: IF( DB.GT.BIGNUM*DA11 )
879: $ SCALOC = ONE / DB
880: END IF
881: X( 1, 1 ) = ( VEC( 1, 1 )*SCALOC ) / A11
882: *
883: IF( SCALOC.NE.ONE ) THEN
884: DO 190 J = 1, N
885: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
886: 190 CONTINUE
887: SCALE = SCALE*SCALOC
888: END IF
889: C( K1, L1 ) = X( 1, 1 )
890: *
891: ELSE IF( L1.EQ.L2 .AND. K1.NE.K2 ) THEN
892: *
893: SUML = DDOT( M-K2, A( K1, MIN( K2+1, M ) ), LDA,
894: $ C( MIN( K2+1, M ), L1 ), 1 )
895: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
896: $ B( L1, MIN( L2+1, N ) ), LDB )
897: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
898: *
899: SUML = DDOT( M-K2, A( K2, MIN( K2+1, M ) ), LDA,
900: $ C( MIN( K2+1, M ), L1 ), 1 )
901: SUMR = DDOT( N-L2, C( K2, MIN( L2+1, N ) ), LDC,
902: $ B( L1, MIN( L2+1, N ) ), LDB )
903: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
904: *
905: CALL DLALN2( .FALSE., 2, 1, SMIN, ONE, A( K1, K1 ),
906: $ LDA, ONE, ONE, VEC, 2, -SGN*B( L1, L1 ),
907: $ ZERO, X, 2, SCALOC, XNORM, IERR )
908: IF( IERR.NE.0 )
909: $ INFO = 1
910: *
911: IF( SCALOC.NE.ONE ) THEN
912: DO 200 J = 1, N
913: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
914: 200 CONTINUE
915: SCALE = SCALE*SCALOC
916: END IF
917: C( K1, L1 ) = X( 1, 1 )
918: C( K2, L1 ) = X( 2, 1 )
919: *
920: ELSE IF( L1.NE.L2 .AND. K1.EQ.K2 ) THEN
921: *
922: SUML = DDOT( M-K1, A( K1, MIN( K1+1, M ) ), LDA,
923: $ C( MIN( K1+1, M ), L1 ), 1 )
924: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
925: $ B( L1, MIN( L2+1, N ) ), LDB )
926: VEC( 1, 1 ) = SGN*( C( K1, L1 )-( SUML+SGN*SUMR ) )
927: *
928: SUML = DDOT( M-K1, A( K1, MIN( K1+1, M ) ), LDA,
929: $ C( MIN( K1+1, M ), L2 ), 1 )
930: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
931: $ B( L2, MIN( L2+1, N ) ), LDB )
932: VEC( 2, 1 ) = SGN*( C( K1, L2 )-( SUML+SGN*SUMR ) )
933: *
934: CALL DLALN2( .FALSE., 2, 1, SMIN, ONE, B( L1, L1 ),
935: $ LDB, ONE, ONE, VEC, 2, -SGN*A( K1, K1 ),
936: $ ZERO, X, 2, SCALOC, XNORM, IERR )
937: IF( IERR.NE.0 )
938: $ INFO = 1
939: *
940: IF( SCALOC.NE.ONE ) THEN
941: DO 210 J = 1, N
942: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
943: 210 CONTINUE
944: SCALE = SCALE*SCALOC
945: END IF
946: C( K1, L1 ) = X( 1, 1 )
947: C( K1, L2 ) = X( 2, 1 )
948: *
949: ELSE IF( L1.NE.L2 .AND. K1.NE.K2 ) THEN
950: *
951: SUML = DDOT( M-K2, A( K1, MIN( K2+1, M ) ), LDA,
952: $ C( MIN( K2+1, M ), L1 ), 1 )
953: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
954: $ B( L1, MIN( L2+1, N ) ), LDB )
955: VEC( 1, 1 ) = C( K1, L1 ) - ( SUML+SGN*SUMR )
956: *
957: SUML = DDOT( M-K2, A( K1, MIN( K2+1, M ) ), LDA,
958: $ C( MIN( K2+1, M ), L2 ), 1 )
959: SUMR = DDOT( N-L2, C( K1, MIN( L2+1, N ) ), LDC,
960: $ B( L2, MIN( L2+1, N ) ), LDB )
961: VEC( 1, 2 ) = C( K1, L2 ) - ( SUML+SGN*SUMR )
962: *
963: SUML = DDOT( M-K2, A( K2, MIN( K2+1, M ) ), LDA,
964: $ C( MIN( K2+1, M ), L1 ), 1 )
965: SUMR = DDOT( N-L2, C( K2, MIN( L2+1, N ) ), LDC,
966: $ B( L1, MIN( L2+1, N ) ), LDB )
967: VEC( 2, 1 ) = C( K2, L1 ) - ( SUML+SGN*SUMR )
968: *
969: SUML = DDOT( M-K2, A( K2, MIN( K2+1, M ) ), LDA,
970: $ C( MIN( K2+1, M ), L2 ), 1 )
971: SUMR = DDOT( N-L2, C( K2, MIN( L2+1, N ) ), LDC,
972: $ B( L2, MIN( L2+1, N ) ), LDB )
973: VEC( 2, 2 ) = C( K2, L2 ) - ( SUML+SGN*SUMR )
974: *
975: CALL DLASY2( .FALSE., .TRUE., ISGN, 2, 2, A( K1, K1 ),
976: $ LDA, B( L1, L1 ), LDB, VEC, 2, SCALOC, X,
977: $ 2, XNORM, IERR )
978: IF( IERR.NE.0 )
979: $ INFO = 1
980: *
981: IF( SCALOC.NE.ONE ) THEN
982: DO 220 J = 1, N
983: CALL DSCAL( M, SCALOC, C( 1, J ), 1 )
984: 220 CONTINUE
985: SCALE = SCALE*SCALOC
986: END IF
987: C( K1, L1 ) = X( 1, 1 )
988: C( K1, L2 ) = X( 1, 2 )
989: C( K2, L1 ) = X( 2, 1 )
990: C( K2, L2 ) = X( 2, 2 )
991: END IF
992: *
993: 230 CONTINUE
994: 240 CONTINUE
995: *
996: END IF
997: *
998: RETURN
999: *
1000: * End of DTRSYL
1001: *
1002: END
CVSweb interface <joel.bertrand@systella.fr>