ScaLAPACK  2.0.2
ScaLAPACK: Scalable Linear Algebra PACKage
pdinvdriver.f
Go to the documentation of this file.
00001       PROGRAM PDINVDRIVER
00002 *
00003 *  -- ScaLAPACK testing driver (version 1.7) --
00004 *     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
00005 *     and University of California, Berkeley.
00006 *     May 1, 1997
00007 *
00008 *  Purpose
00009 *  =======
00010 *
00011 *  PDINVDRIVER is the main test program for the DOUBLE PRECISION
00012 *  SCALAPACK matrix inversion routines.  This test driver computes the
00013 *  inverse of different kind of matrix and tests the results.
00014 *
00015 *  The program must be driven by a short data file. An annotated example
00016 *  of a data file can be obtained by deleting the first 3 characters
00017 *  from the following 14 lines:
00018 *  'ScaLAPACK Matrix Inversion Testing input file'
00019 *  'PVM machine.'
00020 *  'INV.out'                   output file name (if any)
00021 *  6                           device out
00022 *  5                           number of matrix types (next line)
00023 *  'GEN' 'UTR' 'LTR' 'UPD' LPD' GEN, UTR, LTR, UPD, LPD
00024 *  4                           number of problems sizes
00025 *  1000 2000 3000 4000         values of N
00026 *  3                           number of NB's
00027 *  4 30 35                     values of NB
00028 *  2                           number of process grids (ordered P & Q)
00029 *  4 2                         values of P
00030 *  4 4                         values of Q
00031 *  1.0                         threshold
00032 *
00033 *  Internal Parameters
00034 *  ===================
00035 *
00036 *  TOTMEM   INTEGER, default = 2000000
00037 *           TOTMEM is a machine-specific parameter indicating the
00038 *           maximum amount of available memory in bytes.
00039 *           The user should customize TOTMEM to his platform.  Remember
00040 *           to leave room in memory for the operating system, the BLACS
00041 *           buffer, etc.  For example, on a system with 8 MB of memory
00042 *           per process (e.g., one processor on an Intel iPSC/860), the
00043 *           parameters we use are TOTMEM=6200000 (leaving 1.8 MB for OS,
00044 *           code, BLACS buffer, etc).  However, for PVM, we usually set
00045 *           TOTMEM = 2000000.  Some experimenting with the maximum value
00046 *           of TOTMEM may be required.
00047 *
00048 *  INTGSZ   INTEGER, default = 4 bytes.
00049 *  DBLESZ   INTEGER, default = 8 bytes.
00050 *           INTGSZ and DBLESZ indicate the length in bytes on the
00051 *           given platform for an integer and a double precision real.
00052 *  MEM      DOUBLE PRECISION array, dimension ( TOTMEM / DBLESZ )
00053 *
00054 *           All arrays used by SCALAPACK routines are allocated from
00055 *           this array and referenced by pointers.  The integer IPA,
00056 *           for example, is a pointer to the starting element of MEM for
00057 *           the matrix A.
00058 *
00059 *  =====================================================================
00060 *
00061 *     .. Parameters ..
00062       INTEGER            BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
00063      $                   LLD_, MB_, M_, NB_, N_, RSRC_
00064       PARAMETER          ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
00065      $                     CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
00066      $                     RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
00067       INTEGER            DBLESZ, INTGSZ, MEMSIZ, NTESTS, TOTMEM
00068       DOUBLE PRECISION   PADVAL, ZERO
00069       PARAMETER          ( DBLESZ = 8, INTGSZ = 4, TOTMEM = 2000000,
00070      $                     MEMSIZ = TOTMEM / DBLESZ, NTESTS = 20,
00071      $                     PADVAL = -9923.0D+0, ZERO = 0.0D+0 )
00072 *     ..
00073 *     .. Local Scalars ..
00074       CHARACTER          UPLO
00075       CHARACTER*3        MTYP
00076       CHARACTER*6        PASSED
00077       CHARACTER*80       OUTFILE
00078       LOGICAL            CHECK
00079       INTEGER            I, IAM, IASEED, ICTXT, IMIDPAD, INFO, IPA,
00080      $                   IPPIV, IPREPAD, IPOSTPAD, IPIW, IPW, ITEMP, J,
00081      $                   K, KTESTS, KPASS, KFAIL, KSKIP, L, LCM, LIPIV,
00082      $                   LIWORK, LWORK, MYCOL, MYROW, N, NB, NGRIDS,
00083      $                   NMAT, NMTYP, NNB, NOUT, NP, NPCOL, NPROCS,
00084      $                   NPROW, NQ, WORKIINV, WORKINV, WORKSIZ
00085       REAL               THRESH
00086       DOUBLE PRECISION   ANORM, FRESID, NOPS, RCOND, TMFLOPS
00087 *     ..
00088 *     .. Local Arrays ..
00089       CHARACTER*3        MATTYP( NTESTS )
00090       INTEGER            DESCA( DLEN_ ), IERR( 1 ), NBVAL( NTESTS ),
00091      $                   NVAL( NTESTS ), PVAL( NTESTS ),
00092      $                   QVAL( NTESTS )
00093       DOUBLE PRECISION   MEM( MEMSIZ ), CTIME( 2 ), WTIME( 2 )
00094 *     ..
00095 *     .. External Subroutines ..
00096       EXTERNAL           BLACS_BARRIER, BLACS_EXIT, BLACS_GET,
00097      $                   BLACS_GRIDEXIT, BLACS_GRIDINFO, BLACS_GRIDINIT,
00098      $                   BLACS_PINFO, DESCINIT, IGSUM2D, PDCHEKPAD,
00099      $                   PDFILLPAD, PDGETRF, PDGETRI,
00100      $                   PDINVCHK, PDINVINFO, PDLASET,
00101      $                   PDMATGEN, PDPOTRF, PDPOTRI,
00102      $                   PDTRTRI, SLBOOT, SLCOMBINE, SLTIMER
00103 *     ..
00104 *     .. External Functions ..
00105       LOGICAL            LSAMEN
00106       INTEGER            ICEIL, ILCM, NUMROC
00107       DOUBLE PRECISION   PDLANGE, PDLANSY, PDLANTR
00108       EXTERNAL           ICEIL, ILCM, LSAMEN, NUMROC, PDLANGE,
00109      $                   PDLANSY, PDLANTR
00110 *     ..
00111 *     .. Intrinsic Functions ..
00112       INTRINSIC          DBLE, MAX, MOD
00113 *     ..
00114 *     .. Data Statements ..
00115       DATA               KTESTS, KPASS, KFAIL, KSKIP /4*0/
00116 *     ..
00117 *     .. Executable Statements ..
00118 *
00119 *     Get starting information
00120 *
00121       CALL BLACS_PINFO( IAM, NPROCS )
00122       IASEED = 100
00123       CALL PDINVINFO( OUTFILE, NOUT, NMTYP, MATTYP, NTESTS, NMAT, NVAL,
00124      $                NTESTS, NNB, NBVAL, NTESTS, NGRIDS, PVAL, NTESTS,
00125      $                QVAL, NTESTS, THRESH, MEM, IAM, NPROCS )
00126       CHECK = ( THRESH.GE.0.0E+0 )
00127 *
00128 *     Loop over the different matrix types
00129 *
00130       DO 40 I = 1, NMTYP
00131 *
00132          MTYP = MATTYP( I )
00133 *
00134 *        Print headings
00135 *
00136          IF( IAM.EQ.0 ) THEN
00137             WRITE( NOUT, FMT = * )
00138             IF( LSAMEN( 3, MTYP, 'GEN' ) ) THEN
00139                WRITE( NOUT, FMT = 9986 )
00140      $                'A is a general matrix.'
00141             ELSE IF( LSAMEN( 3, MTYP, 'UTR' ) ) THEN
00142                WRITE( NOUT, FMT = 9986 )
00143      $               'A is an upper triangular matrix.'
00144             ELSE IF( LSAMEN( 3, MTYP, 'LTR' ) ) THEN
00145                WRITE( NOUT, FMT = 9986 )
00146      $               'A is a lower triangular matrix.'
00147             ELSE IF( LSAMEN( 3, MTYP, 'UPD' ) ) THEN
00148                WRITE( NOUT, FMT = 9986 )
00149      $               'A is a symmetric positive definite matrix.'
00150                WRITE( NOUT, FMT = 9986 )
00151      $               'Only the upper triangular part will be '//
00152      $               'referenced.'
00153             ELSE IF( LSAMEN( 3, MTYP, 'LPD' ) ) THEN
00154                WRITE( NOUT, FMT = 9986 )
00155      $               'A is a symmetric positive definite matrix.'
00156                WRITE( NOUT, FMT = 9986 )
00157      $               'Only the lower triangular part will be '//
00158      $               'referenced.'
00159             END IF
00160             WRITE( NOUT, FMT = * )
00161             WRITE( NOUT, FMT = 9995 )
00162             WRITE( NOUT, FMT = 9994 )
00163             WRITE( NOUT, FMT = * )
00164          END IF
00165 *
00166 *        Loop over different process grids
00167 *
00168          DO 30 J = 1, NGRIDS
00169 *
00170             NPROW = PVAL( J )
00171             NPCOL = QVAL( J )
00172 *
00173 *           Make sure grid information is correct
00174 *
00175             IERR( 1 ) = 0
00176             IF( NPROW.LT.1 ) THEN
00177                IF( IAM.EQ.0 )
00178      $            WRITE( NOUT, FMT = 9999 ) 'GRID', 'nprow', NPROW
00179                IERR( 1 ) = 1
00180             ELSE IF( NPCOL.LT.1 ) THEN
00181                IF( IAM.EQ.0 )
00182      $            WRITE( NOUT, FMT = 9999 ) 'GRID', 'npcol', NPCOL
00183                IERR( 1 ) = 1
00184             ELSE IF( NPROW*NPCOL.GT.NPROCS ) THEN
00185                IF( IAM.EQ.0 )
00186      $            WRITE( NOUT, FMT = 9998 ) NPROW*NPCOL, NPROCS
00187                IERR( 1 ) = 1
00188             END IF
00189 *
00190             IF( IERR( 1 ).GT.0 ) THEN
00191                IF( IAM.EQ.0 )
00192      $            WRITE( NOUT, FMT = 9997 ) 'grid'
00193                KSKIP = KSKIP + 1
00194                GO TO 30
00195             END IF
00196 *
00197 *           Define process grid
00198 *
00199             CALL BLACS_GET( -1, 0, ICTXT )
00200             CALL BLACS_GRIDINIT( ICTXT, 'Row-major', NPROW, NPCOL )
00201             CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
00202 *
00203 *           Go to bottom of loop if this case doesn't use my process
00204 *
00205             IF( MYROW.GE.NPROW .OR. MYCOL.GE.NPCOL )
00206      $         GO TO 30
00207 *
00208             DO 20 K = 1, NMAT
00209 *
00210                N = NVAL( K )
00211 *
00212 *              Make sure matrix information is correct
00213 *
00214                IERR( 1 ) = 0
00215                IF( N.LT.1 ) THEN
00216                   IF( IAM.EQ.0 )
00217      $               WRITE( NOUT, FMT = 9999 ) 'MATRIX', 'N', N
00218                   IERR( 1 ) = 1
00219                END IF
00220 *
00221 *              Make sure no one had error
00222 *
00223                CALL IGSUM2D( ICTXT, 'All', ' ', 1, 1, IERR, 1, -1, 0 )
00224 *
00225                IF( IERR( 1 ).GT.0 ) THEN
00226                   IF( IAM.EQ.0 )
00227      $               WRITE( NOUT, FMT = 9997 ) 'matrix'
00228                   KSKIP = KSKIP + 1
00229                   GO TO 20
00230                END IF
00231 *
00232 *              Loop over different blocking sizes
00233 *
00234                DO 10 L = 1, NNB
00235 *
00236                   NB = NBVAL( L )
00237 *
00238 *                 Make sure nb is legal
00239 *
00240                   IERR( 1 ) = 0
00241                   IF( NB.LT.1 ) THEN
00242                      IERR( 1 ) = 1
00243                      IF( IAM.EQ.0 )
00244      $                  WRITE( NOUT, FMT = 9999 ) 'NB', 'NB', NB
00245                   END IF
00246 *
00247 *                 Check all processes for an error
00248 *
00249                   CALL IGSUM2D( ICTXT, 'All', ' ', 1, 1, IERR, 1, -1,
00250      $                          0 )
00251 *
00252                   IF( IERR( 1 ).GT.0 ) THEN
00253                      IF( IAM.EQ.0 )
00254      $                  WRITE( NOUT, FMT = 9997 ) 'NB'
00255                      KSKIP = KSKIP + 1
00256                      GO TO 10
00257                   END IF
00258 *
00259 *                 Padding constants
00260 *
00261                   NP = NUMROC( N, NB, MYROW, 0, NPROW )
00262                   NQ = NUMROC( N, NB, MYCOL, 0, NPCOL )
00263                   IF( CHECK ) THEN
00264                      IPREPAD  = MAX( NB, NP )
00265                      IMIDPAD  = NB
00266                      IPOSTPAD = MAX( NB, NQ )
00267                   ELSE
00268                      IPREPAD  = 0
00269                      IMIDPAD  = 0
00270                      IPOSTPAD = 0
00271                   END IF
00272 *
00273 *                 Initialize the array descriptor for the matrix A
00274 *
00275                   CALL DESCINIT( DESCA, N, N, NB, NB, 0, 0, ICTXT,
00276      $                           MAX( 1, NP ) + IMIDPAD, IERR( 1 ) )
00277 *
00278 *                 Check all processes for an error
00279 *
00280                   CALL IGSUM2D( ICTXT, 'All', ' ', 1, 1, IERR, 1, -1,
00281      $                          0 )
00282 *
00283                   IF( IERR( 1 ).LT.0 ) THEN
00284                      IF( IAM.EQ.0 )
00285      $                  WRITE( NOUT, FMT = 9997 ) 'descriptor'
00286                      KSKIP = KSKIP + 1
00287                      GO TO 10
00288                   END IF
00289 *
00290 *                 Assign pointers into MEM for ScaLAPACK arrays, A is
00291 *                 allocated starting at position MEM( IPREPAD+1 )
00292 *
00293                   IPA = IPREPAD+1
00294 *
00295                   LCM = ILCM( NPROW, NPCOL )
00296                   IF( LSAMEN( 3, MTYP, 'GEN' ) ) THEN
00297 *
00298 *                    Pivots are needed by LU factorization
00299 *
00300                      IPPIV = IPA + DESCA( LLD_ ) * NQ + IPOSTPAD +
00301      $                       IPREPAD
00302                      LIPIV = ICEIL( INTGSZ * ( NP + NB ), DBLESZ )
00303                      IPW = IPPIV + LIPIV + IPOSTPAD + IPREPAD
00304 *
00305                      LWORK = MAX( 1, NP * DESCA( NB_ ) )
00306                      WORKINV = LWORK + IPOSTPAD
00307 *
00308 *                    Figure the amount of workspace required by the
00309 *                    general matrix inversion
00310 *
00311                      IF( NPROW.EQ.NPCOL ) THEN
00312                         LIWORK = NQ + DESCA( NB_ )
00313                      ELSE
00314 *
00315 * change the integer workspace needed for PDGETRI
00316 *                        LIWORK = MAX( DESCA( NB_ ), DESCA( MB_ ) *
00317 *     $                           ICEIL( ICEIL( DESCA( LLD_ ),
00318 *     $                                  DESCA( MB_ ) ), LCM / NPROW ) )
00319 *     $                                  + NQ
00320                          LIWORK = NUMROC( DESCA( M_ ) +
00321      $                  DESCA( MB_ ) * NPROW
00322      $                  + MOD ( 1 - 1, DESCA( MB_ ) ), DESCA ( NB_ ),
00323      $                  MYCOL, DESCA( CSRC_ ), NPCOL ) +
00324      $                  MAX ( DESCA( MB_ ) * ICEIL ( ICEIL(
00325      $                  NUMROC( DESCA( M_ ) + DESCA( MB_ ) * NPROW,
00326      $                  DESCA( MB_ ), MYROW, DESCA( RSRC_ ), NPROW ),
00327      $                  DESCA( MB_ ) ), LCM / NPROW ), DESCA( NB_ ) )
00328 *
00329                      END IF
00330                      WORKIINV = ICEIL( LIWORK*INTGSZ, DBLESZ ) +
00331      $                          IPOSTPAD
00332                      IPIW = IPW + WORKINV + IPREPAD
00333                      WORKSIZ = WORKINV + IPREPAD + WORKIINV
00334 *
00335                   ELSE
00336 *
00337 *                    No pivots or workspace needed for triangular or
00338 *                    symmetric positive definite matrices.
00339 *
00340                      IPW = IPA + DESCA( LLD_ ) * NQ + IPOSTPAD + IPREPAD
00341                      WORKSIZ = 1 + IPOSTPAD
00342 *
00343                   END IF
00344 *
00345                   IF( CHECK ) THEN
00346 *
00347 *                    Figure amount of work space for the norm
00348 *                    computations
00349 *
00350                      IF( LSAMEN( 3, MTYP, 'GEN'       ).OR.
00351      $                   LSAMEN( 2, MTYP( 2:3 ), 'TR' ) ) THEN
00352                         ITEMP = NQ
00353                      ELSE
00354                         ITEMP = 2 * NQ + NP
00355                         IF( NPROW.NE.NPCOL ) THEN
00356                            ITEMP = ITEMP +
00357      $                             NB * ICEIL( ICEIL( NP, NB ),
00358      $                                         LCM / NPROW )
00359                         END IF
00360                      END IF
00361                      WORKSIZ = MAX( WORKSIZ-IPOSTPAD, ITEMP )
00362 *
00363 *                    Figure the amount of workspace required by the
00364 *                    checking routine
00365 *
00366                      WORKSIZ = MAX( WORKSIZ, 2 * NB * MAX( 1, NP ) ) +
00367      $                         IPOSTPAD
00368 *
00369                   END IF
00370 *
00371 *                 Check for adequate memory for problem size
00372 *
00373                   IERR( 1 ) = 0
00374                   IF( IPW+WORKSIZ.GT.MEMSIZ ) THEN
00375                      IF( IAM.EQ.0 )
00376      $                  WRITE( NOUT, FMT = 9996 ) 'inversion',
00377      $                         ( IPW + WORKSIZ ) * DBLESZ
00378                      IERR( 1 ) = 1
00379                   END IF
00380 *
00381 *                 Check all processes for an error
00382 *
00383                   CALL IGSUM2D( ICTXT, 'All', ' ', 1, 1, IERR, 1, -1,
00384      $                          0 )
00385 *
00386                   IF( IERR( 1 ).GT.0 ) THEN
00387                      IF( IAM.EQ.0 )
00388      $                  WRITE( NOUT, FMT = 9997 ) 'MEMORY'
00389                      KSKIP = KSKIP + 1
00390                      GO TO 10
00391                   END IF
00392 *
00393                   IF( LSAMEN( 3, MTYP, 'GEN'       ).OR.
00394      $                LSAMEN( 2, MTYP( 2:3 ), 'TR' ) ) THEN
00395 *
00396 *                    Generate a general diagonally dominant matrix A
00397 *
00398                      CALL PDMATGEN( ICTXT, 'N', 'D', DESCA( M_ ),
00399      $                              DESCA( N_ ), DESCA( MB_ ),
00400      $                              DESCA( NB_ ), MEM( IPA ),
00401      $                              DESCA( LLD_ ), DESCA( RSRC_ ),
00402      $                              DESCA( CSRC_ ), IASEED, 0, NP, 0,
00403      $                              NQ, MYROW, MYCOL, NPROW, NPCOL )
00404 *
00405                   ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'PD' ) ) THEN
00406 *
00407 *                    Generate a symmetric positive definite matrix
00408 *
00409                      CALL PDMATGEN( ICTXT, 'S', 'D', DESCA( M_ ),
00410      $                              DESCA( N_ ), DESCA( MB_ ),
00411      $                              DESCA( NB_ ), MEM( IPA ),
00412      $                              DESCA( LLD_ ), DESCA( RSRC_ ),
00413      $                              DESCA( CSRC_ ), IASEED, 0, NP, 0,
00414      $                              NQ, MYROW, MYCOL, NPROW, NPCOL )
00415 *
00416                   END IF
00417 *
00418 *                 Zeros not-referenced part of A, if any.
00419 *
00420                   IF( LSAMEN( 1, MTYP, 'U' ) ) THEN
00421 *
00422                      UPLO = 'U'
00423                      CALL PDLASET( 'Lower', N-1, N-1, ZERO, ZERO,
00424      $                             MEM( IPA ), 2, 1, DESCA )
00425 *
00426                   ELSE IF( LSAMEN( 1, MTYP, 'L' ) ) THEN
00427 *
00428                      UPLO = 'L'
00429                      CALL PDLASET( 'Upper', N-1, N-1, ZERO, ZERO,
00430      $                             MEM( IPA ), 1, 2, DESCA )
00431 *
00432                   ELSE
00433 *
00434                      UPLO = 'G'
00435 *
00436                   END IF
00437 *
00438 *                 Need 1-norm of A for checking
00439 *
00440                   IF( CHECK ) THEN
00441 *
00442                      CALL PDFILLPAD( ICTXT, NP, NQ, MEM( IPA-IPREPAD ),
00443      $                               DESCA( LLD_ ), IPREPAD, IPOSTPAD,
00444      $                               PADVAL )
00445                      CALL PDFILLPAD( ICTXT, WORKSIZ-IPOSTPAD, 1,
00446      $                               MEM( IPW-IPREPAD ),
00447      $                               WORKSIZ-IPOSTPAD, IPREPAD,
00448      $                               IPOSTPAD, PADVAL )
00449 *
00450                      IF( LSAMEN( 3, MTYP, 'GEN' ) ) THEN
00451 *
00452                         CALL PDFILLPAD( ICTXT, LIPIV, 1,
00453      $                                 MEM( IPPIV-IPREPAD ), LIPIV,
00454      $                                 IPREPAD, IPOSTPAD, PADVAL )
00455                         ANORM = PDLANGE( '1', N, N, MEM( IPA ), 1, 1,
00456      $                                   DESCA, MEM( IPW ) )
00457                         CALL PDCHEKPAD( ICTXT, 'PDLANGE', NP, NQ,
00458      $                                  MEM( IPA-IPREPAD ),
00459      $                                  DESCA( LLD_ ),
00460      $                                  IPREPAD, IPOSTPAD, PADVAL )
00461                         CALL PDCHEKPAD( ICTXT, 'PDLANGE',
00462      $                                  WORKSIZ-IPOSTPAD, 1,
00463      $                                  MEM( IPW-IPREPAD ),
00464      $                                  WORKSIZ-IPOSTPAD,
00465      $                                  IPREPAD, IPOSTPAD, PADVAL )
00466                         CALL PDFILLPAD( ICTXT, WORKINV-IPOSTPAD, 1,
00467      $                                  MEM( IPW-IPREPAD ),
00468      $                                  WORKINV-IPOSTPAD,
00469      $                                  IPREPAD, IPOSTPAD, PADVAL )
00470                         CALL PDFILLPAD( ICTXT, WORKIINV-IPOSTPAD, 1,
00471      $                                 MEM( IPIW-IPREPAD ),
00472      $                                 WORKIINV-IPOSTPAD, IPREPAD,
00473      $                                 IPOSTPAD, PADVAL )
00474                      ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'TR' ) ) THEN
00475 *
00476                         ANORM = PDLANTR( '1', UPLO, 'Non unit', N, N,
00477      $                                   MEM( IPA ), 1, 1, DESCA,
00478      $                                   MEM( IPW ) )
00479                         CALL PDCHEKPAD( ICTXT, 'PDLANTR', NP, NQ,
00480      $                                  MEM( IPA-IPREPAD ),
00481      $                                  DESCA( LLD_ ),
00482      $                                  IPREPAD, IPOSTPAD, PADVAL )
00483                         CALL PDCHEKPAD( ICTXT, 'PDLANTR',
00484      $                                  WORKSIZ-IPOSTPAD, 1,
00485      $                                  MEM( IPW-IPREPAD ),
00486      $                                  WORKSIZ-IPOSTPAD,
00487      $                                  IPREPAD, IPOSTPAD, PADVAL )
00488 *
00489                      ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'PD' ) ) THEN
00490 *
00491                         ANORM = PDLANSY( '1', UPLO, N, MEM( IPA ), 1, 1,
00492      $                                   DESCA, MEM( IPW ) )
00493                         CALL PDCHEKPAD( ICTXT, 'PDLANSY', NP, NQ,
00494      $                                  MEM( IPA-IPREPAD ),
00495      $                                  DESCA( LLD_ ),
00496      $                                  IPREPAD, IPOSTPAD, PADVAL )
00497                         CALL PDCHEKPAD( ICTXT, 'PDLANSY',
00498      $                                  WORKSIZ-IPOSTPAD, 1,
00499      $                                  MEM( IPW-IPREPAD ),
00500      $                                  WORKSIZ-IPOSTPAD,
00501      $                                  IPREPAD, IPOSTPAD, PADVAL )
00502 *
00503                      ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'SY' ) ) THEN
00504 *
00505                         CALL PDFILLPAD( ICTXT, LIPIV, 1,
00506      $                                  MEM( IPPIV-IPREPAD ), LIPIV,
00507      $                                  IPREPAD, IPOSTPAD, PADVAL )
00508                         ANORM = PDLANSY( '1', UPLO, N, MEM( IPA ), 1, 1,
00509      $                                   DESCA, MEM( IPW ) )
00510                         CALL PDCHEKPAD( ICTXT, 'PDLANSY', NP, NQ,
00511      $                                  MEM( IPA-IPREPAD ),
00512      $                                  DESCA( LLD_ ),
00513      $                                  IPREPAD, IPOSTPAD, PADVAL )
00514                         CALL PDCHEKPAD( ICTXT, 'PDLANSY',
00515      $                                  WORKSIZ-IPOSTPAD, 1,
00516      $                                  MEM( IPW-IPREPAD ),
00517      $                                  WORKSIZ-IPOSTPAD,
00518      $                                  IPREPAD,IPOSTPAD, PADVAL )
00519 *
00520                      END IF
00521 *
00522                   END IF
00523 *
00524                   CALL SLBOOT()
00525                   CALL BLACS_BARRIER( ICTXT, 'All' )
00526 *
00527                   IF( LSAMEN( 3, MTYP, 'GEN' ) ) THEN
00528 *
00529 *                    Perform LU factorization
00530 *
00531                      CALL SLTIMER( 1 )
00532                      CALL PDGETRF( N, N, MEM( IPA ), 1, 1, DESCA,
00533      $                             MEM( IPPIV ), INFO )
00534                      CALL SLTIMER( 1 )
00535 *
00536                      IF( CHECK ) THEN
00537 *
00538 *                       Check for memory overwrite
00539 *
00540                         CALL PDCHEKPAD( ICTXT, 'PDGETRF', NP, NQ,
00541      $                                  MEM( IPA-IPREPAD ),
00542      $                                  DESCA( LLD_ ),
00543      $                                  IPREPAD, IPOSTPAD, PADVAL )
00544                         CALL PDCHEKPAD( ICTXT, 'PDGETRF', LIPIV, 1,
00545      $                                  MEM( IPPIV-IPREPAD ), LIPIV,
00546      $                                  IPREPAD, IPOSTPAD, PADVAL )
00547                      END IF
00548 *
00549 *                    Perform the general matrix inversion
00550 *
00551                      CALL SLTIMER( 2 )
00552                      CALL PDGETRI( N, MEM( IPA ), 1, 1, DESCA,
00553      $                             MEM( IPPIV ), MEM( IPW ), LWORK,
00554      $                             MEM( IPIW ), LIWORK, INFO )
00555                      CALL SLTIMER( 2 )
00556 *
00557                      IF( CHECK ) THEN
00558 *
00559 *                       Check for memory overwrite
00560 *
00561                         CALL PDCHEKPAD( ICTXT, 'PDGETRI', NP, NQ,
00562      $                                  MEM( IPA-IPREPAD ),
00563      $                                  DESCA( LLD_ ),
00564      $                                  IPREPAD, IPOSTPAD, PADVAL )
00565                         CALL PDCHEKPAD( ICTXT, 'PDGETRI', LIPIV, 1,
00566      $                                  MEM( IPPIV-IPREPAD ), LIPIV,
00567      $                                  IPREPAD, IPOSTPAD, PADVAL )
00568                         CALL PDCHEKPAD( ICTXT, 'PDGETRI',
00569      $                                  WORKIINV-IPOSTPAD, 1,
00570      $                                  MEM( IPIW-IPREPAD ),
00571      $                                  WORKIINV-IPOSTPAD,
00572      $                                  IPREPAD, IPOSTPAD, PADVAL )
00573                         CALL PDCHEKPAD( ICTXT, 'PDGETRI',
00574      $                                  WORKINV-IPOSTPAD, 1,
00575      $                                  MEM( IPW-IPREPAD ),
00576      $                                  WORKINV-IPOSTPAD,
00577      $                                  IPREPAD, IPOSTPAD, PADVAL )
00578                      END IF
00579 *
00580                   ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'TR' ) ) THEN
00581 *
00582 *                    Perform the general matrix inversion
00583 *
00584                      CALL SLTIMER( 2 )
00585                      CALL PDTRTRI( UPLO, 'Non unit', N, MEM( IPA ), 1,
00586      $                             1, DESCA, INFO )
00587                      CALL SLTIMER( 2 )
00588 *
00589                      IF( CHECK ) THEN
00590 *
00591 *                       Check for memory overwrite
00592 *
00593                         CALL PDCHEKPAD( ICTXT, 'PDTRTRI', NP, NQ,
00594      $                                  MEM( IPA-IPREPAD ),
00595      $                                  DESCA( LLD_ ),
00596      $                                  IPREPAD, IPOSTPAD, PADVAL )
00597                      END IF
00598 *
00599                   ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'PD' ) ) THEN
00600 *
00601 *                    Perform Cholesky factorization
00602 *
00603                      CALL SLTIMER( 1 )
00604                      CALL PDPOTRF( UPLO, N, MEM( IPA ), 1, 1, DESCA,
00605      $                             INFO )
00606                      CALL SLTIMER( 1 )
00607 *
00608                      IF( CHECK ) THEN
00609 *
00610 *                       Check for memory overwrite
00611 *
00612                         CALL PDCHEKPAD( ICTXT, 'PDPOTRF', NP, NQ,
00613      $                                  MEM( IPA-IPREPAD ),
00614      $                                  DESCA( LLD_ ),
00615      $                                  IPREPAD, IPOSTPAD, PADVAL )
00616                      END IF
00617 *
00618 *                    Perform the symmetric positive definite matrix
00619 *                    inversion
00620 *
00621                      CALL SLTIMER( 2 )
00622                      CALL PDPOTRI( UPLO, N, MEM( IPA ), 1, 1, DESCA,
00623      $                             INFO )
00624                      CALL SLTIMER( 2 )
00625 *
00626                      IF( CHECK ) THEN
00627 *
00628 *                       Check for memory overwrite
00629 *
00630                         CALL PDCHEKPAD( ICTXT, 'PDPOTRI', NP, NQ,
00631      $                                  MEM( IPA-IPREPAD ),
00632      $                                  DESCA( LLD_ ),
00633      $                                  IPREPAD, IPOSTPAD, PADVAL )
00634                      END IF
00635 *
00636                   END IF
00637 *
00638                   IF( CHECK ) THEN
00639 *
00640                      CALL PDFILLPAD( ICTXT, WORKSIZ-IPOSTPAD, 1,
00641      $                               MEM( IPW-IPREPAD ),
00642      $                               WORKSIZ-IPOSTPAD, IPREPAD,
00643      $                               IPOSTPAD, PADVAL )
00644 *
00645 *                    Compute fresid = || inv(A)*A-I ||
00646 *
00647                      CALL PDINVCHK( MTYP, N, MEM( IPA ), 1, 1, DESCA,
00648      $                              IASEED, ANORM, FRESID, RCOND,
00649      $                              MEM( IPW ) )
00650 *
00651 *                    Check for memory overwrite
00652 *
00653                      CALL PDCHEKPAD( ICTXT, 'PDINVCHK', NP, NQ,
00654      $                               MEM( IPA-IPREPAD ),
00655      $                               DESCA( LLD_ ),
00656      $                               IPREPAD, IPOSTPAD, PADVAL )
00657                      CALL PDCHEKPAD( ICTXT, 'PDINVCHK',
00658      $                               WORKSIZ-IPOSTPAD, 1,
00659      $                               MEM( IPW-IPREPAD ),
00660      $                               WORKSIZ-IPOSTPAD, IPREPAD,
00661      $                               IPOSTPAD, PADVAL )
00662 *
00663 *                    Test residual and detect NaN result
00664 *
00665                      IF( FRESID.LE.THRESH .AND. INFO.EQ.0 .AND.
00666      $                   ( (FRESID-FRESID) .EQ. 0.0D+0 ) ) THEN
00667                         KPASS = KPASS + 1
00668                         PASSED = 'PASSED'
00669                      ELSE
00670                         KFAIL = KFAIL + 1
00671                         IF( INFO.GT.0 ) THEN
00672                            PASSED = 'SINGUL'
00673                         ELSE
00674                            PASSED = 'FAILED'
00675                         END IF
00676                      END IF
00677 *
00678                   ELSE
00679 *
00680 *                    Don't perform the checking, only the timing
00681 *                    operation
00682 *
00683                      KPASS = KPASS + 1
00684                      FRESID = FRESID - FRESID
00685                      PASSED = 'BYPASS'
00686 *
00687                   END IF
00688 *
00689 *                 Gather maximum of all CPU and WALL clock timings
00690 *
00691                   CALL SLCOMBINE( ICTXT, 'All', '>', 'W', 2, 1, WTIME )
00692                   CALL SLCOMBINE( ICTXT, 'All', '>', 'C', 2, 1, CTIME )
00693 *
00694 *                 Print results
00695 *
00696                   IF( MYROW.EQ.0 .AND. MYCOL.EQ.0  ) THEN
00697 *
00698                      IF( LSAMEN( 3, MTYP, 'GEN' ) ) THEN
00699 *
00700 *                       2/3 N^3 - 1/2 N^2 flops for LU factorization
00701 *
00702                         NOPS = ( 2.0D+0 / 3.0D+0 )*( DBLE( N )**3 ) -
00703      $                         ( 1.0D+0 / 2.0D+0 )*( DBLE( N )**2 )
00704 *
00705 *                       4/3 N^3 - N^2 flops for inversion
00706 *
00707                         NOPS = NOPS +
00708      $                         ( 4.0D+0 / 3.0D+0 ) * ( DBLE( N )**3 ) -
00709      $                         DBLE( N )**2
00710 *
00711                      ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'TR' ) ) THEN
00712 *
00713 *                       1/3 N^3 + 2/3 N flops for triangular inversion
00714 *
00715                         CTIME(1) = 0.0D+0
00716                         WTIME(1) = 0.0D+0
00717                         NOPS = ( 1.0D+0 / 3.0D+0 ) * ( DBLE( N )**3 ) +
00718      $                         ( 2.0D+0 / 3.0D+0 ) * ( DBLE( N ) )
00719 *
00720                      ELSE IF( LSAMEN( 2, MTYP( 2:3 ), 'PD' ) ) THEN
00721 *
00722 *                       1/3 N^3 + 1/2 N^2 flops for Cholesky
00723 *                       factorization
00724 *
00725                         NOPS = ( 1.0D+0 / 3.0D+0 ) * ( DBLE( N )**3 ) +
00726      $                         ( 1.0D+0 / 2.0D+0 ) * ( DBLE( N )**2 )
00727 *
00728 *                       2/3 N^3  + 1/2 N^2 flops for Cholesky inversion
00729 *
00730                         NOPS = NOPS +
00731      $                         ( 2.0D+0 / 3.0D+0 ) * ( DBLE( N )**3 ) +
00732      $                         ( 1.0D+0 / 2.0D+0 ) * ( DBLE( N )**2 )
00733 *
00734                      END IF
00735 *
00736 *                    Figure total megaflops -- factorization and
00737 *                    inversion, for WALL and CPU time, and print
00738 *                    output.
00739 *
00740 *                    Print WALL time if machine supports it
00741 *
00742                      IF( WTIME( 1 ) + WTIME( 2 ) .GT. 0.0D+0 ) THEN
00743                         TMFLOPS = NOPS /
00744      $                            ( ( WTIME( 1 )+WTIME( 2 ) ) * 1.0D+6 )
00745                      ELSE
00746                         TMFLOPS = 0.0D+0
00747                      END IF
00748 *
00749                      IF( WTIME( 2 ) .GE. 0.0D+0 )
00750      $                  WRITE( NOUT, FMT = 9993 ) 'WALL', N, NB, NPROW,
00751      $                         NPCOL, WTIME( 1 ), WTIME( 2 ), TMFLOPS,
00752      $                         RCOND, FRESID, PASSED
00753 *
00754 *                    Print CPU time if machine supports it
00755 *
00756                      IF( CTIME( 1 ) + CTIME( 2 ) .GT. 0.0D+0 ) THEN
00757                         TMFLOPS = NOPS /
00758      $                            ( ( CTIME( 1 )+CTIME( 2 ) ) * 1.0D+6 )
00759                      ELSE
00760                         TMFLOPS = 0.0D+0
00761                      END IF
00762 *
00763                      IF( CTIME( 2 ) .GE. 0.0D+0 )
00764      $                  WRITE( NOUT, FMT = 9993 ) 'CPU ', N, NB, NPROW,
00765      $                         NPCOL, CTIME( 1 ), CTIME( 2 ), TMFLOPS,
00766      $                         RCOND, FRESID, PASSED
00767                   END IF
00768 *
00769    10          CONTINUE
00770 *
00771    20       CONTINUE
00772 *
00773             CALL BLACS_GRIDEXIT( ICTXT )
00774 *
00775    30    CONTINUE
00776 *
00777    40 CONTINUE
00778 *
00779 *     Print out ending messages and close output file
00780 *
00781       IF( IAM.EQ.0 ) THEN
00782          KTESTS = KPASS + KFAIL + KSKIP
00783          WRITE( NOUT, FMT = * )
00784          WRITE( NOUT, FMT = 9992 ) KTESTS
00785          IF( CHECK ) THEN
00786             WRITE( NOUT, FMT = 9991 ) KPASS
00787             WRITE( NOUT, FMT = 9989 ) KFAIL
00788          ELSE
00789             WRITE( NOUT, FMT = 9990 ) KPASS
00790          END IF
00791          WRITE( NOUT, FMT = 9988 ) KSKIP
00792          WRITE( NOUT, FMT = * )
00793          WRITE( NOUT, FMT = * )
00794          WRITE( NOUT, FMT = 9987 )
00795          IF( NOUT.NE.6 .AND. NOUT.NE.0 )
00796      $      CLOSE ( NOUT )
00797       END IF
00798 *
00799       CALL BLACS_EXIT( 0 )
00800 *
00801  9999 FORMAT( 'ILLEGAL ', A6, ': ', A5, ' = ', I3,
00802      $        '; It should be at least 1' )
00803  9998 FORMAT( 'ILLEGAL GRID: nprow*npcol = ', I4, '. It can be at most',
00804      $        I4 )
00805  9997 FORMAT( 'Bad ', A6, ' parameters: going on to next test case.' )
00806  9996 FORMAT( 'Unable to perform ', A, ': need TOTMEM of at least',
00807      $        I11 )
00808  9995 FORMAT( 'TIME     N  NB     P     Q Fct Time Inv Time ',
00809      $        '     MFLOPS    Cond   Resid  CHECK' )
00810  9994 FORMAT( '---- ----- --- ----- ----- -------- -------- ',
00811      $        '----------- ------- ------- ------' )
00812  9993 FORMAT( A4, 1X, I5, 1X, I3, 1X, I5, 1X, I5, 1X, F8.2, 1X, F8.2,
00813      $        1X, F11.2, 1X, F7.1, 1X, F7.2, 1X, A6 )
00814  9992 FORMAT( 'Finished ', I6, ' tests, with the following results:' )
00815  9991 FORMAT( I5, ' tests completed and passed residual checks.' )
00816  9990 FORMAT( I5, ' tests completed without checking.' )
00817  9989 FORMAT( I5, ' tests completed and failed residual checks.' )
00818  9988 FORMAT( I5, ' tests skipped because of illegal input values.' )
00819  9987 FORMAT( 'END OF TESTS.' )
00820  9986 FORMAT( A )
00821 *
00822       STOP
00823 *
00824 *     End of PDINVDRIVER
00825 *
00826       END