4
5
6
7
8
9
10
11 CHARACTER DIAG, TRANS, UPLO
12 INTEGER INFO, IA, IB, IX, JA, JB, JX, LRWORK, LWORK,
13 $ N, NRHS
14
15
16 INTEGER DESCA( * ), DESCB( * ), DESCX( * )
17 REAL BERR( * ), FERR( * ), RWORK( * )
18 COMPLEX A( * ), B( * ), WORK( * ), X( * )
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246 INTEGER BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
247 $ LLD_, MB_, M_, NB_, N_, RSRC_
248 parameter( block_cyclic_2d = 1, dlen_ = 9, dtype_ = 1,
249 $ ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
250 $ rsrc_ = 7, csrc_ = 8, lld_ = 9 )
251 REAL ZERO, RONE
252 parameter( zero = 0.0e+0, rone = 1.0e+0 )
253 COMPLEX ONE
254 parameter( one = ( 1.0e+0, 0.0e+0 ) )
255
256
257 LOGICAL LQUERY, NOTRAN, NOUNIT, UPPER
258 CHARACTER TRANSN, TRANST
259 INTEGER IAROW, IXBCOL, IXBROW, IXCOL, IXROW, ICOFFA,
260 $ ICOFFB, ICOFFX, ICTXT, ICURCOL, IDUM, II, IIXB,
261 $ IIW, IOFFXB, IPB, IPR, IPV, IROFFA, IROFFB,
262 $ IROFFX, IW, J, JBRHS, JJ, JJFBE, JJXB, JN, JW,
263 $ K, KASE, LDXB, LRWMIN, LWMIN, MYCOL, MYRHS,
264 $ MYROW, NP, NP0, NPCOL, NPMOD, NPROW, NZ
265 REAL EPS, EST, LSTRES, S, SAFE1, SAFE2, SAFMIN
266 COMPLEX ZDUM
267
268
269 INTEGER DESCW( DLEN_ ), IDUM1( 5 ), IDUM2( 5 )
270
271
272 LOGICAL LSAME
273 INTEGER ICEIL, INDXG2P, NUMROC
274 REAL PSLAMCH
276
277
278 EXTERNAL blacs_gridinfo, cgebr2d, cgebs2d,
chk1mat,
282
283
284 INTRINSIC abs, aimag,
cmplx, ichar,
max,
min, mod, real
285
286
287 REAL CABS1
288
289
290 cabs1( zdum ) = abs( real( zdum ) ) + abs( aimag( zdum ) )
291
292
293
294
295
296 ictxt = desca( ctxt_ )
297 CALL blacs_gridinfo( ictxt, nprow, npcol, myrow, mycol )
298
299
300
301 info = 0
302 IF( nprow.EQ.-1 ) THEN
303 info = -( 900+ctxt_ )
304 ELSE
305 CALL chk1mat( n, 4, n, 4, ia, ja, desca, 9, info )
306 CALL chk1mat( n, 4, nrhs, 5, ib, jb, descb, 13, info )
307 CALL chk1mat( n, 4, nrhs, 5, ix, jx, descx, 17, info )
308 IF( info.EQ.0 ) THEN
309 upper =
lsame( uplo,
'U' )
310 notran =
lsame( trans,
'N' )
311 nounit =
lsame( diag,
'N' )
312 iroffa = mod( ia-1, desca( mb_ ) )
313 icoffa = mod( ja-1, desca( nb_ ) )
314 iroffb = mod( ib-1, descb( mb_ ) )
315 icoffb = mod( jb-1, descb( nb_ ) )
316 iroffx = mod( ix-1, descx( mb_ ) )
317 icoffx = mod( jx-1, descx( nb_ ) )
318 iarow =
indxg2p( ia, desca( mb_ ), myrow, desca( rsrc_ ),
319 $ nprow )
320 CALL infog2l( ib, jb, descb, nprow, npcol, myrow, mycol,
321 $ iixb, jjxb, ixbrow, ixbcol )
322 ixrow =
indxg2p( ix, descx( mb_ ), myrow, descx( rsrc_ ),
323 $ nprow )
324 ixcol =
indxg2p( jx, descx( nb_ ), mycol, descx( csrc_ ),
325 $ npcol )
326 npmod =
numroc( n+iroffa, desca( mb_ ), myrow, iarow,
327 $ nprow )
328 lwmin = 2*npmod
329 work( 1 ) = real( lwmin )
330 lrwmin = npmod
331 rwork( 1 ) = real( lrwmin )
332 lquery = ( lwork.EQ.-1 .OR. lrwork.EQ.-1 )
333
334 IF( .NOT.upper .AND. .NOT.
lsame( uplo,
'L' ) )
THEN
335 info = -1
336 ELSE IF( .NOT.notran .AND. .NOT.
lsame( trans,
'T' ) .AND.
337 $ .NOT.
lsame( trans,
'C' ) )
THEN
338 info = -2
339 ELSE IF( .NOT.nounit .AND. .NOT.
lsame( diag,
'U' ) )
THEN
340 info = -3
341 ELSE IF( n.LT.0 ) THEN
342 info = -4
343 ELSE IF( nrhs.LT.0 ) THEN
344 info = -5
345 ELSE IF( iroffa.NE.0 ) THEN
346 info = -7
347 ELSE IF( icoffa.NE.0 ) THEN
348 info = -8
349 ELSE IF( desca( mb_ ).NE.desca( nb_ ) ) THEN
350 info = -( 900+nb_ )
351 ELSE IF( iroffa.NE.iroffb .OR. iarow.NE.ixbrow ) THEN
352 info = -11
353 ELSE IF( desca( mb_ ).NE.descb( mb_ ) ) THEN
354 info = -( 1300+mb_ )
355 ELSE IF( ictxt.NE.descb( ctxt_ ) ) THEN
356 info = -( 1300+ctxt_ )
357 ELSE IF( iroffx.NE.0 .OR. ixbrow.NE.ixrow ) THEN
358 info = -15
359 ELSE IF( icoffb.NE.icoffx .OR. ixbcol.NE.ixcol ) THEN
360 info = -16
361 ELSE IF( descb( mb_ ).NE.descx( mb_ ) ) THEN
362 info = -( 1700+mb_ )
363 ELSE IF( descb( nb_ ).NE.descx( nb_ ) ) THEN
364 info = -( 1700+nb_ )
365 ELSE IF( ictxt.NE.descx( ctxt_ ) ) THEN
366 info = -( 1700+ctxt_ )
367 ELSE IF( lwork.LT.lwmin .AND. .NOT.lquery ) THEN
368 info = -21
369 ELSE IF( lrwork.LT.lrwmin .AND. .NOT.lquery ) THEN
370 info = -23
371 END IF
372 END IF
373
374 IF( upper ) THEN
375 idum1( 1 ) = ichar( 'U' )
376 ELSE
377 idum1( 1 ) = ichar( 'L' )
378 END IF
379 idum2( 1 ) = 1
380 IF( notran ) THEN
381 idum1( 2 ) = ichar( 'N' )
382 ELSE IF(
lsame( trans,
'T' ) )
THEN
383 idum1( 2 ) = ichar( 'T' )
384 ELSE
385 idum1( 2 ) = ichar( 'C' )
386 END IF
387 idum2( 2 ) = 2
388 IF( nounit ) THEN
389 idum1( 3 ) = ichar( 'N' )
390 ELSE
391 idum1( 3 ) = ichar( 'U' )
392 END IF
393 idum2( 3 ) = 3
394 IF( lwork.EQ.-1 ) THEN
395 idum1( 4 ) = -1
396 ELSE
397 idum1( 4 ) = 1
398 END IF
399 idum2( 4 ) = 21
400 IF( lrwork.EQ.-1 ) THEN
401 idum1( 5 ) = -1
402 ELSE
403 idum1( 5 ) = 1
404 END IF
405 idum2( 5 ) = 23
406 CALL pchk1mat( n, 4, n, 4, ia, ja, desca, 9, 0, idum1, idum2,
407 $ info )
408 CALL pchk2mat( n, 4, nrhs, 5, ib, jb, descb, 13, n, 4, nrhs, 5,
409 $ ix, jx, descx, 17, 5, idum1, idum2, info )
410 END IF
411 IF( info.NE.0 ) THEN
412 CALL pxerbla( ictxt,
'PCTRRFS', -info )
413 RETURN
414 ELSE IF( lquery ) THEN
415 RETURN
416 END IF
417
418 jjfbe = jjxb
419 myrhs =
numroc( jb+nrhs-1, descb( nb_ ), mycol, descb( csrc_ ),
420 $ npcol )
421
422
423
424 IF( n.LE.1 .OR. nrhs.EQ.0 ) THEN
425 DO 10 jj = jjfbe, myrhs
426 ferr( jj ) = zero
427 berr( jj ) = zero
428 10 CONTINUE
429 RETURN
430 END IF
431
432 IF( notran ) THEN
433 transn = 'N'
434 transt = 'C'
435 ELSE
436 transn = 'C'
437 transt = 'N'
438 END IF
439
440 np0 =
numroc( n+iroffb, descb( mb_ ), myrow, ixbrow, nprow )
441 CALL descset( descw, n+iroffb, 1, desca( mb_ ), 1, ixbrow, ixbcol,
442 $ ictxt,
max( 1, np0 ) )
443 ipb = 1
444 ipr = 1
445 ipv = ipr + np0
446 IF( myrow.EQ.ixbrow ) THEN
447 iiw = 1 + iroffb
448 np = np0 - iroffb
449 ELSE
450 iiw = 1
451 np = np0
452 END IF
453 iw = 1 + iroffb
454 jw = 1
455 ldxb = descb( lld_ )
456 ioffxb = ( jjxb-1 )*ldxb
457
458
459
460 nz = n + 1
461 eps =
pslamch( ictxt,
'Epsilon' )
462 safmin =
pslamch( ictxt,
'Safe minimum' )
463 safe1 = nz*safmin
464 safe2 = safe1 / eps
465 jn =
min(
iceil( jb, descb( nb_ ) )*descb( nb_ ), jb+nrhs-1 )
466
467
468
469 jbrhs = jn - jb + 1
470 DO 90 k = 0, jbrhs - 1
471
472
473
474
475 CALL pccopy( n, x, ix, jx+k, descx, 1, work( ipr ), iw, jw,
476 $ descw, 1 )
477 CALL pctrmv( uplo, trans, diag, n, a, ia, ja, desca,
478 $ work( ipr ), iw, jw, descw, 1 )
479 CALL pcaxpy( n, -one, b, ib, jb+k, descb, 1, work( ipr ), iw,
480 $ jw, descw, 1 )
481
482
483
484
485
486
487
488
489
490
491 IF( mycol.EQ.ixbcol ) THEN
492 IF( np.GT.0 ) THEN
493 DO 20 ii = iixb, iixb + np - 1
494 rwork( iiw+ii-iixb ) = cabs1( b( ii+ioffxb ) )
495 20 CONTINUE
496 END IF
497 END IF
498
499 CALL pcatrmv( uplo, trans, diag, n, rone, a, ia, ja, desca, x,
500 $ ix, jx+k, descx, 1, rone, rwork( ipb ), iw, jw,
501 $ descw, 1 )
502
503 s = zero
504 IF( mycol.EQ.ixbcol ) THEN
505 IF( np.GT.0 ) THEN
506 DO 30 ii = iiw - 1, iiw + np - 2
507 IF( rwork( ipb+ii ).GT.safe2 ) THEN
508 s =
max( s, cabs1( work( ipr+ii ) ) /
509 $ rwork( ipb+ii ) )
510 ELSE
511 s =
max( s, ( cabs1( work( ipr+ii ) )+safe1 ) /
512 $ ( rwork( ipb+ii )+safe1 ) )
513 END IF
514 30 CONTINUE
515 END IF
516 END IF
517
518 CALL sgamx2d( ictxt, 'All', ' ', 1, 1, s, 1, idum, idum, 1,
519 $ -1, mycol )
520 IF( mycol.EQ.ixbcol )
521 $ berr( jjfbe ) = s
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545 IF( mycol.EQ.ixbcol ) THEN
546 IF( np.GT.0 ) THEN
547 DO 40 ii = iiw - 1, iiw + np - 2
548 IF( rwork( ipb+ii ).GT.safe2 ) THEN
549 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
550 $ nz*eps*rwork( ipb+ii )
551 ELSE
552 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
553 $ nz*eps*rwork( ipb+ii ) + safe1
554 END IF
555 40 CONTINUE
556 END IF
557 END IF
558
559 kase = 0
560 50 CONTINUE
561 IF( mycol.EQ.ixbcol ) THEN
562 CALL cgebs2d( ictxt, 'Rowwise', ' ', np, 1, work( ipr ),
563 $ descw( lld_ ) )
564 ELSE
565 CALL cgebr2d( ictxt, 'Rowwise', ' ', np, 1, work( ipr ),
566 $ descw( lld_ ), myrow, ixbcol )
567 END IF
568 descw( csrc_ ) = mycol
569 CALL pclacon( n, work( ipv ), iw, jw, descw, work( ipr ),
570 $ iw, jw, descw, est, kase )
571 descw( csrc_ ) = ixbcol
572
573 IF( kase.NE.0 ) THEN
574 IF( kase.EQ.1 ) THEN
575
576
577
578 CALL pctrsv( uplo, transt, diag, n, a, ia, ja, desca,
579 $ work( ipr ), iw, jw, descw, 1 )
580 IF( mycol.EQ.ixbcol ) THEN
581 IF( np.GT.0 ) THEN
582 DO 60 ii = iiw - 1, iiw + np - 2
583 work( ipr+ii ) = rwork( ipb+ii )*work( ipr+ii )
584 60 CONTINUE
585 END IF
586 END IF
587 ELSE
588
589
590
591 IF( mycol.EQ.ixbcol ) THEN
592 IF( np.GT.0 ) THEN
593 DO 70 ii = iiw - 1, iiw + np - 2
594 work( ipr+ii ) = rwork( ipb+ii )*work( ipr+ii )
595 70 CONTINUE
596 END IF
597 END IF
598 CALL pctrsv( uplo, transn, diag, n, a, ia, ja, desca,
599 $ work( ipr ), iw, jw, descw, 1 )
600 END IF
601 GO TO 50
602 END IF
603
604
605
606 lstres = zero
607 IF( mycol.EQ.ixbcol ) THEN
608 IF( np.GT.0 ) THEN
609 DO 80 ii = iixb, iixb + np - 1
610 lstres =
max( lstres, cabs1( x( ioffxb+ii ) ) )
611 80 CONTINUE
612 END IF
613 CALL sgamx2d( ictxt, 'Column', ' ', 1, 1, lstres, 1, idum,
614 $ idum, 1, -1, mycol )
615 IF( lstres.NE.zero )
616 $ ferr( jjfbe ) = est / lstres
617
618 jjxb = jjxb + 1
619 jjfbe = jjfbe + 1
620 ioffxb = ioffxb + ldxb
621
622 END IF
623
624 90 CONTINUE
625
626 icurcol = mod( ixbcol+1, npcol )
627
628
629
630 DO 180 j = jn + 1, jb + nrhs - 1, descb( nb_ )
631 jbrhs =
min( jb+nrhs-j, descb( nb_ ) )
632 descw( csrc_ ) = icurcol
633
634 DO 170 k = 0, jbrhs - 1
635
636
637
638
639 CALL pccopy( n, x, ix, j+k, descx, 1, work( ipr ), iw, jw,
640 $ descw, 1 )
641 CALL pctrmv( uplo, trans, diag, n, a, ia, ja, desca,
642 $ work( ipr ), iw, jw, descw, 1 )
643 CALL pcaxpy( n, -one, b, ib, j+k, descb, 1, work( ipr ),
644 $ iw, jw, descw, 1 )
645
646
647
648
649
650
651
652
653
654
655
656 IF( mycol.EQ.ixbcol ) THEN
657 IF( np.GT.0 ) THEN
658 DO 100 ii = iixb, iixb + np - 1
659 rwork( iiw+ii-iixb ) = cabs1( b( ii+ioffxb ) )
660 100 CONTINUE
661 END IF
662 END IF
663
664 CALL pcatrmv( uplo, trans, diag, n, rone, a, ia, ja, desca,
665 $ x, ix, j+k, descx, 1, rone, rwork( ipb ), iw,
666 $ jw, descw, 1 )
667
668 s = zero
669 IF( mycol.EQ.ixbcol ) THEN
670 IF( np.GT.0 ) THEN
671 DO 110 ii = iiw - 1, iiw + np - 2
672 IF( rwork( ipb+ii ).GT.safe2 ) THEN
673 s =
max( s, cabs1( work( ipr+ii ) ) /
674 $ rwork( ipb+ii ) )
675 ELSE
676 s =
max( s, ( cabs1( work( ipr+ii ) )+safe1 ) /
677 $ ( rwork( ipb+ii )+safe1 ) )
678 END IF
679 110 CONTINUE
680 END IF
681 END IF
682
683 CALL sgamx2d( ictxt, 'All', ' ', 1, 1, s, 1, idum, idum, 1,
684 $ -1, mycol )
685 IF( mycol.EQ.ixbcol )
686 $ berr( jjfbe ) = s
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 IF( mycol.EQ.ixbcol ) THEN
713 IF( np.GT.0 ) THEN
714 DO 120 ii = iiw - 1, iiw + np - 2
715 IF( rwork( ipb+ii ).GT.safe2 ) THEN
716 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
717 $ nz*eps*rwork( ipb+ii )
718 ELSE
719 rwork( ipb+ii ) = cabs1( work( ipr+ii ) ) +
720 $ nz*eps*rwork( ipb+ii ) + safe1
721 END IF
722 120 CONTINUE
723 END IF
724 END IF
725
726 kase = 0
727 130 CONTINUE
728 IF( mycol.EQ.ixbcol ) THEN
729 CALL cgebs2d( ictxt, 'Rowwise', ' ', np, 1, work( ipr ),
730 $ descw( lld_ ) )
731 ELSE
732 CALL cgebr2d( ictxt, 'Rowwise', ' ', np, 1, work( ipr ),
733 $ descw( lld_ ), myrow, ixbcol )
734 END IF
735 descw( csrc_ ) = mycol
736 CALL pclacon( n, work( ipv ), iw, jw, descw, work( ipr ),
737 $ iw, jw, descw, est, kase )
738 descw( csrc_ ) = ixbcol
739
740 IF( kase.NE.0 ) THEN
741 IF( kase.EQ.1 ) THEN
742
743
744
745 CALL pctrsv( uplo, transt, diag, n, a, ia, ja, desca,
746 $ work( ipr ), iw, jw, descw, 1 )
747 IF( mycol.EQ.ixbcol ) THEN
748 IF( np.GT.0 ) THEN
749 DO 140 ii = iiw - 1, iiw + np - 2
750 work( ipr+ii ) = rwork( ipb+ii )*
751 $ work( ipr+ii )
752 140 CONTINUE
753 END IF
754 END IF
755 ELSE
756
757
758
759 IF( mycol.EQ.ixbcol ) THEN
760 IF( np.GT.0 ) THEN
761 DO 150 ii = iiw - 1, iiw + np - 2
762 work( ipr+ii ) = rwork( ipb+ii )*
763 $ work( ipr+ii )
764 150 CONTINUE
765 END IF
766 END IF
767 CALL pctrsv( uplo, transn, diag, n, a, ia, ja, desca,
768 $ work( ipr ), iw, jw, descw, 1 )
769 END IF
770 GO TO 130
771 END IF
772
773
774
775 lstres = zero
776 IF( mycol.EQ.ixbcol ) THEN
777 IF( np.GT.0 ) THEN
778 DO 160 ii = iixb, iixb + np - 1
779 lstres =
max( lstres, cabs1( x( ioffxb+ii ) ) )
780 160 CONTINUE
781 END IF
782 CALL sgamx2d( ictxt, 'Column', ' ', 1, 1, lstres, 1,
783 $ idum, idum, 1, -1, mycol )
784 IF( lstres.NE.zero )
785 $ ferr( jjfbe ) = est / lstres
786
787 jjxb = jjxb + 1
788 jjfbe = jjfbe + 1
789 ioffxb = ioffxb + ldxb
790
791 END IF
792
793 170 CONTINUE
794
795 icurcol = mod( icurcol+1, npcol )
796
797 180 CONTINUE
798
799 work( 1 ) =
cmplx( real( lwmin ) )
800 rwork( 1 ) = real( lrwmin )
801
802 RETURN
803
804
805
subroutine chk1mat(ma, mapos0, na, napos0, ia, ja, desca, descapos0, info)
subroutine descset(desc, m, n, mb, nb, irsrc, icsrc, ictxt, lld)
integer function iceil(inum, idenom)
integer function indxg2p(indxglob, nb, iproc, isrcproc, nprocs)
subroutine infog2l(grindx, gcindx, desc, nprow, npcol, myrow, mycol, lrindx, lcindx, rsrc, csrc)
integer function numroc(n, nb, iproc, isrcproc, nprocs)
real function pslamch(ictxt, cmach)
subroutine pchk1mat(ma, mapos0, na, napos0, ia, ja, desca, descapos0, nextra, ex, expos, info)
subroutine pchk2mat(ma, mapos0, na, napos0, ia, ja, desca, descapos0, mb, mbpos0, nb, nbpos0, ib, jb, descb, descbpos0, nextra, ex, expos, info)
subroutine pclacon(n, v, iv, jv, descv, x, ix, jx, descx, est, kase)
subroutine pxerbla(ictxt, srname, info)