Annotation of rpl/lapack/lapack/dtrsyl3.f, revision 1.1
1.1 ! bertrand 1: *> \brief \b DTRSYL3
! 2: *
! 3: * Definition:
! 4: * ===========
! 5: *
! 6: *
! 7: *> \par Purpose
! 8: * =============
! 9: *>
! 10: *> \verbatim
! 11: *>
! 12: *> DTRSYL3 solves the real Sylvester matrix equation:
! 13: *>
! 14: *> op(A)*X + X*op(B) = scale*C or
! 15: *> op(A)*X - X*op(B) = scale*C,
! 16: *>
! 17: *> where op(A) = A or A**T, and A and B are both upper quasi-
! 18: *> triangular. A is M-by-M and B is N-by-N; the right hand side C and
! 19: *> the solution X are M-by-N; and scale is an output scale factor, set
! 20: *> <= 1 to avoid overflow in X.
! 21: *>
! 22: *> A and B must be in Schur canonical form (as returned by DHSEQR), that
! 23: *> is, block upper triangular with 1-by-1 and 2-by-2 diagonal blocks;
! 24: *> each 2-by-2 diagonal block has its diagonal elements equal and its
! 25: *> off-diagonal elements of opposite sign.
! 26: *>
! 27: *> This is the block version of the algorithm.
! 28: *> \endverbatim
! 29: *
! 30: * Arguments
! 31: * =========
! 32: *
! 33: *> \param[in] TRANA
! 34: *> \verbatim
! 35: *> TRANA is CHARACTER*1
! 36: *> Specifies the option op(A):
! 37: *> = 'N': op(A) = A (No transpose)
! 38: *> = 'T': op(A) = A**T (Transpose)
! 39: *> = 'C': op(A) = A**H (Conjugate transpose = Transpose)
! 40: *> \endverbatim
! 41: *>
! 42: *> \param[in] TRANB
! 43: *> \verbatim
! 44: *> TRANB is CHARACTER*1
! 45: *> Specifies the option op(B):
! 46: *> = 'N': op(B) = B (No transpose)
! 47: *> = 'T': op(B) = B**T (Transpose)
! 48: *> = 'C': op(B) = B**H (Conjugate transpose = Transpose)
! 49: *> \endverbatim
! 50: *>
! 51: *> \param[in] ISGN
! 52: *> \verbatim
! 53: *> ISGN is INTEGER
! 54: *> Specifies the sign in the equation:
! 55: *> = +1: solve op(A)*X + X*op(B) = scale*C
! 56: *> = -1: solve op(A)*X - X*op(B) = scale*C
! 57: *> \endverbatim
! 58: *>
! 59: *> \param[in] M
! 60: *> \verbatim
! 61: *> M is INTEGER
! 62: *> The order of the matrix A, and the number of rows in the
! 63: *> matrices X and C. M >= 0.
! 64: *> \endverbatim
! 65: *>
! 66: *> \param[in] N
! 67: *> \verbatim
! 68: *> N is INTEGER
! 69: *> The order of the matrix B, and the number of columns in the
! 70: *> matrices X and C. N >= 0.
! 71: *> \endverbatim
! 72: *>
! 73: *> \param[in] A
! 74: *> \verbatim
! 75: *> A is DOUBLE PRECISION array, dimension (LDA,M)
! 76: *> The upper quasi-triangular matrix A, in Schur canonical form.
! 77: *> \endverbatim
! 78: *>
! 79: *> \param[in] LDA
! 80: *> \verbatim
! 81: *> LDA is INTEGER
! 82: *> The leading dimension of the array A. LDA >= max(1,M).
! 83: *> \endverbatim
! 84: *>
! 85: *> \param[in] B
! 86: *> \verbatim
! 87: *> B is DOUBLE PRECISION array, dimension (LDB,N)
! 88: *> The upper quasi-triangular matrix B, in Schur canonical form.
! 89: *> \endverbatim
! 90: *>
! 91: *> \param[in] LDB
! 92: *> \verbatim
! 93: *> LDB is INTEGER
! 94: *> The leading dimension of the array B. LDB >= max(1,N).
! 95: *> \endverbatim
! 96: *>
! 97: *> \param[in,out] C
! 98: *> \verbatim
! 99: *> C is DOUBLE PRECISION array, dimension (LDC,N)
! 100: *> On entry, the M-by-N right hand side matrix C.
! 101: *> On exit, C is overwritten by the solution matrix X.
! 102: *> \endverbatim
! 103: *>
! 104: *> \param[in] LDC
! 105: *> \verbatim
! 106: *> LDC is INTEGER
! 107: *> The leading dimension of the array C. LDC >= max(1,M)
! 108: *> \endverbatim
! 109: *>
! 110: *> \param[out] SCALE
! 111: *> \verbatim
! 112: *> SCALE is DOUBLE PRECISION
! 113: *> The scale factor, scale, set <= 1 to avoid overflow in X.
! 114: *> \endverbatim
! 115: *>
! 116: *> \param[out] IWORK
! 117: *> \verbatim
! 118: *> IWORK is INTEGER array, dimension (MAX(1,LIWORK))
! 119: *> On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.
! 120: *> \endverbatim
! 121: *>
! 122: *> \param[in] LIWORK
! 123: *> \verbatim
! 124: *> IWORK is INTEGER
! 125: *> The dimension of the array IWORK. LIWORK >= ((M + NB - 1) / NB + 1)
! 126: *> + ((N + NB - 1) / NB + 1), where NB is the optimal block size.
! 127: *>
! 128: *> If LIWORK = -1, then a workspace query is assumed; the routine
! 129: *> only calculates the optimal dimension of the IWORK array,
! 130: *> returns this value as the first entry of the IWORK array, and
! 131: *> no error message related to LIWORK is issued by XERBLA.
! 132: *> \endverbatim
! 133: *>
! 134: *> \param[out] SWORK
! 135: *> \verbatim
! 136: *> SWORK is DOUBLE PRECISION array, dimension (MAX(2, ROWS),
! 137: *> MAX(1,COLS)).
! 138: *> On exit, if INFO = 0, SWORK(1) returns the optimal value ROWS
! 139: *> and SWORK(2) returns the optimal COLS.
! 140: *> \endverbatim
! 141: *>
! 142: *> \param[in] LDSWORK
! 143: *> \verbatim
! 144: *> LDSWORK is INTEGER
! 145: *> LDSWORK >= MAX(2,ROWS), where ROWS = ((M + NB - 1) / NB + 1)
! 146: *> and NB is the optimal block size.
! 147: *>
! 148: *> If LDSWORK = -1, then a workspace query is assumed; the routine
! 149: *> only calculates the optimal dimensions of the SWORK matrix,
! 150: *> returns these values as the first and second entry of the SWORK
! 151: *> matrix, and no error message related LWORK is issued by XERBLA.
! 152: *> \endverbatim
! 153: *>
! 154: *> \param[out] INFO
! 155: *> \verbatim
! 156: *> INFO is INTEGER
! 157: *> = 0: successful exit
! 158: *> < 0: if INFO = -i, the i-th argument had an illegal value
! 159: *> = 1: A and B have common or very close eigenvalues; perturbed
! 160: *> values were used to solve the equation (but the matrices
! 161: *> A and B are unchanged).
! 162: *> \endverbatim
! 163: *
! 164: * =====================================================================
! 165: * References:
! 166: * E. S. Quintana-Orti and R. A. Van De Geijn (2003). Formal derivation of
! 167: * algorithms: The triangular Sylvester equation, ACM Transactions
! 168: * on Mathematical Software (TOMS), volume 29, pages 218--243.
! 169: *
! 170: * A. Schwarz and C. C. Kjelgaard Mikkelsen (2020). Robust Task-Parallel
! 171: * Solution of the Triangular Sylvester Equation. Lecture Notes in
! 172: * Computer Science, vol 12043, pages 82--92, Springer.
! 173: *
! 174: * Contributor:
! 175: * Angelika Schwarz, Umea University, Sweden.
! 176: *
! 177: * =====================================================================
! 178: SUBROUTINE DTRSYL3( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB, C,
! 179: $ LDC, SCALE, IWORK, LIWORK, SWORK, LDSWORK,
! 180: $ INFO )
! 181: IMPLICIT NONE
! 182: *
! 183: * .. Scalar Arguments ..
! 184: CHARACTER TRANA, TRANB
! 185: INTEGER INFO, ISGN, LDA, LDB, LDC, M, N,
! 186: $ LIWORK, LDSWORK
! 187: DOUBLE PRECISION SCALE
! 188: * ..
! 189: * .. Array Arguments ..
! 190: INTEGER IWORK( * )
! 191: DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( LDC, * ),
! 192: $ SWORK( LDSWORK, * )
! 193: * ..
! 194: * .. Parameters ..
! 195: DOUBLE PRECISION ZERO, ONE
! 196: PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
! 197: * ..
! 198: * .. Local Scalars ..
! 199: LOGICAL NOTRNA, NOTRNB, LQUERY, SKIP
! 200: INTEGER AWRK, BWRK, I, I1, I2, IINFO, J, J1, J2, JJ,
! 201: $ K, K1, K2, L, L1, L2, LL, NBA, NB, NBB, PC
! 202: DOUBLE PRECISION ANRM, BIGNUM, BNRM, CNRM, SCAL, SCALOC,
! 203: $ SCAMIN, SGN, XNRM, BUF, SMLNUM
! 204: * ..
! 205: * .. Local Arrays ..
! 206: DOUBLE PRECISION WNRM( MAX( M, N ) )
! 207: * ..
! 208: * .. External Functions ..
! 209: LOGICAL LSAME
! 210: INTEGER ILAENV
! 211: DOUBLE PRECISION DLANGE, DLAMCH, DLARMM
! 212: EXTERNAL DLANGE, DLAMCH, DLARMM, ILAENV, LSAME
! 213: * ..
! 214: * .. External Subroutines ..
! 215: EXTERNAL DGEMM, DLASCL, DSCAL, DTRSYL, XERBLA
! 216: * ..
! 217: * .. Intrinsic Functions ..
! 218: INTRINSIC ABS, DBLE, EXPONENT, MAX, MIN
! 219: * ..
! 220: * .. Executable Statements ..
! 221: *
! 222: * Decode and Test input parameters
! 223: *
! 224: NOTRNA = LSAME( TRANA, 'N' )
! 225: NOTRNB = LSAME( TRANB, 'N' )
! 226: *
! 227: * Use the same block size for all matrices.
! 228: *
! 229: NB = MAX(8, ILAENV( 1, 'DTRSYL', '', M, N, -1, -1) )
! 230: *
! 231: * Compute number of blocks in A and B
! 232: *
! 233: NBA = MAX( 1, (M + NB - 1) / NB )
! 234: NBB = MAX( 1, (N + NB - 1) / NB )
! 235: *
! 236: * Compute workspace
! 237: *
! 238: INFO = 0
! 239: LQUERY = ( LIWORK.EQ.-1 .OR. LDSWORK.EQ.-1 )
! 240: IWORK( 1 ) = NBA + NBB + 2
! 241: IF( LQUERY ) THEN
! 242: LDSWORK = 2
! 243: SWORK( 1, 1 ) = MAX( NBA, NBB )
! 244: SWORK( 2, 1 ) = 2 * NBB + NBA
! 245: END IF
! 246: *
! 247: * Test the input arguments
! 248: *
! 249: IF( .NOT.NOTRNA .AND. .NOT.LSAME( TRANA, 'T' ) .AND. .NOT.
! 250: $ LSAME( TRANA, 'C' ) ) THEN
! 251: INFO = -1
! 252: ELSE IF( .NOT.NOTRNB .AND. .NOT.LSAME( TRANB, 'T' ) .AND. .NOT.
! 253: $ LSAME( TRANB, 'C' ) ) THEN
! 254: INFO = -2
! 255: ELSE IF( ISGN.NE.1 .AND. ISGN.NE.-1 ) THEN
! 256: INFO = -3
! 257: ELSE IF( M.LT.0 ) THEN
! 258: INFO = -4
! 259: ELSE IF( N.LT.0 ) THEN
! 260: INFO = -5
! 261: ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
! 262: INFO = -7
! 263: ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
! 264: INFO = -9
! 265: ELSE IF( LDC.LT.MAX( 1, M ) ) THEN
! 266: INFO = -11
! 267: END IF
! 268: IF( INFO.NE.0 ) THEN
! 269: CALL XERBLA( 'DTRSYL3', -INFO )
! 270: RETURN
! 271: ELSE IF( LQUERY ) THEN
! 272: RETURN
! 273: END IF
! 274: *
! 275: * Quick return if possible
! 276: *
! 277: SCALE = ONE
! 278: IF( M.EQ.0 .OR. N.EQ.0 )
! 279: $ RETURN
! 280: *
! 281: * Use unblocked code for small problems or if insufficient
! 282: * workspaces are provided
! 283: *
! 284: IF( MIN( NBA, NBB ).EQ.1 .OR. LDSWORK.LT.MAX( NBA, NBB ) .OR.
! 285: $ LIWORK.LT.IWORK(1) ) THEN
! 286: CALL DTRSYL( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB,
! 287: $ C, LDC, SCALE, INFO )
! 288: RETURN
! 289: END IF
! 290: *
! 291: * Set constants to control overflow
! 292: *
! 293: SMLNUM = DLAMCH( 'S' )
! 294: BIGNUM = ONE / SMLNUM
! 295: *
! 296: * Partition A such that 2-by-2 blocks on the diagonal are not split
! 297: *
! 298: SKIP = .FALSE.
! 299: DO I = 1, NBA
! 300: IWORK( I ) = ( I - 1 ) * NB + 1
! 301: END DO
! 302: IWORK( NBA + 1 ) = M + 1
! 303: DO K = 1, NBA
! 304: L1 = IWORK( K )
! 305: L2 = IWORK( K + 1 ) - 1
! 306: DO L = L1, L2
! 307: IF( SKIP ) THEN
! 308: SKIP = .FALSE.
! 309: CYCLE
! 310: END IF
! 311: IF( L.GE.M ) THEN
! 312: * A( M, M ) is a 1-by-1 block
! 313: CYCLE
! 314: END IF
! 315: IF( A( L, L+1 ).NE.ZERO .AND. A( L+1, L ).NE.ZERO ) THEN
! 316: * Check if 2-by-2 block is split
! 317: IF( L + 1 .EQ. IWORK( K + 1 ) ) THEN
! 318: IWORK( K + 1 ) = IWORK( K + 1 ) + 1
! 319: CYCLE
! 320: END IF
! 321: SKIP = .TRUE.
! 322: END IF
! 323: END DO
! 324: END DO
! 325: IWORK( NBA + 1 ) = M + 1
! 326: IF( IWORK( NBA ).GE.IWORK( NBA + 1 ) ) THEN
! 327: IWORK( NBA ) = IWORK( NBA + 1 )
! 328: NBA = NBA - 1
! 329: END IF
! 330: *
! 331: * Partition B such that 2-by-2 blocks on the diagonal are not split
! 332: *
! 333: PC = NBA + 1
! 334: SKIP = .FALSE.
! 335: DO I = 1, NBB
! 336: IWORK( PC + I ) = ( I - 1 ) * NB + 1
! 337: END DO
! 338: IWORK( PC + NBB + 1 ) = N + 1
! 339: DO K = 1, NBB
! 340: L1 = IWORK( PC + K )
! 341: L2 = IWORK( PC + K + 1 ) - 1
! 342: DO L = L1, L2
! 343: IF( SKIP ) THEN
! 344: SKIP = .FALSE.
! 345: CYCLE
! 346: END IF
! 347: IF( L.GE.N ) THEN
! 348: * B( N, N ) is a 1-by-1 block
! 349: CYCLE
! 350: END IF
! 351: IF( B( L, L+1 ).NE.ZERO .AND. B( L+1, L ).NE.ZERO ) THEN
! 352: * Check if 2-by-2 block is split
! 353: IF( L + 1 .EQ. IWORK( PC + K + 1 ) ) THEN
! 354: IWORK( PC + K + 1 ) = IWORK( PC + K + 1 ) + 1
! 355: CYCLE
! 356: END IF
! 357: SKIP = .TRUE.
! 358: END IF
! 359: END DO
! 360: END DO
! 361: IWORK( PC + NBB + 1 ) = N + 1
! 362: IF( IWORK( PC + NBB ).GE.IWORK( PC + NBB + 1 ) ) THEN
! 363: IWORK( PC + NBB ) = IWORK( PC + NBB + 1 )
! 364: NBB = NBB - 1
! 365: END IF
! 366: *
! 367: * Set local scaling factors - must never attain zero.
! 368: *
! 369: DO L = 1, NBB
! 370: DO K = 1, NBA
! 371: SWORK( K, L ) = ONE
! 372: END DO
! 373: END DO
! 374: *
! 375: * Fallback scaling factor to prevent flushing of SWORK( K, L ) to zero.
! 376: * This scaling is to ensure compatibility with TRSYL and may get flushed.
! 377: *
! 378: BUF = ONE
! 379: *
! 380: * Compute upper bounds of blocks of A and B
! 381: *
! 382: AWRK = NBB
! 383: DO K = 1, NBA
! 384: K1 = IWORK( K )
! 385: K2 = IWORK( K + 1 )
! 386: DO L = K, NBA
! 387: L1 = IWORK( L )
! 388: L2 = IWORK( L + 1 )
! 389: IF( NOTRNA ) THEN
! 390: SWORK( K, AWRK + L ) = DLANGE( 'I', K2-K1, L2-L1,
! 391: $ A( K1, L1 ), LDA, WNRM )
! 392: ELSE
! 393: SWORK( L, AWRK + K ) = DLANGE( '1', K2-K1, L2-L1,
! 394: $ A( K1, L1 ), LDA, WNRM )
! 395: END IF
! 396: END DO
! 397: END DO
! 398: BWRK = NBB + NBA
! 399: DO K = 1, NBB
! 400: K1 = IWORK( PC + K )
! 401: K2 = IWORK( PC + K + 1 )
! 402: DO L = K, NBB
! 403: L1 = IWORK( PC + L )
! 404: L2 = IWORK( PC + L + 1 )
! 405: IF( NOTRNB ) THEN
! 406: SWORK( K, BWRK + L ) = DLANGE( 'I', K2-K1, L2-L1,
! 407: $ B( K1, L1 ), LDB, WNRM )
! 408: ELSE
! 409: SWORK( L, BWRK + K ) = DLANGE( '1', K2-K1, L2-L1,
! 410: $ B( K1, L1 ), LDB, WNRM )
! 411: END IF
! 412: END DO
! 413: END DO
! 414: *
! 415: SGN = DBLE( ISGN )
! 416: *
! 417: IF( NOTRNA .AND. NOTRNB ) THEN
! 418: *
! 419: * Solve A*X + ISGN*X*B = scale*C.
! 420: *
! 421: * The (K,L)th block of X is determined starting from
! 422: * bottom-left corner column by column by
! 423: *
! 424: * A(K,K)*X(K,L) + ISGN*X(K,L)*B(L,L) = C(K,L) - R(K,L)
! 425: *
! 426: * Where
! 427: * M L-1
! 428: * R(K,L) = SUM [A(K,I)*X(I,L)] + ISGN*SUM [X(K,J)*B(J,L)].
! 429: * I=K+1 J=1
! 430: *
! 431: * Start loop over block rows (index = K) and block columns (index = L)
! 432: *
! 433: DO K = NBA, 1, -1
! 434: *
! 435: * K1: row index of the first row in X( K, L )
! 436: * K2: row index of the first row in X( K+1, L )
! 437: * so the K2 - K1 is the column count of the block X( K, L )
! 438: *
! 439: K1 = IWORK( K )
! 440: K2 = IWORK( K + 1 )
! 441: DO L = 1, NBB
! 442: *
! 443: * L1: column index of the first column in X( K, L )
! 444: * L2: column index of the first column in X( K, L + 1)
! 445: * so that L2 - L1 is the row count of the block X( K, L )
! 446: *
! 447: L1 = IWORK( PC + L )
! 448: L2 = IWORK( PC + L + 1 )
! 449: *
! 450: CALL DTRSYL( TRANA, TRANB, ISGN, K2-K1, L2-L1,
! 451: $ A( K1, K1 ), LDA,
! 452: $ B( L1, L1 ), LDB,
! 453: $ C( K1, L1 ), LDC, SCALOC, IINFO )
! 454: INFO = MAX( INFO, IINFO )
! 455: *
! 456: IF ( SCALOC * SWORK( K, L ) .EQ. ZERO ) THEN
! 457: IF( SCALOC .EQ. ZERO ) THEN
! 458: * The magnitude of the largest entry of X(K1:K2-1, L1:L2-1)
! 459: * is larger than the product of BIGNUM**2 and cannot be
! 460: * represented in the form (1/SCALE)*X(K1:K2-1, L1:L2-1).
! 461: * Mark the computation as pointless.
! 462: BUF = ZERO
! 463: ELSE
! 464: * Use second scaling factor to prevent flushing to zero.
! 465: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 466: END IF
! 467: DO JJ = 1, NBB
! 468: DO LL = 1, NBA
! 469: * Bound by BIGNUM to not introduce Inf. The value
! 470: * is irrelevant; corresponding entries of the
! 471: * solution will be flushed in consistency scaling.
! 472: SWORK( LL, JJ ) = MIN( BIGNUM,
! 473: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 474: END DO
! 475: END DO
! 476: END IF
! 477: SWORK( K, L ) = SCALOC * SWORK( K, L )
! 478: XNRM = DLANGE( 'I', K2-K1, L2-L1, C( K1, L1 ), LDC,
! 479: $ WNRM )
! 480: *
! 481: DO I = K - 1, 1, -1
! 482: *
! 483: * C( I, L ) := C( I, L ) - A( I, K ) * C( K, L )
! 484: *
! 485: I1 = IWORK( I )
! 486: I2 = IWORK( I + 1 )
! 487: *
! 488: * Compute scaling factor to survive the linear update
! 489: * simulating consistent scaling.
! 490: *
! 491: CNRM = DLANGE( 'I', I2-I1, L2-L1, C( I1, L1 ),
! 492: $ LDC, WNRM )
! 493: SCAMIN = MIN( SWORK( I, L ), SWORK( K, L ) )
! 494: CNRM = CNRM * ( SCAMIN / SWORK( I, L ) )
! 495: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 496: ANRM = SWORK( I, AWRK + K )
! 497: SCALOC = DLARMM( ANRM, XNRM, CNRM )
! 498: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 499: * Use second scaling factor to prevent flushing to zero.
! 500: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 501: DO JJ = 1, NBB
! 502: DO LL = 1, NBA
! 503: SWORK( LL, JJ ) = MIN( BIGNUM,
! 504: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 505: END DO
! 506: END DO
! 507: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 508: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 509: END IF
! 510: CNRM = CNRM * SCALOC
! 511: XNRM = XNRM * SCALOC
! 512: *
! 513: * Simultaneously apply the robust update factor and the
! 514: * consistency scaling factor to C( I, L ) and C( K, L ).
! 515: *
! 516: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 517: IF (SCAL .NE. ONE) THEN
! 518: DO JJ = L1, L2-1
! 519: CALL DSCAL( K2-K1, SCAL, C( K1, JJ ), 1)
! 520: END DO
! 521: ENDIF
! 522: *
! 523: SCAL = ( SCAMIN / SWORK( I, L ) ) * SCALOC
! 524: IF (SCAL .NE. ONE) THEN
! 525: DO LL = L1, L2-1
! 526: CALL DSCAL( I2-I1, SCAL, C( I1, LL ), 1)
! 527: END DO
! 528: ENDIF
! 529: *
! 530: * Record current scaling factor
! 531: *
! 532: SWORK( K, L ) = SCAMIN * SCALOC
! 533: SWORK( I, L ) = SCAMIN * SCALOC
! 534: *
! 535: CALL DGEMM( 'N', 'N', I2-I1, L2-L1, K2-K1, -ONE,
! 536: $ A( I1, K1 ), LDA, C( K1, L1 ), LDC,
! 537: $ ONE, C( I1, L1 ), LDC )
! 538: *
! 539: END DO
! 540: *
! 541: DO J = L + 1, NBB
! 542: *
! 543: * C( K, J ) := C( K, J ) - SGN * C( K, L ) * B( L, J )
! 544: *
! 545: J1 = IWORK( PC + J )
! 546: J2 = IWORK( PC + J + 1 )
! 547: *
! 548: * Compute scaling factor to survive the linear update
! 549: * simulating consistent scaling.
! 550: *
! 551: CNRM = DLANGE( 'I', K2-K1, J2-J1, C( K1, J1 ),
! 552: $ LDC, WNRM )
! 553: SCAMIN = MIN( SWORK( K, J ), SWORK( K, L ) )
! 554: CNRM = CNRM * ( SCAMIN / SWORK( K, J ) )
! 555: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 556: BNRM = SWORK(L, BWRK + J)
! 557: SCALOC = DLARMM( BNRM, XNRM, CNRM )
! 558: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 559: * Use second scaling factor to prevent flushing to zero.
! 560: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 561: DO JJ = 1, NBB
! 562: DO LL = 1, NBA
! 563: SWORK( LL, JJ ) = MIN( BIGNUM,
! 564: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 565: END DO
! 566: END DO
! 567: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 568: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 569: END IF
! 570: CNRM = CNRM * SCALOC
! 571: XNRM = XNRM * SCALOC
! 572: *
! 573: * Simultaneously apply the robust update factor and the
! 574: * consistency scaling factor to C( K, J ) and C( K, L).
! 575: *
! 576: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 577: IF( SCAL .NE. ONE ) THEN
! 578: DO LL = L1, L2-1
! 579: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1 )
! 580: END DO
! 581: ENDIF
! 582: *
! 583: SCAL = ( SCAMIN / SWORK( K, J ) ) * SCALOC
! 584: IF( SCAL .NE. ONE ) THEN
! 585: DO JJ = J1, J2-1
! 586: CALL DSCAL( K2-K1, SCAL, C( K1, JJ ), 1 )
! 587: END DO
! 588: ENDIF
! 589: *
! 590: * Record current scaling factor
! 591: *
! 592: SWORK( K, L ) = SCAMIN * SCALOC
! 593: SWORK( K, J ) = SCAMIN * SCALOC
! 594: *
! 595: CALL DGEMM( 'N', 'N', K2-K1, J2-J1, L2-L1, -SGN,
! 596: $ C( K1, L1 ), LDC, B( L1, J1 ), LDB,
! 597: $ ONE, C( K1, J1 ), LDC )
! 598: END DO
! 599: END DO
! 600: END DO
! 601: ELSE IF( .NOT.NOTRNA .AND. NOTRNB ) THEN
! 602: *
! 603: * Solve A**T*X + ISGN*X*B = scale*C.
! 604: *
! 605: * The (K,L)th block of X is determined starting from
! 606: * upper-left corner column by column by
! 607: *
! 608: * A(K,K)**T*X(K,L) + ISGN*X(K,L)*B(L,L) = C(K,L) - R(K,L)
! 609: *
! 610: * Where
! 611: * K-1 L-1
! 612: * R(K,L) = SUM [A(I,K)**T*X(I,L)] +ISGN*SUM [X(K,J)*B(J,L)]
! 613: * I=1 J=1
! 614: *
! 615: * Start loop over block rows (index = K) and block columns (index = L)
! 616: *
! 617: DO K = 1, NBA
! 618: *
! 619: * K1: row index of the first row in X( K, L )
! 620: * K2: row index of the first row in X( K+1, L )
! 621: * so the K2 - K1 is the column count of the block X( K, L )
! 622: *
! 623: K1 = IWORK( K )
! 624: K2 = IWORK( K + 1 )
! 625: DO L = 1, NBB
! 626: *
! 627: * L1: column index of the first column in X( K, L )
! 628: * L2: column index of the first column in X( K, L + 1)
! 629: * so that L2 - L1 is the row count of the block X( K, L )
! 630: *
! 631: L1 = IWORK( PC + L )
! 632: L2 = IWORK( PC + L + 1 )
! 633: *
! 634: CALL DTRSYL( TRANA, TRANB, ISGN, K2-K1, L2-L1,
! 635: $ A( K1, K1 ), LDA,
! 636: $ B( L1, L1 ), LDB,
! 637: $ C( K1, L1 ), LDC, SCALOC, IINFO )
! 638: INFO = MAX( INFO, IINFO )
! 639: *
! 640: IF( SCALOC * SWORK( K, L ) .EQ. ZERO ) THEN
! 641: IF( SCALOC .EQ. ZERO ) THEN
! 642: * The magnitude of the largest entry of X(K1:K2-1, L1:L2-1)
! 643: * is larger than the product of BIGNUM**2 and cannot be
! 644: * represented in the form (1/SCALE)*X(K1:K2-1, L1:L2-1).
! 645: * Mark the computation as pointless.
! 646: BUF = ZERO
! 647: ELSE
! 648: * Use second scaling factor to prevent flushing to zero.
! 649: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 650: END IF
! 651: DO JJ = 1, NBB
! 652: DO LL = 1, NBA
! 653: * Bound by BIGNUM to not introduce Inf. The value
! 654: * is irrelevant; corresponding entries of the
! 655: * solution will be flushed in consistency scaling.
! 656: SWORK( LL, JJ ) = MIN( BIGNUM,
! 657: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 658: END DO
! 659: END DO
! 660: END IF
! 661: SWORK( K, L ) = SCALOC * SWORK( K, L )
! 662: XNRM = DLANGE( 'I', K2-K1, L2-L1, C( K1, L1 ), LDC,
! 663: $ WNRM )
! 664: *
! 665: DO I = K + 1, NBA
! 666: *
! 667: * C( I, L ) := C( I, L ) - A( K, I )**T * C( K, L )
! 668: *
! 669: I1 = IWORK( I )
! 670: I2 = IWORK( I + 1 )
! 671: *
! 672: * Compute scaling factor to survive the linear update
! 673: * simulating consistent scaling.
! 674: *
! 675: CNRM = DLANGE( 'I', I2-I1, L2-L1, C( I1, L1 ),
! 676: $ LDC, WNRM )
! 677: SCAMIN = MIN( SWORK( I, L ), SWORK( K, L ) )
! 678: CNRM = CNRM * ( SCAMIN / SWORK( I, L ) )
! 679: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 680: ANRM = SWORK( I, AWRK + K )
! 681: SCALOC = DLARMM( ANRM, XNRM, CNRM )
! 682: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 683: * Use second scaling factor to prevent flushing to zero.
! 684: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 685: DO JJ = 1, NBB
! 686: DO LL = 1, NBA
! 687: SWORK( LL, JJ ) = MIN( BIGNUM,
! 688: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 689: END DO
! 690: END DO
! 691: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 692: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 693: END IF
! 694: CNRM = CNRM * SCALOC
! 695: XNRM = XNRM * SCALOC
! 696: *
! 697: * Simultaneously apply the robust update factor and the
! 698: * consistency scaling factor to to C( I, L ) and C( K, L ).
! 699: *
! 700: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 701: IF (SCAL .NE. ONE) THEN
! 702: DO LL = L1, L2-1
! 703: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1 )
! 704: END DO
! 705: ENDIF
! 706: *
! 707: SCAL = ( SCAMIN / SWORK( I, L ) ) * SCALOC
! 708: IF (SCAL .NE. ONE) THEN
! 709: DO LL = L1, L2-1
! 710: CALL DSCAL( I2-I1, SCAL, C( I1, LL ), 1 )
! 711: END DO
! 712: ENDIF
! 713: *
! 714: * Record current scaling factor
! 715: *
! 716: SWORK( K, L ) = SCAMIN * SCALOC
! 717: SWORK( I, L ) = SCAMIN * SCALOC
! 718: *
! 719: CALL DGEMM( 'T', 'N', I2-I1, L2-L1, K2-K1, -ONE,
! 720: $ A( K1, I1 ), LDA, C( K1, L1 ), LDC,
! 721: $ ONE, C( I1, L1 ), LDC )
! 722: END DO
! 723: *
! 724: DO J = L + 1, NBB
! 725: *
! 726: * C( K, J ) := C( K, J ) - SGN * C( K, L ) * B( L, J )
! 727: *
! 728: J1 = IWORK( PC + J )
! 729: J2 = IWORK( PC + J + 1 )
! 730: *
! 731: * Compute scaling factor to survive the linear update
! 732: * simulating consistent scaling.
! 733: *
! 734: CNRM = DLANGE( 'I', K2-K1, J2-J1, C( K1, J1 ),
! 735: $ LDC, WNRM )
! 736: SCAMIN = MIN( SWORK( K, J ), SWORK( K, L ) )
! 737: CNRM = CNRM * ( SCAMIN / SWORK( K, J ) )
! 738: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 739: BNRM = SWORK( L, BWRK + J )
! 740: SCALOC = DLARMM( BNRM, XNRM, CNRM )
! 741: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 742: * Use second scaling factor to prevent flushing to zero.
! 743: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 744: DO JJ = 1, NBB
! 745: DO LL = 1, NBA
! 746: SWORK( LL, JJ ) = MIN( BIGNUM,
! 747: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 748: END DO
! 749: END DO
! 750: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 751: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 752: END IF
! 753: CNRM = CNRM * SCALOC
! 754: XNRM = XNRM * SCALOC
! 755: *
! 756: * Simultaneously apply the robust update factor and the
! 757: * consistency scaling factor to to C( K, J ) and C( K, L ).
! 758: *
! 759: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 760: IF( SCAL .NE. ONE ) THEN
! 761: DO LL = L1, L2-1
! 762: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1 )
! 763: END DO
! 764: ENDIF
! 765: *
! 766: SCAL = ( SCAMIN / SWORK( K, J ) ) * SCALOC
! 767: IF( SCAL .NE. ONE ) THEN
! 768: DO JJ = J1, J2-1
! 769: CALL DSCAL( K2-K1, SCAL, C( K1, JJ ), 1 )
! 770: END DO
! 771: ENDIF
! 772: *
! 773: * Record current scaling factor
! 774: *
! 775: SWORK( K, L ) = SCAMIN * SCALOC
! 776: SWORK( K, J ) = SCAMIN * SCALOC
! 777: *
! 778: CALL DGEMM( 'N', 'N', K2-K1, J2-J1, L2-L1, -SGN,
! 779: $ C( K1, L1 ), LDC, B( L1, J1 ), LDB,
! 780: $ ONE, C( K1, J1 ), LDC )
! 781: END DO
! 782: END DO
! 783: END DO
! 784: ELSE IF( .NOT.NOTRNA .AND. .NOT.NOTRNB ) THEN
! 785: *
! 786: * Solve A**T*X + ISGN*X*B**T = scale*C.
! 787: *
! 788: * The (K,L)th block of X is determined starting from
! 789: * top-right corner column by column by
! 790: *
! 791: * A(K,K)**T*X(K,L) + ISGN*X(K,L)*B(L,L)**T = C(K,L) - R(K,L)
! 792: *
! 793: * Where
! 794: * K-1 N
! 795: * R(K,L) = SUM [A(I,K)**T*X(I,L)] + ISGN*SUM [X(K,J)*B(L,J)**T].
! 796: * I=1 J=L+1
! 797: *
! 798: * Start loop over block rows (index = K) and block columns (index = L)
! 799: *
! 800: DO K = 1, NBA
! 801: *
! 802: * K1: row index of the first row in X( K, L )
! 803: * K2: row index of the first row in X( K+1, L )
! 804: * so the K2 - K1 is the column count of the block X( K, L )
! 805: *
! 806: K1 = IWORK( K )
! 807: K2 = IWORK( K + 1 )
! 808: DO L = NBB, 1, -1
! 809: *
! 810: * L1: column index of the first column in X( K, L )
! 811: * L2: column index of the first column in X( K, L + 1)
! 812: * so that L2 - L1 is the row count of the block X( K, L )
! 813: *
! 814: L1 = IWORK( PC + L )
! 815: L2 = IWORK( PC + L + 1 )
! 816: *
! 817: CALL DTRSYL( TRANA, TRANB, ISGN, K2-K1, L2-L1,
! 818: $ A( K1, K1 ), LDA,
! 819: $ B( L1, L1 ), LDB,
! 820: $ C( K1, L1 ), LDC, SCALOC, IINFO )
! 821: INFO = MAX( INFO, IINFO )
! 822: *
! 823: SWORK( K, L ) = SCALOC * SWORK( K, L )
! 824: IF( SCALOC * SWORK( K, L ) .EQ. ZERO ) THEN
! 825: IF( SCALOC .EQ. ZERO ) THEN
! 826: * The magnitude of the largest entry of X(K1:K2-1, L1:L2-1)
! 827: * is larger than the product of BIGNUM**2 and cannot be
! 828: * represented in the form (1/SCALE)*X(K1:K2-1, L1:L2-1).
! 829: * Mark the computation as pointless.
! 830: BUF = ZERO
! 831: ELSE
! 832: * Use second scaling factor to prevent flushing to zero.
! 833: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 834: END IF
! 835: DO JJ = 1, NBB
! 836: DO LL = 1, NBA
! 837: * Bound by BIGNUM to not introduce Inf. The value
! 838: * is irrelevant; corresponding entries of the
! 839: * solution will be flushed in consistency scaling.
! 840: SWORK( LL, JJ ) = MIN( BIGNUM,
! 841: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 842: END DO
! 843: END DO
! 844: END IF
! 845: XNRM = DLANGE( 'I', K2-K1, L2-L1, C( K1, L1 ), LDC,
! 846: $ WNRM )
! 847: *
! 848: DO I = K + 1, NBA
! 849: *
! 850: * C( I, L ) := C( I, L ) - A( K, I )**T * C( K, L )
! 851: *
! 852: I1 = IWORK( I )
! 853: I2 = IWORK( I + 1 )
! 854: *
! 855: * Compute scaling factor to survive the linear update
! 856: * simulating consistent scaling.
! 857: *
! 858: CNRM = DLANGE( 'I', I2-I1, L2-L1, C( I1, L1 ),
! 859: $ LDC, WNRM )
! 860: SCAMIN = MIN( SWORK( I, L ), SWORK( K, L ) )
! 861: CNRM = CNRM * ( SCAMIN / SWORK( I, L ) )
! 862: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 863: ANRM = SWORK( I, AWRK + K )
! 864: SCALOC = DLARMM( ANRM, XNRM, CNRM )
! 865: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 866: * Use second scaling factor to prevent flushing to zero.
! 867: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 868: DO JJ = 1, NBB
! 869: DO LL = 1, NBA
! 870: SWORK( LL, JJ ) = MIN( BIGNUM,
! 871: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 872: END DO
! 873: END DO
! 874: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 875: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 876: END IF
! 877: CNRM = CNRM * SCALOC
! 878: XNRM = XNRM * SCALOC
! 879: *
! 880: * Simultaneously apply the robust update factor and the
! 881: * consistency scaling factor to C( I, L ) and C( K, L ).
! 882: *
! 883: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 884: IF (SCAL .NE. ONE) THEN
! 885: DO LL = L1, L2-1
! 886: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1 )
! 887: END DO
! 888: ENDIF
! 889: *
! 890: SCAL = ( SCAMIN / SWORK( I, L ) ) * SCALOC
! 891: IF (SCAL .NE. ONE) THEN
! 892: DO LL = L1, L2-1
! 893: CALL DSCAL( I2-I1, SCAL, C( I1, LL ), 1 )
! 894: END DO
! 895: ENDIF
! 896: *
! 897: * Record current scaling factor
! 898: *
! 899: SWORK( K, L ) = SCAMIN * SCALOC
! 900: SWORK( I, L ) = SCAMIN * SCALOC
! 901: *
! 902: CALL DGEMM( 'T', 'N', I2-I1, L2-L1, K2-K1, -ONE,
! 903: $ A( K1, I1 ), LDA, C( K1, L1 ), LDC,
! 904: $ ONE, C( I1, L1 ), LDC )
! 905: END DO
! 906: *
! 907: DO J = 1, L - 1
! 908: *
! 909: * C( K, J ) := C( K, J ) - SGN * C( K, L ) * B( J, L )**T
! 910: *
! 911: J1 = IWORK( PC + J )
! 912: J2 = IWORK( PC + J + 1 )
! 913: *
! 914: * Compute scaling factor to survive the linear update
! 915: * simulating consistent scaling.
! 916: *
! 917: CNRM = DLANGE( 'I', K2-K1, J2-J1, C( K1, J1 ),
! 918: $ LDC, WNRM )
! 919: SCAMIN = MIN( SWORK( K, J ), SWORK( K, L ) )
! 920: CNRM = CNRM * ( SCAMIN / SWORK( K, J ) )
! 921: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 922: BNRM = SWORK( L, BWRK + J )
! 923: SCALOC = DLARMM( BNRM, XNRM, CNRM )
! 924: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 925: * Use second scaling factor to prevent flushing to zero.
! 926: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 927: DO JJ = 1, NBB
! 928: DO LL = 1, NBA
! 929: SWORK( LL, JJ ) = MIN( BIGNUM,
! 930: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 931: END DO
! 932: END DO
! 933: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 934: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 935: END IF
! 936: CNRM = CNRM * SCALOC
! 937: XNRM = XNRM * SCALOC
! 938: *
! 939: * Simultaneously apply the robust update factor and the
! 940: * consistency scaling factor to C( K, J ) and C( K, L ).
! 941: *
! 942: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 943: IF( SCAL .NE. ONE ) THEN
! 944: DO LL = L1, L2-1
! 945: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1)
! 946: END DO
! 947: ENDIF
! 948: *
! 949: SCAL = ( SCAMIN / SWORK( K, J ) ) * SCALOC
! 950: IF( SCAL .NE. ONE ) THEN
! 951: DO JJ = J1, J2-1
! 952: CALL DSCAL( K2-K1, SCAL, C( K1, JJ ), 1 )
! 953: END DO
! 954: ENDIF
! 955: *
! 956: * Record current scaling factor
! 957: *
! 958: SWORK( K, L ) = SCAMIN * SCALOC
! 959: SWORK( K, J ) = SCAMIN * SCALOC
! 960: *
! 961: CALL DGEMM( 'N', 'T', K2-K1, J2-J1, L2-L1, -SGN,
! 962: $ C( K1, L1 ), LDC, B( J1, L1 ), LDB,
! 963: $ ONE, C( K1, J1 ), LDC )
! 964: END DO
! 965: END DO
! 966: END DO
! 967: ELSE IF( NOTRNA .AND. .NOT.NOTRNB ) THEN
! 968: *
! 969: * Solve A*X + ISGN*X*B**T = scale*C.
! 970: *
! 971: * The (K,L)th block of X is determined starting from
! 972: * bottom-right corner column by column by
! 973: *
! 974: * A(K,K)*X(K,L) + ISGN*X(K,L)*B(L,L)**T = C(K,L) - R(K,L)
! 975: *
! 976: * Where
! 977: * M N
! 978: * R(K,L) = SUM [A(K,I)*X(I,L)] + ISGN*SUM [X(K,J)*B(L,J)**T].
! 979: * I=K+1 J=L+1
! 980: *
! 981: * Start loop over block rows (index = K) and block columns (index = L)
! 982: *
! 983: DO K = NBA, 1, -1
! 984: *
! 985: * K1: row index of the first row in X( K, L )
! 986: * K2: row index of the first row in X( K+1, L )
! 987: * so the K2 - K1 is the column count of the block X( K, L )
! 988: *
! 989: K1 = IWORK( K )
! 990: K2 = IWORK( K + 1 )
! 991: DO L = NBB, 1, -1
! 992: *
! 993: * L1: column index of the first column in X( K, L )
! 994: * L2: column index of the first column in X( K, L + 1)
! 995: * so that L2 - L1 is the row count of the block X( K, L )
! 996: *
! 997: L1 = IWORK( PC + L )
! 998: L2 = IWORK( PC + L + 1 )
! 999: *
! 1000: CALL DTRSYL( TRANA, TRANB, ISGN, K2-K1, L2-L1,
! 1001: $ A( K1, K1 ), LDA,
! 1002: $ B( L1, L1 ), LDB,
! 1003: $ C( K1, L1 ), LDC, SCALOC, IINFO )
! 1004: INFO = MAX( INFO, IINFO )
! 1005: *
! 1006: IF( SCALOC * SWORK( K, L ) .EQ. ZERO ) THEN
! 1007: IF( SCALOC .EQ. ZERO ) THEN
! 1008: * The magnitude of the largest entry of X(K1:K2-1, L1:L2-1)
! 1009: * is larger than the product of BIGNUM**2 and cannot be
! 1010: * represented in the form (1/SCALE)*X(K1:K2-1, L1:L2-1).
! 1011: * Mark the computation as pointless.
! 1012: BUF = ZERO
! 1013: ELSE
! 1014: * Use second scaling factor to prevent flushing to zero.
! 1015: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 1016: END IF
! 1017: DO JJ = 1, NBB
! 1018: DO LL = 1, NBA
! 1019: * Bound by BIGNUM to not introduce Inf. The value
! 1020: * is irrelevant; corresponding entries of the
! 1021: * solution will be flushed in consistency scaling.
! 1022: SWORK( LL, JJ ) = MIN( BIGNUM,
! 1023: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 1024: END DO
! 1025: END DO
! 1026: END IF
! 1027: SWORK( K, L ) = SCALOC * SWORK( K, L )
! 1028: XNRM = DLANGE( 'I', K2-K1, L2-L1, C( K1, L1 ), LDC,
! 1029: $ WNRM )
! 1030: *
! 1031: DO I = 1, K - 1
! 1032: *
! 1033: * C( I, L ) := C( I, L ) - A( I, K ) * C( K, L )
! 1034: *
! 1035: I1 = IWORK( I )
! 1036: I2 = IWORK( I + 1 )
! 1037: *
! 1038: * Compute scaling factor to survive the linear update
! 1039: * simulating consistent scaling.
! 1040: *
! 1041: CNRM = DLANGE( 'I', I2-I1, L2-L1, C( I1, L1 ),
! 1042: $ LDC, WNRM )
! 1043: SCAMIN = MIN( SWORK( I, L ), SWORK( K, L ) )
! 1044: CNRM = CNRM * ( SCAMIN / SWORK( I, L ) )
! 1045: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 1046: ANRM = SWORK( I, AWRK + K )
! 1047: SCALOC = DLARMM( ANRM, XNRM, CNRM )
! 1048: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 1049: * Use second scaling factor to prevent flushing to zero.
! 1050: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 1051: DO JJ = 1, NBB
! 1052: DO LL = 1, NBA
! 1053: SWORK( LL, JJ ) = MIN( BIGNUM,
! 1054: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 1055: END DO
! 1056: END DO
! 1057: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 1058: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 1059: END IF
! 1060: CNRM = CNRM * SCALOC
! 1061: XNRM = XNRM * SCALOC
! 1062: *
! 1063: * Simultaneously apply the robust update factor and the
! 1064: * consistency scaling factor to C( I, L ) and C( K, L ).
! 1065: *
! 1066: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 1067: IF (SCAL .NE. ONE) THEN
! 1068: DO LL = L1, L2-1
! 1069: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1 )
! 1070: END DO
! 1071: ENDIF
! 1072: *
! 1073: SCAL = ( SCAMIN / SWORK( I, L ) ) * SCALOC
! 1074: IF (SCAL .NE. ONE) THEN
! 1075: DO LL = L1, L2-1
! 1076: CALL DSCAL( I2-I1, SCAL, C( I1, LL ), 1 )
! 1077: END DO
! 1078: ENDIF
! 1079: *
! 1080: * Record current scaling factor
! 1081: *
! 1082: SWORK( K, L ) = SCAMIN * SCALOC
! 1083: SWORK( I, L ) = SCAMIN * SCALOC
! 1084: *
! 1085: CALL DGEMM( 'N', 'N', I2-I1, L2-L1, K2-K1, -ONE,
! 1086: $ A( I1, K1 ), LDA, C( K1, L1 ), LDC,
! 1087: $ ONE, C( I1, L1 ), LDC )
! 1088: *
! 1089: END DO
! 1090: *
! 1091: DO J = 1, L - 1
! 1092: *
! 1093: * C( K, J ) := C( K, J ) - SGN * C( K, L ) * B( J, L )**T
! 1094: *
! 1095: J1 = IWORK( PC + J )
! 1096: J2 = IWORK( PC + J + 1 )
! 1097: *
! 1098: * Compute scaling factor to survive the linear update
! 1099: * simulating consistent scaling.
! 1100: *
! 1101: CNRM = DLANGE( 'I', K2-K1, J2-J1, C( K1, J1 ),
! 1102: $ LDC, WNRM )
! 1103: SCAMIN = MIN( SWORK( K, J ), SWORK( K, L ) )
! 1104: CNRM = CNRM * ( SCAMIN / SWORK( K, J ) )
! 1105: XNRM = XNRM * ( SCAMIN / SWORK( K, L ) )
! 1106: BNRM = SWORK( L, BWRK + J )
! 1107: SCALOC = DLARMM( BNRM, XNRM, CNRM )
! 1108: IF( SCALOC * SCAMIN .EQ. ZERO ) THEN
! 1109: * Use second scaling factor to prevent flushing to zero.
! 1110: BUF = BUF*2.D0**EXPONENT( SCALOC )
! 1111: DO JJ = 1, NBB
! 1112: DO LL = 1, NBA
! 1113: SWORK( LL, JJ ) = MIN( BIGNUM,
! 1114: $ SWORK( LL, JJ ) / 2.D0**EXPONENT( SCALOC ) )
! 1115: END DO
! 1116: END DO
! 1117: SCAMIN = SCAMIN / 2.D0**EXPONENT( SCALOC )
! 1118: SCALOC = SCALOC / 2.D0**EXPONENT( SCALOC )
! 1119: END IF
! 1120: CNRM = CNRM * SCALOC
! 1121: XNRM = XNRM * SCALOC
! 1122: *
! 1123: * Simultaneously apply the robust update factor and the
! 1124: * consistency scaling factor to C( K, J ) and C( K, L ).
! 1125: *
! 1126: SCAL = ( SCAMIN / SWORK( K, L ) ) * SCALOC
! 1127: IF( SCAL .NE. ONE ) THEN
! 1128: DO JJ = L1, L2-1
! 1129: CALL DSCAL( K2-K1, SCAL, C( K1, JJ ), 1 )
! 1130: END DO
! 1131: ENDIF
! 1132: *
! 1133: SCAL = ( SCAMIN / SWORK( K, J ) ) * SCALOC
! 1134: IF( SCAL .NE. ONE ) THEN
! 1135: DO JJ = J1, J2-1
! 1136: CALL DSCAL( K2-K1, SCAL, C( K1, JJ ), 1 )
! 1137: END DO
! 1138: ENDIF
! 1139: *
! 1140: * Record current scaling factor
! 1141: *
! 1142: SWORK( K, L ) = SCAMIN * SCALOC
! 1143: SWORK( K, J ) = SCAMIN * SCALOC
! 1144: *
! 1145: CALL DGEMM( 'N', 'T', K2-K1, J2-J1, L2-L1, -SGN,
! 1146: $ C( K1, L1 ), LDC, B( J1, L1 ), LDB,
! 1147: $ ONE, C( K1, J1 ), LDC )
! 1148: END DO
! 1149: END DO
! 1150: END DO
! 1151: *
! 1152: END IF
! 1153: *
! 1154: * Reduce local scaling factors
! 1155: *
! 1156: SCALE = SWORK( 1, 1 )
! 1157: DO K = 1, NBA
! 1158: DO L = 1, NBB
! 1159: SCALE = MIN( SCALE, SWORK( K, L ) )
! 1160: END DO
! 1161: END DO
! 1162: *
! 1163: IF( SCALE .EQ. ZERO ) THEN
! 1164: *
! 1165: * The magnitude of the largest entry of the solution is larger
! 1166: * than the product of BIGNUM**2 and cannot be represented in the
! 1167: * form (1/SCALE)*X if SCALE is DOUBLE PRECISION. Set SCALE to
! 1168: * zero and give up.
! 1169: *
! 1170: IWORK(1) = NBA + NBB + 2
! 1171: SWORK(1,1) = MAX( NBA, NBB )
! 1172: SWORK(2,1) = 2 * NBB + NBA
! 1173: RETURN
! 1174: END IF
! 1175: *
! 1176: * Realize consistent scaling
! 1177: *
! 1178: DO K = 1, NBA
! 1179: K1 = IWORK( K )
! 1180: K2 = IWORK( K + 1 )
! 1181: DO L = 1, NBB
! 1182: L1 = IWORK( PC + L )
! 1183: L2 = IWORK( PC + L + 1 )
! 1184: SCAL = SCALE / SWORK( K, L )
! 1185: IF( SCAL .NE. ONE ) THEN
! 1186: DO LL = L1, L2-1
! 1187: CALL DSCAL( K2-K1, SCAL, C( K1, LL ), 1 )
! 1188: END DO
! 1189: ENDIF
! 1190: END DO
! 1191: END DO
! 1192: *
! 1193: IF( BUF .NE. ONE .AND. BUF.GT.ZERO ) THEN
! 1194: *
! 1195: * Decrease SCALE as much as possible.
! 1196: *
! 1197: SCALOC = MIN( SCALE / SMLNUM, ONE / BUF )
! 1198: BUF = BUF * SCALOC
! 1199: SCALE = SCALE / SCALOC
! 1200: END IF
! 1201:
! 1202: IF( BUF.NE.ONE .AND. BUF.GT.ZERO ) THEN
! 1203: *
! 1204: * In case of overly aggressive scaling during the computation,
! 1205: * flushing of the global scale factor may be prevented by
! 1206: * undoing some of the scaling. This step is to ensure that
! 1207: * this routine flushes only scale factors that TRSYL also
! 1208: * flushes and be usable as a drop-in replacement.
! 1209: *
! 1210: * How much can the normwise largest entry be upscaled?
! 1211: *
! 1212: SCAL = C( 1, 1 )
! 1213: DO K = 1, M
! 1214: DO L = 1, N
! 1215: SCAL = MAX( SCAL, ABS( C( K, L ) ) )
! 1216: END DO
! 1217: END DO
! 1218: *
! 1219: * Increase BUF as close to 1 as possible and apply scaling.
! 1220: *
! 1221: SCALOC = MIN( BIGNUM / SCAL, ONE / BUF )
! 1222: BUF = BUF * SCALOC
! 1223: CALL DLASCL( 'G', -1, -1, ONE, SCALOC, M, N, C, LDC, IWORK )
! 1224: END IF
! 1225: *
! 1226: * Combine with buffer scaling factor. SCALE will be flushed if
! 1227: * BUF is less than one here.
! 1228: *
! 1229: SCALE = SCALE * BUF
! 1230: *
! 1231: * Restore workspace dimensions
! 1232: *
! 1233: IWORK(1) = NBA + NBB + 2
! 1234: SWORK(1,1) = MAX( NBA, NBB )
! 1235: SWORK(2,1) = 2 * NBB + NBA
! 1236: *
! 1237: RETURN
! 1238: *
! 1239: * End of DTRSYL3
! 1240: *
! 1241: END
CVSweb interface <joel.bertrand@systella.fr>