1      SUBROUTINE PZGEHRD( N, ILO, IHI, A, IA, JA, DESCA, TAU, WORK,
2     $                    LWORK, INFO )
3*
4*  -- ScaLAPACK routine (version 1.7) --
5*     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
6*     and University of California, Berkeley.
7*     May 25, 2001
8*
9*     .. Scalar Arguments ..
10      INTEGER             IA, IHI, ILO, INFO, JA, LWORK, N
11*     ..
12*     .. Array Arguments ..
13      INTEGER             DESCA( * )
14      COMPLEX*16          A( * ), TAU( * ), WORK( * )
15*     ..
16*
17*  Purpose
18*  =======
19*
20*  PZGEHRD reduces a complex general distributed matrix sub( A )
21*  to upper Hessenberg form H by an unitary similarity transformation:
22*  Q' * sub( A ) * Q = H, where
23*  sub( A ) = A(IA+N-1:IA+N-1,JA+N-1:JA+N-1).
24*
25*  Notes
26*  =====
27*
28*  Each global data object is described by an associated description
29*  vector.  This vector stores the information required to establish
30*  the mapping between an object element and its corresponding process
31*  and memory location.
32*
33*  Let A be a generic term for any 2D block cyclicly distributed array.
34*  Such a global array has an associated description vector DESCA.
35*  In the following comments, the character _ should be read as
36*  "of the global array".
37*
38*  NOTATION        STORED IN      EXPLANATION
39*  --------------- -------------- --------------------------------------
40*  DTYPE_A(global) DESCA( DTYPE_ )The descriptor type.  In this case,
41*                                 DTYPE_A = 1.
42*  CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
43*                                 the BLACS process grid A is distribu-
44*                                 ted over. The context itself is glo-
45*                                 bal, but the handle (the integer
46*                                 value) may vary.
47*  M_A    (global) DESCA( M_ )    The number of rows in the global
48*                                 array A.
49*  N_A    (global) DESCA( N_ )    The number of columns in the global
50*                                 array A.
51*  MB_A   (global) DESCA( MB_ )   The blocking factor used to distribute
52*                                 the rows of the array.
53*  NB_A   (global) DESCA( NB_ )   The blocking factor used to distribute
54*                                 the columns of the array.
55*  RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
56*                                 row of the array A is distributed.
57*  CSRC_A (global) DESCA( CSRC_ ) The process column over which the
58*                                 first column of the array A is
59*                                 distributed.
60*  LLD_A  (local)  DESCA( LLD_ )  The leading dimension of the local
61*                                 array.  LLD_A >= MAX(1,LOCr(M_A)).
62*
63*  Let K be the number of rows or columns of a distributed matrix,
64*  and assume that its process grid has dimension p x q.
65*  LOCr( K ) denotes the number of elements of K that a process
66*  would receive if K were distributed over the p processes of its
67*  process column.
68*  Similarly, LOCc( K ) denotes the number of elements of K that a
69*  process would receive if K were distributed over the q processes of
70*  its process row.
71*  The values of LOCr() and LOCc() may be determined via a call to the
72*  ScaLAPACK tool function, NUMROC:
73*          LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
74*          LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
75*  An upper bound for these quantities may be computed by:
76*          LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
77*          LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
78*
79*  Arguments
80*  =========
81*
82*  N       (global input) INTEGER
83*          The number of rows and columns to be operated on, i.e. the
84*          order of the distributed submatrix sub( A ). N >= 0.
85*
86*  ILO     (global input) INTEGER
87*  IHI     (global input) INTEGER
88*          It is assumed that sub( A ) is already upper triangular in
89*          rows IA:IA+ILO-2 and IA+IHI:IA+N-1 and columns JA:JA+ILO-2
90*          and JA+IHI:JA+N-1. See Further Details. If N > 0,
91*          1 <= ILO <= IHI <= N; otherwise set ILO = 1, IHI = N.
92*
93*  A       (local input/local output) COMPLEX*16 pointer into the
94*          local memory to an array of dimension (LLD_A,LOCc(JA+N-1)).
95*          On entry, this array contains the local pieces of the N-by-N
96*          general distributed matrix sub( A ) to be reduced. On exit,
97*          the upper triangle and the first subdiagonal of sub( A ) are
98*          overwritten with the upper Hessenberg matrix H, and the ele-
99*          ments below the first subdiagonal, with the array TAU, repre-
100*          sent the unitary matrix Q as a product of elementary
101*          reflectors. See Further Details.
102*
103*  IA      (global input) INTEGER
104*          The row index in the global array A indicating the first
105*          row of sub( A ).
106*
107*  JA      (global input) INTEGER
108*          The column index in the global array A indicating the
109*          first column of sub( A ).
110*
111*  DESCA   (global and local input) INTEGER array of dimension DLEN_.
112*          The array descriptor for the distributed matrix A.
113*
114*  TAU     (local output) COMPLEX*16 array, dimension LOCc(JA+N-2)
115*          The scalar factors of the elementary reflectors (see Further
116*          Details). Elements JA:JA+ILO-2 and JA+IHI:JA+N-2 of TAU are
117*          set to zero. TAU is tied to the distributed matrix A.
118*
119*  WORK    (local workspace/local output) COMPLEX*16 array,
120*                                                    dimension (LWORK)
121*          On exit, WORK( 1 ) returns the minimal and optimal LWORK.
122*
123*  LWORK   (local or global input) INTEGER
124*          The dimension of the array WORK.
125*          LWORK is local input and must be at least
126*          LWORK >= NB*NB + NB*MAX( IHIP+1, IHLP+INLQ )
127*
128*          where NB = MB_A = NB_A, IROFFA = MOD( IA-1, NB ),
129*          ICOFFA = MOD( JA-1, NB ), IOFF = MOD( IA+ILO-2, NB ),
130*          IAROW = INDXG2P( IA, NB, MYROW, RSRC_A, NPROW ),
131*          IHIP = NUMROC( IHI+IROFFA, NB, MYROW, IAROW, NPROW ),
132*          ILROW = INDXG2P( IA+ILO-1, NB, MYROW, RSRC_A, NPROW ),
133*          IHLP = NUMROC( IHI-ILO+IOFF+1, NB, MYROW, ILROW, NPROW ),
134*          ILCOL = INDXG2P( JA+ILO-1, NB, MYCOL, CSRC_A, NPCOL ),
135*          INLQ = NUMROC( N-ILO+IOFF+1, NB, MYCOL, ILCOL, NPCOL ),
136*
137*          INDXG2P and NUMROC are ScaLAPACK tool functions;
138*          MYROW, MYCOL, NPROW and NPCOL can be determined by calling
139*          the subroutine BLACS_GRIDINFO.
140*
141*          If LWORK = -1, then LWORK is global input and a workspace
142*          query is assumed; the routine only calculates the minimum
143*          and optimal size for all work arrays. Each of these
144*          values is returned in the first entry of the corresponding
145*          work array, and no error message is issued by PXERBLA.
146*
147*  INFO    (global output) INTEGER
148*          = 0:  successful exit
149*          < 0:  If the i-th argument is an array and the j-entry had
150*                an illegal value, then INFO = -(i*100+j), if the i-th
151*                argument is a scalar and had an illegal value, then
152*                INFO = -i.
153*
154*  Further Details
155*  ===============
156*
157*  The matrix Q is represented as a product of (ihi-ilo) elementary
158*  reflectors
159*
160*     Q = H(ilo) H(ilo+1) . . . H(ihi-1).
161*
162*  Each H(i) has the form
163*
164*     H(i) = I - tau * v * v'
165*
166*  where tau is a complex scalar, and v is a complex vector with
167*  v(1:I) = 0, v(I+1) = 1 and v(IHI+1:N) = 0; v(I+2:IHI) is stored on
168*  exit in A(IA+ILO+I:IA+IHI-1,JA+ILO+I-2), and tau in TAU(JA+ILO+I-2).
169*
170*  The contents of A(IA:IA+N-1,JA:JA+N-1) are illustrated by the follow-
171*  ing example, with N = 7, ILO = 2 and IHI = 6:
172*
173*  on entry                         on exit
174*
175*  ( a   a   a   a   a   a   a )    (  a   a   h   h   h   h   a )
176*  (     a   a   a   a   a   a )    (      a   h   h   h   h   a )
177*  (     a   a   a   a   a   a )    (      h   h   h   h   h   h )
178*  (     a   a   a   a   a   a )    (      v2  h   h   h   h   h )
179*  (     a   a   a   a   a   a )    (      v2  v3  h   h   h   h )
180*  (     a   a   a   a   a   a )    (      v2  v3  v4  h   h   h )
181*  (                         a )    (                          a )
182*
183*  where a denotes an element of the original matrix sub( A ), H denotes
184*  a modified element of the upper Hessenberg matrix H, and vi denotes
185*  an element of the vector defining H(JA+ILO+I-2).
186*
187*  Alignment requirements
188*  ======================
189*
190*  The distributed submatrix sub( A ) must verify some alignment proper-
191*  ties, namely the following expression should be true:
192*  ( MB_A.EQ.NB_A .AND. IROFFA.EQ.ICOFFA )
193*
194*  =====================================================================
195*
196*     .. Parameters ..
197      INTEGER            BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
198     $                   LLD_, MB_, M_, NB_, N_, RSRC_
199      PARAMETER          ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
200     $                     CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
201     $                     RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
202      COMPLEX*16         ONE, ZERO
203      PARAMETER          ( ONE = ( 1.0D+0, 0.0D+0 ),
204     $                   ZERO = ( 0.0D+0, 0.0D+0 ) )
205*     ..
206*     .. Local Scalars ..
207      LOGICAL            LQUERY
208      CHARACTER          COLCTOP, ROWCTOP
209      INTEGER            I, IACOL, IAROW, IB, ICOFFA, ICTXT, IHIP,
210     $                   IHLP, IIA, IINFO, ILCOL, ILROW, IMCOL, INLQ,
211     $                   IOFF, IPT, IPW, IPY, IROFFA, J, JJ, JJA, JY,
212     $                   K, L, LWMIN, MYCOL, MYROW, NB, NPCOL, NPROW,
213     $                   NQ
214      COMPLEX*16         EI
215*     ..
216*     .. Local Arrays ..
217      INTEGER            DESCY( DLEN_ ), IDUM1( 3 ), IDUM2( 3 )
218*     ..
219*     .. External Subroutines ..
220      EXTERNAL           BLACS_GRIDINFO, CHK1MAT, DESCSET, INFOG1L,
221     $                   INFOG2L, PCHK1MAT, PB_TOPGET, PB_TOPSET,
222     $                   PXERBLA, PZGEMM, PZGEHD2, PZLAHRD, PZLARFB
223*     ..
224*     .. External Functions ..
225      INTEGER            INDXG2P, NUMROC
226      EXTERNAL           INDXG2P, NUMROC
227*     ..
228*     .. Intrinsic Functions ..
229      INTRINSIC          DBLE, DCMPLX, MAX, MIN, MOD
230*     ..
231*     .. Executable Statements ..
232*
233*     Get grid parameters
234*
235      ICTXT = DESCA( CTXT_ )
236      CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
237*
238*     Test the input parameters
239*
240      INFO = 0
241      IF( NPROW.EQ.-1 ) THEN
242         INFO = -(700+CTXT_)
243      ELSE
244         CALL CHK1MAT( N, 1, N, 1, IA, JA, DESCA, 7, INFO )
245         IF( INFO.EQ.0 ) THEN
246            NB = DESCA( NB_ )
247            IROFFA = MOD( IA-1, NB )
248            ICOFFA = MOD( JA-1, NB )
249            CALL INFOG2L( IA, JA, DESCA, NPROW, NPCOL, MYROW, MYCOL,
250     $                    IIA, JJA, IAROW, IACOL )
251            IHIP = NUMROC( IHI+IROFFA, NB, MYROW, IAROW, NPROW )
252            IOFF = MOD( IA+ILO-2, NB )
253            ILROW = INDXG2P( IA+ILO-1, NB, MYROW, DESCA( RSRC_ ),
254     $                       NPROW )
255            IHLP = NUMROC( IHI-ILO+IOFF+1, NB, MYROW, ILROW, NPROW )
256            ILCOL = INDXG2P( JA+ILO-1, NB, MYCOL, DESCA( CSRC_ ),
257     $                       NPCOL )
258            INLQ = NUMROC( N-ILO+IOFF+1, NB, MYCOL, ILCOL, NPCOL )
259            LWMIN = NB*( NB + MAX( IHIP+1, IHLP+INLQ ) )
260*
261            WORK( 1 ) = DCMPLX( DBLE( LWMIN ) )
262            LQUERY = ( LWORK.EQ.-1 )
263            IF( ILO.LT.1 .OR. ILO.GT.MAX( 1, N ) ) THEN
264               INFO = -2
265            ELSE IF( IHI.LT.MIN( ILO, N ) .OR. IHI.GT.N ) THEN
266               INFO = -3
267            ELSE IF( IROFFA.NE.ICOFFA .OR. IROFFA.NE.0 ) THEN
268               INFO = -6
269            ELSE IF( DESCA( MB_ ).NE.DESCA( NB_ ) ) THEN
270               INFO = -(700+NB_)
271            ELSE IF( LWORK.LT.LWMIN .AND. .NOT.LQUERY ) THEN
272               INFO = -10
273            END IF
274         END IF
275         IDUM1( 1 ) = ILO
276         IDUM2( 1 ) = 2
277         IDUM1( 2 ) = IHI
278         IDUM2( 2 ) = 3
279         IF( LWORK.EQ.-1 ) THEN
280            IDUM1( 3 ) = -1
281         ELSE
282            IDUM1( 3 ) = 1
283         END IF
284         IDUM2( 3 ) = 10
285         CALL PCHK1MAT( N, 1, N, 1, IA, JA, DESCA, 7, 3, IDUM1, IDUM2,
286     $                  INFO )
287      END IF
288*
289      IF( INFO.NE.0 ) THEN
290         CALL PXERBLA( ICTXT, 'PZGEHRD', -INFO )
291         RETURN
292      ELSE IF( LQUERY ) THEN
293         RETURN
294      END IF
295*
296*     Set elements JA:JA+ILO-2 and JA+JHI-1:JA+N-2 of TAU to zero.
297*
298      NQ = NUMROC( JA+N-2, NB, MYCOL, DESCA( CSRC_ ), NPCOL )
299      CALL INFOG1L( JA+ILO-2, NB, NPCOL, MYCOL, DESCA( CSRC_ ), JJ,
300     $              IMCOL )
301      DO 10 J = JJA, MIN( JJ, NQ )
302         TAU( J ) = ZERO
303   10 CONTINUE
304*
305      CALL INFOG1L( JA+IHI-1, NB, NPCOL, MYCOL, DESCA( CSRC_ ), JJ,
306     $              IMCOL )
307      DO 20 J = JJ, NQ
308         TAU( J ) = ZERO
309   20 CONTINUE
310*
311*     Quick return if possible
312*
313      IF( IHI-ILO.LE.0 )
314     $   RETURN
315*
316      CALL PB_TOPGET( ICTXT, 'Combine', 'Columnwise', COLCTOP )
317      CALL PB_TOPGET( ICTXT, 'Combine', 'Rowwise',    ROWCTOP )
318      CALL PB_TOPSET( ICTXT, 'Combine', 'Columnwise', '1-tree' )
319      CALL PB_TOPSET( ICTXT, 'Combine', 'Rowwise',    '1-tree' )
320*
321      IPT = 1
322      IPY = IPT + NB * NB
323      IPW = IPY + IHIP * NB
324      CALL DESCSET( DESCY, IHI+IROFFA, NB, NB, NB, IAROW, ILCOL, ICTXT,
325     $              MAX( 1, IHIP ) )
326*
327      K = ILO
328      IB = NB - IOFF
329      JY = IOFF + 1
330*
331*     Loop over remaining block of columns
332*
333      DO 30 L = 1, IHI-ILO+IOFF-NB, NB
334         I = IA + K - 1
335         J = JA + K - 1
336*
337*        Reduce columns j:j+ib-1 to Hessenberg form, returning the
338*        matrices V and T of the block reflector H = I - V*T*V'
339*        which performs the reduction, and also the matrix Y = A*V*T
340*
341         CALL PZLAHRD( IHI, K, IB, A, IA, J, DESCA, TAU, WORK( IPT ),
342     $                 WORK( IPY ), 1, JY, DESCY, WORK( IPW ) )
343*
344*        Apply the block reflector H to A(ia:ia+ihi-1,j+ib:ja+ihi-1)
345*        from the right, computing  A := A - Y * V'.
346*        V(i+ib,ib-1) must be set to 1.
347*
348         CALL PZELSET2( EI, A, I+IB, J+IB-1, DESCA, ONE )
349         CALL PZGEMM( 'No transpose', 'Conjugate transpose', IHI,
350     $                IHI-K-IB+1, IB, -ONE, WORK( IPY ), 1, JY, DESCY,
351     $                A, I+IB, J, DESCA, ONE, A, IA, J+IB, DESCA )
352         CALL PZELSET( A, I+IB, J+IB-1, DESCA, EI )
353*
354*        Apply the block reflector H to A(i+1:ia+ihi-1,j+ib:ja+n-1) from
355*        the left
356*
357         CALL PZLARFB( 'Left', 'Conjugate transpose', 'Forward',
358     $                 'Columnwise', IHI-K, N-K-IB+1, IB, A, I+1, J,
359     $                 DESCA, WORK( IPT ), A, I+1, J+IB, DESCA,
360     $                 WORK( IPY ) )
361*
362         K = K + IB
363         IB = NB
364         JY = 1
365         DESCY( CSRC_ ) = MOD( DESCY( CSRC_ ) + 1, NPCOL )
366*
367   30 CONTINUE
368*
369*     Use unblocked code to reduce the rest of the matrix
370*
371      CALL PZGEHD2( N, K, IHI, A, IA, JA, DESCA, TAU, WORK, LWORK,
372     $              IINFO )
373*
374      CALL PB_TOPSET( ICTXT, 'Combine', 'Columnwise', COLCTOP )
375      CALL PB_TOPSET( ICTXT, 'Combine', 'Rowwise',    ROWCTOP )
376*
377      WORK( 1 ) = DCMPLX( DBLE( LWMIN ) )
378*
379      RETURN
380*
381*     End of PZGEHRD
382*
383      END
384