1      DOUBLE PRECISION FUNCTION PZLANSY( NORM, UPLO, N, A, IA, JA,
2     $                                   DESCA, WORK )
3      IMPLICIT NONE
4*
5*  -- ScaLAPACK auxiliary routine (version 1.7) --
6*     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
7*     and University of California, Berkeley.
8*     May 1, 1997
9*
10*     .. Scalar Arguments ..
11      CHARACTER          NORM, UPLO
12      INTEGER            IA, JA, N
13*     ..
14*     .. Array Arguments ..
15      INTEGER            DESCA( * )
16      DOUBLE PRECISION   WORK( * )
17      COMPLEX*16         A( * )
18*     ..
19*
20*  Purpose
21*  =======
22*
23*  PZLANSY  returns the value of the one norm, or the Frobenius norm,
24*  or the infinity norm, or the element of largest absolute value of a
25*  real symmetric distributed matrix sub( A ) = A(IA:IA+N-1,JA:JA+N-1).
26*
27*  PZLANSY returns the value
28*
29*     ( max(abs(A(i,j))),  NORM = 'M' or 'm' with IA <= i <= IA+N-1,
30*     (                                      and  JA <= j <= JA+N-1,
31*     (
32*     ( norm1( sub( A ) ), NORM = '1', 'O' or 'o'
33*     (
34*     ( normI( sub( A ) ), NORM = 'I' or 'i'
35*     (
36*     ( normF( sub( A ) ), NORM = 'F', 'f', 'E' or 'e'
37*
38*  where norm1  denotes the  one norm of a matrix (maximum column sum),
39*  normI denotes the  infinity norm  of a matrix  (maximum row sum) and
40*  normF denotes the  Frobenius norm of a matrix (square root of sum of
41*  squares).  Note that  max(abs(A(i,j)))  is not a  matrix norm.
42*
43*  Notes
44*  =====
45*
46*  Each global data object is described by an associated description
47*  vector.  This vector stores the information required to establish
48*  the mapping between an object element and its corresponding process
49*  and memory location.
50*
51*  Let A be a generic term for any 2D block cyclicly distributed array.
52*  Such a global array has an associated description vector DESCA.
53*  In the following comments, the character _ should be read as
54*  "of the global array".
55*
56*  NOTATION        STORED IN      EXPLANATION
57*  --------------- -------------- --------------------------------------
58*  DTYPE_A(global) DESCA( DTYPE_ )The descriptor type.  In this case,
59*                                 DTYPE_A = 1.
60*  CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
61*                                 the BLACS process grid A is distribu-
62*                                 ted over. The context itself is glo-
63*                                 bal, but the handle (the integer
64*                                 value) may vary.
65*  M_A    (global) DESCA( M_ )    The number of rows in the global
66*                                 array A.
67*  N_A    (global) DESCA( N_ )    The number of columns in the global
68*                                 array A.
69*  MB_A   (global) DESCA( MB_ )   The blocking factor used to distribute
70*                                 the rows of the array.
71*  NB_A   (global) DESCA( NB_ )   The blocking factor used to distribute
72*                                 the columns of the array.
73*  RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
74*                                 row of the array A is distributed.
75*  CSRC_A (global) DESCA( CSRC_ ) The process column over which the
76*                                 first column of the array A is
77*                                 distributed.
78*  LLD_A  (local)  DESCA( LLD_ )  The leading dimension of the local
79*                                 array.  LLD_A >= MAX(1,LOCr(M_A)).
80*
81*  Let K be the number of rows or columns of a distributed matrix,
82*  and assume that its process grid has dimension p x q.
83*  LOCr( K ) denotes the number of elements of K that a process
84*  would receive if K were distributed over the p processes of its
85*  process column.
86*  Similarly, LOCc( K ) denotes the number of elements of K that a
87*  process would receive if K were distributed over the q processes of
88*  its process row.
89*  The values of LOCr() and LOCc() may be determined via a call to the
90*  ScaLAPACK tool function, NUMROC:
91*          LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
92*          LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
93*  An upper bound for these quantities may be computed by:
94*          LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
95*          LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
96*
97*  Arguments
98*  =========
99*
100*  NORM    (global input) CHARACTER
101*          Specifies the value to be returned in PZLANSY as described
102*          above.
103*
104*  UPLO    (global input) CHARACTER
105*          Specifies whether the upper or lower triangular part of the
106*          symmetric matrix sub( A ) is to be referenced.
107*          = 'U':  Upper triangular part of sub( A ) is referenced,
108*          = 'L':  Lower triangular part of sub( A ) is referenced.
109*
110*  N       (global input) INTEGER
111*          The number of rows and columns to be operated on i.e the
112*          number of rows and columns of the distributed submatrix
113*          sub( A ). When N = 0, PZLANSY is set to zero. N >= 0.
114*
115*  A       (local input) COMPLEX*16 pointer into the local memory
116*          to an array of dimension (LLD_A, LOCc(JA+N-1)) containing the
117*          local pieces of the symmetric distributed matrix sub( A ).
118*          If UPLO = 'U', the leading N-by-N upper triangular part of
119*          sub( A ) contains the upper triangular matrix which norm is
120*          to be computed, and the strictly lower triangular part of
121*          this matrix is not referenced.  If UPLO = 'L', the leading
122*          N-by-N lower triangular part of sub( A ) contains the lower
123*          triangular matrix which norm is to be computed, and the
124*          strictly upper triangular part of sub( A ) is not referenced.
125*
126*  IA      (global input) INTEGER
127*          The row index in the global array A indicating the first
128*          row of sub( A ).
129*
130*  JA      (global input) INTEGER
131*          The column index in the global array A indicating the
132*          first column of sub( A ).
133*
134*  DESCA   (global and local input) INTEGER array of dimension DLEN_.
135*          The array descriptor for the distributed matrix A.
136*
137*  WORK    (local workspace) DOUBLE PRECISION array dimension (LWORK)
138*          LWORK >= 0 if NORM = 'M' or 'm' (not referenced),
139*                   2*Nq0+Np0+LDW if NORM = '1', 'O', 'o', 'I' or 'i',
140*                     where LDW is given by:
141*                     IF( NPROW.NE.NPCOL ) THEN
142*                        LDW = MB_A*CEIL(CEIL(Np0/MB_A)/(LCM/NPROW))
143*                     ELSE
144*                        LDW = 0
145*                     END IF
146*                   0 if NORM = 'F', 'f', 'E' or 'e' (not referenced),
147*
148*          where LCM is the least common multiple of NPROW and NPCOL
149*          LCM = ILCM( NPROW, NPCOL ) and CEIL denotes the ceiling
150*          operation (ICEIL).
151*
152*          IROFFA = MOD( IA-1, MB_A ), ICOFFA = MOD( JA-1, NB_A ),
153*          IAROW = INDXG2P( IA, MB_A, MYROW, RSRC_A, NPROW ),
154*          IACOL = INDXG2P( JA, NB_A, MYCOL, CSRC_A, NPCOL ),
155*          Np0 = NUMROC( N+IROFFA, MB_A, MYROW, IAROW, NPROW ),
156*          Nq0 = NUMROC( N+ICOFFA, NB_A, MYCOL, IACOL, NPCOL ),
157*
158*          ICEIL, ILCM, INDXG2P and NUMROC are ScaLAPACK tool functions;
159*          MYROW, MYCOL, NPROW and NPCOL can be determined by calling
160*          the subroutine BLACS_GRIDINFO.
161*
162*  =====================================================================
163*
164*     .. Parameters ..
165      INTEGER            BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
166     $                   LLD_, MB_, M_, NB_, N_, RSRC_
167      PARAMETER          ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
168     $                     CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
169     $                     RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
170      DOUBLE PRECISION   ONE, ZERO
171      PARAMETER          ( ONE = 1.0D+0, ZERO = 0.0D+0 )
172*     ..
173*     .. Local Scalars ..
174      INTEGER            I, IAROW, IACOL, IB, ICOFF, ICTXT, ICURCOL,
175     $                   ICURROW, II, IIA, IN, IROFF, ICSR, ICSR0,
176     $                   IOFFA, IRSC, IRSC0, IRSR, IRSR0, JJ, JJA, K,
177     $                   LDA, LL, MYCOL, MYROW, NP, NPCOL, NPROW, NQ
178      DOUBLE PRECISION   SUM, VALUE
179*     ..
180*     .. Local Arrays ..
181      DOUBLE PRECISION   SSQ( 2 ), COLSSQ( 2 )
182*     ..
183*     .. External Subroutines ..
184      EXTERNAL           BLACS_GRIDINFO, DAXPY, DCOMBSSQ,
185     $                   DGAMX2D, DGSUM2D, DGEBR2D,
186     $                   DGEBS2D,  PDCOL2ROW, PDTREECOMB,
187     $                   ZLASSQ
188*     ..
189*     .. External Functions ..
190      LOGICAL            LSAME
191      INTEGER            ICEIL, IDAMAX, NUMROC
192      EXTERNAL           ICEIL, IDAMAX, LSAME, NUMROC
193*     ..
194*     .. Intrinsic Functions ..
195      INTRINSIC          ABS, MAX, MIN, MOD, SQRT
196*     ..
197*     .. Executable Statements ..
198*
199*     Get grid parameters and local indexes.
200*
201      ICTXT = DESCA( CTXT_ )
202      CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
203      CALL INFOG2L( IA, JA, DESCA, NPROW, NPCOL, MYROW, MYCOL,
204     $              IIA, JJA, IAROW, IACOL )
205*
206      IROFF = MOD( IA-1, DESCA( MB_ ) )
207      ICOFF = MOD( JA-1, DESCA( NB_ ) )
208      NP = NUMROC( N+IROFF, DESCA( MB_ ), MYROW, IAROW, NPROW )
209      NQ = NUMROC( N+ICOFF, DESCA( NB_ ), MYCOL, IACOL, NPCOL )
210      ICSR = 1
211      IRSR = ICSR + NQ
212      IRSC = IRSR + NQ
213      IF( MYROW.EQ.IAROW ) THEN
214         IRSC0 = IRSC + IROFF
215         NP = NP - IROFF
216      ELSE
217         IRSC0 = IRSC
218      END IF
219      IF( MYCOL.EQ.IACOL ) THEN
220         ICSR0 = ICSR + ICOFF
221         IRSR0 = IRSR + ICOFF
222         NQ = NQ - ICOFF
223      ELSE
224         ICSR0 = ICSR
225         IRSR0 = IRSR
226      END IF
227      IN = MIN( ICEIL( IA, DESCA( MB_ ) ) * DESCA( MB_ ), IA+N-1 )
228      LDA = DESCA( LLD_ )
229*
230*     If the matrix is symmetric, we address only a triangular portion
231*     of the matrix.  A sum of row (column) i of the complete matrix
232*     can be obtained by adding along row i and column i of the the
233*     triangular matrix, stopping/starting at the diagonal, which is
234*     the point of reflection.  The pictures below demonstrate this.
235*     In the following code, the row sums created by --- rows below are
236*     refered to as ROWSUMS, and the column sums shown by | are refered
237*     to as COLSUMS. Infinity-norm = 1-norm = ROWSUMS+COLSUMS.
238*
239*      UPLO = 'U'                        UPLO = 'L'
240*      ____i______                       ___________
241*     |\   |      |                     |\          |
242*     | \  |      |                     | \         |
243*     |  \ |      |                     |  \        |
244*     |   \|------| i                  i|---\       |
245*     |    \      |                     |   |\      |
246*     |     \     |                     |   | \     |
247*     |      \    |                     |   |  \    |
248*     |       \   |                     |   |   \   |
249*     |        \  |                     |   |    \  |
250*     |         \ |                     |   |     \ |
251*     |__________\|                     |___|______\|
252*                                           i
253*
254*     II, JJ  : local indices into array A
255*     ICURROW : process row containing diagonal block
256*     ICURCOL : process column containing diagonal block
257*     IRSC0   : pointer to part of work used to store the ROWSUMS while
258*               they are stored along a process column
259*     IRSR0   : pointer to part of work used to store the ROWSUMS after
260*               they have been transposed to be along a process row
261*
262      II = IIA
263      JJ = JJA
264*
265      IF( N.EQ.0 ) THEN
266*
267         VALUE = ZERO
268*
269************************************************************************
270* max norm
271*
272      ELSE IF( LSAME( NORM, 'M' ) ) THEN
273*
274*        Find max(abs(A(i,j))).
275*
276         VALUE = ZERO
277*
278         IF( LSAME( UPLO, 'U' ) ) THEN
279*
280*           Handle first block separately
281*
282            IB = IN-IA+1
283*
284*           Find COLMAXS
285*
286            IF( MYCOL.EQ.IACOL ) THEN
287               DO 20 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
288                  IF( II.GT.IIA ) THEN
289                     DO 10 LL = IIA, II-1
290                        VALUE = MAX( VALUE, ABS( A( LL+K ) ) )
291   10                CONTINUE
292                  END IF
293                  IF( MYROW.EQ.IAROW )
294     $               II = II + 1
295   20          CONTINUE
296*
297*              Reset local indices so we can find ROWMAXS
298*
299               IF( MYROW.EQ.IAROW )
300     $            II = II - IB
301*
302            END IF
303*
304*           Find ROWMAXS
305*
306            IF( MYROW.EQ.IAROW ) THEN
307               DO 40 K = II, II+IB-1
308                  IF( JJ.LE.JJA+NQ-1 ) THEN
309                     DO 30 LL = (JJ-1)*LDA, (JJA+NQ-2)*LDA, LDA
310                        VALUE = MAX( VALUE, ABS( A( K+LL ) ) )
311   30                CONTINUE
312                  END IF
313                  IF( MYCOL.EQ.IACOL )
314     $               JJ = JJ + 1
315   40          CONTINUE
316               II = II + IB
317            ELSE IF( MYCOL.EQ.IACOL ) THEN
318               JJ = JJ + IB
319            END IF
320*
321            ICURROW = MOD( IAROW+1, NPROW )
322            ICURCOL = MOD( IACOL+1, NPCOL )
323*
324*           Loop over the remaining rows/columns of the matrix.
325*
326            DO 90 I = IN+1, IA+N-1, DESCA( MB_ )
327               IB = MIN( DESCA( MB_ ), IA+N-I )
328*
329*              Find COLMAXS
330*
331               IF( MYCOL.EQ.ICURCOL ) THEN
332                  DO 60 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
333                     IF( II.GT.IIA ) THEN
334                        DO 50 LL = IIA, II-1
335                           VALUE = MAX( VALUE, ABS( A( LL+K ) ) )
336   50                   CONTINUE
337                     END IF
338                     IF( MYROW.EQ.ICURROW )
339     $                  II = II + 1
340   60             CONTINUE
341*
342*                 Reset local indices so we can find ROWMAXS
343*
344                  IF( MYROW.EQ.ICURROW )
345     $               II = II - IB
346               END IF
347*
348*              Find ROWMAXS
349*
350               IF( MYROW.EQ.ICURROW ) THEN
351                  DO 80 K = II, II+IB-1
352                     IF( JJ.LE.JJA+NQ-1 ) THEN
353                        DO 70 LL = (JJ-1)*LDA, (JJA+NQ-2)*LDA, LDA
354                           VALUE = MAX( VALUE, ABS( A( K+LL ) ) )
355   70                   CONTINUE
356                     END IF
357                     IF( MYCOL.EQ.ICURCOL )
358     $                  JJ = JJ + 1
359   80             CONTINUE
360                  II = II + IB
361               ELSE IF( MYCOL.EQ.ICURCOL ) THEN
362                  JJ = JJ + IB
363               END IF
364               ICURROW = MOD( ICURROW+1, NPROW )
365               ICURCOL = MOD( ICURCOL+1, NPCOL )
366   90       CONTINUE
367*
368         ELSE
369*
370*           Handle first block separately
371*
372            IB = IN-IA+1
373*
374*           Find COLMAXS
375*
376            IF( MYCOL.EQ.IACOL ) THEN
377               DO 110 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
378                  IF( II.LE.IIA+NP-1 ) THEN
379                     DO 100 LL = II, IIA+NP-1
380                        VALUE = MAX( VALUE, ABS( A( LL+K ) ) )
381  100                CONTINUE
382                  END IF
383                  IF( MYROW.EQ.IAROW )
384     $               II = II + 1
385  110          CONTINUE
386*
387*              Reset local indices so we can find ROWMAXS
388*
389               IF( MYROW.EQ.IAROW )
390     $            II = II - IB
391            END IF
392*
393*           Find ROWMAXS
394*
395            IF( MYROW.EQ.IAROW ) THEN
396               DO 130 K = 0, IB-1
397                  IF( JJ.GT.JJA ) THEN
398                     DO 120 LL = (JJA-1)*LDA, (JJ-2)*LDA, LDA
399                        VALUE = MAX( VALUE, ABS( A( II+LL ) ) )
400  120                CONTINUE
401                  END IF
402                  II = II + 1
403                  IF( MYCOL.EQ.IACOL )
404     $               JJ = JJ + 1
405  130          CONTINUE
406            ELSE IF( MYCOL.EQ.IACOL ) THEN
407               JJ = JJ + IB
408            END IF
409*
410            ICURROW = MOD( IAROW+1, NPROW )
411            ICURCOL = MOD( IACOL+1, NPCOL )
412*
413*           Loop over rows/columns of global matrix.
414*
415            DO 180 I = IN+1, IA+N-1, DESCA( MB_ )
416               IB = MIN( DESCA( MB_ ), IA+N-I )
417*
418*              Find COLMAXS
419*
420               IF( MYCOL.EQ.ICURCOL ) THEN
421                  DO 150 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
422                     IF( II.LE.IIA+NP-1 ) THEN
423                        DO 140 LL = II, IIA+NP-1
424                           VALUE = MAX( VALUE, ABS( A( LL+K ) ) )
425  140                   CONTINUE
426                     END IF
427                      IF( MYROW.EQ.ICURROW )
428     $                   II = II + 1
429  150             CONTINUE
430*
431*                 Reset local indices so we can find ROWMAXS
432*
433                  IF( MYROW.EQ.ICURROW )
434     $               II = II - IB
435               END IF
436*
437*              Find ROWMAXS
438*
439               IF( MYROW.EQ.ICURROW ) THEN
440                  DO 170 K = 0, IB-1
441                     IF( JJ.GT.JJA ) THEN
442                        DO 160 LL = (JJA-1)*LDA, (JJ-2)*LDA, LDA
443                           VALUE = MAX( VALUE, ABS( A( II+LL ) ) )
444  160                   CONTINUE
445                     END IF
446                     II = II + 1
447                     IF( MYCOL.EQ.ICURCOL )
448     $                  JJ = JJ + 1
449  170             CONTINUE
450               ELSE IF( MYCOL.EQ.ICURCOL ) THEN
451                  JJ = JJ + IB
452               END IF
453               ICURROW = MOD( ICURROW+1, NPROW )
454               ICURCOL = MOD( ICURCOL+1, NPCOL )
455*
456  180       CONTINUE
457*
458         END IF
459*
460*        Gather the result on process (IAROW,IACOL).
461*
462         CALL DGAMX2D( ICTXT, 'All', ' ', 1, 1, VALUE, 1, I, K, -1,
463     $                 IAROW, IACOL )
464*
465************************************************************************
466* one or inf norm
467*
468      ELSE IF( LSAME( NORM, 'I' ) .OR. LSAME( NORM, 'O' ) .OR.
469     $         NORM.EQ.'1' ) THEN
470*
471*        Find normI( sub( A ) ) ( = norm1( sub( A ) ), since sub( A ) is
472*        symmetric).
473*
474         IF( LSAME( UPLO, 'U' ) ) THEN
475*
476*           Handle first block separately
477*
478            IB = IN-IA+1
479*
480*           Find COLSUMS
481*
482            IF( MYCOL.EQ.IACOL ) THEN
483               IOFFA = ( JJ - 1 ) * LDA
484               DO 200 K = 0, IB-1
485                  SUM = ZERO
486                  IF( II.GT.IIA ) THEN
487                     DO 190 LL = IIA, II-1
488                        SUM = SUM + ABS( A( LL+IOFFA ) )
489  190                CONTINUE
490                  END IF
491                  IOFFA = IOFFA + LDA
492                  WORK( JJ+K-JJA+ICSR0 ) = SUM
493                  IF( MYROW.EQ.IAROW )
494     $               II = II + 1
495  200          CONTINUE
496*
497*              Reset local indices so we can find ROWSUMS
498*
499               IF( MYROW.EQ.IAROW )
500     $            II = II - IB
501*
502            END IF
503*
504*           Find ROWSUMS
505*
506            IF( MYROW.EQ.IAROW ) THEN
507               DO 220 K = II, II+IB-1
508                  SUM = ZERO
509                  IF( JJA+NQ.GT.JJ ) THEN
510                     DO 210 LL = (JJ-1)*LDA, (JJA+NQ-2)*LDA, LDA
511                        SUM = SUM + ABS( A( K+LL ) )
512  210                CONTINUE
513                  END IF
514                  WORK( K-IIA+IRSC0 ) = SUM
515                  IF( MYCOL.EQ.IACOL )
516     $               JJ = JJ + 1
517  220          CONTINUE
518               II = II + IB
519            ELSE IF( MYCOL.EQ.IACOL ) THEN
520               JJ = JJ + IB
521            END IF
522*
523            ICURROW = MOD( IAROW+1, NPROW )
524            ICURCOL = MOD( IACOL+1, NPCOL )
525*
526*           Loop over remaining rows/columns of global matrix.
527*
528            DO 270 I = IN+1, IA+N-1, DESCA( MB_ )
529               IB = MIN( DESCA( MB_ ), IA+N-I )
530*
531*              Find COLSUMS
532*
533               IF( MYCOL.EQ.ICURCOL ) THEN
534                  IOFFA = ( JJ - 1 ) * LDA
535                  DO 240 K = 0, IB-1
536                     SUM = ZERO
537                     IF( II.GT.IIA ) THEN
538                        DO 230 LL = IIA, II-1
539                           SUM = SUM + ABS( A( IOFFA+LL ) )
540  230                   CONTINUE
541                     END IF
542                     IOFFA = IOFFA + LDA
543                     WORK( JJ+K-JJA+ICSR0 ) = SUM
544                     IF( MYROW.EQ.ICURROW )
545     $                  II = II + 1
546  240             CONTINUE
547*
548*                 Reset local indices so we can find ROWSUMS
549*
550                  IF( MYROW.EQ.ICURROW )
551     $               II = II - IB
552*
553               END IF
554*
555*              Find ROWSUMS
556*
557               IF( MYROW.EQ.ICURROW ) THEN
558                  DO 260 K = II, II+IB-1
559                     SUM = ZERO
560                     IF( JJA+NQ.GT.JJ ) THEN
561                        DO 250 LL = (JJ-1)*LDA, (JJA+NQ-2)*LDA, LDA
562                           SUM = SUM + ABS( A( K+LL ) )
563  250                   CONTINUE
564                     END IF
565                     WORK( K-IIA+IRSC0 ) = SUM
566                     IF( MYCOL.EQ.ICURCOL )
567     $                  JJ = JJ + 1
568  260             CONTINUE
569                  II = II + IB
570               ELSE IF( MYCOL.EQ.ICURCOL ) THEN
571                  JJ = JJ + IB
572               END IF
573*
574               ICURROW = MOD( ICURROW+1, NPROW )
575               ICURCOL = MOD( ICURCOL+1, NPCOL )
576*
577  270       CONTINUE
578*
579         ELSE
580*
581*           Handle first block separately
582*
583            IB = IN-IA+1
584*
585*           Find COLSUMS
586*
587            IF( MYCOL.EQ.IACOL ) THEN
588               IOFFA = (JJ-1)*LDA
589               DO 290 K = 0, IB-1
590                  SUM = ZERO
591                  IF( IIA+NP.GT.II ) THEN
592                     DO 280 LL = II, IIA+NP-1
593                        SUM = SUM + ABS( A( IOFFA+LL ) )
594  280                CONTINUE
595                  END IF
596                  IOFFA = IOFFA + LDA
597                  WORK( JJ+K-JJA+ICSR0 ) = SUM
598                  IF( MYROW.EQ.IAROW )
599     $               II = II + 1
600  290          CONTINUE
601*
602*              Reset local indices so we can find ROWSUMS
603*
604               IF( MYROW.EQ.IAROW )
605     $            II = II - IB
606*
607            END IF
608*
609*           Find ROWSUMS
610*
611            IF( MYROW.EQ.IAROW ) THEN
612               DO 310 K = II, II+IB-1
613                  SUM = ZERO
614                  IF( JJ.GT.JJA ) THEN
615                     DO 300 LL = (JJA-1)*LDA, (JJ-2)*LDA, LDA
616                        SUM = SUM + ABS( A( K+LL ) )
617  300                CONTINUE
618                  END IF
619                  WORK( K-IIA+IRSC0 ) = SUM
620                  IF( MYCOL.EQ.IACOL )
621     $               JJ = JJ + 1
622  310          CONTINUE
623               II = II + IB
624            ELSE IF( MYCOL.EQ.IACOL ) THEN
625               JJ = JJ + IB
626            END IF
627*
628            ICURROW = MOD( IAROW+1, NPROW )
629            ICURCOL = MOD( IACOL+1, NPCOL )
630*
631*           Loop over rows/columns of global matrix.
632*
633            DO 360 I = IN+1, IA+N-1, DESCA( MB_ )
634               IB = MIN( DESCA( MB_ ), IA+N-I )
635*
636*              Find COLSUMS
637*
638               IF( MYCOL.EQ.ICURCOL ) THEN
639                  IOFFA = ( JJ - 1 ) * LDA
640                  DO 330 K = 0, IB-1
641                     SUM = ZERO
642                     IF( IIA+NP.GT.II ) THEN
643                        DO 320 LL = II, IIA+NP-1
644                           SUM = SUM + ABS( A( LL+IOFFA ) )
645  320                   CONTINUE
646                     END IF
647                     IOFFA = IOFFA + LDA
648                     WORK( JJ+K-JJA+ICSR0 ) = SUM
649                     IF( MYROW.EQ.ICURROW )
650     $                  II = II + 1
651  330             CONTINUE
652*
653*                 Reset local indices so we can find ROWSUMS
654*
655                  IF( MYROW.EQ.ICURROW )
656     $               II = II - IB
657*
658               END IF
659*
660*              Find ROWSUMS
661*
662               IF( MYROW.EQ.ICURROW ) THEN
663                  DO 350 K = II, II+IB-1
664                     SUM = ZERO
665                     IF( JJ.GT.JJA ) THEN
666                        DO 340 LL = (JJA-1)*LDA, (JJ-2)*LDA, LDA
667                           SUM = SUM + ABS( A( K+LL ) )
668  340                   CONTINUE
669                     END IF
670                     WORK(K-IIA+IRSC0) = SUM
671                     IF( MYCOL.EQ.ICURCOL )
672     $                  JJ = JJ + 1
673  350             CONTINUE
674                  II = II + IB
675               ELSE IF( MYCOL.EQ.ICURCOL ) THEN
676                  JJ = JJ + IB
677               END IF
678*
679               ICURROW = MOD( ICURROW+1, NPROW )
680               ICURCOL = MOD( ICURCOL+1, NPCOL )
681*
682  360       CONTINUE
683         END IF
684*
685*        After calls to DGSUM2D, process row 0 will have global
686*        COLSUMS and process column 0 will have global ROWSUMS.
687*        Transpose ROWSUMS and add to COLSUMS to get global row/column
688*        sum, the max of which is the infinity or 1 norm.
689*
690         IF( MYCOL.EQ.IACOL )
691     $      NQ = NQ + ICOFF
692         CALL DGSUM2D( ICTXT, 'Columnwise', ' ', 1, NQ, WORK( ICSR ), 1,
693     $                 IAROW, MYCOL )
694         IF( MYROW.EQ.IAROW )
695     $      NP = NP + IROFF
696         CALL DGSUM2D( ICTXT, 'Rowwise', ' ', NP, 1, WORK( IRSC ),
697     $                 MAX( 1, NP ), MYROW, IACOL )
698*
699         CALL PDCOL2ROW( ICTXT, N, 1, DESCA( MB_ ), WORK( IRSC ),
700     $                   MAX( 1, NP ), WORK( IRSR ), MAX( 1, NQ ),
701     $                   IAROW, IACOL, IAROW, IACOL, WORK( IRSC+NP ) )
702*
703         IF( MYROW.EQ.IAROW ) THEN
704            IF( MYCOL.EQ.IACOL )
705     $         NQ = NQ - ICOFF
706            CALL DAXPY( NQ, ONE, WORK( IRSR0 ), 1, WORK( ICSR0 ), 1 )
707            IF( NQ.LT.1 ) THEN
708               VALUE = ZERO
709            ELSE
710               VALUE = WORK( IDAMAX( NQ, WORK( ICSR0 ), 1 ) )
711            END IF
712            CALL DGAMX2D( ICTXT, 'Rowwise', ' ', 1, 1, VALUE, 1, I, K,
713     $                    -1, IAROW, IACOL )
714         END IF
715*
716************************************************************************
717* Frobenius norm
718* SSQ(1) is scale
719* SSQ(2) is sum-of-squares
720*
721      ELSE IF( LSAME( NORM, 'F' ) .OR. LSAME( NORM, 'E' ) ) THEN
722*
723*        Find normF( sub( A ) ).
724*
725         SSQ(1) = ZERO
726         SSQ(2) = ONE
727*
728*        Add off-diagonal entries, first
729*
730         IF( LSAME( UPLO, 'U' ) ) THEN
731*
732*           Handle first block separately
733*
734            IB = IN-IA+1
735*
736            IF( MYCOL.EQ.IACOL ) THEN
737               DO 370 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
738                  COLSSQ(1) = ZERO
739                  COLSSQ(2) = ONE
740                  CALL ZLASSQ( II-IIA, A( IIA+K ), 1,
741     $                         COLSSQ(1), COLSSQ(2) )
742                  IF( MYROW.EQ.IAROW )
743     $               II = II + 1
744                  CALL ZLASSQ( II-IIA, A( IIA+K ), 1,
745     $                         COLSSQ(1), COLSSQ(2) )
746                  CALL DCOMBSSQ( SSQ, COLSSQ )
747  370          CONTINUE
748*
749               JJ = JJ + IB
750            ELSE IF( MYROW.EQ.IAROW ) THEN
751               II = II + IB
752            END IF
753*
754            ICURROW = MOD( IAROW+1, NPROW )
755            ICURCOL = MOD( IACOL+1, NPCOL )
756*
757*           Loop over rows/columns of global matrix.
758*
759            DO 390 I = IN+1, IA+N-1, DESCA( MB_ )
760               IB = MIN( DESCA( MB_ ), IA+N-I )
761*
762               IF( MYCOL.EQ.ICURCOL ) THEN
763                  DO 380 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
764                     COLSSQ(1) = ZERO
765                     COLSSQ(2) = ONE
766                     CALL ZLASSQ( II-IIA, A( IIA+K ), 1,
767     $                            COLSSQ(1), COLSSQ(2) )
768                     IF( MYROW.EQ.ICURROW )
769     $                  II = II + 1
770                     CALL ZLASSQ( II-IIA, A (IIA+K ), 1,
771     $                            COLSSQ(1), COLSSQ(2) )
772                     CALL DCOMBSSQ( SSQ, COLSSQ )
773  380             CONTINUE
774*
775                  JJ = JJ + IB
776               ELSE IF( MYROW.EQ.ICURROW ) THEN
777                  II = II + IB
778               END IF
779*
780               ICURROW = MOD( ICURROW+1, NPROW )
781               ICURCOL = MOD( ICURCOL+1, NPCOL )
782*
783  390       CONTINUE
784*
785         ELSE
786*
787*           Handle first block separately
788*
789            IB = IN-IA+1
790*
791            IF( MYCOL.EQ.IACOL ) THEN
792               DO 400 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
793                  COLSSQ(1) = ZERO
794                  COLSSQ(2) = ONE
795                  CALL ZLASSQ( IIA+NP-II, A( II+K ), 1,
796     $                         COLSSQ(1), COLSSQ(2) )
797                  IF( MYROW.EQ.IAROW )
798     $               II = II + 1
799                  CALL ZLASSQ( IIA+NP-II, A( II+K ), 1,
800     $                         COLSSQ(1), COLSSQ(2) )
801                  CALL DCOMBSSQ( SSQ, COLSSQ )
802  400          CONTINUE
803*
804               JJ = JJ + IB
805            ELSE IF( MYROW.EQ.IAROW ) THEN
806               II = II + IB
807            END IF
808*
809            ICURROW = MOD( IAROW+1, NPROW )
810            ICURCOL = MOD( IACOL+1, NPCOL )
811*
812*           Loop over rows/columns of global matrix.
813*
814            DO 420 I = IN+1, IA+N-1, DESCA( MB_ )
815               IB = MIN( DESCA( MB_ ), IA+N-I )
816*
817               IF( MYCOL.EQ.ICURCOL ) THEN
818                  DO 410 K = (JJ-1)*LDA, (JJ+IB-2)*LDA, LDA
819                     COLSSQ(1) = ZERO
820                     COLSSQ(2) = ONE
821                     CALL ZLASSQ( IIA+NP-II, A( II+K ), 1,
822     $                            COLSSQ(1), COLSSQ(2) )
823                     IF( MYROW.EQ.ICURROW )
824     $                  II = II + 1
825                     CALL ZLASSQ( IIA+NP-II, A( II+K ), 1,
826     $                            COLSSQ(1), COLSSQ(2) )
827                     CALL DCOMBSSQ( SSQ, COLSSQ )
828  410             CONTINUE
829*
830                  JJ = JJ + IB
831               ELSE IF( MYROW.EQ.ICURROW ) THEN
832                  II = II + IB
833               END IF
834*
835               ICURROW = MOD( ICURROW+1, NPROW )
836               ICURCOL = MOD( ICURCOL+1, NPCOL )
837*
838  420       CONTINUE
839*
840         END IF
841*
842*        Perform the global scaled sum
843*
844         CALL PDTREECOMB( ICTXT, 'All', 2, SSQ, IAROW, IACOL,
845     $                    DCOMBSSQ )
846         VALUE = SSQ( 1 ) * SQRT( SSQ( 2 ) )
847*
848      END IF
849*
850*     Broadcast the result to the other processes
851*
852      IF( MYROW.EQ.IAROW .AND. MYCOL.EQ.IACOL ) THEN
853          CALL DGEBS2D( ICTXT, 'All', ' ', 1, 1, VALUE, 1 )
854      ELSE
855          CALL DGEBR2D( ICTXT, 'All', ' ', 1, 1, VALUE, 1, IAROW,
856     $                  IACOL )
857      END IF
858*
859      PZLANSY = VALUE
860*
861      RETURN
862*
863*     End of PZLANSY
864*
865      END
866