File:  [local] / rpl / lapack / lapack / dtrsyl3.f
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Mon Aug 7 08:55:30 2023 UTC (8 months, 3 weeks ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_35, rpl-4_1_34, HEAD
Ajout de fichiers de lapack 3.11

    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>