umfpack_report_info.c 21.4 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 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 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
/* ========================================================================== */
/* === UMFPACK_report_info ================================================== */
/* ========================================================================== */

/* -------------------------------------------------------------------------- */
/* UMFPACK Copyright (c) Timothy A. Davis, CISE,                              */
/* Univ. of Florida.  All Rights Reserved.  See ../Doc/License for License.   */
/* web: http://www.cise.ufl.edu/research/sparse/umfpack                       */
/* -------------------------------------------------------------------------- */

/*
    User-callable.  Prints the Info array.  See umfpack_report_info.h for
    details.
*/

#include "umf_internal.h"

#define PRINT_INFO(format,x) \
{ \
    if (SCALAR_IS_NAN (x) || (!SCALAR_IS_LTZERO (x))) \
    { \
	PRINTF ((format, x)) ; \
    } \
}

/* RATIO macro uses a double relop, but ignore NaN case: */
#define RATIO(a,b,c) (((b) == 0) ? (c) : (((double) a)/((double) b)))

/* ========================================================================== */
/* === print_ratio ========================================================== */
/* ========================================================================== */

PRIVATE void print_ratio
(
    char *what,
    char *format,
    double estimate,
    double actual
)
{
    if (estimate < 0 && actual < 0)	/* double relop, but ignore Nan case */
    {
	return ;
    }
    PRINTF (("    %-27s", what)) ;
    if (estimate >= 0)			/* double relop, but ignore Nan case */
    {
	PRINTF ((format, estimate)) ;
    }
    else
    {
	PRINTF (("                    -")) ;
    }
    if (actual >= 0)			/* double relop, but ignore Nan case */
    {
	PRINTF ((format, actual)) ;
    }
    else
    {
	PRINTF (("                    -")) ;
    }
    if (estimate >= 0 && actual >= 0)	/* double relop, but ignore Nan case */
    {
	PRINTF ((" %5.0f%%\n", 100 * RATIO (actual, estimate, 1))) ;
    }
    else
    {
	PRINTF (("      -\n")) ;
    }
}

/* ========================================================================== */
/* === UMFPACK_report_info ================================================== */
/* ========================================================================== */

GLOBAL void UMFPACK_report_info
(
    const double Control [UMFPACK_CONTROL],
    const double Info [UMFPACK_INFO]
)
{

    double lnz_est, unz_est, lunz_est, lnz, unz, lunz, tsym, tnum, fnum, tsolve,
	fsolve, ttot, ftot, twsym, twnum, twsolve, twtot, n2 ;
    Int n_row, n_col, n_inner, prl, is_sym ;

    /* ---------------------------------------------------------------------- */
    /* get control settings and status to determine what to print */
    /* ---------------------------------------------------------------------- */

    prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;

    if (!Info || prl < 2)
    {
	/* no output generated if Info is (double *) NULL */
	/* or if prl is less than 2 */
	return ;
    }

    /* ---------------------------------------------------------------------- */
    /* print umfpack version */
    /* ---------------------------------------------------------------------- */

    PRINTF  (("UMFPACK V%d.%d.%d (%s), Info:\n", UMFPACK_MAIN_VERSION,
	UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ;

#ifndef NDEBUG
    PRINTF ((
"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
    )) ;
#endif

    /* ---------------------------------------------------------------------- */
    /* print run-time options */
    /* ---------------------------------------------------------------------- */

#ifdef DINT
    PRINTF (("    matrix entry defined as:          double\n")) ;
    PRINTF (("    Int (generic integer) defined as: int\n")) ;
#endif
#ifdef DLONG
    PRINTF (("    matrix entry defined as:          double\n")) ;
    PRINTF (("    Int (generic integer) defined as: UF_long\n")) ;
#endif
#ifdef ZINT
    PRINTF (("    matrix entry defined as:          double complex\n")) ;
    PRINTF (("    Int (generic integer) defined as: int\n")) ;
#endif
#ifdef ZLONG
    PRINTF (("    matrix entry defined as:          double complex\n")) ;
    PRINTF (("    Int (generic integer) defined as: UF_long\n")) ;
#endif

    /* ---------------------------------------------------------------------- */
    /* print compile-time options */
    /* ---------------------------------------------------------------------- */

    PRINTF (("    BLAS library used: ")) ;

#ifdef NBLAS
    PRINTF (("none.  UMFPACK will be slow.\n")) ;
#else
    PRINTF (("Fortran BLAS.  size of BLAS integer: "ID"\n",
	(Int) (sizeof (BLAS_INT)))) ;
#endif

    PRINTF (("    MATLAB:                           ")) ;
#ifdef MATLAB_MEX_FILE
    PRINTF (("yes.\n")) ;
#else
#ifdef MATHWORKS
    PRINTF (("yes.\n")) ;
#else
    PRINTF (("no.\n")) ;
#endif
#endif

    PRINTF (("    CPU timer:                        ")) ;
#ifdef NO_TIMER
    PRINTF (("none.\n")) ;
#else
#ifndef NPOSIX
    PRINTF (("POSIX times ( ) routine.\n")) ;
#else
#ifdef GETRUSAGE
    PRINTF (("getrusage ( ) routine.\n")) ;
#else
    PRINTF (("ANSI clock ( ) routine.\n")) ;
#endif
#endif
#endif

    /* ---------------------------------------------------------------------- */
    /* print n and nz */
    /* ---------------------------------------------------------------------- */

    n_row = (Int) Info [UMFPACK_NROW] ;
    n_col = (Int) Info [UMFPACK_NCOL] ;
    n_inner = MIN (n_row, n_col) ;

    PRINT_INFO ("    number of rows in matrix A:       "ID"\n", n_row) ;
    PRINT_INFO ("    number of columns in matrix A:    "ID"\n", n_col) ;
    PRINT_INFO ("    entries in matrix A:              "ID"\n",
	(Int) Info [UMFPACK_NZ]) ;
    PRINT_INFO ("    memory usage reported in:         "ID"-byte Units\n",
	(Int) Info [UMFPACK_SIZE_OF_UNIT]) ;

    PRINT_INFO ("    size of int:                      "ID" bytes\n",
	(Int) Info [UMFPACK_SIZE_OF_INT]) ;
    PRINT_INFO ("    size of UF_long:                  "ID" bytes\n",
	(Int) Info [UMFPACK_SIZE_OF_LONG]) ;
    PRINT_INFO ("    size of pointer:                  "ID" bytes\n",
	(Int) Info [UMFPACK_SIZE_OF_POINTER]) ;
    PRINT_INFO ("    size of numerical entry:          "ID" bytes\n",
	(Int) Info [UMFPACK_SIZE_OF_ENTRY]) ;

    /* ---------------------------------------------------------------------- */
    /* symbolic parameters */
    /* ---------------------------------------------------------------------- */

    if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_SYMMETRIC)
    {
	PRINTF (("\n    strategy used:                    symmetric\n")) ;
    }
    else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_UNSYMMETRIC)
    {
	PRINTF (("\n    strategy used:                    unsymmetric\n")) ;
    }
    else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_2BY2)
    {
	PRINTF (("\n    strategy used:                    symmetric 2-by-2\n"));
    }

    if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_AMD)
    {
	PRINTF (("    ordering used:                    amd on A+A'\n")) ;
    }
    else if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_COLAMD)
    {
	PRINTF (("    ordering used:                    colamd on A\n")) ;
    }
    else if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_GIVEN)
    {
	PRINTF (("    ordering used:                    provided by user\n")) ;
    }

    if (Info [UMFPACK_QFIXED] == 1)
    {
	PRINTF (("    modify Q during factorization:    no\n")) ;
    }
    else if (Info [UMFPACK_QFIXED] == 0)
    {
	PRINTF (("    modify Q during factorization:    yes\n")) ;
    }

    if (Info [UMFPACK_DIAG_PREFERRED] == 0)
    {
	PRINTF (("    prefer diagonal pivoting:         no\n")) ;
    }
    else if (Info [UMFPACK_DIAG_PREFERRED] == 1)
    {
	PRINTF (("    prefer diagonal pivoting:         yes\n")) ;
    }

    /* ---------------------------------------------------------------------- */
    /* singleton statistics */
    /* ---------------------------------------------------------------------- */

    PRINT_INFO ("    pivots with zero Markowitz cost:               %0.f\n",
	Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS]) ;
    PRINT_INFO ("    submatrix S after removing zero-cost pivots:\n"
		"        number of \"dense\" rows:                    %.0f\n",
	Info [UMFPACK_NDENSE_ROW]) ;
    PRINT_INFO ("        number of \"dense\" columns:                 %.0f\n",
	Info [UMFPACK_NDENSE_COL]) ;
    PRINT_INFO ("        number of empty rows:                      %.0f\n",
	Info [UMFPACK_NEMPTY_ROW]) ;
    PRINT_INFO ("        number of empty columns                    %.0f\n",
	Info [UMFPACK_NEMPTY_COL]) ;
    is_sym = Info [UMFPACK_S_SYMMETRIC] ;
    if (is_sym > 0)
    {
	PRINTF (("        submatrix S square and diagonal preserved\n")) ;
    }
    else if (is_sym == 0)
    {
	PRINTF (("        submatrix S not square or diagonal not preserved\n"));
    }

    /* ---------------------------------------------------------------------- */
    /* statistics from amd_aat */
    /* ---------------------------------------------------------------------- */

    n2 = Info [UMFPACK_N2] ;
    if (n2 >= 0)
    {
	PRINTF (("    pattern of square submatrix S:\n")) ;
    }
    PRINT_INFO ("        number rows and columns                    %.0f\n",
	n2) ;
    PRINT_INFO ("        symmetry of nonzero pattern:               %.6f\n",
	Info [UMFPACK_PATTERN_SYMMETRY]) ;
    PRINT_INFO ("        nz in S+S' (excl. diagonal):               %.0f\n",
	Info [UMFPACK_NZ_A_PLUS_AT]) ;
    PRINT_INFO ("        nz on diagonal of matrix S:                %.0f\n",
	Info [UMFPACK_NZDIAG]) ;
    if (Info [UMFPACK_NZDIAG] >= 0 && n2 > 0)
    {
	PRINTF (("        fraction of nz on diagonal:                %.6f\n",
	Info [UMFPACK_NZDIAG] / n2)) ;
    }

    /* ---------------------------------------------------------------------- */
    /* statistics from 2-by-2 permutation */
    /* ---------------------------------------------------------------------- */

    PRINT_INFO ("    2-by-2 pivoting to place large entries on diagonal:\n"
		"        # of small diagonal entries of S:          %.0f\n",
	Info [UMFPACK_2BY2_NWEAK]) ;
    PRINT_INFO ("        # unmatched:                               %.0f\n",
	Info [UMFPACK_2BY2_UNMATCHED]) ;
    PRINT_INFO ("        symmetry of P2*S:                          %.6f\n",
	Info [UMFPACK_2BY2_PATTERN_SYMMETRY]) ;
    PRINT_INFO ("        nz in P2*S+(P2*S)' (excl. diag.):          %.0f\n",
	Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT]) ;
    PRINT_INFO ("        nz on diagonal of P2*S:                    %.0f\n",
	Info [UMFPACK_2BY2_NZDIAG]) ;
    if (Info [UMFPACK_2BY2_NZDIAG] >= 0 && n2 > 0)
    {
	PRINTF (("        fraction of nz on diag of P2*S:            %.6f\n",
	Info [UMFPACK_2BY2_NZDIAG] / n2)) ;
    }

    /* ---------------------------------------------------------------------- */
    /* statistics from AMD */
    /* ---------------------------------------------------------------------- */

    if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_AMD)
    {
	double dmax = Info [UMFPACK_SYMMETRIC_DMAX] ;
	PRINTF (("    AMD statistics, for strict diagonal pivoting:\n")) ;
	PRINT_INFO ("        est. flops for LU factorization:           %.5e\n",
	    Info [UMFPACK_SYMMETRIC_FLOPS]) ;
	PRINT_INFO ("        est. nz in L+U (incl. diagonal):           %.0f\n",
	    Info [UMFPACK_SYMMETRIC_LUNZ]) ;
	PRINT_INFO ("        est. largest front (# entries):            %.0f\n",
	    dmax*dmax) ;
	PRINT_INFO ("        est. max nz in any column of L:            %.0f\n",
	    dmax) ;
	PRINT_INFO (
	    "        number of \"dense\" rows/columns in S+S':    %.0f\n",
	    Info [UMFPACK_SYMMETRIC_NDENSE]) ;
    }

    /* ---------------------------------------------------------------------- */
    /* symbolic factorization */
    /* ---------------------------------------------------------------------- */

    tsym = Info [UMFPACK_SYMBOLIC_TIME] ;
    twsym = Info [UMFPACK_SYMBOLIC_WALLTIME] ;

    PRINT_INFO ("    symbolic factorization defragmentations:       %.0f\n",
	Info [UMFPACK_SYMBOLIC_DEFRAG]) ;
    PRINT_INFO ("    symbolic memory usage (Units):                 %.0f\n",
	Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]) ;
    PRINT_INFO ("    symbolic memory usage (MBytes):                %.1f\n",
	MBYTES (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY])) ;
    PRINT_INFO ("    Symbolic size (Units):                         %.0f\n",
	Info [UMFPACK_SYMBOLIC_SIZE]) ;
    PRINT_INFO ("    Symbolic size (MBytes):                        %.0f\n",
	MBYTES (Info [UMFPACK_SYMBOLIC_SIZE])) ;
    PRINT_INFO ("    symbolic factorization CPU time (sec):         %.2f\n",
	tsym) ;
    PRINT_INFO ("    symbolic factorization wallclock time(sec):    %.2f\n",
	twsym) ;

    /* ---------------------------------------------------------------------- */
    /* scaling, from numerical factorization */
    /* ---------------------------------------------------------------------- */

    if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_NONE)
    {
	PRINTF (("\n    matrix scaled: no\n")) ;
    }
    else if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_SUM)
    {
	PRINTF (("\n    matrix scaled: yes ")) ;
	PRINTF (("(divided each row by sum of abs values in each row)\n")) ;
	PRINTF (("    minimum sum (abs (rows of A)):              %.5e\n",
	    Info [UMFPACK_RSMIN])) ;
	PRINTF (("    maximum sum (abs (rows of A)):              %.5e\n",
	    Info [UMFPACK_RSMAX])) ;
    }
    else if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_MAX)
    {
	PRINTF (("\n    matrix scaled: yes ")) ;
	PRINTF (("(divided each row by max abs value in each row)\n")) ;
	PRINTF (("    minimum max (abs (rows of A)):              %.5e\n",
	    Info [UMFPACK_RSMIN])) ;
	PRINTF (("    maximum max (abs (rows of A)):              %.5e\n",
	    Info [UMFPACK_RSMAX])) ;
    }

    /* ---------------------------------------------------------------------- */
    /* estimate/actual in symbolic/numeric factorization */
    /* ---------------------------------------------------------------------- */

    /* double relop, but ignore NaN case: */
    if (Info [UMFPACK_SYMBOLIC_DEFRAG] >= 0	/* UMFPACK_*symbolic called */
    ||  Info [UMFPACK_NUMERIC_DEFRAG] >= 0)	/* UMFPACK_numeric called */
    {
	PRINTF (("\n    symbolic/numeric factorization:      upper bound")) ;
	PRINTF (("               actual      %%\n")) ;
	PRINTF (("    variable-sized part of Numeric object:\n")) ;
    }
    print_ratio ("    initial size (Units)", " %20.0f",
	Info [UMFPACK_VARIABLE_INIT_ESTIMATE], Info [UMFPACK_VARIABLE_INIT]) ;
    print_ratio ("    peak size (Units)", " %20.0f",
	Info [UMFPACK_VARIABLE_PEAK_ESTIMATE], Info [UMFPACK_VARIABLE_PEAK]) ;
    print_ratio ("    final size (Units)", " %20.0f",
	Info [UMFPACK_VARIABLE_FINAL_ESTIMATE], Info [UMFPACK_VARIABLE_FINAL]) ;
    print_ratio ("Numeric final size (Units)", " %20.0f",
	Info [UMFPACK_NUMERIC_SIZE_ESTIMATE], Info [UMFPACK_NUMERIC_SIZE]) ;
    print_ratio ("Numeric final size (MBytes)", " %20.1f",
	MBYTES (Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]),
	MBYTES (Info [UMFPACK_NUMERIC_SIZE])) ;
    print_ratio ("peak memory usage (Units)", " %20.0f",
	Info [UMFPACK_PEAK_MEMORY_ESTIMATE], Info [UMFPACK_PEAK_MEMORY]) ;
    print_ratio ("peak memory usage (MBytes)", " %20.1f",
	MBYTES (Info [UMFPACK_PEAK_MEMORY_ESTIMATE]),
	MBYTES (Info [UMFPACK_PEAK_MEMORY])) ;
    print_ratio ("numeric factorization flops", " %20.5e",
	Info [UMFPACK_FLOPS_ESTIMATE], Info [UMFPACK_FLOPS]) ;

    lnz_est = Info [UMFPACK_LNZ_ESTIMATE] ;
    unz_est = Info [UMFPACK_UNZ_ESTIMATE] ;
    if (lnz_est >= 0 && unz_est >= 0)	/* double relop, but ignore NaN case */
    {
	lunz_est = lnz_est + unz_est - n_inner ;
    }
    else
    {
	lunz_est = EMPTY ;
    }
    lnz = Info [UMFPACK_LNZ] ;
    unz = Info [UMFPACK_UNZ] ;
    if (lnz >= 0 && unz >= 0)		/* double relop, but ignore NaN case */
    {
	lunz = lnz + unz - n_inner ;
    }
    else
    {
	lunz = EMPTY ;
    }
    print_ratio ("nz in L (incl diagonal)", " %20.0f", lnz_est, lnz) ;
    print_ratio ("nz in U (incl diagonal)", " %20.0f", unz_est, unz) ;
    print_ratio ("nz in L+U (incl diagonal)", " %20.0f", lunz_est, lunz) ;

    print_ratio ("largest front (# entries)", " %20.0f",
	Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE], Info [UMFPACK_MAX_FRONT_SIZE]) ;
    print_ratio ("largest # rows in front", " %20.0f",
	Info [UMFPACK_MAX_FRONT_NROWS_ESTIMATE],
	Info [UMFPACK_MAX_FRONT_NROWS]) ;
    print_ratio ("largest # columns in front", " %20.0f",
	Info [UMFPACK_MAX_FRONT_NCOLS_ESTIMATE],
	Info [UMFPACK_MAX_FRONT_NCOLS]) ;

    /* ---------------------------------------------------------------------- */
    /* numeric factorization */
    /* ---------------------------------------------------------------------- */

    tnum = Info [UMFPACK_NUMERIC_TIME] ;
    twnum = Info [UMFPACK_NUMERIC_WALLTIME] ;
    fnum = Info [UMFPACK_FLOPS] ;

    PRINT_INFO ("\n    initial allocation ratio used:                 %0.3g\n",
	Info [UMFPACK_ALLOC_INIT_USED]) ;
    PRINT_INFO ("    # of forced updates due to frontal growth:     %.0f\n",
	Info [UMFPACK_FORCED_UPDATES]) ;
    PRINT_INFO ("    number of off-diagonal pivots:                 %.0f\n",
	Info [UMFPACK_NOFF_DIAG]) ;
    PRINT_INFO ("    nz in L (incl diagonal), if none dropped       %.0f\n",
	Info [UMFPACK_ALL_LNZ]) ;
    PRINT_INFO ("    nz in U (incl diagonal), if none dropped       %.0f\n",
	Info [UMFPACK_ALL_UNZ]) ;
    PRINT_INFO ("    number of small entries dropped                %.0f\n",
	Info [UMFPACK_NZDROPPED]) ;
    PRINT_INFO ("    nonzeros on diagonal of U:                     %.0f\n",
	Info [UMFPACK_UDIAG_NZ]) ;
    PRINT_INFO ("    min abs. value on diagonal of U:               %.2e\n",
	Info [UMFPACK_UMIN]) ;
    PRINT_INFO ("    max abs. value on diagonal of U:               %.2e\n",
	Info [UMFPACK_UMAX]) ;
    PRINT_INFO ("    estimate of reciprocal of condition number:    %.2e\n",
	Info [UMFPACK_RCOND]) ;
    PRINT_INFO ("    indices in compressed pattern:                 %.0f\n",
	Info [UMFPACK_COMPRESSED_PATTERN]) ;
    PRINT_INFO ("    numerical values stored in Numeric object:     %.0f\n",
	Info [UMFPACK_LU_ENTRIES]) ;
    PRINT_INFO ("    numeric factorization defragmentations:        %.0f\n",
	Info [UMFPACK_NUMERIC_DEFRAG]) ;
    PRINT_INFO ("    numeric factorization reallocations:           %.0f\n",
	Info [UMFPACK_NUMERIC_REALLOC]) ;
    PRINT_INFO ("    costly numeric factorization reallocations:    %.0f\n",
	Info [UMFPACK_NUMERIC_COSTLY_REALLOC]) ;
    PRINT_INFO ("    numeric factorization CPU time (sec):          %.2f\n",
	tnum) ;
    PRINT_INFO ("    numeric factorization wallclock time (sec):    %.2f\n",
	twnum) ;

#define TMIN 0.001

    if (tnum > TMIN && fnum > 0)
    {
	PRINT_INFO (
	   "    numeric factorization mflops (CPU time):       %.2f\n",
	   1e-6 * fnum / tnum) ;
    }
    if (twnum > TMIN && fnum > 0)
    {
	PRINT_INFO (
	   "    numeric factorization mflops (wallclock):      %.2f\n",
	   1e-6 * fnum / twnum) ;
    }

    ttot = EMPTY ;
    ftot = fnum ;
    if (tsym >= TMIN && tnum >= 0)
    {
	ttot = tsym + tnum ;
	PRINT_INFO ("    symbolic + numeric CPU time (sec):             %.2f\n",
	    ttot) ;
	if (ftot > 0 && ttot > TMIN)
	{
	    PRINT_INFO (
		"    symbolic + numeric mflops (CPU time):          %.2f\n",
		1e-6 * ftot / ttot) ;
	}
    }

    twtot = EMPTY ;
    if (twsym >= TMIN && twnum >= TMIN)
    {
	twtot = twsym + twnum ;
	PRINT_INFO ("    symbolic + numeric wall clock time (sec):      %.2f\n",
	    twtot) ;
	if (ftot > 0 && twtot > TMIN)
	{
	    PRINT_INFO (
		"    symbolic + numeric mflops (wall clock):        %.2f\n",
		1e-6 * ftot / twtot) ;
	}
    }

    /* ---------------------------------------------------------------------- */
    /* solve */
    /* ---------------------------------------------------------------------- */

    tsolve = Info [UMFPACK_SOLVE_TIME] ;
    twsolve = Info [UMFPACK_SOLVE_WALLTIME] ;
    fsolve = Info [UMFPACK_SOLVE_FLOPS] ;

    PRINT_INFO ("\n    solve flops:                                   %.5e\n",
	fsolve) ;
    PRINT_INFO ("    iterative refinement steps taken:              %.0f\n",
	Info [UMFPACK_IR_TAKEN]) ;
    PRINT_INFO ("    iterative refinement steps attempted:          %.0f\n",
	Info [UMFPACK_IR_ATTEMPTED]) ;
    PRINT_INFO ("    sparse backward error omega1:                  %.2e\n",
	Info [UMFPACK_OMEGA1]) ;
    PRINT_INFO ("    sparse backward error omega2:                  %.2e\n",
	Info [UMFPACK_OMEGA2]) ;
    PRINT_INFO ("    solve CPU time (sec):                          %.2f\n",
	tsolve) ;
    PRINT_INFO ("    solve wall clock time (sec):                   %.2f\n",
	twsolve) ;
    if (fsolve > 0 && tsolve > TMIN)
    {
	PRINT_INFO (
	    "    solve mflops (CPU time):                       %.2f\n",
	    1e-6 * fsolve / tsolve) ;
    }
    if (fsolve > 0 && twsolve > TMIN)
    {
	PRINT_INFO (
	    "    solve mflops (wall clock time):                %.2f\n",
	    1e-6 * fsolve / twsolve) ;
    }

    if (ftot >= 0 && fsolve >= 0)
    {
	ftot += fsolve ;
	PRINT_INFO (
	"\n    total symbolic + numeric + solve flops:        %.5e\n", ftot) ;
    }

    if (tsolve >= TMIN)
    {
	if (ttot >= TMIN && ftot >= 0)
	{
	    ttot += tsolve ;
	    PRINT_INFO (
		"    total symbolic + numeric + solve CPU time:     %.2f\n",
		ttot) ;
	    if (ftot > 0 && ttot > TMIN)
	    {
		PRINT_INFO (
		"    total symbolic + numeric + solve mflops (CPU): %.2f\n",
		1e-6 * ftot / ttot) ;
	    }
	}
    }

    if (twsolve >= TMIN)
    {
	if (twtot >= TMIN && ftot >= 0)
	{
	    twtot += tsolve ;
	    PRINT_INFO (
		"    total symbolic+numeric+solve wall clock time:  %.2f\n",
		twtot) ;
	    if (ftot > 0 && twtot > TMIN)
	    {
		PRINT_INFO (
		"    total symbolic+numeric+solve mflops(wallclock) %.2f\n",
		1e-6 * ftot / twtot) ;
	    }
	}
    }
    PRINTF (("\n")) ;
}