/* ========================================================================== */
/* === Check/cholmod_check ================================================== */
/* ========================================================================== */
/* -----------------------------------------------------------------------------
* CHOLMOD/Check Module. Copyright (C) 2005-2006, 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_internal.h"
#include "cholmod_check.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) (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 ;
UF_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 (".%d", CHOLMOD_SUBSUB_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(UF_long): %d\n", (int) sizeof (UF_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: %8.0f\n", (double) (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
if (Common->default_nesdis)
{
P3 ("%s", " Try NESDIS if AMD reports flops/nnz(L) >= 500 and "
"nnz(L)/nnz(A) >= 5.\n") ;
}
else
{
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: %g\n", (double) (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 <= %g) or (no new zero entries) or\n",
(double) (Common->nrelax [0])) ;
P4 (" (s <= %g and ", (double) (Common->nrelax [1])) ;
P4 ("z < %.5g%%) or", Common->zrelax [0] * 100) ;
P4 (" (s <= %g and ", (double) (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 UF_long check_sparse
(
Int *Wi,
Int print,
char *name,
cholmod_sparse *A,
UF_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 ("mixed int/UF_long type unsupported") ;
case CHOLMOD_LONG: P4 ("%s", "\n scalar types: UF_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 (packed && (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 ;
}
/* Note that space can be negative if the matrix is non-monotonic */
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)
{
ERR ("pointer invalid") ;
}
if (nz < 0 || nz > nrow)
{
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
)
{
UF_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
)
{
UF_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,
UF_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 */
UF_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 */
UF_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 ("mixed int/UF_long type unsupported") ;
case CHOLMOD_LONG: P4 ("%s", "\n scalar types: UF_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 ("mixed int/UF_long type unsupported") ;
case CHOLMOD_LONG: P4 ("%s", "\n scalar types: UF_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 ================================================== */
/* ========================================================================== */
UF_long CHOLMOD(dump_sparse) /* returns nnz (diag (A)) or EMPTY if error */
(
cholmod_sparse *A,
char *name,
cholmod_common *Common
)
{
Int *Wi ;
UF_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, UF_long nrow, UF_long ncol, int lower, int xentry,
cholmod_common *Common
)
{
/* dump an nrow-by-ncol real dense matrix */
UF_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)
(
UF_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, UF_long should, cholmod_common *Common)
{
UF_long diff = should - Common->memory_inuse ;
if (diff != 0)
{
PRINT0 (("mem: %-15s peak %10g inuse %10g should %10g\n",
where, (double) Common->memory_usage, (double) Common->memory_inuse,
(double) 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)
(
UF_long n,
Int *Cp,
Int *Ci,
Int *Cnw,
Int *Part,
UF_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, UF_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
syntax highlighted by Code2HTML, v. 0.9.1