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