1      SUBROUTINE pzpbtrsv( UPLO, TRANS, N, BW, NRHS, A, JA, DESCA, B,
 
    2     $                     IB, DESCB, AF, LAF, WORK, LWORK, INFO )
 
   10      INTEGER            BW, IB, INFO, JA, LAF, LWORK, N, NRHS
 
   13      INTEGER            DESCA( * ), DESCB( * )
 
   14      COMPLEX*16         A( * ), AF( * ), B( * ), WORK( * )
 
  370      DOUBLE PRECISION   ONE, ZERO
 
  371      parameter( one = 1.0d+0 )
 
  372      parameter( zero = 0.0d+0 )
 
  373      COMPLEX*16         CONE, CZERO
 
  374      parameter( cone = ( 1.0d+0, 0.0d+0 ) )
 
  375      parameter( czero = ( 0.0d+0, 0.0d+0 ) )
 
  377      parameter( int_one = 1 )
 
  378      INTEGER            DESCMULT, BIGNUM
 
  379      parameter(descmult = 100, bignum = descmult * descmult)
 
  380      INTEGER            BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
 
  381     $                   lld_, mb_, m_, nb_, n_, rsrc_
 
  382      parameter( block_cyclic_2d = 1, dlen_ = 9, dtype_ = 1,
 
  383     $                     ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
 
  384     $                     rsrc_ = 7, csrc_ = 8, lld_ = 9 )
 
  387      INTEGER            CSRC, FIRST_PROC, ICTXT, ICTXT_NEW, ICTXT_SAVE,
 
  388     $                   idum1, idum2, idum3, ja_new, level_dist, llda,
 
  389     $                   lldb, mbw2, mycol, myrow, my_num_cols, nb, np,
 
  390     $                   npcol, nprow, np_save, odd_size, ofst,
 
  391     $                   part_offset, part_size, return_code, store_m_b,
 
  392     $                   store_n_a, work_size_min
 
  395      INTEGER            DESCA_1XP( 7 ), DESCB_PX1( 7 ),
 
  396     $                   param_check( 17, 3 )
 
  399      EXTERNAL           blacs_get, blacs_gridexit, blacs_gridinfo,
 
  401     $                   zgerv2d, zgesd2d, zlamov, 
zmatadd, ztbtrs,
 
  407      EXTERNAL           lsame, numroc
 
  410      INTRINSIC          ichar, 
min, mod
 
  426      IF( return_code .NE. 0) 
THEN 
  427         info = -( 8*100 + 2 )
 
  432      IF( return_code .NE. 0) 
THEN 
  433         info = -( 11*100 + 2 )
 
  439      IF( desca_1xp( 2 ) .NE. descb_px1( 2 ) ) 
THEN 
  440         info = -( 11*100 + 2 )
 
  447      IF( desca_1xp( 4 ) .NE. descb_px1( 4 ) ) 
THEN 
  448         info = -( 11*100 + 4 )
 
  453      IF( desca_1xp( 5 ) .NE. descb_px1( 5 ) ) 
THEN 
  454         info = -( 11*100 + 5 )
 
  459      ictxt = desca_1xp( 2 )
 
  460      csrc = desca_1xp( 5 )
 
  462      llda = desca_1xp( 6 )
 
  463      store_n_a = desca_1xp( 3 )
 
  464      lldb = descb_px1( 6 )
 
  465      store_m_b = descb_px1( 3 )
 
  474      CALL blacs_gridinfo( ictxt, nprow, npcol, myrow, mycol )
 
  479      IF( lsame( uplo, 
'U' ) ) 
THEN 
  481      ELSE IF ( lsame( uplo, 
'L' ) ) 
THEN 
  487      IF( lsame( trans, 
'N' ) ) 
THEN 
  489      ELSE IF ( lsame( trans, 
'C' ) ) 
THEN 
  495      IF( lwork .LT. -1) 
THEN 
  497      ELSE IF ( lwork .EQ. -1 ) 
THEN 
  507      IF( n+ja-1 .GT. store_n_a ) 
THEN 
  508         info = -( 8*100 + 6 )
 
  511      IF(( bw .GT. n-1 ) .OR.
 
  512     $   ( bw .LT. 0 ) ) 
THEN 
  516      IF( llda .LT. (bw+1) ) 
THEN 
  517         info = -( 8*100 + 6 )
 
  521         info = -( 8*100 + 4 )
 
  524      IF( n+ib-1 .GT. store_m_b ) 
THEN 
  525         info = -( 11*100 + 3 )
 
  528      IF( lldb .LT. nb ) 
THEN 
  529         info = -( 11*100 + 6 )
 
  532      IF( nrhs .LT. 0 ) 
THEN 
  544      IF( nprow .NE. 1 ) 
THEN 
  548      IF( n .GT. np*nb-mod( ja-1, nb )) 
THEN 
  551     $      
'PZPBTRSV, D&C alg.: only 1 block per proc',
 
  556      IF((ja+n-1.GT.nb) .AND. ( nb.LT.2*bw )) 
THEN 
  559     $      
'PZPBTRSV, D&C alg.: NB too small',
 
  568      work( 1 ) = work_size_min
 
  570      IF( lwork .LT. work_size_min ) 
THEN 
  571         IF( lwork .NE. -1 ) 
THEN 
  574     $      
'PZPBTRSV: worksize error',
 
  582      param_check( 17, 1 ) = descb(5)
 
  583      param_check( 16, 1 ) = descb(4)
 
  584      param_check( 15, 1 ) = descb(3)
 
  585      param_check( 14, 1 ) = descb(2)
 
  586      param_check( 13, 1 ) = descb(1)
 
  587      param_check( 12, 1 ) = ib
 
  588      param_check( 11, 1 ) = desca(5)
 
  589      param_check( 10, 1 ) = desca(4)
 
  590      param_check(  9, 1 ) = desca(3)
 
  591      param_check(  8, 1 ) = desca(1)
 
  592      param_check(  7, 1 ) = ja
 
  593      param_check(  6, 1 ) = nrhs
 
  594      param_check(  5, 1 ) = bw
 
  595      param_check(  4, 1 ) = n
 
  596      param_check(  3, 1 ) = idum3
 
  597      param_check(  2, 1 ) = idum2
 
  598      param_check(  1, 1 ) = idum1
 
  600      param_check( 17, 2 ) = 1105
 
  601      param_check( 16, 2 ) = 1104
 
  602      param_check( 15, 2 ) = 1103
 
  603      param_check( 14, 2 ) = 1102
 
  604      param_check( 13, 2 ) = 1101
 
  605      param_check( 12, 2 ) = 10
 
  606      param_check( 11, 2 ) = 805
 
  607      param_check( 10, 2 ) = 804
 
  608      param_check(  9, 2 ) = 803
 
  609      param_check(  8, 2 ) = 801
 
  610      param_check(  7, 2 ) = 7
 
  611      param_check(  6, 2 ) = 5
 
  612      param_check(  5, 2 ) = 4
 
  613      param_check(  4, 2 ) = 3
 
  614      param_check(  3, 2 ) = 14
 
  615      param_check(  2, 2 ) = 2
 
  616      param_check(  1, 2 ) = 1
 
  624      ELSE IF( info.LT.-descmult ) 
THEN 
  627         info = -info * descmult
 
  632      CALL globchk( ictxt, 17, param_check, 17,
 
  633     $              param_check( 1, 3 ), info )
 
  638      IF( info.EQ.bignum ) 
THEN 
  640      ELSE IF( mod( info, descmult ) .EQ. 0 ) 
THEN 
  641         info = -info / descmult
 
  647         CALL pxerbla( ictxt, 
'PZPBTRSV', -info )
 
  663      part_offset = nb*( (ja-1)/(npcol*nb) )
 
  665      IF ( (mycol-csrc) .LT. (ja-part_offset-1)/nb ) 
THEN 
  666         part_offset = part_offset + nb
 
  669      IF ( mycol .LT. csrc ) 
THEN 
  670         part_offset = part_offset - nb
 
  679      first_proc = mod( ( ja-1 )/nb+csrc, npcol )
 
  683      ja_new = mod( ja-1, nb ) + 1
 
  688      np = ( ja_new+n-2 )/nb + 1
 
  692      CALL reshape( ictxt, int_one, ictxt_new, int_one,
 
  693     $              first_proc, int_one, np )
 
  699      desca_1xp( 2 ) = ictxt_new
 
  700      descb_px1( 2 ) = ictxt_new
 
  704      CALL blacs_gridinfo( ictxt, nprow, npcol, myrow, mycol )
 
  708      IF( myrow .LT. 0 ) 
THEN 
  721      my_num_cols = numroc( n, part_size, mycol, 0, npcol )
 
  725      IF ( mycol .EQ. 0 ) 
THEN 
  726        part_offset = part_offset+mod( ja_new-1, part_size )
 
  727        my_num_cols = my_num_cols - mod(ja_new-1, part_size )
 
  732      ofst = part_offset*llda
 
  736      odd_size = my_num_cols
 
  737      IF ( mycol .LT. np-1 ) 
THEN 
  738         odd_size = odd_size - bw
 
  745      IF ( lsame( uplo, 
'L' ) ) 
THEN 
  747      IF ( lsame( trans, 
'N' ) ) 
THEN 
  758        CALL ztbtrs( uplo, 
'N', 
'N', odd_size,
 
  761     $                    b( part_offset+1 ), lldb, info )
 
  764        IF ( mycol .LT. np-1 ) 
THEN 
  772            CALL zlamov( 
'N', bw, nrhs,
 
  773     $                b( part_offset+odd_size-bw+1), lldb,
 
  776            CALL ztrmm( 
'L', 
'U', 
'N', 
'N', bw, nrhs, -cone,
 
  777     $                  a(( ofst+(bw+1)+(odd_size-bw)*llda )), llda-1,
 
  780            CALL zmatadd( bw, nrhs, cone, work( 1 ), bw,
 
  781     $                cone, b( part_offset+odd_size+1 ), lldb )
 
  786        IF ( mycol .NE. 0 ) 
THEN 
  790            CALL zgemm( 
'C', 
'N', bw, nrhs, odd_size, -cone, af( 1 ),
 
  791     $                  odd_size, b( part_offset+1 ), lldb, czero,
 
  792     $                  work( 1+bw-bw ), bw )
 
  803        IF( mycol .GT. 0) 
THEN 
  805          CALL zgesd2d( ictxt, bw, nrhs,
 
  813        IF( mycol .LT. npcol-1) 
THEN 
  815          CALL zgerv2d( ictxt, bw, nrhs,
 
  822     $                work( 1 ), bw, cone,
 
  823     $                b( part_offset+odd_size + 1 ), lldb )
 
  830        IF( mycol .EQ. npcol-1 ) 
THEN 
  845        IF( mod( (mycol+1)/level_dist, 2) .NE. 0 ) 
GOTO 11
 
  849          IF( mycol-level_dist .GE. 0 ) 
THEN 
  851            CALL zgerv2d( ictxt, bw, nrhs,
 
  853     $                     bw, 0, mycol-level_dist )
 
  856     $                work( 1 ), bw, cone,
 
  857     $                b( part_offset+odd_size + 1 ), lldb )
 
  863          IF( mycol+level_dist .LT. npcol-1 ) 
THEN 
  865            CALL zgerv2d( ictxt, bw, nrhs,
 
  867     $                     bw, 0, mycol+level_dist )
 
  870     $                work( 1 ), bw, cone,
 
  871     $                b( part_offset+odd_size + 1 ), lldb )
 
  875          level_dist = level_dist*2
 
  888        CALL ztrtrs( 
'L', 
'N', 
'N', bw, nrhs, af( odd_size*bw+mbw2+1 ),
 
  889     $               bw, b( part_offset+odd_size+1 ), lldb, info )
 
  898        IF( mycol/level_dist .LE. (npcol-1)/level_dist-2 )
THEN 
  902          CALL zgemm( 
'C', 
'N', bw, nrhs, bw, -cone,
 
  903     $                     af( (odd_size)*bw+1 ),
 
  905     $                     b( part_offset+odd_size+1 ),
 
  912          CALL zgesd2d( ictxt, bw, nrhs,
 
  914     $                     bw, 0, mycol+level_dist )
 
  920        IF( (mycol/level_dist .GT. 0 ).AND.
 
  921     $      ( mycol/level_dist .LE. (npcol-1)/level_dist-1 ) ) 
THEN 
  927          CALL zgemm( 
'N', 
'N', bw, nrhs, bw, -cone,
 
  928     $                     af( odd_size*bw+2*mbw2+1 ),
 
  930     $                     b( part_offset+odd_size+1 ),
 
  937          CALL zgesd2d( ictxt, bw, nrhs,
 
  939     $                     bw, 0, mycol-level_dist )
 
  958        IF( mycol .EQ. npcol-1 ) 
THEN 
  966        IF( mod( (mycol+1)/level_dist, 2) .NE. 0 ) 
GOTO 26
 
  968          level_dist = level_dist*2
 
  974        IF( (mycol/level_dist .GT. 0 ).AND.
 
  975     $      ( mycol/level_dist .LE. (npcol-1)/level_dist-1 ) ) 
THEN 
  979          CALL zgerv2d( ictxt, bw, nrhs,
 
  981     $                     bw, 0, mycol-level_dist )
 
  987          CALL zgemm( 
'C', 
'N', bw, nrhs, bw, -cone,
 
  988     $                     af( odd_size*bw+2*mbw2+1 ),
 
  992     $                     b( part_offset+odd_size+1 ),
 
  998        IF( mycol/level_dist .LE. (npcol-1)/level_dist-2 )
THEN 
 1002          CALL zgerv2d( ictxt, bw, nrhs,
 
 1004     $                     bw, 0, mycol+level_dist )
 
 1008          CALL zgemm( 
'N', 
'N', bw, nrhs, bw, -cone,
 
 1009     $                     af( (odd_size)*bw+1 ),
 
 1013     $                     b( part_offset+odd_size+1 ),
 
 1022        CALL ztrtrs( 
'L', 
'C', 
'N', bw, nrhs, af( odd_size*bw+mbw2+1 ),
 
 1023     $               bw, b( part_offset+odd_size+1 ), lldb, info )
 
 1025        IF( info.NE.0 ) 
THEN 
 1034        IF( level_dist .EQ. 1 ) 
GOTO 21
 
 1036          level_dist = level_dist/2
 
 1040          IF( mycol+level_dist .LT. npcol-1 ) 
THEN 
 1042          CALL zgesd2d( ictxt, bw, nrhs,
 
 1043     $                     b( part_offset+odd_size+1 ),
 
 1044     $                     lldb, 0, mycol+level_dist )
 
 1050          IF( mycol-level_dist .GE. 0 ) 
THEN 
 1052          CALL zgesd2d( ictxt, bw, nrhs,
 
 1053     $                     b( part_offset+odd_size+1 ),
 
 1054     $                     lldb, 0, mycol-level_dist )
 
 1072        IF( mycol .LT. npcol-1) 
THEN 
 1074          CALL zgesd2d( ictxt, bw, nrhs,
 
 1075     $                     b( part_offset+odd_size+1 ), lldb,
 
 1082        IF( mycol .GT. 0) 
THEN 
 1084          CALL zgerv2d( ictxt, bw, nrhs,
 
 1096        IF ( mycol .NE. 0 ) 
THEN 
 1100          CALL zgemm( 
'N', 
'N', odd_size, nrhs, bw, -cone, af( 1 ),
 
 1101     $                odd_size, work( 1+bw-bw ), bw, cone,
 
 1102     $                b( part_offset+1 ), lldb )
 
 1107        IF ( mycol .LT. np-1 ) 
THEN 
 1115          CALL zlamov( 
'N', bw, nrhs, b( part_offset+odd_size+1), lldb,
 
 1116     $                 work( 1+bw-bw ), bw )
 
 1118          CALL ztrmm( 
'L', 
'U', 
'C', 
'N', bw, nrhs, -cone,
 
 1119     $                a(( ofst+(bw+1)+(odd_size-bw)*llda )), llda-1,
 
 1120     $                work( 1+bw-bw ), bw )
 
 1122          CALL zmatadd( bw, nrhs, cone, work( 1+bw-bw ), bw, cone,
 
 1123     $                  b( part_offset+odd_size-bw+1 ), lldb )
 
 1129        CALL ztbtrs( uplo, 
'C', 
'N', odd_size,
 
 1132     $                    llda,  b( part_offset+1 ),
 
 1143      IF ( lsame( trans, 
'C' ) ) 
THEN 
 1154        CALL ztbtrs( uplo, 
'C', 
'N', odd_size,
 
 1156     $                    a( ofst+1 ), llda,
 
 1157     $                    b( part_offset+1 ), lldb, info )
 
 1160        IF ( mycol .LT. np-1 ) 
THEN 
 1168            CALL zlamov( 
'N', bw, nrhs,
 
 1169     $                b( part_offset+odd_size-bw+1), lldb,
 
 1172            CALL ztrmm( 
'L', 
'L', 
'C', 
'N', bw, nrhs, -cone,
 
 1173     $                  a(( ofst+1+odd_size*llda )), llda-1, work( 1 ),
 
 1176            CALL zmatadd( bw, nrhs, cone, work( 1 ), bw,
 
 1177     $                cone, b( part_offset+odd_size+1 ), lldb )
 
 1182        IF ( mycol .NE. 0 ) 
THEN 
 1186            CALL zgemm( 
'C', 
'N', bw, nrhs, odd_size, -cone, af( 1 ),
 
 1187     $                  odd_size, b( part_offset+1 ), lldb, czero,
 
 1188     $                  work( 1+bw-bw ), bw )
 
 1199        IF( mycol .GT. 0) 
THEN 
 1201          CALL zgesd2d( ictxt, bw, nrhs,
 
 1209        IF( mycol .LT. npcol-1) 
THEN 
 1211          CALL zgerv2d( ictxt, bw, nrhs,
 
 1218     $                work( 1 ), bw, cone,
 
 1219     $                b( part_offset+odd_size + 1 ), lldb )
 
 1226        IF( mycol .EQ. npcol-1 ) 
THEN 
 1241        IF( mod( (mycol+1)/level_dist, 2) .NE. 0 ) 
GOTO 41
 
 1245          IF( mycol-level_dist .GE. 0 ) 
THEN 
 1247            CALL zgerv2d( ictxt, bw, nrhs,
 
 1249     $                     bw, 0, mycol-level_dist )
 
 1252     $                work( 1 ), bw, cone,
 
 1253     $                b( part_offset+odd_size + 1 ), lldb )
 
 1259          IF( mycol+level_dist .LT. npcol-1 ) 
THEN 
 1261            CALL zgerv2d( ictxt, bw, nrhs,
 
 1263     $                     bw, 0, mycol+level_dist )
 
 1266     $                work( 1 ), bw, cone,
 
 1267     $                b( part_offset+odd_size + 1 ), lldb )
 
 1271          level_dist = level_dist*2
 
 1284        CALL ztrtrs( 
'L', 
'N', 
'N', bw, nrhs, af( odd_size*bw+mbw2+1 ),
 
 1285     $               bw, b( part_offset+odd_size+1 ), lldb, info )
 
 1287        IF( info.NE.0 ) 
THEN 
 1294        IF( mycol/level_dist .LE. (npcol-1)/level_dist-2 )
THEN 
 1298          CALL zgemm( 
'C', 
'N', bw, nrhs, bw, -cone,
 
 1299     $                     af( (odd_size)*bw+1 ),
 
 1301     $                     b( part_offset+odd_size+1 ),
 
 1308          CALL zgesd2d( ictxt, bw, nrhs,
 
 1310     $                     bw, 0, mycol+level_dist )
 
 1316        IF( (mycol/level_dist .GT. 0 ).AND.
 
 1317     $      ( mycol/level_dist .LE. (npcol-1)/level_dist-1 ) ) 
THEN 
 1323          CALL zgemm( 
'N', 
'N', bw, nrhs, bw, -cone,
 
 1324     $                     af( odd_size*bw+2*mbw2+1 ),
 
 1326     $                     b( part_offset+odd_size+1 ),
 
 1333          CALL zgesd2d( ictxt, bw, nrhs,
 
 1335     $                     bw, 0, mycol-level_dist )
 
 1354        IF( mycol .EQ. npcol-1 ) 
THEN 
 1362        IF( mod( (mycol+1)/level_dist, 2) .NE. 0 ) 
GOTO 56
 
 1364          level_dist = level_dist*2
 
 1370        IF( (mycol/level_dist .GT. 0 ).AND.
 
 1371     $      ( mycol/level_dist .LE. (npcol-1)/level_dist-1 ) ) 
THEN 
 1375          CALL zgerv2d( ictxt, bw, nrhs,
 
 1377     $                     bw, 0, mycol-level_dist )
 
 1383          CALL zgemm( 
'C', 
'N', bw, nrhs, bw, -cone,
 
 1384     $                     af( odd_size*bw+2*mbw2+1 ),
 
 1388     $                     b( part_offset+odd_size+1 ),
 
 1394        IF( mycol/level_dist .LE. (npcol-1)/level_dist-2 )
THEN 
 1398          CALL zgerv2d( ictxt, bw, nrhs,
 
 1400     $                     bw, 0, mycol+level_dist )
 
 1404          CALL zgemm( 
'N', 
'N', bw, nrhs, bw, -cone,
 
 1405     $                     af( (odd_size)*bw+1 ),
 
 1409     $                     b( part_offset+odd_size+1 ),
 
 1418        CALL ztrtrs( 
'L', 
'C', 
'N', bw, nrhs, af( odd_size*bw+mbw2+1 ),
 
 1419     $               bw, b( part_offset+odd_size+1 ), lldb, info )
 
 1421        IF( info.NE.0 ) 
THEN 
 1430        IF( level_dist .EQ. 1 ) 
GOTO 51
 
 1432          level_dist = level_dist/2
 
 1436          IF( mycol+level_dist .LT. npcol-1 ) 
THEN 
 1438          CALL zgesd2d( ictxt, bw, nrhs,
 
 1439     $                     b( part_offset+odd_size+1 ),
 
 1440     $                     lldb, 0, mycol+level_dist )
 
 1446          IF( mycol-level_dist .GE. 0 ) 
THEN 
 1448          CALL zgesd2d( ictxt, bw, nrhs,
 
 1449     $                     b( part_offset+odd_size+1 ),
 
 1450     $                     lldb, 0, mycol-level_dist )
 
 1468        IF( mycol .LT. npcol-1) 
THEN 
 1470          CALL zgesd2d( ictxt, bw, nrhs,
 
 1471     $                     b( part_offset+odd_size+1 ), lldb,
 
 1478        IF( mycol .GT. 0) 
THEN 
 1480          CALL zgerv2d( ictxt, bw, nrhs,
 
 1492        IF ( mycol .NE. 0 ) 
THEN 
 1496          CALL zgemm( 
'N', 
'N', odd_size, nrhs, bw, -cone, af( 1 ),
 
 1497     $                odd_size, work( 1+bw-bw ), bw, cone,
 
 1498     $                b( part_offset+1 ), lldb )
 
 1503        IF ( mycol .LT. np-1 ) 
THEN 
 1511          CALL zlamov( 
'N', bw, nrhs, b( part_offset+odd_size+1), lldb,
 
 1512     $                 work( 1+bw-bw ), bw )
 
 1514          CALL ztrmm( 
'L', 
'L', 
'N', 
'N', bw, nrhs, -cone,
 
 1515     $                a(( ofst+1+odd_size*llda )), llda-1,
 
 1516     $                work( 1+bw-bw ), bw )
 
 1518          CALL zmatadd( bw, nrhs, cone, work( 1+bw-bw ), bw, cone,
 
 1519     $                  b( part_offset+odd_size-bw+1 ), lldb )
 
 1525        CALL ztbtrs( uplo, 
'N', 
'N', odd_size,
 
 1528     $                    llda,  b( part_offset+1 ),
 
 1542      IF( ictxt_save .NE. ictxt_new ) 
THEN 
 1543         CALL blacs_gridexit( ictxt_new )
 
 1555      work( 1 ) = work_size_min