|
SRC\pztrevc.f |
|
| #lines: 567 size: 21 Kb creation: 29/03/2007 01:44:42 last modification: 08/05/2008 18:38:19 attribute: ARCH Find Reload | |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: |
SUBROUTINE PZTREVC( SIDE, HOWMNY, SELECT, N, T, DESCT, VL, DESCVL,
$ VR, DESCVR, MM, M, WORK, RWORK, INFO )
*
* -- ScaLAPACK routine (version 1.7) --
* University of Tennessee, Knoxville, Oak Ridge National Laboratory,
* and University of California, Berkeley.
* July 31, 2001
*
* .. Scalar Arguments ..
CHARACTER HOWMNY, SIDE
INTEGER INFO, M, MM, N
* ..
* .. Array Arguments ..
LOGICAL SELECT( * )
INTEGER DESCT( * ), DESCVL( * ), DESCVR( * )
DOUBLE PRECISION RWORK( * )
COMPLEX*16 T( * ), VL( * ), VR( * ), WORK( * )
* ..
*
* Purpose
* =======
*
* PZTREVC computes some or all of the right and/or left eigenvectors of
* a complex upper triangular matrix T in parallel.
*
* The right eigenvector x and the left eigenvector y of T corresponding
* to an eigenvalue w are defined by:
*
* T*x = w*x, y'*T = w*y'
*
* where y' denotes the conjugate transpose of the vector y.
*
* If all eigenvectors are requested, the routine may either return the
* matrices X and/or Y of right or left eigenvectors of T, or the
* products Q*X and/or Q*Y, where Q is an input unitary
* matrix. If T was obtained from the Schur factorization of an
* original matrix A = Q*T*Q', then Q*X and Q*Y are the matrices of
* right or left eigenvectors of A.
*
* Notes
* =====
*
* Each global data object is described by an associated description
* vector. This vector stores the information required to establish
* the mapping between an object element and its corresponding process
* and memory location.
*
* Let A be a generic term for any 2D block cyclicly distributed array.
* Such a global array has an associated description vector DESCA.
* In the following comments, the character _ should be read as
* "of the global array".
*
* NOTATION STORED IN EXPLANATION
* --------------- -------------- --------------------------------------
* DTYPE_A(global) DESCA( DTYPE_ )The descriptor type. In this case,
* DTYPE_A = 1.
* CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
* the BLACS process grid A is distribu-
* ted over. The context itself is glo-
* bal, but the handle (the integer
* value) may vary.
* M_A (global) DESCA( M_ ) The number of rows in the global
* array A.
* N_A (global) DESCA( N_ ) The number of columns in the global
* array A.
* MB_A (global) DESCA( MB_ ) The blocking factor used to distribute
* the rows of the array.
* NB_A (global) DESCA( NB_ ) The blocking factor used to distribute
* the columns of the array.
* RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
* row of the array A is distributed.
* CSRC_A (global) DESCA( CSRC_ ) The process column over which the
* first column of the array A is
* distributed.
* LLD_A (local) DESCA( LLD_ ) The leading dimension of the local
* array. LLD_A >= MAX(1,LOCr(M_A)).
*
* Let K be the number of rows or columns of a distributed matrix,
* and assume that its process grid has dimension r x c.
* LOCr( K ) denotes the number of elements of K that a process
* would receive if K were distributed over the r processes of its
* process column.
* Similarly, LOCc( K ) denotes the number of elements of K that a
* process would receive if K were distributed over the c processes of
* its process row.
* The values of LOCr() and LOCc() may be determined via a call to the
* ScaLAPACK tool function, NUMROC:
* LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
* LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
* An upper bound for these quantities may be computed by:
* LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
* LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
*
* Arguments
* =========
*
* SIDE (global input) CHARACTER*1
* = 'R': compute right eigenvectors only;
* = 'L': compute left eigenvectors only;
* = 'B': compute both right and left eigenvectors.
*
* HOWMNY (global input) CHARACTER*1
* = 'A': compute all right and/or left eigenvectors;
* = 'B': compute all right and/or left eigenvectors,
* and backtransform them using the input matrices
* supplied in VR and/or VL;
* = 'S': compute selected right and/or left eigenvectors,
* specified by the logical array SELECT.
*
* SELECT (global input) LOGICAL array, dimension (N)
* If HOWMNY = 'S', SELECT specifies the eigenvectors to be
* computed.
* If HOWMNY = 'A' or 'B', SELECT is not referenced.
* To select the eigenvector corresponding to the j-th
* eigenvalue, SELECT(j) must be set to .TRUE..
*
* N (global input) INTEGER
* The order of the matrix T. N >= 0.
*
* T (global input/output) COMPLEX*16 array, dimension
* (DESCT(LLD_),*)
* The upper triangular matrix T. T is modified, but restored
* on exit.
*
* DESCT (global and local input) INTEGER array of dimension DLEN_.
* The array descriptor for the distributed matrix T.
*
* VL (global input/output) COMPLEX*16 array, dimension
* (DESCVL(LLD_),MM)
* On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must
* contain an N-by-N matrix Q (usually the unitary matrix Q of
* Schur vectors returned by ZHSEQR).
* On exit, if SIDE = 'L' or 'B', VL contains:
* if HOWMNY = 'A', the matrix Y of left eigenvectors of T;
* if HOWMNY = 'B', the matrix Q*Y;
* if HOWMNY = 'S', the left eigenvectors of T specified by
* SELECT, stored consecutively in the columns
* of VL, in the same order as their
* eigenvalues.
* If SIDE = 'R', VL is not referenced.
*
* DESCVL (global and local input) INTEGER array of dimension DLEN_.
* The array descriptor for the distributed matrix VL.
*
* VR (global input/output) COMPLEX*16 array, dimension
* (DESCVR(LLD_),MM)
* On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must
* contain an N-by-N matrix Q (usually the unitary matrix Q of
* Schur vectors returned by ZHSEQR).
* On exit, if SIDE = 'R' or 'B', VR contains:
* if HOWMNY = 'A', the matrix X of right eigenvectors of T;
* if HOWMNY = 'B', the matrix Q*X;
* if HOWMNY = 'S', the right eigenvectors of T specified by
* SELECT, stored consecutively in the columns
* of VR, in the same order as their
* eigenvalues.
* If SIDE = 'L', VR is not referenced.
*
* DESCVR (global and local input) INTEGER array of dimension DLEN_.
* The array descriptor for the distributed matrix VR.
*
* MM (global input) INTEGER
* The number of columns in the arrays VL and/or VR. MM >= M.
*
* M (global output) INTEGER
* The number of columns in the arrays VL and/or VR actually
* used to store the eigenvectors. If HOWMNY = 'A' or 'B', M
* is set to N. Each selected eigenvector occupies one
* column.
*
* WORK (local workspace) COMPLEX*16 array,
* dimension ( 2*DESCT(LLD_) )
* Additional workspace may be required if PZLATTRS is updated
* to use WORK.
*
* RWORK (local workspace) DOUBLE PRECISION array,
* dimension ( DESCT(LLD_) )
*
* INFO (global output) INTEGER
* = 0: successful exit
* < 0: if INFO = -i, the i-th argument had an illegal value
*
* Further Details
* ===============
*
* The algorithm used in this program is basically backward (forward)
* substitution. It is the hope that scaling would be used to make the
* the code robust against possible overflow. But scaling has not yet
* been implemented in PZLATTRS which is called by this routine to solve
* the triangular systems. PZLATTRS just calls PZTRSV.
*
* Each eigenvector is normalized so that the element of largest
* magnitude has magnitude 1; here the magnitude of a complex number
* (x,y) is taken to be |x| + |y|.
*
* Further Details
* ===============
*
* Implemented by Mark R. Fahey, June, 2000
*
* =====================================================================
*
* .. Parameters ..
DOUBLE PRECISION ZERO, ONE
PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
COMPLEX*16 CZERO, CONE
PARAMETER ( CZERO = ( 0.0D+0, 0.0D+0 ),
$ CONE = ( 1.0D+0, 0.0D+0 ) )
INTEGER BLOCK_CYCLIC_2D, DLEN_, DTYPE_, CTXT_, M_, N_,
$ MB_, NB_, RSRC_, CSRC_, LLD_
PARAMETER ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
$ CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
$ RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
* ..
* .. Local Scalars ..
LOGICAL ALLV, BOTHV, LEFTV, OVER, RIGHTV, SOMEV
INTEGER CONTXT, CSRC, I, ICOL, II, IROW, IS, ITMP1,
$ ITMP2, J, K, KI, LDT, LDVL, LDVR, LDW, MB,
$ MYCOL, MYROW, NB, NPCOL, NPROW, RSRC
REAL SELF
DOUBLE PRECISION OVFL, REMAXD, SCALE, SMIN, SMLNUM, ULP, UNFL
COMPLEX*16 CDUM, REMAXC, SHIFT
* ..
* .. Local Arrays ..
INTEGER DESCW( DLEN_ )
* ..
* .. External Functions ..
LOGICAL LSAME
DOUBLE PRECISION PDLAMCH
EXTERNAL LSAME, PDLAMCH
* ..
* .. External Subroutines ..
EXTERNAL BLACS_GRIDINFO, DESCINIT, DGSUM2D, IGAMN2D,
$ INFOG2L, PDLABAD, PDZASUM, PXERBLA, PZAMAX,
$ PZCOPY, PZDSCAL, PZGEMV, PZLASET, PZLATTRS,
$ ZGSUM2D
* ..
* .. Intrinsic Functions ..
INTRINSIC ABS, DBLE, DCMPLX, DCONJG, DIMAG, MAX
* ..
* .. Statement Functions ..
DOUBLE PRECISION CABS1
* ..
* .. Statement Function definitions ..
CABS1( CDUM ) = ABS( DBLE( CDUM ) ) + ABS( DIMAG( CDUM ) )
* ..
* .. Executable Statements ..
*
* This is just to keep ftnchek happy
IF( BLOCK_CYCLIC_2D*CSRC_*CTXT_*DLEN_*DTYPE_*LLD_*MB_*M_*NB_*N_*
$ RSRC_.LT.0 )RETURN
*
CONTXT = DESCT( CTXT_ )
RSRC = DESCT( RSRC_ )
CSRC = DESCT( CSRC_ )
MB = DESCT( MB_ )
NB = DESCT( NB_ )
LDT = DESCT( LLD_ )
LDW = LDT
LDVR = DESCVR( LLD_ )
LDVL = DESCVL( LLD_ )
*
CALL BLACS_GRIDINFO( CONTXT, NPROW, NPCOL, MYROW, MYCOL )
SELF = MYROW*NPCOL + MYCOL
*
* Decode and test the input parameters
*
BOTHV = LSAME( SIDE, 'B' )
RIGHTV = LSAME( SIDE, 'R' ) .OR. BOTHV
LEFTV = LSAME( SIDE, 'L' ) .OR. BOTHV
*
ALLV = LSAME( HOWMNY, 'A' )
OVER = LSAME( HOWMNY, 'B' ) .OR. LSAME( HOWMNY, 'O' )
SOMEV = LSAME( HOWMNY, 'S' )
*
* Set M to the number of columns required to store the selected
* eigenvectors.
*
IF( SOMEV ) THEN
M = 0
DO 10 J = 1, N
IF( SELECT( J ) )
$ M = M + 1
10 CONTINUE
ELSE
M = N
END IF
*
INFO = 0
IF( .NOT.RIGHTV .AND. .NOT.LEFTV ) THEN
INFO = -1
ELSE IF( .NOT.ALLV .AND. .NOT.OVER .AND. .NOT.SOMEV ) THEN
INFO = -2
ELSE IF( N.LT.0 ) THEN
INFO = -4
ELSE IF( MM.LT.M ) THEN
INFO = -11
END IF
CALL IGAMN2D( CONTXT, 'ALL', ' ', 1, 1, INFO, 1, ITMP1, ITMP2, -1,
$ -1, -1 )
IF( INFO.LT.0 ) THEN
CALL PXERBLA( CONTXT, 'PZTREVC', -INFO )
RETURN
END IF
*
* Quick return if possible.
*
IF( N.EQ.0 )
$ RETURN
*
* Set the constants to control overflow.
*
UNFL = PDLAMCH( CONTXT, 'Safe minimum' )
OVFL = ONE / UNFL
CALL PDLABAD( CONTXT, UNFL, OVFL )
ULP = PDLAMCH( CONTXT, 'Precision' )
SMLNUM = UNFL*( N / ULP )
*
* Store the diagonal elements of T in working array WORK( LDW+1 ).
*
DO 20 I = 1, N
CALL INFOG2L( I, I, DESCT, NPROW, NPCOL, MYROW, MYCOL, IROW,
$ ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
WORK( LDW+IROW ) = T( ( ICOL-1 )*LDT+IROW )
END IF
20 CONTINUE
*
* Compute 1-norm of each column of strictly upper triangular
* part of T to control overflow in triangular solver. Computed,
* but not used. For use in PZLATTRS.
*
RWORK( 1 ) = ZERO
DO 30 J = 2, N
CALL PDZASUM( J-1, RWORK( J ), T, 1, J, DESCT, 1 )
30 CONTINUE
* I replicate the norms in RWORK. Should they be distributed
* over the process rows?
CALL DGSUM2D( CONTXT, 'Row', ' ', N, 1, RWORK, N, -1, -1 )
*
IF( RIGHTV ) THEN
*
* Compute right eigenvectors.
*
* Need to set the distribution pattern of WORK
*
CALL DESCINIT( DESCW, N, 1, NB, 1, RSRC, CSRC, CONTXT, LDW,
$ INFO )
*
IS = M
DO 70 KI = N, 1, -1
*
IF( SOMEV ) THEN
IF( .NOT.SELECT( KI ) )
$ GO TO 70
END IF
*
SMIN = ZERO
SHIFT = CZERO
CALL INFOG2L( KI, KI, DESCT, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
SHIFT = T( ( ICOL-1 )*LDT+IROW )
SMIN = MAX( ULP*( CABS1( SHIFT ) ), SMLNUM )
END IF
CALL DGSUM2D( CONTXT, 'ALL', ' ', 1, 1, SMIN, 1, -1, -1 )
CALL ZGSUM2D( CONTXT, 'ALL', ' ', 1, 1, SHIFT, 1, -1, -1 )
*
CALL INFOG2L( 1, 1, DESCW, NPROW, NPCOL, MYROW, MYCOL, IROW,
$ ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
WORK( 1 ) = CONE
END IF
*
* Form right-hand side. Distribute rhs onto first column
* of processor grid.
*
IF( KI.GT.1 ) THEN
CALL PZCOPY( KI-1, T, 1, KI, DESCT, 1, WORK, 1, 1, DESCW,
$ 1 )
END IF
DO 40 K = 1, KI - 1
CALL INFOG2L( K, 1, DESCW, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( MYROW.EQ.ITMP1 .AND. MYCOL.EQ.ITMP2 ) THEN
WORK( IROW ) = -WORK( IROW )
END IF
40 CONTINUE
*
* Solve the triangular system:
* (T(1:KI-1,1:KI-1) - T(KI,KI))*X = SCALE*WORK.
*
DO 50 K = 1, KI - 1
CALL INFOG2L( K, K, DESCT, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
T( ( ICOL-1 )*LDT+IROW ) = T( ( ICOL-1 )*LDT+IROW ) -
$ SHIFT
IF( CABS1( T( ( ICOL-1 )*LDT+IROW ) ).LT.SMIN ) THEN
T( ( ICOL-1 )*LDT+IROW ) = DCMPLX( SMIN )
END IF
END IF
50 CONTINUE
*
IF( KI.GT.1 ) THEN
CALL PZLATTRS( 'Upper', 'No transpose', 'Non-unit', 'Y',
$ KI-1, T, 1, 1, DESCT, WORK, 1, 1, DESCW,
$ SCALE, RWORK, INFO )
CALL INFOG2L( KI, 1, DESCW, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( MYROW.EQ.ITMP1 .AND. MYCOL.EQ.ITMP2 ) THEN
WORK( IROW ) = DCMPLX( SCALE )
END IF
END IF
*
* Copy the vector x or Q*x to VR and normalize.
*
IF( .NOT.OVER ) THEN
CALL PZCOPY( KI, WORK, 1, 1, DESCW, 1, VR, 1, IS, DESCVR,
$ 1 )
*
CALL PZAMAX( KI, REMAXC, II, VR, 1, IS, DESCVR, 1 )
REMAXD = ONE / MAX( CABS1( REMAXC ), UNFL )
CALL PZDSCAL( KI, REMAXD, VR, 1, IS, DESCVR, 1 )
*
CALL PZLASET( ' ', N-KI, 1, CZERO, CZERO, VR, KI+1, IS,
$ DESCVR )
ELSE
IF( KI.GT.1 )
$ CALL PZGEMV( 'N', N, KI-1, CONE, VR, 1, 1, DESCVR,
$ WORK, 1, 1, DESCW, 1, DCMPLX( SCALE ),
$ VR, 1, KI, DESCVR, 1 )
*
CALL PZAMAX( N, REMAXC, II, VR, 1, KI, DESCVR, 1 )
REMAXD = ONE / MAX( CABS1( REMAXC ), UNFL )
CALL PZDSCAL( N, REMAXD, VR, 1, KI, DESCVR, 1 )
END IF
*
* Set back the original diagonal elements of T.
*
DO 60 K = 1, KI - 1
CALL INFOG2L( K, K, DESCT, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
T( ( ICOL-1 )*LDT+IROW ) = WORK( LDW+IROW )
END IF
60 CONTINUE
*
IS = IS - 1
70 CONTINUE
END IF
*
IF( LEFTV ) THEN
*
* Compute left eigenvectors.
*
* Need to set the distribution pattern of WORK
*
CALL DESCINIT( DESCW, N, 1, MB, 1, RSRC, CSRC, CONTXT, LDW,
$ INFO )
*
IS = 1
DO 110 KI = 1, N
*
IF( SOMEV ) THEN
IF( .NOT.SELECT( KI ) )
$ GO TO 110
END IF
*
SMIN = ZERO
SHIFT = CZERO
CALL INFOG2L( KI, KI, DESCT, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
SHIFT = T( ( ICOL-1 )*LDT+IROW )
SMIN = MAX( ULP*( CABS1( SHIFT ) ), SMLNUM )
END IF
CALL DGSUM2D( CONTXT, 'ALL', ' ', 1, 1, SMIN, 1, -1, -1 )
CALL ZGSUM2D( CONTXT, 'ALL', ' ', 1, 1, SHIFT, 1, -1, -1 )
*
CALL INFOG2L( N, 1, DESCW, NPROW, NPCOL, MYROW, MYCOL, IROW,
$ ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
WORK( IROW ) = CONE
END IF
*
* Form right-hand side.
*
IF( KI.LT.N ) THEN
CALL PZCOPY( N-KI, T, KI, KI+1, DESCT, N, WORK, KI+1, 1,
$ DESCW, 1 )
END IF
DO 80 K = KI + 1, N
CALL INFOG2L( K, 1, DESCW, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( MYROW.EQ.ITMP1 .AND. MYCOL.EQ.ITMP2 ) THEN
WORK( IROW ) = -DCONJG( WORK( IROW ) )
END IF
80 CONTINUE
*
* Solve the triangular system:
* (T(KI+1:N,KI+1:N) - T(KI,KI))'*X = SCALE*WORK.
*
DO 90 K = KI + 1, N
CALL INFOG2L( K, K, DESCT, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
T( ( ICOL-1 )*LDT+IROW ) = T( ( ICOL-1 )*LDT+IROW ) -
$ SHIFT
IF( CABS1( T( ( ICOL-1 )*LDT+IROW ) ).LT.SMIN )
$ T( ( ICOL-1 )*LDT+IROW ) = DCMPLX( SMIN )
END IF
90 CONTINUE
*
IF( KI.LT.N ) THEN
CALL PZLATTRS( 'Upper', 'Conjugate transpose', 'Nonunit',
$ 'Y', N-KI, T, KI+1, KI+1, DESCT, WORK,
$ KI+1, 1, DESCW, SCALE, RWORK, INFO )
CALL INFOG2L( KI, 1, DESCW, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( MYROW.EQ.ITMP1 .AND. MYCOL.EQ.ITMP2 ) THEN
WORK( IROW ) = DCMPLX( SCALE )
END IF
END IF
*
* Copy the vector x or Q*x to VL and normalize.
*
IF( .NOT.OVER ) THEN
CALL PZCOPY( N-KI+1, WORK, KI, 1, DESCW, 1, VL, KI, IS,
$ DESCVL, 1 )
*
CALL PZAMAX( N-KI+1, REMAXC, II, VL, KI, IS, DESCVL, 1 )
REMAXD = ONE / MAX( CABS1( REMAXC ), UNFL )
CALL PZDSCAL( N-KI+1, REMAXD, VL, KI, IS, DESCVL, 1 )
*
CALL PZLASET( ' ', KI-1, 1, CZERO, CZERO, VL, 1, IS,
$ DESCVL )
ELSE
IF( KI.LT.N )
$ CALL PZGEMV( 'N', N, N-KI, CONE, VL, 1, KI+1, DESCVL,
$ WORK, KI+1, 1, DESCW, 1, DCMPLX( SCALE ),
$ VL, 1, KI, DESCVL, 1 )
*
CALL PZAMAX( N, REMAXC, II, VL, 1, KI, DESCVL, 1 )
REMAXD = ONE / MAX( CABS1( REMAXC ), UNFL )
CALL PZDSCAL( N, REMAXD, VL, 1, KI, DESCVL, 1 )
END IF
*
* Set back the original diagonal elements of T.
*
DO 100 K = KI + 1, N
CALL INFOG2L( K, K, DESCT, NPROW, NPCOL, MYROW, MYCOL,
$ IROW, ICOL, ITMP1, ITMP2 )
IF( ( MYROW.EQ.ITMP1 ) .AND. ( MYCOL.EQ.ITMP2 ) ) THEN
T( ( ICOL-1 )*LDT+IROW ) = WORK( LDW+IROW )
END IF
100 CONTINUE
*
IS = IS + 1
110 CONTINUE
END IF
*
RETURN
*
* End of PZTREVC
*
END
|