1 SUBROUTINE pzgerfs( 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 DOUBLE PRECISION BERR( * ), FERR( * ), RWORK( * )
20 COMPLEX*16 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 double precision zero, rone, two, three
268 parameter( zero = 0.0d+0, rone = 1.0d+0, two = 2.0d+0,
271 parameter( one = ( 1.0d+0, 0.0d+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 DOUBLE PRECISION EPS, EST, LSTRES, S, SAFE1, SAFE2, SAFMIN
287 INTEGER DESCW( DLEN_ ), IDUM1( 5 ), IDUM2( 5 )
291 INTEGER ICEIL, INDXG2P, NUMROC
292 DOUBLE PRECISION PDLAMCH
293 EXTERNAL iceil, indxg2p, lsame, numroc, pdlamch
302 INTRINSIC abs, dble, dcmplx, dimag, ichar,
max,
min, mod
305 DOUBLE PRECISION CABS1
308 cabs1( zdum ) = abs( dble( zdum ) ) + abs( dimag( 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 ) = dcmplx( dble( lwmin ) )
357 rwork( 1 ) = dble( 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,
'PZGERFS', -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 = pdlamch( ictxt,
'Epsilon' )
486 safmin = pdlamch( ictxt,
'Safe minimum' )
489 jn =
min( iceil( jb, descb( nb_ ) ) * descb( nb_ ), jb+nrhs-1 )
494 DO 100 k = 0, jbrhs-1
506 CALL pzcopy( n, b, ib, jb+k, descb, 1, work( ipr ), iw, jw,
508 CALL pzgemv( 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 pzagemv( 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 dgamx2d( 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 pzgetrs( trans, n, 1, af, iaf, jaf, descaf, ipiv,
565 $ work( ipr ), iw, jw, descw, info )
566 CALL pzaxpy( 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 zgebs2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
619 CALL zgebr2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
620 $ descw( lld_ ), myrow, ixbcol )
622 descw( csrc_ ) = mycol
623 CALL pzlacon( n, work( ipv ), iw, jw, descw, work( ipr ),
624 $ iw, jw, descw, est, kase )
625 descw( csrc_ ) = ixbcol
632 CALL pzgetrs( 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 pzgetrs( 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 dgamx2d( 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 pzcopy( n, b, ib, j+k, descb, 1, work( ipr ), iw, jw,
704 CALL pzgemv( 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 pzagemv( 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 dgamx2d( 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 pzgetrs( trans, n, 1, af, iaf, jaf, descaf, ipiv,
764 $ work( ipr ), iw, jw, descw, info )
765 CALL pzaxpy( 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 zgebs2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
818 CALL zgebr2d( ictxt,
'Rowwise',
' ', np, 1, work( ipr ),
819 $ descw( lld_ ), myrow, icurcol )
821 descw( csrc_ ) = mycol
822 CALL pzlacon( n, work( ipv ), iw, jw, descw, work( ipr ),
823 $ iw, jw, descw, est, kase )
824 descw( csrc_ ) = icurcol
831 CALL pzgetrs( 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 pzgetrs( 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 dgamx2d( 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 ) = dcmplx( dble( lwmin ) )
889 rwork( 1 ) = dble( lrwmin )