1 SUBROUTINE pdgerfs( TRANS, N, NRHS, A, IA, JA, DESCA, AF, IAF,
2 $ JAF, DESCAF, IPIV, B, IB, JB, DESCB, X, IX,
3 $ JX, DESCX, FERR, BERR, WORK, LWORK, IWORK,
13 INTEGER IA, IAF, IB, IX, INFO, JA, JAF, JB, JX,
14 $ LIWORK, LWORK, N, NRHS
17 INTEGER DESCA( * ), DESCAF( * ), DESCB( * ),
18 $ DESCX( * ),IPIV( * ), IWORK( * )
19 DOUBLE PRECISION A( * ), AF( * ), B( * ), BERR( * ), FERR( * ),
261 INTEGER BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
262 $ LLD_, MB_, M_, NB_, N_, RSRC_
263 PARAMETER ( BLOCK_CYCLIC_2D = 1, dlen_ = 9, dtype_ = 1,
264 $ ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
265 $ rsrc_ = 7, csrc_ = 8, lld_ = 9 )
267 PARAMETER ( ITMAX = 5 )
268 double precision zero, one
269 parameter( zero = 0.0d+0, one = 1.0d+0 )
270 DOUBLE PRECISION TWO, THREE
271 parameter( two = 2.0d+0, three = 3.0d+0 )
274 LOGICAL LQUERY, NOTRAN
276 INTEGER COUNT, IACOL, IAFCOL, IAFROW, IAROW, IXBCOL,
277 $ ixbrow, ixcol, ixrow, icoffa, icoffaf, icoffb,
278 $ icoffx, ictxt, icurcol, idum, ii, iixb, iiw,
279 $ ioffxb, ipb, ipr, ipv, iroffa, iroffaf, iroffb,
280 $ iroffx, iw, j, jbrhs, jj, jjfbe, jjxb, jn, jw,
281 $ k, kase, ldxb, liwmin, lwmin, mycol, myrhs,
282 $ myrow, np, np0, npcol, npmod, nprow, nz
283 DOUBLE PRECISION EPS, EST, LSTRES, S, SAFE1, SAFE2, SAFMIN
286 INTEGER DESCW( DLEN_ ), IDUM1( 5 ), IDUM2( 5 )
290 INTEGER ICEIL, INDXG2P, NUMROC
291 DOUBLE PRECISION PDLAMCH
292 EXTERNAL iceil, indxg2p, lsame, numroc, pdlamch
297 $ pdagemv,
pdaxpy, pdcopy, pdgemv,
301 INTRINSIC abs, dble, ichar,
max,
min, mod
307 ictxt = desca( ctxt_ )
312 notran = lsame( trans,
'N' )
315 IF( nprow.EQ.-1 )
THEN
318 CALL chk1mat( n, 2, n, 2, ia, ja, desca, 7, info )
319 CALL chk1mat( n, 2, n, 2, iaf, jaf, descaf, 11, info )
320 CALL chk1mat( n, 2, nrhs, 3, ib, jb, descb, 16, info )
321 CALL chk1mat( n, 2, nrhs, 3, ix, jx, descx, 20, info )
323 iroffa = mod( ia-1, desca( mb_ ) )
324 icoffa = mod( ja-1, desca( nb_ ) )
325 iroffaf = mod( iaf-1, descaf( mb_ ) )
326 icoffaf = mod( jaf-1, descaf( nb_ ) )
327 iroffb = mod( ib-1, descb( mb_ ) )
328 icoffb = mod( jb-1, descb( nb_ ) )
329 iroffx = mod( ix-1, descx( mb_ ) )
330 icoffx = mod( jx-1, descx( nb_ ) )
331 iarow = indxg2p( ia, desca( mb_ ), myrow, desca( rsrc_ ),
333 iafcol = indxg2p( jaf, descaf( nb_ ), mycol,
334 $ descaf( csrc_ ), npcol )
335 iafrow = indxg2p( iaf, descaf( mb_ ), myrow,
336 $ descaf( rsrc_ ), nprow )
337 iacol = indxg2p( ja, desca( nb_ ), mycol, desca( csrc_ ),
339 CALL infog2l( ib, jb, descb, nprow, npcol, myrow, mycol,
340 $ iixb, jjxb, ixbrow, ixbcol )
341 ixrow = indxg2p( ix, descx( mb_ ), myrow, descx( rsrc_ ),
343 ixcol = indxg2p( jx, descx( nb_ ), mycol, descx( csrc_ ),
349 work( 1 ) = dble( lwmin )
351 lquery = ( lwork.EQ.-1 .OR. liwork.EQ.-1 )
353 IF( ( .NOT.notran ) .AND. ( .NOT.lsame( trans,
'T' ) ) .AND.
354 $ ( .NOT.lsame( trans,
'C' ) ) )
THEN
356 ELSE IF( n.LT.0 )
THEN
358 ELSE IF( nrhs.LT.0 )
THEN
360 ELSE IF( iroffa.NE.0 )
THEN
362 ELSE IF( icoffa.NE.0 )
THEN
364 ELSE IF( desca( mb_ ).NE.desca( nb_ ) )
THEN
365 info = -( 700 + nb_ )
366 ELSE IF( desca( mb_ ).NE.descaf( mb_ ) )
THEN
367 info = -( 1100 + mb_ )
368 ELSE IF( iroffaf.NE.0 .OR. iarow.NE.iafrow )
THEN
370 ELSE IF( desca( nb_ ).NE.descaf( nb_ ) )
THEN
371 info = -( 1100 + nb_ )
372 ELSE IF( icoffaf.NE.0 .OR. iacol.NE.iafcol )
THEN
374 ELSE IF( ictxt.NE.descaf( ctxt_
THEN
375 info = -( 1100 + ctxt_ )
376 ELSE IF( iroffa.NE.iroffb .OR. iarow.NE.ixbrow )
THEN
379 info = -( 1600 + mb_ )
380 ELSE IF( ictxt.NE.descb( ctxt_ ) )
THEN
381 info = -( 1600 + ctxt_ )
383 info = -( 2000 + mb_ )
384 ELSE IF( iroffx.NE.0 .OR. ixbrow.NE.ixrow )
THEN
386 ELSE IF( descb( nb_ ).NE.descx( nb_ ) )
THEN
387 info = -( 2000 + nb_ )
388 ELSE IF( icoffb.NE.icoffx .OR. ixbcol.NE.ixcol )
THEN
390 ELSE IF( ictxt.NE.descx( ctxt_ ) )
THEN
391 info = -( 2000 + ctxt_ )
392 ELSE IF( lwork.LT.lwmin .AND. .NOT.lquery )
THEN
394 ELSE IF( liwork.LT.liwmin .AND. .NOT.lquery )
THEN
400 idum1( 1 ) = ichar(
'N' )
401 ELSE IF( lsame( trans,
'T' ) )
THEN
402 idum1( 1 ) = ichar(
'T' )
404 idum1( 1 ) = ichar(
'C'
411 IF( lwork.EQ.-1 )
THEN
417 IF( liwork.EQ.-1 )
THEN
423 CALL pchk2mat( n, 2, n, 2, ia, ja, desca, 7, n, 2, n, 2, iaf,
424 $ jaf, descaf, 11, 5, idum1, idum2, info )
425 CALL pchk2mat( n, 2, nrhs, 3, ib, jb, descb, 16, n, 2, nrhs, 3,
426 $ ix, jx, descx, 20, 5, idum1, idum2, info )
429 CALL pxerbla( ictxt,
'PDGERFS', -info )
431 ELSE IF( lquery )
THEN
436 myrhs = numroc( jb+nrhs-1, descb( nb_ ), mycol, descb( csrc_ ),
441 IF( n.LE.1 .OR. nrhs.EQ.0 )
THEN
442 DO 10 jj = jjfbe, myrhs
455 np0 = numroc( n+iroffb, descb( mb_ ), myrow, ixbrow, nprow )
456 CALL descset( descw, n+iroffb, 1, desca( mb_ ), 1, ixbrow, ixbcol,
457 $ ictxt,
max( 1, np0 ) )
461 IF( myrow.EQ.ixbrow )
THEN
471 ioffxb = ( jjxb-1 )*ldxb
476 eps = pdlamch( ictxt,
'Epsilon' )
477 safmin = pdlamch( ictxt,
'Safe minimum' )
480 jn =
min( iceil( jb, descb( nb_ ) ) * descb( nb_ ), jb+nrhs-1 )
485 DO 100 k = 0, jbrhs-1
497 CALL pdcopy( n, b, ib, jb+k, descb, 1, work( ipr ), iw, jw,
499 CALL pdgemv( trans, n, n, -one, a, ia, ja, desca, x, ix,
500 $ jx+k, descx, 1, one, work( ipr ), iw, jw,
513 IF( mycol.EQ.ixbcol )
THEN
515 DO 30 ii = iixb, iixb + np - 1
516 work( iiw+ii-iixb ) = abs( b( ii+ioffxb )
521 CALL pdagemv( trans, n, n, one, a, ia, ja, desca, x, ix, jx+k,
522 $ descx, 1, one, work( ipb ), iw, jw, descw, 1 )
525 IF( mycol.EQ.ixbcol )
THEN
527 DO 40 ii = iiw-1, iiw+np-2
528 IF( work( ipb+ii ).GT.safe2 )
THEN
529 s =
max( s, abs( work( ipr+ii ) ) /
532 s =
max( s, ( abs( work( ipr+ii ) )+safe1 ) /
533 $ ( work( ipb+ii )+safe1 ) )
539 CALL dgamx2d( ictxt,
'All', '
', 1, 1, S, 1, IDUM, IDUM, 1,
541.EQ.
IF( MYCOLIXBCOL )
551.GT..AND..LE..AND..LE.
IF( SEPS TWO*SLSTRES COUNTITMAX ) THEN
555 CALL PDGETRS( TRANS, N, 1, AF, IAF, JAF, DESCAF, IPIV,
556 $ WORK( IPR ), IW, JW, DESCW, INFO )
557 CALL PDAXPY( N, ONE, WORK( IPR ), IW, JW, DESCW, 1, X, IX,
590.EQ.
IF( MYCOLIXBCOL ) THEN
592 DO 50 II = IIW-1, IIW+NP-2
593.GT.
IF( WORK( IPB+II )SAFE2 ) THEN
594 WORK( IPB+II ) = ABS( WORK( IPR+II ) ) +
595 $ NZ*EPS*WORK( IPB+II )
597 WORK( IPB+II ) = ABS( WORK( IPR+II ) ) +
598 $ NZ*EPS*WORK( IPB+II ) + SAFE1
606.EQ.
IF( MYCOLIXBCOL ) THEN
607 CALL DGEBS2D( ICTXT, 'rowwise
', ' ', NP, 1, WORK( IPR ),
610 CALL DGEBR2D( ICTXT, 'rowwise
', '', NP, 1, WORK( IPR ),
611 $ DESCW( LLD_ ), MYROW, IXBCOL )
613 DESCW( CSRC_ ) = MYCOL
614 CALL PDLACON( N, WORK( IPV ), IW, JW, DESCW, WORK( IPR ),
615 $ IW, JW, DESCW, IWORK, EST, KASE )
616 DESCW( CSRC_ ) = IXBCOL
623 CALL PDGETRS( TRANST, N, 1, AF, IAF, JAF, DESCAF,
624 $ IPIV, WORK( IPR ), IW, JW, DESCW, INFO )
626.EQ.
IF( MYCOLIXBCOL ) THEN
628 DO 70 II = IIW-1, IIW+NP-2
629 WORK( IPR+II ) = WORK( IPB+II )*WORK( IPR+II )
637.EQ.
IF( MYCOLIXBCOL ) THEN
639 DO 80 II = IIW-1, IIW+NP-2
640 WORK( IPR+II ) = WORK( IPB+II )*WORK( IPR+II )
645 CALL PDGETRS( TRANS, N, 1, AF, IAF, JAF, DESCAF, IPIV,
646 $ WORK( IPR ), IW, JW, DESCW, INFO )
654.EQ.
IF( MYCOLIXBCOL ) THEN
656 DO 90 II = IIXB, IIXB+NP-1
657 LSTRES = MAX( LSTRES, ABS( X( IOFFXB+II ) ) )
660 CALL DGAMX2D( ICTXT, 'column
', ' ', 1, 1, LSTRES, 1, IDUM,
661 $ IDUM, 1, -1, MYCOL )
663 $ FERR( JJFBE ) = EST / LSTRES
667 IOFFXB = IOFFXB + LDXB
673 ICURCOL = MOD( IXBCOL+1, NPCOL )
677 DO 200 J = JN+1, JB+NRHS-1, DESCB( NB_ )
678 JBRHS = MIN( JB+NRHS-J, DESCB( NB_ ) )
679 DESCW( CSRC_ ) = ICURCOL
681 DO 190 K = 0, JBRHS-1
693 CALL PDCOPY( N, B, IB, J+K, DESCB, 1, WORK( IPR ), IW, JW,
695 CALL PDGEMV( TRANS, N, N, -ONE, A, IA, JA, DESCA, X,
696 $ IX, J+K, DESCX, 1, ONE, WORK( IPR ), IW, JW,
710.EQ.
IF( MYCOLICURCOL ) THEN
712 DO 120 II = IIXB, IIXB+NP-1
713 WORK( IIW+II-IIXB ) = ABS( B( II+IOFFXB ) )
718 CALL PDAGEMV( TRANS, N, N, ONE, A, IA, JA, DESCA, X, IX,
719 $ J+K, DESCX, 1, ONE, WORK( IPB ), IW, JW,
723.EQ.
IF( MYCOLICURCOL ) THEN
725 DO 130 II = IIW-1, IIW+NP-2
726.GT.
IF( WORK( IPB+II )SAFE2 ) THEN
727 S = MAX( S, ABS( WORK( IPR+II ) ) /
730 S = MAX( S, ( ABS( WORK( IPR+II ) )+SAFE1 ) /
731 $ ( WORK( IPB+II )+SAFE1 ) )
737 CALL DGAMX2D( ICTXT, 'all
', ' ', 1, 1, S, 1, IDUM, IDUM, 1,
739.EQ.
IF( MYCOLICURCOL )
749.GT..AND..LE..AND.
IF( SEPS TWO*SLSTRES
750.LE.
$ COUNTITMAX ) THEN
754 CALL PDGETRS( TRANS, N, 1, AF, IAF, JAF, DESCAF, IPIV,
755 $ WORK( IPR ), IW, JW, DESCW, INFO )
756 CALL PDAXPY( N, ONE, WORK( IPR ), IW, JW, DESCW, 1, X,
757 $ IX, J+K, DESCX, 1 )
789.EQ.
IF( MYCOLICURCOL ) THEN
791 DO 140 II = IIW-1, IIW+NP-2
792.GT.
IF( WORK( IPB+II )SAFE2 ) THEN
793 WORK( IPB+II ) = ABS( WORK( IPR+II ) ) +
794 $ NZ*EPS*WORK( IPB+II )
796 WORK( IPB+II ) = ABS( WORK( IPR+II ) ) +
797 $ NZ*EPS*WORK( IPB+II ) + SAFE1
805.EQ.
IF( MYCOLICURCOL ) THEN
806 CALL DGEBS2D( ICTXT, 'rowwise
', ' ', NP, 1, WORK( IPR ),
809 CALL DGEBR2D( ICTXT, 'rowwise
', ' ', NP, 1, WORK( IPR ),
810 $ DESCW( LLD_ ), MYROW, ICURCOL )
812 DESCW( CSRC_ ) = MYCOL
813 CALL PDLACON( N, WORK( IPV ), IW, JW, DESCW, WORK( IPR ),
814 $ IW, JW, DESCW, IWORK, EST, KASE )
815 DESCW( CSRC_ ) = ICURCOL
822 CALL PDGETRS( TRANST, N, 1, AF, IAF, JAF, DESCAF,
823 $ IPIV, WORK( IPR ), IW, JW, DESCW, INFO )
825.EQ.
IF( MYCOLICURCOL ) THEN
827 DO 160 II = IIW-1, IIW+NP-2
828 WORK( IPR+II ) = WORK( IPB+II )*
837.EQ.
IF( MYCOLICURCOL ) THEN
839 DO 170 II = IIW-1, IIW+NP-2
840 WORK( IPR+II ) = WORK( IPB+II )*
846 CALL PDGETRS( TRANS, N, 1, AF, IAF, JAF, DESCAF,
847 $ IPIV, WORK( IPR ), IW, JW, DESCW,
856.EQ.
IF( MYCOLICURCOL ) THEN
858 DO 180 II = IIXB, IIXB+NP-1
859 LSTRES = MAX( LSTRES, ABS( X( IOFFXB+II ) ) )
862 CALL DGAMX2D( ICTXT, 'column
', ' ', 1, 1, lstres,
863 $ 1, idum, idum, 1, -1, mycol )
865 $ ferr( jjfbe ) = est / lstres
869 ioffxb = ioffxb + ldxb
875 icurcol = mod( icurcol+1, npcol )
879 work( 1 ) = dble( lwmin )