5
6
7
8
9
10
11
12 CHARACTER JOBZ, RANGE, UPLO
13 INTEGER IA, IL, INFO, IU, IZ, JA, JZ, LIWORK, LRWORK,
14 $ LWORK, M, N, NZ
15 DOUBLE PRECISION ABSTOL, ORFAC, VL, VU
16
17
18 INTEGER DESCA( * ), DESCZ( * ), ICLUSTR( * ),
19 $ IFAIL( * ), IWORK( * )
20 DOUBLE PRECISION GAP( * ), RWORK( * ), W( * )
21 COMPLEX*16 A( * ), WORK( * ), Z( * )
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470 INTEGER BLOCK_CYCLIC_2D, DLEN_, DTYPE_, CTXT_, M_, N_,
471 $ MB_, NB_, RSRC_, CSRC_, LLD_
472 parameter( block_cyclic_2d = 1, dlen_ = 9, dtype_ = 1,
473 $ ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
474 $ rsrc_ = 7, csrc_ = 8, lld_ = 9 )
475 DOUBLE PRECISION ZERO, ONE, TEN, FIVE
476 parameter( zero = 0.0d+0, one = 1.0d+0, ten = 10.0d+0,
477 $ five = 5.0d+0 )
478 INTEGER IERREIN, IERRCLS, IERRSPC, IERREBZ
479 parameter( ierrein = 1, ierrcls = 2, ierrspc = 4,
480 $ ierrebz = 8 )
481
482
483 LOGICAL ALLEIG, INDEIG, LOWER, LQUERY, QUICKRETURN,
484 $ VALEIG, WANTZ
485 CHARACTER ORDER
486 INTEGER ANB, CSRC_A, I, IAROW, ICOFFA, ICTXT, IINFO,
487 $ INDD, INDD2, INDE, INDE2, INDIBL, INDISP,
488 $ INDRWORK, INDTAU, INDWORK, IROFFA, IROFFZ,
489 $ ISCALE, ISIZESTEBZ, ISIZESTEIN, IZROW,
490 $ LALLWORK, LIWMIN, LLRWORK, LLWORK, LRWMIN,
491 $ LRWOPT, LWMIN, LWOPT, MAXEIGS, MB_A, MQ0,
492 $ MYCOL, MYROW, NB, NB_A, NEIG, NHETRD_LWOPT, NN,
493 $ NNP, NP0, NPCOL, NPROCS, NPROW, NPS, NQ0,
494 $ NSPLIT, NZZ, OFFSET, RSRC_A, RSRC_Z, SIZEHEEVX,
495 $ SIZESTEIN, SQNPC
496 DOUBLE PRECISION ABSTLL, ANRM, BIGNUM, EPS, RMAX, RMIN, SAFMIN,
497 $ SIGMA, SMLNUM, VLL, VUU
498
499
500 INTEGER IDUM1( 4 ), IDUM2( 4 )
501
502
503 LOGICAL LSAME
504 INTEGER ICEIL, INDXG2P, NUMROC, PJLAENV
505 DOUBLE PRECISION PDLAMCH, PZLANHE
508
509
510 EXTERNAL blacs_gridinfo,
chk1mat, dgebr2d, dgebs2d,
514
515
516 INTRINSIC abs, dble, dcmplx, ichar, int,
max,
min, mod,
517 $ sqrt
518
519
520
521 IF( block_cyclic_2d*csrc_*ctxt_*dlen_*dtype_*lld_*mb_*m_*nb_*n_*
522 $ rsrc_.LT.0 )RETURN
523
524 quickreturn = ( n.EQ.0 )
525
526
527
528 ictxt = desca( ctxt_ )
529 CALL blacs_gridinfo( ictxt, nprow, npcol, myrow, mycol )
530 info = 0
531
532 wantz =
lsame( jobz,
'V' )
533 IF( nprow.EQ.-1 ) THEN
534 info = -( 800+ctxt_ )
535 ELSE IF( wantz ) THEN
536 IF( ictxt.NE.descz( ctxt_ ) ) THEN
537 info = -( 2100+ctxt_ )
538 END IF
539 END IF
540 IF( info.EQ.0 ) THEN
541 CALL chk1mat( n, 4, n, 4, ia, ja, desca, 8, info )
542 IF( wantz )
543 $
CALL chk1mat( n, 4, n, 4, iz, jz, descz, 21, info )
544
545 IF( info.EQ.0 ) THEN
546
547
548
549 safmin =
pdlamch( ictxt,
'Safe minimum' )
550 eps =
pdlamch( ictxt,
'Precision' )
551 smlnum = safmin / eps
552 bignum = one / smlnum
553 rmin = sqrt( smlnum )
554 rmax =
min( sqrt( bignum ), one / sqrt( sqrt( safmin ) ) )
555
556 nprocs = nprow*npcol
557 lower =
lsame( uplo,
'L' )
558 alleig =
lsame( range,
'A' )
559 valeig =
lsame( range,
'V' )
560 indeig =
lsame( range,
'I' )
561
562
563
564 indtau = 1
565 indwork = indtau + n
566 llwork = lwork - indwork + 1
567
568
569
570 inde = 1
571 indd = inde + n
572 indd2 = indd + n
573 inde2 = indd2 + n
574 indrwork = inde2 + n
575 llrwork = lrwork - indrwork + 1
576
577
578
579 isizestein = 3*n + nprocs + 1
580 isizestebz =
max( 4*n, 14, nprocs )
581 indibl = (
max( isizestein, isizestebz ) ) + 1
582 indisp = indibl + n
583
584
585
586 lquery = .false.
587 IF( lwork.EQ.-1 .OR. liwork.EQ.-1 .OR. lrwork.EQ.-1 )
588 $ lquery = .true.
589
590 nnp =
max( n, nprocs+1, 4 )
591 liwmin = 6*nnp
592
593 nprocs = nprow*npcol
594 nb_a = desca( nb_ )
595 mb_a = desca( mb_ )
596 nb = nb_a
598
599 rsrc_a = desca( rsrc_ )
600 csrc_a = desca( csrc_ )
601 iroffa = mod( ia-1, mb_a )
602 icoffa = mod( ja-1, nb_a )
603 iarow =
indxg2p( 1, nb_a, myrow, rsrc_a, nprow )
604 np0 =
numroc( n+iroffa, nb, 0, 0, nprow )
605 mq0 =
numroc( n+icoffa, nb, 0, 0, npcol )
606 IF( wantz ) THEN
607 rsrc_z = descz( rsrc_ )
608 iroffz = mod( iz-1, mb_a )
609 izrow =
indxg2p( 1, nb_a, myrow, rsrc_z, nprow )
610 ELSE
611 iroffz = 0
612 izrow = 0
613 END IF
614
615 IF( ( .NOT.wantz ) .OR. ( valeig .AND. ( .NOT.lquery ) ) )
616 $ THEN
617 lwmin = n +
max( nb*( np0+1 ), 3 )
618 lwopt = lwmin
619 lrwmin = 5*nn + 4*n
620 IF( wantz ) THEN
621 mq0 =
numroc(
max( n, nb, 2 ), nb, 0, 0, npcol )
622 lrwopt = 4*n +
max( 5*nn, np0*mq0 ) +
623 $
iceil( n, nprow*npcol )*nn
624 ELSE
625 lrwopt = lrwmin
626 END IF
627 neig = 0
628 ELSE
629 IF( alleig .OR. valeig ) THEN
630 neig = n
631 ELSE IF( indeig ) THEN
632 neig = iu - il + 1
633 END IF
634 mq0 =
numroc(
max( neig, nb, 2 ), nb, 0, 0, npcol )
635 nq0 =
numroc( nn, nb, 0, 0, npcol )
636 lwmin = n + ( np0+nq0+nb )*nb
637 lrwmin = 4*n +
max( 5*nn, np0*mq0 ) +
638 $
iceil( neig, nprow*npcol )*nn
639 lrwopt = lrwmin
640 lwopt = lwmin
641
642 END IF
643
644
645
646
647 anb =
pjlaenv( ictxt, 3,
'PZHETTRD',
'L', 0, 0, 0, 0 )
648 sqnpc = int( sqrt( dble( nprow*npcol ) ) )
649 nps =
max(
numroc( n, 1, 0, 0, sqnpc ), 2*anb )
650 nhetrd_lwopt = 2*( anb+1 )*( 4*nps+2 ) + ( nps+2 )*nps
651 lwopt =
max( lwopt, n+nhetrd_lwopt )
652
653 END IF
654 IF( info.EQ.0 ) THEN
655 IF( myrow.EQ.0 .AND. mycol.EQ.0 ) THEN
656 rwork( 1 ) = abstol
657 IF( valeig ) THEN
658 rwork( 2 ) = vl
659 rwork( 3 ) = vu
660 ELSE
661 rwork( 2 ) = zero
662 rwork( 3 ) = zero
663 END IF
664 CALL dgebs2d( ictxt, 'ALL', ' ', 3, 1, rwork, 3 )
665 ELSE
666 CALL dgebr2d( ictxt, 'ALL', ' ', 3, 1, rwork, 3, 0, 0 )
667 END IF
668 IF( .NOT.( wantz .OR.
lsame( jobz,
'N' ) ) )
THEN
669 info = -1
670 ELSE IF( .NOT.( alleig .OR. valeig .OR. indeig ) ) THEN
671 info = -2
672 ELSE IF( .NOT.( lower .OR.
lsame( uplo,
'U' ) ) )
THEN
673 info = -3
674 ELSE IF( valeig .AND. n.GT.0 .AND. vu.LE.vl ) THEN
675 info = -10
676 ELSE IF( indeig .AND. ( il.LT.1 .OR. il.GT.
max( 1, n ) ) )
677 $ THEN
678 info = -11
679 ELSE IF( indeig .AND. ( iu.LT.
min( n, il ) .OR. iu.GT.n ) )
680 $ THEN
681 info = -12
682 ELSE IF( lwork.LT.lwmin .AND. lwork.NE.-1 ) THEN
683 info = -23
684 ELSE IF( lrwork.LT.lrwmin .AND. lrwork.NE.-1 ) THEN
685 info = -25
686 ELSE IF( liwork.LT.liwmin .AND. liwork.NE.-1 ) THEN
687 info = -27
688 ELSE IF( valeig .AND. ( abs( rwork( 2 )-vl ).GT.five*eps*
689 $ abs( vl ) ) ) THEN
690 info = -9
691 ELSE IF( valeig .AND. ( abs( rwork( 3 )-vu ).GT.five*eps*
692 $ abs( vu ) ) ) THEN
693 info = -10
694 ELSE IF( abs( rwork( 1 )-abstol ).GT.five*eps*
695 $ abs( abstol ) ) THEN
696 info = -13
697 ELSE IF( iroffa.NE.0 ) THEN
698 info = -6
699 ELSE IF( desca( mb_ ).NE.desca( nb_ ) ) THEN
700 info = -( 800+nb_ )
701 END IF
702 IF( wantz ) THEN
703 IF( iroffa.NE.iroffz ) THEN
704 info = -19
705 ELSE IF( iarow.NE.izrow ) THEN
706 info = -19
707 ELSE IF( desca( m_ ).NE.descz( m_ ) ) THEN
708 info = -( 2100+m_ )
709 ELSE IF( desca( n_ ).NE.descz( n_ ) ) THEN
710 info = -( 2100+n_ )
711 ELSE IF( desca( mb_ ).NE.descz( mb_ ) ) THEN
712 info = -( 2100+mb_ )
713 ELSE IF( desca( nb_ ).NE.descz( nb_ ) ) THEN
714 info = -( 2100+nb_ )
715 ELSE IF( desca( rsrc_ ).NE.descz( rsrc_ ) ) THEN
716 info = -( 2100+rsrc_ )
717 ELSE IF( desca( csrc_ ).NE.descz( csrc_ ) ) THEN
718 info = -( 2100+csrc_ )
719 ELSE IF( ictxt.NE.descz( ctxt_ ) ) THEN
720 info = -( 2100+ctxt_ )
721 END IF
722 END IF
723 END IF
724 IF( wantz ) THEN
725 idum1( 1 ) = ichar( 'V' )
726 ELSE
727 idum1( 1 ) = ichar( 'N' )
728 END IF
729 idum2( 1 ) = 1
730 IF( lower ) THEN
731 idum1( 2 ) = ichar( 'L' )
732 ELSE
733 idum1( 2 ) = ichar( 'U' )
734 END IF
735 idum2( 2 ) = 2
736 IF( alleig ) THEN
737 idum1( 3 ) = ichar( 'A' )
738 ELSE IF( indeig ) THEN
739 idum1( 3 ) = ichar( 'I' )
740 ELSE
741 idum1( 3 ) = ichar( 'V' )
742 END IF
743 idum2( 3 ) = 3
744 IF( lquery ) THEN
745 idum1( 4 ) = -1
746 ELSE
747 idum1( 4 ) = 1
748 END IF
749 idum2( 4 ) = 4
750 IF( wantz ) THEN
751 CALL pchk2mat( n, 4, n, 4, ia, ja, desca, 8, n, 4, n, 4, iz,
752 $ jz, descz, 21, 4, idum1, idum2, info )
753 ELSE
754 CALL pchk1mat( n, 4, n, 4, ia, ja, desca, 8, 4, idum1,
755 $ idum2, info )
756 END IF
757 work( 1 ) = dcmplx( lwopt )
758 rwork( 1 ) = dble( lrwopt )
759 iwork( 1 ) = liwmin
760 END IF
761
762 IF( info.NE.0 ) THEN
763 CALL pxerbla( ictxt,
'PZHEEVX', -info )
764 RETURN
765 ELSE IF( lquery ) THEN
766 RETURN
767 END IF
768
769
770
771 IF( quickreturn ) THEN
772 IF( wantz ) THEN
773 nz = 0
774 iclustr( 1 ) = 0
775 END IF
776 m = 0
777 work( 1 ) = dcmplx( lwopt )
778 rwork( 1 ) = dble( lrwmin )
779 iwork( 1 ) = liwmin
780 RETURN
781 END IF
782
783
784
785 abstll = abstol
786 iscale = 0
787 IF( valeig ) THEN
788 vll = vl
789 vuu = vu
790 ELSE
791 vll = zero
792 vuu = zero
793 END IF
794
795 anrm =
pzlanhe(
'M', uplo, n, a, ia, ja, desca,
796 $ rwork( indrwork ) )
797
798 IF( anrm.GT.zero .AND. anrm.LT.rmin ) THEN
799 iscale = 1
800 sigma = rmin / anrm
801 anrm = anrm*sigma
802 ELSE IF( anrm.GT.rmax ) THEN
803 iscale = 1
804 sigma = rmax / anrm
805 anrm = anrm*sigma
806 END IF
807
808 IF( iscale.EQ.1 ) THEN
809 CALL pzlascl( uplo, one, sigma, n, n, a, ia, ja, desca, iinfo )
810 IF( abstol.GT.0 )
811 $ abstll = abstol*sigma
812 IF( valeig ) THEN
813 vll = vl*sigma
814 vuu = vu*sigma
815 IF( vuu.EQ.vll ) THEN
816 vuu = vuu + 2*
max( abs( vuu )*eps, safmin )
817 END IF
818 END IF
819 END IF
820
821
822
823 lallwork = llrwork
824
825 CALL pzhentrd( uplo, n, a, ia, ja, desca, rwork( indd ),
826 $ rwork( inde ), work( indtau ), work( indwork ),
827 $ llwork, rwork( indrwork ), llrwork, iinfo )
828
829
830
831
832
833
834
835
836 offset = 0
837 IF( ia.EQ.1 .AND. ja.EQ.1 .AND. rsrc_a.EQ.0 .AND. csrc_a.EQ.0 )
838 $ THEN
839 CALL pdlared1d( n, ia, ja, desca, rwork( indd ),
840 $ rwork( indd2 ), rwork( indrwork ), llrwork )
841
842 CALL pdlared1d( n, ia, ja, desca, rwork( inde ),
843 $ rwork( inde2 ), rwork( indrwork ), llrwork )
844 IF( .NOT.lower )
845 $ offset = 1
846 ELSE
847 DO 10 i = 1, n
848 CALL pzelget(
'A',
' ', work( indd2+i-1 ), a, i+ia-1,
849 $ i+ja-1, desca )
850 rwork( indd2+i-1 ) = dble( work( indd2+i-1 ) )
851 10 CONTINUE
852 IF(
lsame( uplo,
'U' ) )
THEN
853 DO 20 i = 1, n - 1
854 CALL pzelget(
'A',
' ', work( inde2+i-1 ), a, i+ia-1,
855 $ i+ja, desca )
856 rwork( inde2+i-1 ) = dble( work( inde2+i-1 ) )
857 20 CONTINUE
858 ELSE
859 DO 30 i = 1, n - 1
860 CALL pzelget(
'A',
' ', work( inde2+i-1 ), a, i+ia,
861 $ i+ja-1, desca )
862 rwork( inde2+i-1 ) = dble( work( inde2+i-1 ) )
863 30 CONTINUE
864 END IF
865 END IF
866
867
868
869 IF( wantz ) THEN
870 order = 'B'
871 ELSE
872 order = 'E'
873 END IF
874
875 CALL pdstebz( ictxt, range, order, n, vll, vuu, il, iu, abstll,
876 $ rwork( indd2 ), rwork( inde2+offset ), m, nsplit, w,
877 $ iwork( indibl ), iwork( indisp ), rwork( indrwork ),
878 $ llrwork, iwork( 1 ), isizestebz, iinfo )
879
880
881
882
883
884
885
886
887
888 IF( iinfo.NE.0 ) THEN
889 info = info + ierrebz
890 DO 40 i = 1, m
891 iwork( indibl+i-1 ) = abs( iwork( indibl+i-1 ) )
892 40 CONTINUE
893 END IF
894 IF( wantz ) THEN
895
896 IF( valeig ) THEN
897
898
899
900
901
902
903
904
905
906
907
908 CALL igamn2d( ictxt, 'A', ' ', 1, 1, lallwork, 1, 1, 1, -1,
909 $ -1, -1 )
910
911 maxeigs = descz( n_ )
912
913 DO 50 nz =
min( maxeigs, m ), 0, -1
914 mq0 =
numroc( nz, nb, 0, 0, npcol )
915 sizestein =
iceil( nz, nprocs )*n +
max( 5*n, np0*mq0 )
916 sizeheevx = sizestein
917 IF( sizeheevx.LE.lallwork )
918 $ GO TO 60
919 50 CONTINUE
920 60 CONTINUE
921 ELSE
922 nz = m
923 END IF
925 IF( nz.NE.m ) THEN
926 info = info + ierrspc
927
928 DO 70 i = 1, m
929 ifail( i ) = 0
930 70 CONTINUE
931
932
933
934
935
936
937
938
939
940
941 IF( nsplit.GT.1 ) THEN
942 CALL dlasrt( 'I', m, w, iinfo )
943 nzz = 0
944 IF( nz.GT.0 ) THEN
945
946 vuu = w( nz ) - ten*( eps*anrm+safmin )
947 IF( vll.GE.vuu ) THEN
948 nzz = 0
949 ELSE
950 CALL pdstebz( ictxt, range, order, n, vll, vuu, il,
951 $ iu, abstll, rwork( indd2 ),
952 $ rwork( inde2+offset ), nzz, nsplit,
953 $ w, iwork( indibl ), iwork( indisp ),
954 $ rwork( indrwork ), llrwork,
955 $ iwork( 1 ), isizestebz, iinfo )
956 END IF
957
958 IF( mod( info / ierrebz, 1 ).EQ.0 ) THEN
959 IF( nzz.GT.nz .OR. iinfo.NE.0 ) THEN
960 info = info + ierrebz
961 END IF
962 END IF
963 END IF
965
966 END IF
967 END IF
968 CALL pzstein( n, rwork( indd2 ), rwork( inde2+offset ), nz, w,
969 $ iwork( indibl ), iwork( indisp ), orfac, z, iz,
970 $ jz, descz, rwork( indrwork ), lallwork,
971 $ iwork( 1 ), isizestein, ifail, iclustr, gap,
972 $ iinfo )
973
974 IF( iinfo.GE.nz+1 )
975 $ info = info + ierrcls
976 IF( mod( iinfo, nz+1 ).NE.0 )
977 $ info = info + ierrein
978
979
980
981
982 IF( nz.GT.0 ) THEN
983 CALL pzunmtr(
'L', uplo,
'N', n, nz, a, ia, ja, desca,
984 $ work( indtau ), z, iz, jz, descz,
985 $ work( indwork ), llwork, iinfo )
986 END IF
987
988 END IF
989
990
991
992 IF( iscale.EQ.1 ) THEN
993 CALL dscal( m, one / sigma, w, 1 )
994 END IF
995
996 work( 1 ) = dcmplx( lwopt )
997 rwork( 1 ) = dble( lrwopt )
998 iwork( 1 ) = liwmin
999
1000 RETURN
1001
1002
1003
subroutine chk1mat(ma, mapos0, na, napos0, ia, ja, desca, descapos0, info)
integer function iceil(inum, idenom)
integer function indxg2p(indxglob, nb, iproc, isrcproc, nprocs)
integer function numroc(n, nb, iproc, isrcproc, nprocs)
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)
double precision function pdlamch(ictxt, cmach)
subroutine pdlared1d(n, ia, ja, desc, bycol, byall, work, lwork)
subroutine pdstebz(ictxt, range, order, n, vl, vu, il, iu, abstol, d, e, m, nsplit, w, iblock, isplit, work, lwork, iwork, liwork, info)
integer function pjlaenv(ictxt, ispec, name, opts, n1, n2, n3, n4)
subroutine pxerbla(ictxt, srname, info)
subroutine pzelget(scope, top, alpha, a, ia, ja, desca)
subroutine pzhentrd(uplo, n, a, ia, ja, desca, d, e, tau, work, lwork, rwork, lrwork, info)
double precision function pzlanhe(norm, uplo, n, a, ia, ja, desca, work)
subroutine pzlascl(type, cfrom, cto, m, n, a, ia, ja, desca, info)
subroutine pzstein(n, d, e, m, w, iblock, isplit, orfac, z, iz, jz, descz, work, lwork, iwork, liwork, ifail, iclustr, gap, info)
subroutine pzunmtr(side, uplo, trans, m, n, a, ia, ja, desca, tau, c, ic, jc, descc, work, lwork, info)