The R Project SVN R-packages

Rev

Rev 1824 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/* ========================================================================== */
/* === Check/cholmod_check ================================================== */
/* ========================================================================== */

/* -----------------------------------------------------------------------------
 * CHOLMOD/Check Module.  Version 0.6.
 * Copyright (C) 2005, Timothy A. Davis
 * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU
 * Lesser General Public License.  See lesser.txt for a text of the license.
 * CHOLMOD is also available under other licenses; contact authors for details.
 * http://www.cise.ufl.edu/research/sparse
 * -------------------------------------------------------------------------- */

/* Routines to check and print the contents of the 5 CHOLMOD objects:
 *
 * No CHOLMOD routine calls the check or print routines.  If a user wants to
 * check CHOLMOD's input parameters, a separate call to the appropriate check
 * routine should be used before calling other CHOLMOD routines.
 *
 * cholmod_check_common     check statistics and workspace in Common
 * cholmod_check_sparse     check sparse matrix in compressed column form
 * cholmod_check_dense      check dense matrix
 * cholmod_check_factor     check factorization
 * cholmod_check_triplet    check sparse matrix in triplet form
 *
 * cholmod_print_common     print statistics in Common
 * cholmod_print_sparse     print sparse matrix in compressed column form
 * cholmod_print_dense      print dense matrix
 * cholmod_print_factor     print factorization
 * cholmod_print_triplet    print sparse matrix in triplet form
 *
 * In addition, this file contains routines to check and print three types of
 * integer vectors:
 * 
 * cholmod_check_perm       check a permutation of 0:n-1 (no duplicates)
 * cholmod_check_subset     check a subset of 0:n-1 (duplicates OK)
 * cholmod_check_parent     check an elimination tree
 *
 * cholmod_print_perm       print a permutation
 * cholmod_print_subset     print a subset
 * cholmod_print_parent     print an elimination tree
 *
 * Each Common->print level prints the items at or below the given level:
 *
 *  0: print nothing; just check the data structures and return TRUE/FALSE
 *  1: error messages
 *  2: warning messages
 *  3: one-line summary of each object printed
 *  4: short summary of each object (first and last few entries)
 *  5: entire contents of the object
 *
 * No CHOLMOD routine calls these routines, so no printing occurs unless
 * the user specifically calls a cholmod_print_* routine.  Thus, the default
 * print level is 3.
 *
 * Common->precise controls the # of digits printed for numerical entries
 * (5 if FALSE, 15 if TRUE).
 *
 * If Common->print_function is NULL, then no printing occurs.  The
 * cholmod_check_* and cholmod_print_* routines still check their inputs and
 * return TRUE/FALSE if the object is valid or not.
 *
 * This file also includes debugging routines that are enabled only when
 * NDEBUG is defined in cholmod_internal.h (cholmod_dump_*).
 */

#ifndef NCHECK

#include "cholmod_check.h"
#include "cholmod_internal.h"

/* ========================================================================== */
/* === printing definitions ================================================= */
/* ========================================================================== */

#ifdef LONG
#define I8 "%8ld"
#define I_8 "%-8ld"
#else
#define I8 "%8d"
#define I_8 "%-8d"
#endif

#define PR(i,format,arg) \
{ \
    if (print >= i && Common->print_function != NULL) \
    { \
    /* (Common->print_function) */ printf (format, arg) ; \
    } \
}

#define P1(format,arg) PR(1,format,arg)
#define P2(format,arg) PR(2,format,arg)
#define P3(format,arg) PR(3,format,arg)
#define P4(format,arg) PR(4,format,arg)

#define ERR(msg) \
{ \
    P1 ("\nCHOLMOD ERROR: %s: ", type) ; \
    if (name != NULL) \
    { \
    P1 ("%s", name) ; \
    } \
    P1 (": %s\n", msg) ; \
    ERROR (CHOLMOD_INVALID, "invalid") ; \
    return (FALSE) ; \
}

/* print a numerical value */
#define PRINTVALUE(value) \
{ \
    if (Common->precise) \
    { \
    P4 (" %23.15e", value) ; \
    } \
    else \
    { \
    P4 (" %.5g", value) ; \
    } \
}

/* start printing */
#define ETC_START(count,limit) \
{ \
    count = (init_print == 4) ? (limit) : (-1) ; \
}

/* re-enable printing if condition is met */
#define ETC_ENABLE(condition,count,limit) \
{ \
    if ((condition) && init_print == 4) \
    { \
    count = limit ; \
    print = 4 ; \
    } \
}

/* turn off printing if limit is reached */
#define ETC_DISABLE(count) \
{ \
    if ((count >= 0) && (count-- == 0) && print == 4) \
    { \
    P4 ("%s", "    ...\n")  ; \
    print = 3 ; \
    } \
}

/* re-enable printing, or turn if off after limit is reached */
#define ETC(condition,count,limit) \
{ \
    ETC_ENABLE (condition, count, limit) ; \
    ETC_DISABLE (count) ; \
}

#define BOOLSTR(x) ((x) ? "true " : "false")

/* ========================================================================== */
/* === print_value ========================================================== */
/* ========================================================================== */

static void print_value
(
    Int print,
    Int xtype,
    double *Xx,
    double *Xz,
    Int p,
    cholmod_common *Common)
{
    if (xtype == CHOLMOD_REAL)
    {
    PRINTVALUE (Xx [p]) ;
    }
    else if (xtype == CHOLMOD_COMPLEX)
    {
    P4 ("%s", "(") ;
    PRINTVALUE (Xx [2*p  ]) ;
    P4 ("%s", " , ") ;
    PRINTVALUE (Xx [2*p+1]) ;
    P4 ("%s", ")") ;
    }
    else if (xtype == CHOLMOD_ZOMPLEX)
    {
    P4 ("%s", "(") ;
    PRINTVALUE (Xx [p]) ;
    P4 ("%s", " , ") ;
    PRINTVALUE (Xz [p]) ;
    P4 ("%s", ")") ;
    }
}

/* ========================================================================== */
/* === cholmod_check_common ================================================= */
/* ========================================================================== */

/* Print and verify the contents of Common */

static int check_common
(
    Int print,
    char *name,
    cholmod_common *Common
)
{
    double fl, lnz ;
    double *Xwork ;
    Int *Flag, *Head ;
    long mark ;
    Int i, nrow, nmethods, ordering, xworksize, amd_printed, init_print ;
    char *type = "common" ;

    /* ---------------------------------------------------------------------- */
    /* print control parameters and statistics */
    /* ---------------------------------------------------------------------- */

    RETURN_IF_NULL_COMMON (FALSE) ;
    init_print = print ;

    P2 ("%s", "\n") ;

    P1 ("CHOLMOD version %d", CHOLMOD_MAIN_VERSION) ;
    P1 (".%d", CHOLMOD_SUB_VERSION) ;
    P1 (", %s: ", CHOLMOD_DATE) ;

    if (name != NULL)
    {
    P1 ("%s: ", name) ;
    }
    switch (Common->status)
    {

    case CHOLMOD_OK:
        P1 ("%s", "status: OK\n") ;
        break ;

    case CHOLMOD_OUT_OF_MEMORY:
        P1 ("%s", "status: ERROR, out of memory\n") ;
        break ;

    case CHOLMOD_INVALID:
        P1 ("%s", "status: ERROR, invalid parameter\n") ;
        break ;

    case CHOLMOD_TOO_LARGE:
        P1 ("%s", "status: ERROR, problem too large\n") ;
        break ;

    case CHOLMOD_NOT_INSTALLED:
        P1 ("%s", "status: ERROR, method not installed\n") ;
        break ;

    case CHOLMOD_NOT_POSDEF:
        P1 ("%s", "status: warning, matrix not positive definite\n") ;
        break ;

    case CHOLMOD_DSMALL:
        P1 ("%s", "status: warning, diagonal entry has tiny abs. value\n") ;
        break ;

    default:
        ERR ("unknown status") ;
    }

    P2 ("  Architecture: %s\n", CHOLMOD_ARCHITECTURE) ;
    P3 ("    sizeof(int):      %d\n", (int) sizeof (int)) ;
    P3 ("    sizeof(long):     %d\n", (int) sizeof (long)) ;
    P3 ("    sizeof(void *):   %d\n", (int) sizeof (void *)) ;
    P3 ("    sizeof(double):   %d\n", (int) sizeof (double)) ;
    P3 ("    sizeof(Int):      %d (CHOLMOD's basic integer)\n", (int) sizeof (Int)) ;
    P3 ("    sizeof(BLAS_INT): %d (integer used in the BLAS)\n",
        (int) sizeof (BLAS_INT)) ;

    if (Common->fl != EMPTY)
    {
    P2 ("%s", "  Results from most recent analysis:\n") ;
    P2 ("    Cholesky flop count: %.5g\n", Common->fl) ;
    P2 ("    Nonzeros in L:       %.5g\n", Common->lnz) ;
    }
    if (Common->modfl != EMPTY)
    {
    P2 ("    Update/downdate flop count: %.5g\n", Common->modfl) ;
    }

    P2 ("  memory blocks in use:    %8ld\n", (long) (Common->malloc_count)) ;
    P2 ("  memory in use (MB):      %8.1f\n", 
    (double) (Common->memory_inuse) / 1048576.) ;
    P2 ("  peak memory usage (MB):  %8.1f\n", 
    (double) (Common->memory_usage) / 1048576.) ;

    /* ---------------------------------------------------------------------- */
    /* primary control parameters and related ordering statistics */
    /* ---------------------------------------------------------------------- */

    P3 ("  maxrank:    update/downdate rank:   "ID"\n",
        (Int) CHOLMOD(maxrank) (0, Common)) ;
    P3 ("  supernodal control: %d", Common->supernodal) ;
    P3 (" %g ", Common->supernodal_switch) ;
    if (Common->supernodal <= CHOLMOD_SIMPLICIAL)
    {
    P3 ("%s", "(always do simplicial)\n") ;
    }
    else if (Common->supernodal == CHOLMOD_AUTO)
    {
    P3 ("(supernodal if flops/lnz >= %g)\n", Common->supernodal_switch) ;
    }
    else
    {
    P3 ("%s", "(always do supernodal)\n") ;
    }

    nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ;
    nmethods = MAX (0, nmethods) ;

    if (nmethods > 0)
    {
    P3 ("%s", "  nmethods:   number of ordering methods to try: ") ;
    P3 (""ID"\n", nmethods) ;
    }
    else
    {
    P3 ("%s", "  nmethods=0: default strategy:  Try user permutation if "
        "given.  Try AMD.\n") ;
#ifndef NPARTITION
    P3 ("%s", "    Try METIS if AMD reports flops/nnz(L) >= 500 and "
        "nnz(L)/nnz(A) >= 5.\n") ;
#endif
    P3 ("%s", "    Select best ordering tried.\n") ;
    Common->method [0].ordering = CHOLMOD_GIVEN ;
    Common->method [1].ordering = CHOLMOD_AMD ;
    Common->method [2].ordering = CHOLMOD_METIS ;
#ifndef NPARTITION
    nmethods = 3 ;
#else
    nmethods = 2 ;
#endif
    }

    amd_printed = FALSE ;
    for (i = 0 ; i < nmethods ; i++)
    {
    P3 ("    method "ID": ", i) ;
    ordering = Common->method [i].ordering ;
    fl = Common->method [i].fl ;
    lnz = Common->method [i].lnz ;
    switch (ordering)
    {

        case CHOLMOD_NATURAL:
        P3 ("%s", "natural\n") ;
        break ;

        case CHOLMOD_GIVEN:
        P3 ("%s", "user permutation (if given)\n") ;
        break ;

        case CHOLMOD_AMD:
        P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ;
        amd_printed = TRUE ;
        break ;

        case CHOLMOD_COLAMD:
        P3 ("%s", "AMD if factorizing A, COLAMD if factorizing AA')\n");
        amd_printed = TRUE ;
        break ;

        case CHOLMOD_METIS:
        P3 ("%s", "METIS_NodeND nested dissection\n") ;
        break ;

        case CHOLMOD_NESDIS:
        P3 ("%s", "CHOLMOD nested dissection\n") ;

        P3 ("        nd_small: # nodes in uncut subgraph: "ID"\n",
            (Int) (Common->method [i].nd_small)) ;
        P3 ("        nd_compress: compress the graph:     %s\n",
            BOOLSTR (Common->method [i].nd_compress)) ;
        P3 ("        nd_camd: use constrained min degree: %s\n",
            BOOLSTR (Common->method [i].nd_camd)) ;
        break ;

        default:
        P3 (ID, ordering) ;
        ERR ("unknown ordering method") ;
        break ;

    }

    if (!(ordering == CHOLMOD_NATURAL || ordering == CHOLMOD_GIVEN))
    {
        if (Common->method [i].prune_dense < 0)
        {
        P3 ("        prune_dense: for pruning dense nodes:   %s\n",
            " none pruned") ;
        }
        else
        {
        P3 ("        prune_dense: for pruning dense nodes:   "
            "%.5g\n",
            Common->method [i].prune_dense) ;
        P3 ("        a dense node has degree "
            ">= max(16,(%.5g)*sqrt(n))\n",
            Common->method [i].prune_dense) ;
        }
    }

    if (ordering == CHOLMOD_COLAMD || ordering == CHOLMOD_NESDIS)
    {
        if (Common->method [i].prune_dense2 < 0)
        {
        P3 ("        prune_dense2: for pruning dense rows for AA':"
            "  %s\n", " none pruned") ;
        }
        else
        {
        P3 ("        prune_dense2: for pruning dense rows for AA':"
            " %.5g\n", Common->method [i].prune_dense2) ;
        P3 ("        a dense row has degree "
            ">= max(16,(%.5g)*sqrt(ncol))\n",
            Common->method [i].prune_dense2) ;
        }
    }

    if (fl  != EMPTY) P3 ("        flop count: %.5g\n", fl) ;
    if (lnz != EMPTY) P3 ("        nnz(L):     %.5g\n", lnz) ;
    }

    /* backup AMD results, if any */
    if (!amd_printed)
    {
    P3 ("%s", "    backup method: ") ;
    P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ;
    fl = Common->method [nmethods].fl ;
    lnz = Common->method [nmethods].lnz ;
    if (fl  != EMPTY) P3 ("        AMD flop count: %.5g\n", fl) ;
    if (lnz != EMPTY) P3 ("        AMD nnz(L):     %.5g\n", lnz) ;
    }

    /* ---------------------------------------------------------------------- */
    /* arcane control parameters */
    /* ---------------------------------------------------------------------- */

    if (Common->final_asis)
    {
    P4 ("%s", "  final_asis: TRUE, leave as is\n") ;
    }
    else
    {
    P4 ("%s", "  final_asis: FALSE, convert when done\n") ;
    if (Common->final_super)
    {
        P4 ("%s", "  final_super: TRUE, leave in supernodal form\n") ;
    }
    else
    {
        P4 ("%s", "  final_super: FALSE, convert to simplicial form\n") ;
    }
    if (Common->final_ll)
    {
        P4 ("%s", "  final_ll: TRUE, convert to LL' form\n") ;
    }
    else
    {
        P4 ("%s", "  final_ll: FALSE, convert to LDL' form\n") ;
    }
    if (Common->final_pack)
    {
        P4 ("%s", "  final_pack: TRUE, pack when done\n") ;
    }
    else
    {
        P4 ("%s", "  final_pack: FALSE, do not pack when done\n") ;
    }
    if (Common->final_monotonic)
    {
        P4 ("%s", "  final_monotonic: TRUE, ensure L is monotonic\n") ;
    }
    else
    {
        P4 ("%s",
        "  final_monotonic: FALSE, do not ensure L is monotonic\n") ;
    }
    P4 ("  final_resymbol: remove zeros from amalgamation: %s\n",
        BOOLSTR (Common->final_resymbol)) ;
    }

    P4 ("  dbound:  LDL' diagonal threshold: % .5g\n    Entries with abs. value"
        " less than dbound are replaced with +/- dbound.\n",
        Common->dbound) ;

    P4 ("  grow0: memory reallocation: % .5g\n", Common->grow0) ;
    P4 ("  grow1: memory reallocation: % .5g\n", Common->grow1) ;
    P4 ("  grow2: memory reallocation: %ld\n", (long) (Common->grow2)) ;

    P4 ("%s", "  nrelax, zrelax:  supernodal amalgamation rule:\n") ;
    P4 ("%s", "    s = # columns in two adjacent supernodes\n") ;
    P4 ("%s", "    z = % of zeros in new supernode if they are merged.\n") ;
    P4 ("%s", "    Two supernodes are merged if") ;
    P4 (" (s <= %ld) or (no new zero entries) or\n",
        (long) (Common->nrelax [0])) ;
    P4 ("    (s <= %ld and ",  (long) (Common->nrelax [1])) ;
    P4 ("z < %.5g%%) or",      Common->zrelax [0] * 100) ;
    P4 (" (s <= %ld and ",     (long) (Common->nrelax [2])) ;
    P4 ("z < %.5g%%) or",      Common->zrelax [1] * 100) ;
    P4 (" (z < %.5g%%)\n",     Common->zrelax [2] * 100) ;

    /* ---------------------------------------------------------------------- */
    /* check workspace */
    /* ---------------------------------------------------------------------- */

    mark = Common->mark ;
    nrow = Common->nrow ;
    Flag = Common->Flag ;
    Head = Common->Head ;
    if (nrow > 0)
    {
    if (mark < 0 || Flag == NULL || Head == NULL)
    {
        ERR ("workspace corrupted (Flag and/or Head missing)") ;
    }
    for (i = 0 ; i < nrow ; i++)
    {
        if (Flag [i] >= mark)
        {
        PRINT0 (("Flag ["ID"]="ID", mark = %ld\n", i, Flag [i], mark)) ;
        ERR ("workspace corrupted (Flag)") ;
        }
    }
    for (i = 0 ; i <= nrow ; i++)
    {
        if (Head [i] != EMPTY)
        {
        PRINT0 (("Head ["ID"] = "ID",\n", i, Head [i])) ;
        ERR ("workspace corrupted (Head)") ;
        }
    }
    }
    xworksize = Common->xworksize ;
    Xwork = Common->Xwork ;
    if (xworksize > 0)
    {
    if (Xwork == NULL)
    {
        ERR ("workspace corrupted (Xwork missing)") ;
    }
    for (i = 0 ; i < xworksize ; i++)
    {
        if (Xwork [i] != 0.)
        {
        PRINT0 (("Xwork ["ID"] = %g\n", i, Xwork [i])) ;
        ERR ("workspace corrupted (Xwork)") ;
        }
    }
    }

    /* workspace and parameters are valid */
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
}


int CHOLMOD(check_common)
(
    cholmod_common *Common
)
{
    return (check_common (0, NULL, Common)) ;
}


int CHOLMOD(print_common)
(
    /* ---- input ---- */
    char *name,     /* printed name of Common object */
    /* --------------- */
    cholmod_common *Common
)
{
    Int print = (Common == NULL) ? 3 : (Common->print) ;
    return (check_common (print, name, Common)) ;
}


/* ========================================================================== */
/* === cholmod_check_sparse ================================================= */
/* ========================================================================== */

/* Ensure that a sparse matrix in column-oriented form is valid, and optionally
 * print it.  Returns the number of entries on the diagonal or -1 if error.
 *
 * workspace: Iwork (nrow)
 */

static long check_sparse
(
    Int *Wi,
    Int print,
    char *name,
    cholmod_sparse *A,
    long *nnzdiag,
    cholmod_common *Common
)
{
    double *Ax, *Az ;
    Int *Ap, *Ai, *Anz ;
    Int nrow, ncol, nzmax, sorted, packed, j, p, pend, i, nz, ilast,
    space, init_print, dnz, count, xtype ;
    char *type = "sparse" ;

    /* ---------------------------------------------------------------------- */
    /* print header information */
    /* ---------------------------------------------------------------------- */

    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD sparse:  ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }

    if (A == NULL)
    {
    ERR ("null") ;
    }

    nrow = A->nrow ;
    ncol = A->ncol ;
    nzmax = A->nzmax ;
    sorted = A->sorted ;
    packed = A->packed ;
    xtype = A->xtype ;
    Ap = A->p ;
    Ai = A->i ;
    Ax = A->x ;
    Az = A->z ;
    Anz = A->nz ;
    nz = CHOLMOD(nnz) (A, Common) ;

    P3 (" "ID"", nrow) ;
    P3 ("-by-"ID", ", ncol) ;
    P3 ("nz "ID",", nz) ;
    if (A->stype > 0)
    {
    P3 ("%s", " upper.") ;
    }
    else if (A->stype < 0)
    {
    P3 ("%s", " lower.") ;
    }
    else
    {
    P3 ("%s", " up/lo.") ;
    }

    P4 ("\n  nzmax "ID", ", nzmax) ;
    if (nz > nzmax)
    {
    ERR ("nzmax too small") ;
    }
    if (!sorted)
    {
    P4 ("%s", "un") ;
    }
    P4 ("%s", "sorted, ") ;
    if (!packed)
    {
    P4 ("%s", "un") ;
    }
    P4 ("%s", "packed, ") ;

    switch (A->itype)
    {
    case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
    case CHOLMOD_INTLONG: ERR ("int/long type unsupported") ;
    case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: long, ") ; break ;
    default:          ERR ("unknown itype") ;
    }

    switch (A->xtype)
    {
    case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;    break ;
    case CHOLMOD_REAL:    P4 ("%s", "real") ;   break ;
    case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;    break ;
    case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;    break ;
    default:          ERR ("unknown xtype") ;
    }

    switch (A->dtype)
    {
    case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;        break ;
    case CHOLMOD_SINGLE:  ERR ("float unsupported") ;
    default:          ERR ("unknown dtype") ;
    }

    if (A->itype != ITYPE || A->dtype != DTYPE)
    {
    ERR ("integer and real type must match routine") ;
    }

    if (A->stype && nrow != ncol)
    {
    ERR ("symmetric but not square") ;
    }

    /* check for existence of Ap, Ai, Anz, Ax, and Az arrays */
    if (Ap == NULL)
    {
    ERR ("p array not present") ;
    }
    if (Ai == NULL)
    {
    ERR ("i array not present") ;
    }
    if (!packed && Anz == NULL)
    {
    ERR ("nz array not present") ;
    }
    if (xtype != CHOLMOD_PATTERN && Ax == NULL)
    {
    ERR ("x array not present") ;
    }
    if (xtype == CHOLMOD_ZOMPLEX && Az == NULL)
    {
    ERR ("z array not present") ;
    }

    /* packed matrices must start at Ap [0] = 0 */
    if (packed && Ap [0] != 0)
    {
    ERR ("p [0] must be zero") ;
    }
    if (Ap [ncol] < Ap [0] || Ap [ncol] > nzmax)
    {
    ERR ("p [ncol] invalid") ;
    }

    /* ---------------------------------------------------------------------- */
    /* allocate workspace if needed */
    /* ---------------------------------------------------------------------- */

    if (!sorted)
    {
    if (Wi == NULL)
    {
        CHOLMOD(allocate_work) (0, nrow, 0, Common) ;
        Wi = Common->Iwork ;    /* size nrow, (i/i/l) */
    }
    if (Common->status < CHOLMOD_OK)
    {
        return (FALSE) ;        /* out of memory */
    }
    for (i = 0 ; i < nrow ; i++)
    {
        Wi [i] = EMPTY ;
    }
    }

    /* ---------------------------------------------------------------------- */
    /* check and print each column */
    /* ---------------------------------------------------------------------- */

    init_print = print ;
    dnz = 0 ;
    ETC_START (count, 8) ;

    for (j = 0 ; j < ncol ; j++)
    {
    ETC (j == ncol-1, count, 4) ;
    p = Ap [j] ;
    if (packed)
    {
        pend = Ap [j+1] ;
        nz = pend - p ;
    }
    else
    {
        /* Note that Anz [j] < 0 is treated as zero */
        nz = MAX (0, Anz [j]) ;
        pend = p + nz ;
    }
    space = Ap [j+1] - p ;
    P4 ("  col "ID":", j) ;
    P4 (" nz "ID"", nz) ;
    P4 (" start "ID"", p) ;
    P4 (" end "ID"", pend) ;
    if (!packed)
    {
        P4 (" space "ID"", space) ;
    }
    P4 ("%s", ":\n") ;
    if (p < 0 || pend > nzmax || space < 0)
    {
        ERR ("pointer invalid") ;
    }
    if (nz < 0 || nz > nrow || nz > space)
    {
        ERR ("nz invalid") ;
    }
    ilast = EMPTY ;

    for ( ; p < pend ; p++)
    {
        ETC (j == ncol-1 && p >= pend-4, count, -1) ;
        i = Ai [p] ;
        P4 ("  "I8":", i) ;

        print_value (print, xtype, Ax, Az, p, Common) ;

        if (i == j)
        {
        dnz++ ;
        }
        if (i < 0 || i >= nrow)
        {
        ERR ("row index out of range") ;
        }
        if (sorted && i <= ilast)
        {
        ERR ("row indices out of order") ;
        }
        if (!sorted && Wi [i] == j)
        {
        ERR ("duplicate row index") ;
        }
        P4 ("%s", "\n") ;
        ilast = i ;
        if (!sorted)
        {
        Wi [i] = j ;
        }
    }
    }

    /* matrix is valid */
    P4 ("  nnz on diagonal: "ID"\n", dnz) ;
    P3 ("%s", "  OK\n") ;
    *nnzdiag = dnz ;
    return (TRUE) ;
}


int CHOLMOD(check_sparse)
(
    /* ---- input ---- */
    cholmod_sparse *A,  /* sparse matrix to check */
    /* --------------- */
    cholmod_common *Common
)
{
    long nnzdiag ;
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_sparse (NULL, 0, NULL, A, &nnzdiag, Common)) ;
}


int CHOLMOD(print_sparse)
(
    /* ---- input ---- */
    cholmod_sparse *A,  /* sparse matrix to print */
    char *name,     /* printed name of sparse matrix */
    /* --------------- */
    cholmod_common *Common
)
{
    long nnzdiag ;
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_sparse (NULL, Common->print, name, A, &nnzdiag, Common)) ;
}


/* ========================================================================== */
/* === cholmod_check_dense ================================================== */
/* ========================================================================== */

/* Ensure a dense matrix is valid, and optionally print it. */

static int check_dense
(
    Int print,
    char *name,
    cholmod_dense *X,
    cholmod_common *Common
)
{
    double *Xx, *Xz ;
    Int i, j, d, nrow, ncol, nzmax, nz, init_print, count, xtype ;
    char *type = "dense" ;

    /* ---------------------------------------------------------------------- */
    /* print header information */
    /* ---------------------------------------------------------------------- */

    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD dense:   ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }

    if (X == NULL)
    {
    ERR ("null") ;
    }

    nrow = X->nrow ;
    ncol = X->ncol ;
    nzmax = X->nzmax ;
    d = X->d ;
    Xx = X->x ;
    Xz = X->z ;
    xtype = X->xtype ;

    P3 (" "ID"", nrow) ;
    P3 ("-by-"ID", ", ncol) ;
    P4 ("\n  leading dimension "ID", ", d) ;
    P4 ("nzmax "ID", ", nzmax) ;
    if (d * ncol > nzmax)
    {
    ERR ("nzmax too small") ;
    }
    if (d < nrow)
    {
    ERR ("leading dimension must be >= # of rows") ;
    }
    if (Xx == NULL)
    {
    ERR ("null") ;
    }

    switch (X->xtype)
    {
    case CHOLMOD_PATTERN: ERR ("pattern unsupported") ;  break ;
    case CHOLMOD_REAL:    P4 ("%s", "real") ;   break ;
    case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;    break ;
    case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;    break ;
    default:          ERR ("unknown xtype") ;
    }

    switch (X->dtype)
    {
    case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;        break ;
    case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
    default:          ERR ("unknown dtype") ;
    }

    /* ---------------------------------------------------------------------- */
    /* check and print each entry */
    /* ---------------------------------------------------------------------- */

    if (print >= 4)
    {
    init_print = print ;
    ETC_START (count, 9) ;
    nz = nrow * ncol ;
    for (j = 0 ; j < ncol ; j++)
    {
        ETC (j == ncol-1, count, 5) ;
        P4 ("  col "ID":\n", j) ;
        for (i = 0 ; i < nrow ; i++)
        {
        ETC (j == ncol-1 && i >= nrow-4, count, -1) ;
        P4 ("  "I8":", i) ;

        print_value (print, xtype, Xx, Xz, i+j*d, Common) ;

        P4 ("%s", "\n") ;
        }
    }
    }

    /* dense  is valid */
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
}


int CHOLMOD(check_dense)
(
    /* ---- input ---- */
    cholmod_dense *X,   /* dense matrix to check */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_dense (0, NULL, X, Common)) ;
}


int CHOLMOD(print_dense)
(
    /* ---- input ---- */
    cholmod_dense *X,   /* dense matrix to print */
    char *name,     /* printed name of dense matrix */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_dense (Common->print, name, X, Common)) ;
}


/* ========================================================================== */
/* === cholmod_check_subset ================================================= */
/* ========================================================================== */

/* Ensure S (0:len-1) is a subset of 0:n-1.  Duplicates are allowed.  S may be
 * NULL.  A negative len denotes the set 0:n-1.
 *
 * To check the rset and cset for A(rset,cset), where nc and nr are the length
 * of cset and rset respectively:
 *
 *  cholmod_check_subset (cset, nc, A->ncol, Common) ;
 *  cholmod_check_subset (rset, nr, A->nrow, Common) ;
 *
 * workspace: none
 */

static int check_subset
(
    Int *S,
    long len,
    size_t n,
    Int print,
    char *name,
    cholmod_common *Common
)
{
    Int i, k, init_print, count ;
    char *type = "subset" ;

    init_print = print ;

    if (S == NULL)
    {
    /* zero len denotes S = [ ], negative len denotes S = 0:n-1 */
    len = (len < 0) ? (-1) : 0 ;
    }

    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD subset:  ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }

    P3 (" len: %ld ", len) ;
    if (len < 0)
    {
    P3 ("%s", "(denotes 0:n-1) ") ;
    }
    P3 ("n: "ID"", (Int) n) ;
    P4 ("%s", "\n") ;

    if (len <= 0 || S == NULL)
    {
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
    }

    if (print >= 4)
    {
    ETC_START (count, 8) ;
    for (k = 0 ; k < ((Int) len) ; k++)
    {
        ETC (k == ((Int) len) - 4, count, -1) ;
        i = S [k] ;
        P4 ("  "I8":", k) ;
        P4 (" "ID"\n", i) ;
        if (i < 0 || i >= ((Int) n))
        {
        ERR ("entry out range") ;
        }
    }
    }
    else
    {
    for (k = 0 ; k < ((Int) len) ; k++)
    {
        i = S [k] ;
        if (i < 0 || i >= ((Int) n))
        {
        ERR ("entry out range") ;
        }
    }
    }
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
}


int CHOLMOD(check_subset)
(
    /* ---- input ---- */
    Int *Set,       /* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
    long len,       /* size of Set (an integer array), or < 0 if 0:n-1 */
    size_t n,       /* 0:n-1 is valid range */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_subset (Set, len, n, 0, NULL, Common)) ;
}


int CHOLMOD(print_subset)
(
    /* ---- input ---- */
    Int *Set,       /* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
    long len,       /* size of Set (an integer array), or < 0 if 0:n-1 */
    size_t n,       /* 0:n-1 is valid range */
    char *name,     /* printed name of Set */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_subset (Set, len, n, Common->print, name, Common)) ;
}


/* ========================================================================== */
/* === cholmod_check_perm =================================================== */
/* ========================================================================== */

/* Ensure that Perm [0..len-1] is a permutation of a subset of 0:n-1.  Perm
 * may be NULL, which is interpreted as the identity permutation.  There can
 * be no duplicate entries (len must be <= n).
 *
 * If n <= Common->nrow, then this routine takes O(len) time and does not
 * allocate any memory, by using Common->Flag.  Otherwise, it takes O(n) time
 * and ensures that Common->Iwork is at least n*sizeof(Int) in size.
 *
 * To check the fset:       cholmod_check_perm (fset, fsize, ncol, Common) ;
 * To check a permutation:  cholmod_check_perm (Perm, n, n, Common) ;
 *
 * workspace:  Flag (n) if n <= Common->nrow, Iwork (n) otherwise.
 */

static int check_perm
(
    Int *Wi,
    Int print,
    char *name,
    Int *Perm,
    size_t len,
    size_t n,
    cholmod_common *Common
)
{
    Int *Flag ;
    Int i, k, mark, init_print, count ;
    char *type = "perm" ;

    /* ---------------------------------------------------------------------- */
    /* checks that take O(1) time */
    /* ---------------------------------------------------------------------- */

    if (Perm == NULL || n == 0)
    {
    /* Perm is valid implicit identity, or empty */
    return (TRUE) ;
    }

    /* ---------------------------------------------------------------------- */
    /* checks that take O(n) time or require memory allocation */
    /* ---------------------------------------------------------------------- */

    init_print = print ;
    ETC_START (count, 8) ;

    if (Wi == NULL && n <= Common->nrow)
    {
    /* use the Common->Flag array if it's big enough */
    mark = CHOLMOD(clear_flag) (Common) ;
    Flag = Common->Flag ;
    ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
    if (print >= 4)
    {
        for (k = 0 ; k < ((Int) len) ; k++)
        {
        ETC (k >= ((Int) len) - 4, count, -1) ;
        i = Perm [k] ;
        P4 ("  "I8":", k) ;
        P4 (""ID"\n", i) ;
        if (i < 0 || i >= ((Int) n) || Flag [i] == mark)
        {
            CHOLMOD(clear_flag) (Common) ;
            ERR ("invalid permutation") ;
        }
        Flag [i] = mark ;
        }
    }
    else
    {
        for (k = 0 ; k < ((Int) len) ; k++)
        {
        i = Perm [k] ;
        if (i < 0 || i >= ((Int) n) || Flag [i] == mark)
        {
            CHOLMOD(clear_flag) (Common) ;
            ERR ("invalid permutation") ;
        }
        Flag [i] = mark ;
        }
    }
    CHOLMOD(clear_flag) (Common) ;
    ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
    }
    else
    {
    if (Wi == NULL)
    {
        /* use Common->Iwork instead, but initialize it first */
        CHOLMOD(allocate_work) (0, n, 0, Common) ;
        Wi = Common->Iwork ;            /* size n, (i/i/i) is OK */
    }
    if (Common->status < CHOLMOD_OK)
    {
        return (FALSE) ;        /* out of memory */
    }
    for (i = 0 ; i < ((Int) n) ; i++)
    {
        Wi [i] = FALSE ;
    }
    if (print >= 4)
    {
        for (k = 0 ; k < ((Int) len) ; k++)
        {
        ETC (k >= ((Int) len) - 4, count, -1) ;
        i = Perm [k] ;
        P4 ("  "I8":", k) ;
        P4 (""ID"\n", i) ;
        if (i < 0 || i >= ((Int) n) || Wi [i])
        {
            ERR ("invalid permutation") ;
        }
        Wi [i] = TRUE ;
        }
    }
    else
    {
        for (k = 0 ; k < ((Int) len) ; k++)
        {
        i = Perm [k] ;
        if (i < 0 || i >= ((Int) n) || Wi [i])
        {
            ERR ("invalid permutation") ;
        }
        Wi [i] = TRUE ;
        }
    }
    }

    /* perm is valid */
    return (TRUE) ;
}


int CHOLMOD(check_perm)
(
    /* ---- input ---- */
    Int *Perm,      /* Perm [0:len-1] is a permutation of subset of 0:n-1 */
    size_t len,     /* size of Perm (an integer array) */
    size_t n,       /* 0:n-1 is valid range */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_perm (NULL, 0, NULL, Perm, len, n, Common)) ;
}


int CHOLMOD(print_perm)
(
    /* ---- input ---- */
    Int *Perm,      /* Perm [0:len-1] is a permutation of subset of 0:n-1 */
    size_t len,     /* size of Perm (an integer array) */
    size_t n,       /* 0:n-1 is valid range */
    char *name,     /* printed name of Perm */
    /* --------------- */
    cholmod_common *Common
)
{
    Int ok, print ;
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    print = Common->print ;
    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD perm:    ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }
    P3 (" len: "ID"", (Int) len) ;
    P3 (" n: "ID"", (Int) n) ;
    P4 ("%s", "\n") ;
    ok = check_perm (NULL, print, name, Perm, len, n, Common) ;
    if (ok)
    {
    P3 ("%s", "  OK\n") ;
    }
    return (ok) ;
}


/* ========================================================================== */
/* === cholmod_check_parent ================================================= */
/* ========================================================================== */

/* Ensure that Parent is a valid elimination tree of nodes 0 to n-1.
 * If j is a root of the tree then Parent [j] is EMPTY (-1).
 *
 * NOTE: this check will fail if applied to the component tree (CParent) in
 * cholmod_nested_dissection, unless it has been postordered and renumbered.
 *
 * workspace: none
 */

static int check_parent
(
    Int *Parent,
    size_t n,
    Int print,
    char *name,
    cholmod_common *Common
)
{
    Int j, p, init_print, count ;
    char *type = "parent" ;

    init_print = print ;

    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD parent:  ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }

    P3 (" n: "ID"", (Int) n) ;
    P4 ("%s", "\n") ;

    if (Parent == NULL)
    {
    ERR ("null") ;
    }

    /* ---------------------------------------------------------------------- */
    /* checks that take O(n) time */
    /* ---------------------------------------------------------------------- */

    ETC_START (count, 8) ;
    for (j = 0 ; j < ((Int) n) ; j++)
    {
    ETC (j == ((Int) n) - 4, count, -1) ;
    p = Parent [j] ;
    P4 ("  "I8":", j) ;
    P4 (" "ID"\n", p) ;
    if (!(p == EMPTY || p > j))
    {
        ERR ("invalid") ;
    }
    }
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
}


int CHOLMOD(check_parent)
(
    /* ---- input ---- */
    Int *Parent,    /* Parent [0:n-1] is an elimination tree */
    size_t n,       /* size of Parent */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_parent (Parent, n, 0, NULL, Common)) ;
}


int CHOLMOD(print_parent)
(
    /* ---- input ---- */
    Int *Parent,    /* Parent [0:n-1] is an elimination tree */
    size_t n,       /* size of Parent */
    char *name,     /* printed name of Parent */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_parent (Parent, n, Common->print, name, Common)) ;
}


/* ========================================================================== */
/* === cholmod_check_factor ================================================= */
/* ========================================================================== */

static int check_factor
(
    Int *Wi,
    Int print,
    char *name,
    cholmod_factor *L,
    cholmod_common *Common
)
{
    double *Lx, *Lz ;
    Int *Lp, *Li, *Lnz, *Lnext, *Lprev, *Perm, *ColCount, *Lpi, *Lpx, *Super,
    *Ls ;
    Int n, nzmax, j, p, pend, i, nz, ordering, space, is_monotonic, minor,
    count, precise, init_print, ilast, lnz, head, tail, jprev, plast,
    jnext, examine_super, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol,
    ps2, psxend, ssize, xsize, maxcsize, maxesize, nsrow2, jj, ii, xtype ;
    char *type = "factor" ;

    /* ---------------------------------------------------------------------- */
    /* print header information */
    /* ---------------------------------------------------------------------- */

    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD factor:  ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }

    if (L == NULL)
    {
    ERR ("null") ;
    }

    n = L->n ;
    minor = L->minor ;
    ordering = L->ordering ;
    xtype = L->xtype ;

    Perm = L->Perm ;
    ColCount = L->ColCount ;
    lnz = 0 ;

    precise = Common->precise ;

    P3 (" "ID"", n) ;
    P3 ("-by-"ID"", n) ;

    if (minor < n)
    {
    P3 (" not positive definite (column "ID")", minor) ;
    }

    switch (L->itype)
    {
    case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
    case CHOLMOD_INTLONG: ERR ("int/long type unsupported") ;
    case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: long, ") ; break ;
    default:          ERR ("unknown itype") ;
    }

    switch (L->xtype)
    {
    case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;    break ;
    case CHOLMOD_REAL:    P4 ("%s", "real") ;   break ;
    case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;    break ;
    case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;    break ;
    default:          ERR ("unknown xtype") ;
    }

    switch (L->dtype)
    {
    case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;        break ;
    case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
    default:          ERR ("unknown dtype") ;
    }

    if (L->itype != ITYPE || L->dtype != DTYPE)
    {
    ERR ("integer and real type must match routine") ;
    }

    if (L->is_super)
    {
    P3 ("%s", "  supernodal") ;
    }
    else
    {
    P3 ("%s", "  simplicial") ;
    }

    if (L->is_ll)
    {
    P3 ("%s", ", LL'.") ;
    }
    else
    {
    P3 ("%s", ", LDL'.") ;
    }

    P4 ("%s", "\n  ordering method used: ") ;
    switch (L->ordering)
    {
    case CHOLMOD_POSTORDERED:P4 ("%s", "natural (postordered)") ;    break ;
    case CHOLMOD_NATURAL:   P4 ("%s", "natural") ;           break ;
    case CHOLMOD_GIVEN: P4 ("%s", "user-provided") ;         break ;
    case CHOLMOD_AMD:   P4 ("%s", "AMD") ;           break ;
    case CHOLMOD_COLAMD:    P4 ("%s", "AMD for A, COLAMD for A*A'") ;break ;
#ifndef NPARTITION
    case CHOLMOD_METIS: P4 ("%s", "METIS NodeND") ;      break ;
    case CHOLMOD_NESDIS:    P4 ("%s", "CHOLMOD nested dissection") ; break ;
#endif
    default:        ERR ("unknown ordering") ;
    }

    P4 ("%s", "\n") ;

    init_print = print ;

    if (L->is_super && L->xtype == CHOLMOD_ZOMPLEX)
    {
    ERR ("Supernodal zomplex L not supported") ;
    }

    /* ---------------------------------------------------------------------- */
    /* check L->Perm */
    /* ---------------------------------------------------------------------- */

    if (!check_perm (Wi, print, name, Perm, n, n, Common))
    {
    return (FALSE) ;
    }

    /* ---------------------------------------------------------------------- */
    /* check L->ColCount */
    /* ---------------------------------------------------------------------- */

    if (ColCount == NULL)
    {
    ERR ("ColCount vector invalid") ;
    }

    ETC_START (count, 8) ;
    for (j = 0 ; j < n ; j++)
    {
    ETC (j >= n-4, count, -1) ;
    P4 ("  col: "ID" ", j) ;
    nz = ColCount [j] ;
    P4 ("colcount: "ID"\n", nz) ;
    if (nz < 0 || nz > n-j)
    {
        ERR ("ColCount out of range") ;
    }
    }

    /* ---------------------------------------------------------------------- */
    /* check factor */
    /* ---------------------------------------------------------------------- */

    if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
    {

    /* ------------------------------------------------------------------ */
    /* check simplicial symbolic factor */
    /* ------------------------------------------------------------------ */

    /* nothing else to do */ ;

    }
    else if (L->xtype != CHOLMOD_PATTERN && !(L->is_super))
    {

    /* ------------------------------------------------------------------ */
    /* check simplicial numerical factor */
    /* ------------------------------------------------------------------ */

    P4 ("monotonic: %d\n", L->is_monotonic) ;
    nzmax = L->nzmax ;
    P3 (" nzmax "ID".", nzmax) ;
    P4 ("%s", "\n") ;
    Lp = L->p ;
    Li = L->i ;
    Lx = L->x ;
    Lz = L->z ;
    Lnz = L->nz ;
    Lnext = L->next ;
    Lprev = L->prev ;

    /* check for existence of Lp, Li, Lnz, Lnext, Lprev, and Lx arrays */
    if (Lp == NULL)
    {
        ERR ("p array not present") ;
    }
    if (Li == NULL)
    {
        ERR ("i array not present") ;
    }
    if (Lnz == NULL)
    {
        ERR ("nz array not present") ;
    }
    if (Lx == NULL)
    {
        ERR ("x array not present") ;
    }
    if (xtype == CHOLMOD_ZOMPLEX && Lz == NULL)
    {
        ERR ("z array not present") ;
    }
    if (Lnext == NULL)
    {
        ERR ("next array not present") ;
    }
    if (Lprev == NULL)
    {
        ERR ("prev array not present") ;
    }

    ETC_START (count, 8) ;

    /* check each column of L */
    plast = 0 ;
    is_monotonic = TRUE ;
    for (j = 0 ; j < n ; j++)
    {
        ETC (j >= n-3, count, -1) ;
        p = Lp [j] ;
        nz = Lnz [j] ;
        pend = p + nz ;
        lnz += nz ;

        P4 ("  col "ID":", j) ;
        P4 (" nz "ID"", nz) ;
        P4 (" start "ID"", p) ;
        P4 (" end "ID"", pend) ;

        if (Lnext [j] < 0 || Lnext [j] > n)
        {
        ERR ("invalid link list")  ;
        }
        space = Lp [Lnext [j]] - p ;

        P4 (" space "ID"", space) ;
        P4 (" free "ID":\n", space - nz) ;

        if (p < 0 || pend > nzmax || space < 1)
        {
        ERR ("pointer invalid") ;
        }
        if (nz < 1 || nz > (n-j) || nz > space)
        {
        ERR ("nz invalid") ;
        }
        ilast = j-1 ;

        if (p < plast)
        {
        is_monotonic = FALSE ;
        }
        plast = p ;

        i = Li [p] ;
        P4 ("  "I8":", i) ;
        if (i != j)
        {
        ERR ("diagonal missing") ;
        }

        print_value (print, xtype, Lx, Lz, p, Common) ;

        P4 ("%s", "\n") ;
        ilast = j ;
        for (p++ ; p < pend ; p++)
        {
        ETC_DISABLE (count) ;
        i = Li [p] ;
        P4 ("  "I8":", i) ;
        if (i < j || i >= n)
        {
            ERR ("row index out of range") ;
        }
        if (i <= ilast)
        {
            ERR ("row indices out of order") ;
        }

        print_value (print, xtype, Lx, Lz, p, Common) ;

        P4 ("%s", "\n") ;
        ilast = i ;
        }
    }

    if (L->is_monotonic && !is_monotonic)
    {
        ERR ("columns not monotonic") ;
    }

    /* check the link list */
    head = n+1 ;
    tail = n ;
    j = head ;
    jprev = EMPTY ;
    count = 0 ;
    for ( ; ; )
    {
        if (j < 0 || j > n+1 || count > n+2)
        {
        ERR ("invalid link list") ;
        }
        jnext = Lnext [j] ;
        if (j >= 0 && j < n)
        {
        if (jprev != Lprev [j])
        {
            ERR ("invalid link list") ;
        }
        }
        count++ ;
        if (j == tail)
        {
        break ;
        }
        jprev = j ;
        j = jnext ;
    }
    if (Lnext [tail] != EMPTY || count != n+2)
    {
        ERR ("invalid link list") ;
    }

    }
    else
    {

    /* ------------------------------------------------------------------ */
    /* check supernodal numeric or symbolic factor */
    /* ------------------------------------------------------------------ */

    nsuper = L->nsuper ;
    ssize = L->ssize ;
    xsize = L->xsize ;
    maxcsize = L->maxcsize ;
    maxesize = L->maxesize ;
    Ls = L->s ;
    Lpi = L->pi ;
    Lpx = L->px ;
    Super = L->super ;
    Lx = L->x ;
    ETC_START (count, 8) ;

    P4 ("  ssize "ID" ", ssize) ;
    P4 ("xsize "ID" ", xsize) ;
    P4 ("maxcsize "ID" ", maxcsize) ;
    P4 ("maxesize "ID"\n", maxesize) ;

    if (Ls == NULL)
    {
        ERR ("invalid: L->s missing") ;
    }
    if (Lpi == NULL)
    {
        ERR ("invalid: L->pi missing") ;
    }
    if (Lpx == NULL)
    {
        ERR ("invalid: L->px missing") ;
    }
    if (Super == NULL)
    {
        ERR ("invalid: L->super missing") ;
    }

    if (L->xtype != CHOLMOD_PATTERN)
    {
        /* numerical supernodal factor */
        if (Lx == NULL)
        {
        ERR ("invalid: L->x missing") ;
        }
        if (Ls [0] == EMPTY)
        {
        ERR ("invalid: L->s not defined") ;
        }
        examine_super = TRUE ;
    }
    else
    {
        /* symbolic supernodal factor, but only if it has been computed */
        examine_super = (Ls [0] != EMPTY) ;
    }

    if (examine_super)
    {
        if (Lpi [0] != 0 || MAX (1, Lpi [nsuper]) != ssize)
        {
        PRINT0 (("Lpi [0] "ID", Lpi [nsuper = "ID"] = "ID"\n",
            Lpi [0], nsuper, Lpi [nsuper])) ;
        ERR ("invalid: L->pi invalid") ;
        }
        if (Lpx [0] != 0 || MAX (1, Lpx [nsuper]) != xsize)
        {
        ERR ("invalid: L->px invalid") ;
        }

        /* check and print each supernode */
        for (s = 0 ; s < nsuper ; s++)
        {
        k1 = Super [s] ;
        k2 = Super [s+1] ;
        psi = Lpi [s] ;
        psend = Lpi [s+1] ;
        psx = Lpx [s] ;
        nsrow = psend - psi ;
        nscol = k2 - k1 ;
        nsrow2 = nsrow - nscol ;
        ps2 = psi + nscol ;
        psxend = Lpx [s+1] ;

        ETC (s == nsuper-1, count, 4) ;

        P4 ("  supernode "ID", ", s) ;
        P4 ("col "ID" ", k1) ;
        P4 ("to "ID". ", k2-1) ;
        P4 ("nz in first col: "ID".\n", nsrow) ;
        P4 ("  values start "ID", ", psx) ;
        P4 ("end "ID"\n", psxend) ;

        if (k1 > k2 || k1 < 0 || k2 > n || nsrow < nscol || nsrow2 < 0
            || psxend - psx != nsrow * nscol)
        {
            ERR ("invalid supernode") ;
        }

        lnz += nscol * nsrow - (nscol*nscol - nscol)/2 ;

        if (L->xtype != CHOLMOD_PATTERN)
        {
            /* print each column of the supernode */
            for (jj = 0 ; jj < nscol ; jj++)
            {
            ETC_ENABLE (s == nsuper-1 && jj >= nscol-3, count, -1) ;
            j = k1 + jj ;
            P4 ("  col "ID"\n", j) ;
            ilast = j ;
            i = Ls [psi + jj] ;
            P4 ("  "I8":", i) ;
            if (i != j)
            {
                ERR ("row index invalid") ;
            }

            /* PRINTVALUE (Lx [psx + jj + jj*nsrow]) ; */
            print_value (print, xtype, Lx, NULL,
                psx + jj + jj*nsrow, Common) ;

            P4 ("%s", "\n") ;
            for (ii = jj + 1 ; ii < nsrow ; ii++)
            {
                ETC_DISABLE (count) ;
                i = Ls [psi + ii] ;
                P4 ("  "I8":", i) ;
                if (i <= ilast || i > n)
                {
                ERR ("row index out of range") ;
                }

                /* PRINTVALUE (Lx [psx + ii + jj*nsrow]) ; */
                print_value (print, xtype, Lx, NULL,
                    psx + ii + jj*nsrow, Common) ;

                P4 ("%s", "\n") ;
                ilast = i ;
            }
            }
        }
        else
        {
            /* just print the leading column of the supernode */
            P4 ("  col "ID"\n", k1) ;
            for (jj = 0 ; jj < nscol ; jj++)
            {
            ETC (s == nsuper-1 && jj >= nscol-3, count, -1) ;
            j = k1 + jj ;
            i = Ls [psi + jj] ;
            P4 ("  "I8"", i) ;
            if (i != j)
            {
                ERR ("row index invalid") ;
            }
            P4 ("%s", "\n") ;
            }
            ilast = j ;
            for (ii = nscol ; ii < nsrow ; ii++)
            {
            ETC_DISABLE (count) ;
            i = Ls [psi + ii] ;
            P4 ("  "I8"", i) ;
            if (i <= ilast || i > n)
            {
                ERR ("row index out of range") ;
            }
            P4 ("%s", "\n") ;
            ilast = i ;
            }
        }
        }
    }
    }

    /* factor is valid */
    P3 ("  nz "ID"", lnz) ;
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
}


int CHOLMOD(check_factor)
(
    /* ---- input ---- */
    cholmod_factor *L,  /* factor to check */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_factor (NULL, 0, NULL, L, Common)) ;
}


int CHOLMOD(print_factor)
(
    /* ---- input ---- */
    cholmod_factor *L,  /* factor to print */
    char *name,     /* printed name of factor */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_factor (NULL, Common->print, name, L, Common)) ;
}


/* ========================================================================== */
/* === cholmod_check_triplet ================================================ */
/* ========================================================================== */

/* Ensure a triplet matrix is valid, and optionally print it. */

static int check_triplet
(
    Int print,
    char *name,
    cholmod_triplet *T,
    cholmod_common *Common
)
{
    double *Tx, *Tz ;
    Int *Ti, *Tj ;
    Int i, j, p, nrow, ncol, nzmax, nz, xtype, init_print, count ;
    char *type = "triplet" ;

    /* ---------------------------------------------------------------------- */
    /* print header information */
    /* ---------------------------------------------------------------------- */

    P4 ("%s", "\n") ;
    P3 ("%s", "CHOLMOD triplet: ") ;
    if (name != NULL)
    {
    P3 ("%s: ", name) ;
    }

    if (T == NULL)
    {
    ERR ("null") ;
    }

    nrow = T->nrow ;
    ncol = T->ncol ;
    nzmax = T->nzmax ;
    nz = T->nnz ;
    Ti = T->i ;
    Tj = T->j ;
    Tx = T->x ;
    Tz = T->z ;
    xtype = T->xtype ;


    P3 (" "ID"", nrow) ;
    P3 ("-by-"ID", ", ncol) ;
    P3 ("nz "ID",", nz) ;
    if (T->stype > 0)
    {
    P3 ("%s", " upper.") ;
    }
    else if (T->stype < 0)
    {
    P3 ("%s", " lower.") ;
    }
    else
    {
    P3 ("%s", " up/lo.") ;
    }

    P4 ("\n  nzmax "ID", ", nzmax) ;
    if (nz > nzmax)
    {
    ERR ("nzmax too small") ;
    }

    switch (T->itype)
    {
    case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
    case CHOLMOD_INTLONG: ERR ("int/long type unsupported") ;
    case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: long, ") ; break ;
    default:          ERR ("unknown itype") ;
    }

    switch (T->xtype)
    {
    case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;    break ;
    case CHOLMOD_REAL:    P4 ("%s", "real") ;   break ;
    case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;    break ;
    case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;    break ;
    default:          ERR ("unknown xtype") ;
    }

    switch (T->dtype)
    {
    case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;        break ;
    case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
    default:          ERR ("unknown dtype") ;
    }

    if (T->itype != ITYPE || T->dtype != DTYPE)
    {
    ERR ("integer and real type must match routine") ;
    }

    if (T->stype && nrow != ncol)
    {
    ERR ("symmetric but not square") ;
    }

    /* check for existence of Ti, Tj, Tx arrays */
    if (Tj == NULL)
    {
    ERR ("j array not present") ;
    }
    if (Ti == NULL)
    {
    ERR ("i array not present") ;
    }

    if (xtype != CHOLMOD_PATTERN && Tx == NULL)
    {
    ERR ("x array not present") ;
    }
    if (xtype == CHOLMOD_ZOMPLEX && Tz == NULL)
    {
    ERR ("z array not present") ;
    }

    /* ---------------------------------------------------------------------- */
    /* check and print each entry */
    /* ---------------------------------------------------------------------- */

    init_print = print ;
    ETC_START (count, 8) ;

    for (p = 0 ; p < nz ; p++)
    {
    ETC (p >= nz-4, count, -1) ;
    i = Ti [p] ;
    P4 ("  "I8":", p) ;
    P4 (" "I_8"", i) ;
    if (i < 0 || i >= nrow)
    {
        ERR ("row index out of range") ;
    }
    j = Tj [p] ;
    P4 (" "I_8"", j) ;
    if (j < 0 || j >= ncol)
    {
        ERR ("column index out of range") ;
    }

    print_value (print, xtype, Tx, Tz, p, Common) ;

    P4 ("%s", "\n") ;
    }

    /* triplet matrix is valid */
    P3 ("%s", "  OK\n") ;
    return (TRUE) ;
}



int CHOLMOD(check_triplet)
(
    /* ---- input ---- */
    cholmod_triplet *T, /* triplet matrix to check */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_triplet (0, NULL, T, Common)) ;
}


int CHOLMOD(print_triplet)
(
    /* ---- input ---- */
    cholmod_triplet *T, /* triplet matrix to print */
    char *name,     /* printed name of triplet matrix */
    /* --------------- */
    cholmod_common *Common
)
{
    RETURN_IF_NULL_COMMON (FALSE) ;
    Common->status = CHOLMOD_OK ;
    return (check_triplet (Common->print, name, T, Common)) ;
}



/* ========================================================================== */
/* === CHOLMOD debugging routines =========================================== */
/* ========================================================================== */

#ifndef NDEBUG

/* The global variables present only when debugging enabled. */
int CHOLMOD(dump) = 0 ;
int CHOLMOD(dump_malloc) = -1 ;

/* workspace: no debug routines use workspace in Common */

/* ========================================================================== */
/* === cholmod_dump_init ==================================================== */
/* ========================================================================== */

void CHOLMOD(dump_init) (char *s, cholmod_common *Common)
{
    FILE *f ;
    f = fopen ("debug", "r") ;
    if (f == NULL)
    {
    CHOLMOD(dump) = 0 ;
    }
    else
    {
    fscanf (f, "%d", &CHOLMOD(dump)) ;
    fclose (f) ;
    }
    PRINT1 (("%s: cholmod_dump_init, D = %d\n", s, CHOLMOD(dump))) ;
}


/* ========================================================================== */
/* === cholmod_dump_sparse ================================================== */
/* ========================================================================== */

long CHOLMOD(dump_sparse)   /* returns nnz (diag (A)) or EMPTY if error */
(
    cholmod_sparse *A,
    char *name,
    cholmod_common *Common
)
{
    Int *Wi ;
    long nnzdiag ;
    Int ok ;

    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (0) ;
    }

    RETURN_IF_NULL_COMMON (FALSE) ;
    RETURN_IF_NULL (A, FALSE) ;
    Wi = malloc (MAX (1, A->nrow) * sizeof (Int)) ;
    ok = check_sparse (Wi, CHOLMOD(dump), name, A, &nnzdiag, Common) ;
    if (Wi != NULL) free (Wi) ;
    return (ok ? nnzdiag : EMPTY) ;
}


/* ========================================================================== */
/* === cholmod_dump_factor ================================================== */
/* ========================================================================== */

int CHOLMOD(dump_factor)
(
    cholmod_factor *L,
    char *name,
    cholmod_common *Common
)
{
    Int *Wi ;
    int ok ;

    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }
    RETURN_IF_NULL_COMMON (FALSE) ;
    RETURN_IF_NULL (L, FALSE) ;
    Wi = malloc (MAX (1, L->n) * sizeof (Int)) ;
    ok = check_factor (Wi, CHOLMOD(dump), name, L, Common) ;
    if (Wi != NULL) free (Wi) ;
    return (ok) ;
}


/* ========================================================================== */
/* === cholmod_dump_perm ==================================================== */
/* ========================================================================== */

int CHOLMOD(dump_perm)
(
    Int *Perm,
    size_t len,
    size_t n,
    char *name,
    cholmod_common *Common
)
{
    Int *Wi ;
    int ok ;

    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }
    RETURN_IF_NULL_COMMON (FALSE) ;
    Wi = malloc (MAX (1, n) * sizeof (Int)) ;
    ok = check_perm (Wi, CHOLMOD(dump), name, Perm, len, n,Common) ;
    if (Wi != NULL) free (Wi) ;
    return (ok) ;
}


/* ========================================================================== */
/* === cholmod_dump_dense =================================================== */
/* ========================================================================== */

int CHOLMOD(dump_dense)
(
    cholmod_dense *X,
    char *name,
    cholmod_common *Common
)
{
    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }
    RETURN_IF_NULL_COMMON (FALSE) ;
    return (check_dense (CHOLMOD(dump), name, X, Common)) ;
}


/* ========================================================================== */
/* === cholmod_dump_triplet ================================================= */
/* ========================================================================== */

int CHOLMOD(dump_triplet)
(
    cholmod_triplet *T,
    char *name,
    cholmod_common *Common
)
{
    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }
    RETURN_IF_NULL_COMMON (FALSE) ;
    return (check_triplet (CHOLMOD(dump), name, T, Common)) ;
}


/* ========================================================================== */
/* === cholmod_dump_subset ================================================== */
/* ========================================================================== */

int CHOLMOD(dump_subset)
(
    Int *S,
    size_t len,
    size_t n,
    char *name,
    cholmod_common *Common
)
{
    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }
    RETURN_IF_NULL_COMMON (FALSE) ;
    return (check_subset (S, len, n, CHOLMOD(dump), name, Common)) ;
}


/* ========================================================================== */
/* === cholmod_dump_parent ================================================== */
/* ========================================================================== */

int CHOLMOD(dump_parent)
(
    Int *Parent,
    size_t n,
    char *name,
    cholmod_common *Common
)
{
    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }
    RETURN_IF_NULL_COMMON (FALSE) ;
    return (check_parent (Parent, n, CHOLMOD(dump), name, Common)) ;
}


/* ========================================================================== */
/* === cholmod_dump_real ==================================================== */
/* ========================================================================== */

void CHOLMOD(dump_real)
(
    char *name, Real *X, long nrow, long ncol, int lower, int xentry,
    cholmod_common *Common
)
{
    /* dump an nrow-by-ncol real dense matrix */
    long i, j ;
    double x, z ;
    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return ;
    }
    PRINT1 (("%s: dump_real, nrow: %ld ncol: %ld lower: %d\n",
        name, nrow, ncol, lower)) ;
    for (j = 0 ; j < ncol ; j++)
    {
    PRINT2 (("    col %ld\n", j)) ;
    for (i = 0 ; i < nrow ; i++)
    {
        /* X is stored in column-major form */
        if (lower && i < j)
        {
        PRINT2 (("        %5ld: -", i)) ;
        }
        else
        {
        x = *X ;
        PRINT2 (("        %5ld: %e", i, x)) ;
        if (xentry == 2)
        {
            z = *(X+1) ;
            PRINT2 ((", %e", z)) ;
        }
        }
        PRINT2 (("\n")) ;
        X += xentry ;
    }
    }
}


/* ========================================================================== */
/* === cholmod_dump_super =================================================== */
/* ========================================================================== */

void CHOLMOD(dump_super)
(
    long s,
    Int *Super, Int *Lpi, Int *Ls, Int *Lpx, double *Lx,
    int xentry,
    cholmod_common *Common
)
{
    Int k1, k2, do_values, psi, psx, nsrow, nscol, psend, ilast, p, i ;
    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return ;
    }
    k1 = Super [s] ;
    k2 = Super [s+1] ;
    nscol = k2 - k1 ;
    do_values = (Lpx != NULL) && (Lx != NULL) ;
    psi = Lpi [s] ;
    psend = Lpi [s+1] ;
    nsrow = psend - psi ;
    PRINT1 (("\nSuper %ld, columns "ID" to "ID", "ID" rows "ID" cols\n",
        s, k1, k2-1, nsrow, nscol)) ;
    ilast = -1 ;
    for (p = psi ; p < psend ; p++)
    {
    i = Ls [p] ;
    PRINT2 (("  "ID" : p-psi "ID"\n", i, p-psi)) ;
    ASSERT (IMPLIES (p-psi < nscol, i == k1 + (p-psi))) ;
    if (p-psi == nscol-1) PRINT2 (("------\n")) ;
    ASSERT (i > ilast) ;
    ilast = i ;
    }
    if (do_values)
    {
    psx = Lpx [s] ;
    CHOLMOD(dump_real) ("Supernode", Lx + xentry*psx, nsrow, nscol, TRUE, 
        xentry, Common) ;
    }
}


/* ========================================================================== */
/* === cholmod_dump_mem ===================================================== */
/* ========================================================================== */

int CHOLMOD(dump_mem) (char *where, long should, cholmod_common *Common)
{
    long diff = should - Common->memory_inuse ;
    if (diff != 0)
    {
    PRINT0 (("mem: %-15s peak %10ld inuse %10ld should %10ld\n",
        where, (long) Common->memory_usage, (long) Common->memory_inuse,
        should)) ;
    PRINT0 (("mem: %s diff %ld !\n", where, diff)) ;
    }
    return (diff == 0) ;
}


/* ========================================================================== */
/* === cholmod_dump_partition =============================================== */
/* ========================================================================== */

/* make sure we have a proper separator (for debugging only)
 *
 * workspace: none
 */

int CHOLMOD(dump_partition)
(
    long n,
    Int *Cp,
    Int *Ci,
    Int *Cnw,
    Int *Part,
    long sepsize,
    cholmod_common *Common
)
{
    Int chek [3], which, ok, i, j, p ;
    PRINT1 (("bisect sepsize %ld\n", sepsize)) ;
    ok = TRUE ;
    chek [0] = 0 ;
    chek [1] = 0 ;
    chek [2] = 0 ;
    for (j = 0 ; j < n ; j++)
    {
    PRINT2 (("--------j "ID" in part "ID" nw "ID"\n", j, Part [j], Cnw[j]));
    which = Part [j] ;
    for (p = Cp [j] ; p < Cp [j+1] ; p++)
    {
        i = Ci [p] ;
        PRINT3 (("i "ID", part "ID"\n", i, Part [i])) ;
        if (which == 0)
        {
        if (Part [i] == 1)
        {
            PRINT0 (("Error! "ID" "ID"\n", i, j)) ;
            ok = FALSE ;
        }
        }
        else if (which == 1)
        {
        if (Part [i] == 0)
        {
            PRINT0 (("Error! "ID" "ID"\n", i, j)) ;
            ok = FALSE ;
        }
        }
    }
    if (which < 0 || which > 2)
    {
        PRINT0 (("Part out of range\n")) ;
        ok = FALSE ;
    }
    chek [which] += Cnw [j] ;
    }
    PRINT1 (("sepsize %ld check "ID" "ID" "ID"\n",
        sepsize, chek[0], chek[1],chek[2]));
    if (sepsize != chek[2])
    {
    PRINT0 (("mismatch!\n")) ;
    ok = FALSE ;
    }
    return (ok) ;
}


/* ========================================================================== */
/* === cholmod_dump_work ==================================================== */
/* ========================================================================== */

int CHOLMOD(dump_work) (int flag, int head, long wsize, cholmod_common *Common)
{
    double *W ;
    Int *Flag, *Head ;
    Int k, nrow, mark ;

    if (CHOLMOD(dump) < -1)
    {
    /* no checks if debug level is -2 or less */
    return (TRUE) ;
    }

    RETURN_IF_NULL_COMMON (FALSE) ;
    nrow = Common->nrow ;
    Flag = Common->Flag ;
    Head = Common->Head ;
    W = Common->Xwork ;
    mark = Common->mark ;
    
    if (wsize < 0)
    {
    /* check all of Xwork */
    wsize = Common->xworksize ;
    }
    else
    {
    /* check on the first wsize doubles in Xwork */
    wsize = MIN (wsize, (Int) (Common->xworksize)) ;
    }

    if (flag)
    {
    for (k = 0 ; k < nrow ; k++)
    {
        if (Flag [k] >= mark)
        {
        PRINT0 (("Flag invalid, Flag ["ID"] = "ID", mark = "ID"\n",
                k, Flag [k], mark)) ;
        ASSERT (0) ;
        return (FALSE) ;
        }
    }
    }

    if (head)
    {
    for (k = 0 ; k < nrow ; k++)
    {
        if (Head [k] != EMPTY)
        {
        PRINT0 (("Head invalid, Head ["ID"] = "ID"\n", k, Head [k])) ;
        ASSERT (0) ;
        return (FALSE) ;
        }
    }
    }

    for (k = 0 ; k < wsize ; k++)
    {
    if (W [k] != 0.)
    {
        PRINT0 (("W invalid, W ["ID"] = %g\n", k, W [k])) ;
        ASSERT (0) ;
        return (FALSE) ;
    }
    }

    return (TRUE) ;
}
#endif
#endif