1 SUBROUTINE pcgerfs( 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, RWORK,
13 INTEGER IA, IAF, IB, IX, INFO, JA, JAF, JB, JX,
14 $ LRWORK, LWORK, N, NRHS
17 INTEGER DESCA( * ), DESCAF( * ), DESCB( * ),
18 $ DESCX( * ), IPIV( * )
19 REAL BERR( * ), FERR( * ), RWORK( * )
20 COMPLEX A( * ), AF( * ), B( * ), WORK( * ), X( * )
260 INTEGER BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
261 $ LLD_, MB_, M_, NB_, N_, RSRC_
262 PARAMETER ( BLOCK_CYCLIC_2D = 1, dlen_ = 9, dtype_ = 1,
263 $ ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
264 $ rsrc_ = 7, csrc_ = 8, lld_ = 9 )
266 PARAMETER ( ITMAX = 5 )
267 real zero, rone, two, three
268 parameter( zero = 0.0e+0, rone = 1.0e+0, two = 2.0e+0,
271 parameter( one = ( 1.0e+0, 0.0e+0 ) )
274 LOGICAL LQUERY, NOTRAN
275 CHARACTER TRANSN, TRANST
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, lrwmin, lwmin, mycol, myrhs,
282 $ myrow, np, np0, npcol, npmod, nprow, nz
283 REAL EPS, EST, LSTRES, S, SAFE1, SAFE2, SAFMIN
287 INTEGER DESCW( DLEN_ ), IDUM1( 5 ), IDUM2( 5 )
291 INTEGER ICEIL, INDXG2P, NUMROC
293 EXTERNAL iceil, indxg2p, lsame, numroc, pslamch
296 EXTERNAL blacs_gridinfo, cgebr2d, cgebs2d,
chk1mat,
302 INTRINSIC abs, aimag,
cmplx, ichar,
max,
min, mod, real
308 cabs1( zdum ) = abs( real( zdum ) ) + abs( aimag( zdum ) )
314 ictxt = desca( ctxt_ )
315 CALL blacs_gridinfo( ictxt, nprow, npcol, myrow, mycol )
319 notran = lsame( trans,
'N' )
322 IF( nprow.EQ.-1 )
THEN
325 CALL chk1mat( n, 2, n, 2, ia, ja, desca, 7, info )
326 CALL chk1mat( n, 2, n, 2, iaf, jaf, descaf, 11, info )
327 CALL chk1mat( n, 2, nrhs, 3, ib, jb, descb, 16, info )
328 CALL chk1mat( n, 2, nrhs, 3, ix, jx, descx, 20, info )
330 iroffa = mod( ia-1, desca( mb_ ) )
331 icoffa = mod( ja-1, desca( nb_ ) )
332 iroffaf = mod( iaf-1, descaf( mb_ ) )
333 icoffaf = mod( jaf-1, descaf( nb_ ) )
334 iroffb = mod( ib-1, descb( mb_ ) )
335 icoffb = mod( jb-1, descb( nb_ ) )
336 iroffx = mod( ix-1, descx( mb_ ) )
337 icoffx = mod( jx-1, descx( nb_ ) )
338 iarow = indxg2p( ia, desca( mb_ ), myrow, desca( rsrc_ ),
340 iafcol = indxg2p( jaf, descaf( nb_ ), mycol,
341 $ descaf( csrc_ ), npcol )
342 iafrow = indxg2p( iaf, descaf( mb_ ), myrow,
343 $ descaf( rsrc_ ), nprow )
344 iacol = indxg2p( ja, desca( nb_ ), mycol, desca( csrc_ ),
346 CALL infog2l( ib, jb, descb, nprow, npcol, myrow, mycol,
347 $ iixb, jjxb, ixbrow, ixbcol )
348 ixrow = indxg2p( ix, descx( mb_ ), myrow, descx( rsrc_ ),
350 ixcol = indxg2p( jx, descx( nb_ ), mycol, descx( csrc_ ),
352 npmod = numroc( n+iroffa, desca( mb_ ), myrow, iarow,
356 work( 1 ) =
cmplx( real( lwmin ) )
357 rwork( 1 ) = real( lrwmin )
358 lquery = ( lwork.EQ.-1 .OR. lrwork.EQ.-1 )
360 IF( ( .NOT.notran ) .AND. ( .NOT.lsame( trans,
'T' ) ) .AND.
361 $ ( .NOT.lsame( trans,
'C' ) ) )
THEN
363 ELSE IF( n.LT.0 )
THEN
365 ELSE IF( nrhs.LT.0 )
THEN
367 ELSE IF( iroffa.NE.0 )
THEN
369 ELSE IF( icoffa.NE.0 )
THEN
371 ELSE IF( desca( mb_ ).NE.desca( nb_ ) )
THEN
372 info = -( 700 + nb_ )
373 ELSE IF( desca( mb_ ).NE.descaf( mb_ ) )
THEN
374 info = -( 1100 + mb_ )
375 ELSE IF( iroffaf.NE.0 .OR. iarow.NE.iafrow )
THEN
377 ELSE IF( desca( nb_ ).NE.descaf( nb_ ) )
THEN
378 info = -( 1100 + nb_ )
379 ELSE IF( icoffaf.NE.0 .OR. iacol.NE.iafcol )
THEN
381 ELSE IF( ictxt.NE.descaf( ctxt_ ) )
THEN
382 info = -( 1100 + ctxt_ )
383 ELSE IF( iroffa.NE.iroffb .OR. iarow.NE.ixbrow )
THEN
385 ELSE IF( desca( mb_ ).NE.descb( mb_ ) )
THEN
386 info = -( 1600 + mb_ )
387 ELSE IF( ictxt.NE.descb( ctxt_ ) )
THEN
388 info = -( 1600 + ctxt_ )
389 ELSE IF( descb( mb_ ).NE.descx( mb_ ) )
THEN
390 info = -( 2000 + mb_ )
391 ELSE IF( iroffx.NE.0 .OR. ixbrow.NE.ixrow )
THEN
393 ELSE IF( descb( nb_ ).NE.descx( nb_ ) )
THEN
394 info = -( 2000 + nb_ )
395 ELSE IF( icoffb.NE.icoffx .OR. ixbcol.NE.ixcol )
THEN
397 ELSE IF( ictxt.NE.descx( ctxt_ ) )
THEN
398 info = -( 2000 + ctxt_ )
399 ELSE IF( lwork.LT.lwmin .AND. .NOT.lquery )
THEN
401 ELSE IF( lrwork.LT.lrwmin .AND. .NOT.lquery )
THEN
407 idum1( 1 ) = ichar(
'N' )
408 ELSE IF( lsame( trans,
'T' ) )
THEN
409 idum1( 1 ) = ichar(
'T' )
411 idum1( 1 ) = ichar(
'C' )
418 IF( lwork.EQ.-1 )
THEN
424 IF( lrwork.EQ.-1 )
THEN
430 CALL pchk2mat( n, 2, n, 2, ia, ja, desca, 7, n, 2, n, 2, iaf,
431 $ jaf, descaf, 11, 5, idum1, idum2, info )
432 CALL pchk2mat( n, 2, nrhs, 3, ib, jb, descb, 16, n, 2, nrhs, 3,
433 $ ix, jx, descx, 20, 5, idum1, idum2, info )
436 CALL pxerbla( ictxt,
'PCGERFS', -info )
438 ELSE IF( lquery )
THEN
443 myrhs = numroc( jb+nrhs-1, descb( nb_ ), mycol, descb( csrc_ ),
448 IF( n.LE.1 .OR. nrhs.EQ.0 )
THEN
449 DO 10 jj = jjfbe, myrhs
464 np0 = numroc( n+iroffb, descb( mb_ ), myrow, ixbrow, nprow )
465 CALL descset( descw, n+iroffb, 1, desca( mb_ ), 1, ixbrow, ixbcol,
466 $ ictxt,
max( 1, np0 ) )
470 IF( myrow.EQ.ixbrow )
THEN
480 ioffxb = ( jjxb-1 )*ldxb
485 eps = pslamch( ictxt,
'Epsilon' )
486 safmin = pslamch( ictxt,
'Safe minimum' )
489 jn =
min( iceil( jb, descb( nb_ ) ) * descb( nb_ ), jb+nrhs-1 )
494 DO 100 k = 0, jbrhs-1
506 CALL pccopy( n, b, ib, jb+k, descb, 1, work( ipr ), iw, jw,
508 CALL pcgemv( trans, n, n, -one, a, ia, ja, desca, x, ix,
509 $ jx+k, descx, 1, one, work( ipr ), iw, jw,
522 IF( mycol.EQ.ixbcol )
THEN
524 DO 30 ii = iixb, iixb + np - 1
525 rwork( iiw+ii-iixb ) = cabs1( b( ii+ioffxb ) )
530 CALL pcagemv( trans, n, n, rone, a, ia, ja, desca, x, ix, jx+k,
531 $ descx, 1, rone, rwork( ipb ), iw, jw, descw, 1 )
534 IF( mycol.EQ.ixbcol )
THEN
536 DO 40 ii = iiw-1, iiw+np-2
537 IF( rwork( ipb+ii ).GT.safe2 )
THEN
538 s =
max( s, cabs1( work( ipr+ii ) ) /
541 s =
max( s, ( cabs1( work( ipr+ii ) )+safe1 ) /
542 $ ( rwork( ipb+ii )+safe1 ) )
548 CALL sgamx2d( ictxt,
'All',
' ', 1, 1, s, 1, idum, idum, 1,
550 IF( mycol.EQ.ixbcol )
560 IF( s.GT.eps .AND. two*s.LE.lstres .AND. count.LE.itmax )
THEN
564 CALL pcgetrs( trans, n, 1, af, iaf, jaf, descaf, ipiv,
565 $ work( ipr ), iw, jw, descw, info )
566 CALL pcaxpy( n, one, work( ipr ), iw, jw, descw, 1, x, ix,
599 IF( mycol.EQ.ixbcol )
THEN
601 DO 50 ii = iiw-1, iiw+np-2
602 IF( rwork( ipb+ii ).GT.safe2 )
THEN
603 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
604 $ nz*eps*rwork( ipb+ii )
606 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
607 $ nz*eps*rwork( ipb+ii ) + safe1
615 IF( mycol.EQ.ixbcol )
THEN
616 CALL cgebs2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
619 CALL cgebr2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
620 $ descw( lld_ ), myrow, ixbcol )
622 descw( csrc_ ) = mycol
623 CALL pclacon( n, work( ipv ), iw, jw, descw, work( ipr ),
624 $ iw, jw, descw, est, kase )
625 descw( csrc_ ) = ixbcol
632 CALL pcgetrs( transt, n, 1, af, iaf, jaf, descaf,
633 $ ipiv, work( ipr ), iw, jw, descw, info )
635 IF( mycol.EQ.ixbcol )
THEN
637 DO 70 ii = iiw-1, iiw+np-2
638 work( ipr+ii ) = rwork( ipb+ii )*work( ipr+ii )
646 IF( mycol.EQ.ixbcol )
THEN
648 DO 80 ii = iiw-1, iiw+np-2
649 work( ipr+ii ) = rwork( ipb+ii )*work( ipr+ii )
654 CALL pcgetrs( transn, n, 1, af, iaf, jaf, descaf,
655 $ ipiv, work( ipr ), iw, jw, descw, info )
663 IF( mycol.EQ.ixbcol )
THEN
665 DO 90 ii = iixb, iixb+np-1
666 lstres =
max( lstres, cabs1( x( ioffxb+ii ) ) )
669 CALL sgamx2d( ictxt,
'Column',
' ', 1, 1, lstres, 1, idum,
670 $ idum, 1, -1, mycol )
672 $ ferr( jjfbe ) = est / lstres
676 ioffxb = ioffxb + ldxb
682 icurcol = mod( ixbcol+1, npcol )
686 DO 200 j = jn+1, jb+nrhs-1, descb( nb_ )
687 jbrhs =
min( jb+nrhs-j, descb( nb_ ) )
688 descw( csrc_ ) = icurcol
690 DO 190 k = 0, jbrhs-1
702 CALL pccopy( n, b, ib, j+k, descb, 1, work( ipr ), iw, jw,
704 CALL pcgemv( trans, n, n, -one, a, ia, ja, desca, x,
705 $ ix, j+k, descx, 1, one, work( ipr ), iw, jw,
719 IF( mycol.EQ.icurcol )
THEN
721 DO 120 ii = iixb, iixb+np-1
722 rwork( iiw+ii-iixb ) = cabs1( b( ii+ioffxb ) )
727 CALL pcagemv( trans, n, n, rone, a, ia, ja, desca, x, ix,
728 $ j+k, descx, 1, rone, rwork( ipb ), iw, jw,
732 IF( mycol.EQ.icurcol )
THEN
734 DO 130 ii = iiw-1, iiw+np-2
735 IF( rwork( ipb+ii ).GT.safe2 )
THEN
736 s =
max( s, cabs1( work( ipr+ii ) ) /
739 s =
max( s, ( cabs1( work( ipr+ii ) )+safe1 ) /
740 $ ( rwork( ipb+ii )+safe1 ) )
746 CALL sgamx2d( ictxt,
'All',
' ', 1, 1, s, 1, idum, idum, 1,
748 IF( mycol.EQ.icurcol )
758 IF( s.GT.eps .AND. two*s.LE.lstres .AND.
759 $ count.LE.itmax )
THEN
763 CALL pcgetrs( trans, n, 1, af, iaf, jaf, descaf, ipiv,
764 $ work( ipr ), iw, jw, descw, info )
765 CALL pcaxpy( n, one, work( ipr ), iw, jw, descw, 1, x,
766 $ ix, j+k, descx, 1 )
798 IF( mycol.EQ.icurcol )
THEN
800 DO 140 ii = iiw-1, iiw+np-2
801 IF( rwork( ipb+ii ).GT.safe2 )
THEN
802 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
803 $ nz*eps*rwork( ipb+ii )
805 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
806 $ nz*eps*rwork( ipb+ii ) + safe1
814 IF( mycol.EQ.icurcol )
THEN
815 CALL cgebs2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
818 CALL cgebr2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
819 $ descw( lld_ ), myrow, icurcol )
821 descw( csrc_ ) = mycol
822 CALL pclacon( n, work( ipv ), iw, jw, descw, work( ipr ),
823 $ iw, jw, descw, est, kase )
824 descw( csrc_ ) = icurcol
831 CALL pcgetrs( transt, n, 1, af, iaf, jaf, descaf,
832 $ ipiv, work( ipr ), iw, jw, descw, info )
834 IF( mycol.EQ.icurcol )
THEN
836 DO 160 ii = iiw-1, iiw+np-2
837 work( ipr+ii ) = rwork( ipb+ii )*
846 IF( mycol.EQ.icurcol )
THEN
848 DO 170 ii = iiw-1, iiw+np-2
849 work( ipr+ii ) = rwork( ipb+ii )*
855 CALL pcgetrs( transn, n, 1, af, iaf, jaf, descaf,
856 $ ipiv, work( ipr ), iw, jw, descw,
865 IF( mycol.EQ.icurcol )
THEN
867 DO 180 ii = iixb, iixb+np-1
868 lstres =
max( lstres, cabs1( x( ioffxb+ii ) ) )
871 CALL sgamx2d( ictxt,
'Column',
' ', 1, 1, lstres,
872 $ 1, idum, idum, 1, -1, mycol )
874 $ ferr( jjfbe ) = est / lstres
878 ioffxb = ioffxb + ldxb
884 icurcol = mod( icurcol+1, npcol )
888 work( 1 ) =
cmplx( real( lwmin ) )
889 rwork( 1 ) = real( lrwmin )