diff --git a/Makefile.am b/Makefile.am index a9cb84897..ff5fec1b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,15 +11,14 @@ ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = foreign nostdinc # All the sub-directories that need to be built -SUBDIRS = CppUnitLite colamd spqr_mini base geometry inference linear nonlinear slam . tests wrap examples +SUBDIRS = CppUnitLite base geometry inference linear nonlinear slam . tests wrap examples # And the corresponding libraries produced -SUBLIBS = colamd/libcolamd.la \ - base/libbase.la geometry/libgeometry.la inference/libinference.la \ +SUBLIBS = base/libbase.la geometry/libgeometry.la inference/libinference.la \ linear/liblinear.la nonlinear/libnonlinear.la slam/libslam.la if USE_LAPACK -SUBLIBS += spqr_mini/libspqr_mini.la +SUBLIBS += -L$(SparseLib) -lcholmod -lspqr endif # TODO: UFconfig, CCOLAMD, and LDL automake magic without adding or touching any file @@ -31,7 +30,7 @@ endif lib_LTLIBRARIES = libgtsam.la libgtsam_la_SOURCES = nodist_EXTRA_libgtsam_la_SOURCES = dummy.cxx -libgtsam_la_LIBADD = $(SUBLIBS) +libgtsam_la_LIBADD = $(SUBLIBS) -L$(SparseLib) -lcolamd -lccolamd libgtsam_la_LDFLAGS = -no-undefined -version-info 0:0:0 if USE_ACCELERATE_MACOS diff --git a/base/Makefile.am b/base/Makefile.am index 673c8f1e8..9e3770fc8 100644 --- a/base/Makefile.am +++ b/base/Makefile.am @@ -50,7 +50,7 @@ base_HEADERS = $(headers) noinst_LTLIBRARIES = libbase.la libbase_la_SOURCES = $(sources) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. if USE_BLAS AM_CPPFLAGS += -DGT_USE_CBLAS @@ -70,7 +70,7 @@ endif #---------------------------------------------------------------------------------------------------- TESTS = $(check_PROGRAMS) AM_DEFAULT_SOURCE_EXT = .cpp -AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) +AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) LDADD = libbase.la ../CppUnitLite/libCppUnitLite.a if USE_BLAS_LINUX @@ -78,7 +78,7 @@ AM_LDFLAGS += -lcblas -latlas endif if USE_LAPACK -LDADD += ../spqr_mini/libspqr_mini.la +AM_LDFLAGS += -L$(SparseLib) -lcholmod -lspqr endif if USE_LAPACK_LINUX diff --git a/base/SPQRUtil.h b/base/SPQRUtil.h index 257b5232a..0a1254c79 100644 --- a/base/SPQRUtil.h +++ b/base/SPQRUtil.h @@ -11,7 +11,10 @@ #include #ifdef GT_USE_LAPACK -#include +extern "C" { +#include +} +#include namespace gtsam { diff --git a/colamd/Makefile.am b/colamd/Makefile.am deleted file mode 100644 index 97596f6a5..000000000 --- a/colamd/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -#---------------------------------------------------------------------------------------------------- -# colamd -# replaced Makefile with automake for easy linking -#---------------------------------------------------------------------------------------------------- - -# Create a libtool library that is not installed -# It will be packaged in the toplevel libgtsam.la as specfied in ../Makefile.am -noinst_LTLIBRARIES = libcolamd.la - -# We normally would not install these headers -# but they are included in the templated class FactorGraph-inl.h so we need them -colamddir = $(pkgincludedir)/colamd -colamd_HEADERS = colamd.h ccolamd.h UFconfig.h - -# These are the sources for the library: -libcolamd_la_SOURCES = colamd.c colamd_global.c ccolamd.c ccolamd_global.c diff --git a/colamd/UFconfig.h b/colamd/UFconfig.h deleted file mode 100755 index 54208d58b..000000000 --- a/colamd/UFconfig.h +++ /dev/null @@ -1,118 +0,0 @@ -/* ========================================================================== */ -/* === UFconfig.h =========================================================== */ -/* ========================================================================== */ - -/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages - * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others). - * - * UFconfig.h provides the definition of the long integer. On most systems, - * a C program can be compiled in LP64 mode, in which long's and pointers are - * both 64-bits, and int's are 32-bits. Windows 64, however, uses the LLP64 - * model, in which int's and long's are 32-bits, and long long's and pointers - * are 64-bits. - * - * SuiteSparse packages that include long integer versions are - * intended for the LP64 mode. However, as a workaround for Windows 64 - * (and perhaps other systems), the long integer can be redefined. - * - * If _WIN64 is defined, then the __int64 type is used instead of long. - * - * The long integer can also be defined at compile time. For example, this - * could be added to UFconfig.mk: - * - * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \ - * -D'UF_long_id="%lld"' - * - * This file defines UF_long as either long (on all but _WIN64) or - * __int64 on Windows 64. The intent is that a UF_long is always a 64-bit - * integer in a 64-bit code. ptrdiff_t might be a better choice than long; - * it is always the same size as a pointer. - * - * This file also defines the SUITESPARSE_VERSION and related definitions. - * - * Copyright (c) 2007, University of Florida. No licensing restrictions - * apply to this file or to the UFconfig directory. Author: Timothy A. Davis. - */ - -#ifndef _UFCONFIG_H -#define _UFCONFIG_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* ========================================================================== */ -/* === UF_long ============================================================== */ -/* ========================================================================== */ - -#ifndef UF_long - -#ifdef _WIN64 - -#define UF_long __int64 -#define UF_long_max _I64_MAX -#define UF_long_id "%I64d" - -#else - -#define UF_long long -#define UF_long_max LONG_MAX -#define UF_long_id "%ld" - -#endif -#endif - -/* ========================================================================== */ -/* === SuiteSparse version ================================================== */ -/* ========================================================================== */ - -/* SuiteSparse is not a package itself, but a collection of packages, some of - * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD, - * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the - * collection itself. The versions of packages within each version of - * SuiteSparse are meant to work together. Combining one packge from one - * version of SuiteSparse, with another package from another version of - * SuiteSparse, may or may not work. - * - * SuiteSparse Version 3.2.0 contains the following packages: - * - * AMD version 2.2.0 - * CAMD version 2.2.0 - * COLAMD version 2.7.1 - * CCOLAMD version 2.7.1 - * CHOLMOD version 1.7.0 - * CSparse version 2.2.1 - * CXSparse version 2.2.1 - * KLU version 1.0.1 - * BTF version 1.0.1 - * LDL version 2.0.1 - * UFconfig version number is the same as SuiteSparse - * UMFPACK version 5.2.0 - * RBio version 1.1.1 - * UFcollection version 1.1.1 - * LINFACTOR version 1.1.0 - * MESHND version 1.1.0 - * SSMULT version 1.1.0 - * MATLAB_Tools no specific version number - * SuiteSparseQR version 1.1.0 - * - * Other package dependencies: - * BLAS required by CHOLMOD and UMFPACK - * LAPACK required by CHOLMOD - * METIS 4.0.1 required by CHOLMOD (optional) and KLU (optional) - */ - -#define SUITESPARSE_DATE "Sept 20, 2008" -#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_MAIN_VERSION 3 -#define SUITESPARSE_SUB_VERSION 2 -#define SUITESPARSE_SUBSUB_VERSION 0 -#define SUITESPARSE_VERSION \ - SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/colamd/ccolamd.c b/colamd/ccolamd.c deleted file mode 100644 index bfcb29729..000000000 --- a/colamd/ccolamd.c +++ /dev/null @@ -1,4620 +0,0 @@ -/* ========================================================================== */ -/* === CCOLAMD/CSYMAMD - a constrained column ordering algorithm ============ */ -/* ========================================================================== */ - -/* ---------------------------------------------------------------------------- - * CCOLAMD, Copyright (C) Univ. of Florida. Authors: Timothy A. Davis, - * Sivasankaran Rajamanickam, and Stefan Larimore - * See License.txt for the Version 2.1 of the GNU Lesser General Public License - * http://www.cise.ufl.edu/research/sparse - * -------------------------------------------------------------------------- */ - -/* - * ccolamd: a constrained approximate minimum degree column ordering - * algorithm, LU factorization of symmetric or unsymmetric matrices, - * QR factorization, least squares, interior point methods for - * linear programming problems, and other related problems. - * - * csymamd: a constrained approximate minimum degree ordering algorithm for - * Cholesky factorization of symmetric matrices. - * - * Purpose: - * - * CCOLAMD computes a permutation Q such that the Cholesky factorization of - * (AQ)'(AQ) has less fill-in and requires fewer floating point operations - * than A'A. This also provides a good ordering for sparse partial - * pivoting methods, P(AQ) = LU, where Q is computed prior to numerical - * factorization, and P is computed during numerical factorization via - * conventional partial pivoting with row interchanges. CCOLAMD is an - * extension of COLAMD, available as built-in function in MATLAB Version 6, - * available from MathWorks, Inc. (http://www.mathworks.com). This - * routine can be used in place of COLAMD in MATLAB. - * - * CSYMAMD computes a permutation P of a symmetric matrix A such that the - * Cholesky factorization of PAP' has less fill-in and requires fewer - * floating point operations than A. CSYMAMD constructs a matrix M such - * that M'M has the same nonzero pattern of A, and then orders the columns - * of M using colmmd. The column ordering of M is then returned as the - * row and column ordering P of A. CSYMAMD is an extension of SYMAMD. - * - * Authors: - * - * Timothy A. Davis and S. Rajamanickam wrote CCOLAMD, based directly on - * COLAMD by Stefan I. Larimore and Timothy A. Davis, University of - * Florida. The algorithm was developed in collaboration with John - * Gilbert, (UCSB, then at Xerox PARC), and Esmond Ng, (Lawrence Berkeley - * National Lab, then at Oak Ridge National Laboratory). - * - * Acknowledgements: - * - * This work was supported by the National Science Foundation, under - * grants DMS-9504974 and DMS-9803599, CCR-0203270, and a grant from the - * Sandia National Laboratory (Dept. of Energy). - * - * Copyright and License: - * - * Copyright (c) 1998-2005 by the University of Florida. - * All Rights Reserved. - * COLAMD is also available under alternate licenses, contact T. Davis - * for details. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - * USA - * - * Permission is hereby granted to use or copy this program under the - * terms of the GNU LGPL, provided that the Copyright, this License, - * and the Availability of the original version is retained on all copies. - * User documentation of any code that uses this code or any modified - * version of this code must cite the Copyright, this License, the - * Availability note, and "Used by permission." Permission to modify - * the code and to distribute modified code is granted, provided the - * Copyright, this License, and the Availability note are retained, - * and a notice that the code was modified is included. - * - * Availability: - * - * The CCOLAMD/CSYMAMD library is available at - * - * http://www.cise.ufl.edu/research/sparse/ccolamd/ - * - * This is the http://www.cise.ufl.edu/research/sparse/ccolamd/ccolamd.c - * file. - * - * See the ChangeLog file for changes since Version 1.0. - */ - -/* ========================================================================== */ -/* === Description of user-callable routines ================================ */ -/* ========================================================================== */ - -/* CCOLAMD includes both int and UF_long versions of all its routines. The - * description below is for the int version. For UF_long, all int arguments - * become UF_long integers. UF_long is normally defined as long, except for - * WIN64 */ - -/* ---------------------------------------------------------------------------- - * ccolamd_recommended: - * ---------------------------------------------------------------------------- - * - * C syntax: - * - * #include "ccolamd.h" - * size_t ccolamd_recommended (int nnz, int n_row, int n_col) ; - * size_t ccolamd_l_recommended (UF_long nnz, UF_long n_row, - * UF_long n_col) ; - * - * Purpose: - * - * Returns recommended value of Alen for use by ccolamd. Returns 0 - * if any input argument is negative. The use of this routine - * is optional. Not needed for csymamd, which dynamically allocates - * its own memory. - * - * Arguments (all input arguments): - * - * int nnz ; Number of nonzeros in the matrix A. This must - * be the same value as p [n_col] in the call to - * ccolamd - otherwise you will get a wrong value - * of the recommended memory to use. - * - * int n_row ; Number of rows in the matrix A. - * - * int n_col ; Number of columns in the matrix A. - * - * ---------------------------------------------------------------------------- - * ccolamd_set_defaults: - * ---------------------------------------------------------------------------- - * - * C syntax: - * - * #include "ccolamd.h" - * ccolamd_set_defaults (double knobs [CCOLAMD_KNOBS]) ; - * ccolamd_l_set_defaults (double knobs [CCOLAMD_KNOBS]) ; - * - * Purpose: - * - * Sets the default parameters. The use of this routine is optional. - * Passing a (double *) NULL pointer for the knobs results in the - * default parameter settings. - * - * Arguments: - * - * double knobs [CCOLAMD_KNOBS] ; Output only. - * - * knobs [0] and knobs [1] behave differently than they did in COLAMD. - * The other knobs are new to CCOLAMD. - * - * knobs [0]: dense row control - * - * For CCOLAMD, rows with more than - * max (16, knobs [CCOLAMD_DENSE_ROW] * sqrt (n_col)) - * entries are removed prior to ordering. - * - * For CSYMAMD, rows and columns with more than - * max (16, knobs [CCOLAMD_DENSE_ROW] * sqrt (n)) - * entries are removed prior to ordering, and placed last in the - * output ordering (subject to the constraints). - * - * If negative, only completely dense rows are removed. If you - * intend to use CCOLAMD for a Cholesky factorization of A*A', set - * knobs [CCOLAMD_DENSE_ROW] to -1, which is more appropriate for - * that case. - * - * Default: 10. - * - * knobs [1]: dense column control - * - * For CCOLAMD, columns with more than - * max (16, knobs [CCOLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col))) - * entries are removed prior to ordering, and placed last in the - * output column ordering (subject to the constraints). - * Not used by CSYMAMD. If negative, only completely dense - * columns are removed. Default: 10. - * - * knobs [2]: aggressive absorption - * - * knobs [CCOLAMD_AGGRESSIVE] controls whether or not to do - * aggressive absorption during the ordering. Default is TRUE - * (nonzero). If zero, no aggressive absorption is performed. - * - * knobs [3]: optimize ordering for LU or Cholesky - * - * knobs [CCOLAMD_LU] controls an option that optimizes the - * ordering for the LU of A or the Cholesky factorization of A'A. - * If TRUE (nonzero), an ordering optimized for LU is performed. - * If FALSE (zero), an ordering for Cholesky is performed. - * Default is FALSE. CSYMAMD ignores this parameter; it always - * orders for Cholesky. - * - * ---------------------------------------------------------------------------- - * ccolamd: - * ---------------------------------------------------------------------------- - * - * C syntax: - * - * #include "ccolamd.h" - * int ccolamd (int n_row, int n_col, int Alen, int *A, int *p, - * double knobs [CCOLAMD_KNOBS], int stats [CCOLAMD_STATS], - * int *cmember) ; - * - * UF_long ccolamd_l (UF_long n_row, UF_long n_col, UF_long Alen, - * UF_long *A, UF_long *p, double knobs [CCOLAMD_KNOBS], - * UF_long stats [CCOLAMD_STATS], UF_long *cmember) ; - * - * Purpose: - * - * Computes a column ordering (Q) of A such that P(AQ)=LU or - * (AQ)'AQ=LL' have less fill-in and require fewer floating point - * operations than factorizing the unpermuted matrix A or A'A, - * respectively. - * - * Returns: - * - * TRUE (1) if successful, FALSE (0) otherwise. - * - * Arguments (for int version): - * - * int n_row ; Input argument. - * - * Number of rows in the matrix A. - * Restriction: n_row >= 0. - * ccolamd returns FALSE if n_row is negative. - * - * int n_col ; Input argument. - * - * Number of columns in the matrix A. - * Restriction: n_col >= 0. - * ccolamd returns FALSE if n_col is negative. - * - * int Alen ; Input argument. - * - * Restriction (see note): - * Alen >= MAX (2*nnz, 4*n_col) + 17*n_col + 7*n_row + 7, where - * nnz = p [n_col]. ccolamd returns FALSE if this condition is - * not met. We recommend about nnz/5 more space for better - * efficiency. This restriction makes an modest assumption - * regarding the size of two typedef'd structures in ccolamd.h. - * We do, however, guarantee that - * - * Alen >= ccolamd_recommended (nnz, n_row, n_col) - * - * will work efficiently. - * - * int A [Alen] ; Input argument, undefined on output. - * - * A is an integer array of size Alen. Alen must be at least as - * large as the bare minimum value given above, but this is very - * low, and can result in excessive run time. For best - * performance, we recommend that Alen be greater than or equal to - * ccolamd_recommended (nnz, n_row, n_col), which adds - * nnz/5 to the bare minimum value given above. - * - * On input, the row indices of the entries in column c of the - * matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices - * in a given column c need not be in ascending order, and - * duplicate row indices may be be present. However, ccolamd will - * work a little faster if both of these conditions are met - * (ccolamd puts the matrix into this format, if it finds that the - * the conditions are not met). - * - * The matrix is 0-based. That is, rows are in the range 0 to - * n_row-1, and columns are in the range 0 to n_col-1. ccolamd - * returns FALSE if any row index is out of range. - * - * The contents of A are modified during ordering, and are - * undefined on output. - * - * int p [n_col+1] ; Both input and output argument. - * - * p is an integer array of size n_col+1. On input, it holds the - * "pointers" for the column form of the matrix A. Column c of - * the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first - * entry, p [0], must be zero, and p [c] <= p [c+1] must hold - * for all c in the range 0 to n_col-1. The value nnz = p [n_col] - * is thus the total number of entries in the pattern of the - * matrix A. ccolamd returns FALSE if these conditions are not - * met. - * - * On output, if ccolamd returns TRUE, the array p holds the column - * permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is - * the first column index in the new ordering, and p [n_col-1] is - * the last. That is, p [k] = j means that column j of A is the - * kth pivot column, in AQ, where k is in the range 0 to n_col-1 - * (p [0] = j means that column j of A is the first column in AQ). - * - * If ccolamd returns FALSE, then no permutation is returned, and - * p is undefined on output. - * - * double knobs [CCOLAMD_KNOBS] ; Input argument. - * - * See ccolamd_set_defaults for a description. - * - * int stats [CCOLAMD_STATS] ; Output argument. - * - * Statistics on the ordering, and error status. - * See ccolamd.h for related definitions. - * ccolamd returns FALSE if stats is not present. - * - * stats [0]: number of dense or empty rows ignored. - * - * stats [1]: number of dense or empty columns ignored (and - * ordered last in the output permutation p, subject to the - * constraints). Note that a row can become "empty" if it - * contains only "dense" and/or "empty" columns, and similarly - * a column can become "empty" if it only contains "dense" - * and/or "empty" rows. - * - * stats [2]: number of garbage collections performed. This can - * be excessively high if Alen is close to the minimum - * required value. - * - * stats [3]: status code. < 0 is an error code. - * > 1 is a warning or notice. - * - * 0 OK. Each column of the input matrix contained row - * indices in increasing order, with no duplicates. - * - * 1 OK, but columns of input matrix were jumbled (unsorted - * columns or duplicate entries). CCOLAMD had to do some - * extra work to sort the matrix first and remove - * duplicate entries, but it still was able to return a - * valid permutation (return value of ccolamd was TRUE). - * - * stats [4]: highest column index of jumbled columns - * stats [5]: last seen duplicate or unsorted row index - * stats [6]: number of duplicate or unsorted row indices - * - * -1 A is a null pointer - * - * -2 p is a null pointer - * - * -3 n_row is negative. stats [4]: n_row - * - * -4 n_col is negative. stats [4]: n_col - * - * -5 number of nonzeros in matrix is negative - * - * stats [4]: number of nonzeros, p [n_col] - * - * -6 p [0] is nonzero - * - * stats [4]: p [0] - * - * -7 A is too small - * - * stats [4]: required size - * stats [5]: actual size (Alen) - * - * -8 a column has a negative number of entries - * - * stats [4]: column with < 0 entries - * stats [5]: number of entries in col - * - * -9 a row index is out of bounds - * - * stats [4]: column with bad row index - * stats [5]: bad row index - * stats [6]: n_row, # of rows of matrx - * - * -10 (unused; see csymamd) - * - * int cmember [n_col] ; Input argument. - * - * cmember is new to CCOLAMD. It did not appear in COLAMD. - * It places contraints on the output ordering. s = cmember [j] - * gives the constraint set s that contains the column j - * (Restriction: 0 <= s < n_col). In the output column - * permutation, all columns in set 0 appear first, followed by - * all columns in set 1, and so on. If NULL, all columns are - * treated as if they were in a single constraint set, and you - * will obtain the same ordering as COLAMD (with one exception: - * the dense row/column threshold and other default knobs in - * CCOLAMD and COLAMD are different). - * - * Example: - * - * See - * http://www.cise.ufl.edu/research/sparse/ccolamd/ccolamd_example.c - * for a complete example. - * - * To order the columns of a 5-by-4 matrix with 11 nonzero entries in - * the following nonzero pattern - * - * x 0 x 0 - * x 0 x x - * 0 x x 0 - * 0 0 x x - * x x 0 0 - * - * with default knobs, no output statistics, and no ordering - * constraints, do the following: - * - * #include "ccolamd.h" - * #define ALEN 144 - * int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; - * int p [ ] = {0, 3, 5, 9, 11} ; - * int stats [CCOLAMD_STATS] ; - * ccolamd (5, 4, ALEN, A, p, (double *) NULL, stats, NULL) ; - * - * The permutation is returned in the array p, and A is destroyed. - * - * ---------------------------------------------------------------------------- - * csymamd: - * ---------------------------------------------------------------------------- - * - * C syntax: - * - * #include "ccolamd.h" - * - * int csymamd (int n, int *A, int *p, int *perm, - * double knobs [CCOLAMD_KNOBS], int stats [CCOLAMD_STATS], - * void (*allocate) (size_t, size_t), void (*release) (void *), - * int *cmember, int stype) ; - * - * UF_long csymamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm, - * double knobs [CCOLAMD_KNOBS], UF_long stats [CCOLAMD_STATS], - * void (*allocate) (size_t, size_t), void (*release) (void *), - * UF_long *cmember, UF_long stype) ; - * - * Purpose: - * - * The csymamd routine computes an ordering P of a symmetric sparse - * matrix A such that the Cholesky factorization PAP' = LL' remains - * sparse. It is based on a column ordering of a matrix M constructed - * so that the nonzero pattern of M'M is the same as A. Either the - * lower or upper triangular part of A can be used, or the pattern - * A+A' can be used. You must pass your selected memory allocator - * (usually calloc/free or mxCalloc/mxFree) to csymamd, for it to - * allocate memory for the temporary matrix M. - * - * Returns: - * - * TRUE (1) if successful, FALSE (0) otherwise. - * - * Arguments: - * - * int n ; Input argument. - * - * Number of rows and columns in the symmetrix matrix A. - * Restriction: n >= 0. - * csymamd returns FALSE if n is negative. - * - * int A [nnz] ; Input argument. - * - * A is an integer array of size nnz, where nnz = p [n]. - * - * The row indices of the entries in column c of the matrix are - * held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a - * given column c need not be in ascending order, and duplicate - * row indices may be present. However, csymamd will run faster - * if the columns are in sorted order with no duplicate entries. - * - * The matrix is 0-based. That is, rows are in the range 0 to - * n-1, and columns are in the range 0 to n-1. csymamd - * returns FALSE if any row index is out of range. - * - * The contents of A are not modified. - * - * int p [n+1] ; Input argument. - * - * p is an integer array of size n+1. On input, it holds the - * "pointers" for the column form of the matrix A. Column c of - * the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first - * entry, p [0], must be zero, and p [c] <= p [c+1] must hold - * for all c in the range 0 to n-1. The value p [n] is - * thus the total number of entries in the pattern of the matrix A. - * csymamd returns FALSE if these conditions are not met. - * - * The contents of p are not modified. - * - * int perm [n+1] ; Output argument. - * - * On output, if csymamd returns TRUE, the array perm holds the - * permutation P, where perm [0] is the first index in the new - * ordering, and perm [n-1] is the last. That is, perm [k] = j - * means that row and column j of A is the kth column in PAP', - * where k is in the range 0 to n-1 (perm [0] = j means - * that row and column j of A are the first row and column in - * PAP'). The array is used as a workspace during the ordering, - * which is why it must be of length n+1, not just n. - * - * double knobs [CCOLAMD_KNOBS] ; Input argument. - * - * See colamd_set_defaults for a description. - * - * int stats [CCOLAMD_STATS] ; Output argument. - * - * Statistics on the ordering, and error status. - * See ccolamd.h for related definitions. - * csymand returns FALSE if stats is not present. - * - * stats [0]: number of dense or empty row and columns ignored - * (and ordered last in the output permutation perm, subject - * to the constraints). Note that a row/column can become - * "empty" if it contains only "dense" and/or "empty" - * columns/rows. - * - * stats [1]: (same as stats [0]) - * - * stats [2]: number of garbage collections performed. - * - * stats [3]: status code. < 0 is an error code. - * > 1 is a warning or notice. - * - * 0 to -9: same as ccolamd, with n replacing n_col and n_row, - * and -3 and -7 are unused. - * - * -10 out of memory (unable to allocate temporary workspace - * for M or count arrays using the "allocate" routine - * passed into csymamd). - * - * void * (*allocate) (size_t, size_t) - * - * A pointer to a function providing memory allocation. The - * allocated memory must be returned initialized to zero. For a - * C application, this argument should normally be a pointer to - * calloc. For a MATLAB mexFunction, the routine mxCalloc is - * passed instead. - * - * void (*release) (size_t, size_t) - * - * A pointer to a function that frees memory allocated by the - * memory allocation routine above. For a C application, this - * argument should normally be a pointer to free. For a MATLAB - * mexFunction, the routine mxFree is passed instead. - * - * int cmember [n] ; Input argument. - * - * Same as ccolamd, except that cmember is of size n, and it places - * contraints symmetrically, on both the row and column ordering. - * Entries in cmember must be in the range 0 to n-1. - * - * int stype ; Input argument. - * - * If stype < 0, then only the strictly lower triangular part of - * A is accessed. The upper triangular part is assumed to be the - * transpose of the lower triangular part. This is the same as - * SYMAMD, which did not have an stype parameter. - * - * If stype > 0, only the strictly upper triangular part of A is - * accessed. The lower triangular part is assumed to be the - * transpose of the upper triangular part. - * - * If stype == 0, then the nonzero pattern of A+A' is ordered. - * - * ---------------------------------------------------------------------------- - * ccolamd_report: - * ---------------------------------------------------------------------------- - * - * C syntax: - * - * #include "ccolamd.h" - * ccolamd_report (int stats [CCOLAMD_STATS]) ; - * ccolamd_l_report (UF_long stats [CCOLAMD_STATS]) ; - * - * Purpose: - * - * Prints the error status and statistics recorded in the stats - * array on the standard error output (for a standard C routine) - * or on the MATLAB output (for a mexFunction). - * - * Arguments: - * - * int stats [CCOLAMD_STATS] ; Input only. Statistics from ccolamd. - * - * - * ---------------------------------------------------------------------------- - * csymamd_report: - * ---------------------------------------------------------------------------- - * - * C syntax: - * - * #include "ccolamd.h" - * csymamd_report (int stats [CCOLAMD_STATS]) ; - * csymamd_l_report (UF_long stats [CCOLAMD_STATS]) ; - * - * Purpose: - * - * Prints the error status and statistics recorded in the stats - * array on the standard error output (for a standard C routine) - * or on the MATLAB output (for a mexFunction). - * - * Arguments: - * - * int stats [CCOLAMD_STATS] ; Input only. Statistics from csymamd. - * - */ - - -/* ========================================================================== */ -/* === Scaffolding code definitions ======================================== */ -/* ========================================================================== */ - -/* Ensure that debugging is turned off: */ -#ifndef SPQR_NDEBUG -#define SPQR_NDEBUG -#endif - -/* turn on debugging by uncommenting the following line - #undef SPQR_NDEBUG - */ - -/* ========================================================================== */ -/* === Include files ======================================================== */ -/* ========================================================================== */ - -#include "ccolamd.h" - -#include -#include -#include - -#ifdef MATLAB_MEX_FILE -#include "mex.h" -#include "matrix.h" -#endif - -#if !defined (NPRINT) || !defined (SPQR_NDEBUG) -#include -#endif - -#ifndef NULL -#define NULL ((void *) 0) -#endif - -/* ========================================================================== */ -/* === int or UF_long ======================================================= */ -/* ========================================================================== */ - -/* define UF_long */ -#include "UFconfig.h" - -#ifdef DLONG - -#define Int UF_long -#define ID UF_long_id -#define Int_MAX UF_long_max - -#define CCOLAMD_recommended ccolamd_l_recommended -#define CCOLAMD_set_defaults ccolamd_l_set_defaults -#define CCOLAMD_2 ccolamd2_l -#define CCOLAMD_MAIN ccolamd_l -#define CCOLAMD_apply_order ccolamd_l_apply_order -#define CCOLAMD_postorder ccolamd_l_postorder -#define CCOLAMD_post_tree ccolamd_l_post_tree -#define CCOLAMD_fsize ccolamd_l_fsize -#define CSYMAMD_MAIN csymamd_l -#define CCOLAMD_report ccolamd_l_report -#define CSYMAMD_report csymamd_l_report - -#else - -#define Int int -#define ID "%d" -#define Int_MAX INT_MAX - -#define CCOLAMD_recommended ccolamd_recommended -#define CCOLAMD_set_defaults ccolamd_set_defaults -#define CCOLAMD_2 ccolamd2 -#define CCOLAMD_MAIN ccolamd -#define CCOLAMD_apply_order ccolamd_apply_order -#define CCOLAMD_postorder ccolamd_postorder -#define CCOLAMD_post_tree ccolamd_post_tree -#define CCOLAMD_fsize ccolamd_fsize -#define CSYMAMD_MAIN csymamd -#define CCOLAMD_report ccolamd_report -#define CSYMAMD_report csymamd_report - -#endif - -/* ========================================================================== */ -/* === Row and Column structures ============================================ */ -/* ========================================================================== */ - -typedef struct CColamd_Col_struct -{ - /* size of this struct is 8 integers if no padding occurs */ - - Int start ; /* index for A of first row in this column, or DEAD */ - /* if column is dead */ - Int length ; /* number of rows in this column */ - union - { - Int thickness ; /* number of original columns represented by this */ - /* col, if the column is alive */ - Int parent ; /* parent in parent tree super-column structure, if */ - /* the column is dead */ - } shared1 ; - union - { - Int score ; - Int order ; - } shared2 ; - union - { - Int headhash ; /* head of a hash bucket, if col is at the head of */ - /* a degree list */ - Int hash ; /* hash value, if col is not in a degree list */ - Int prev ; /* previous column in degree list, if col is in a */ - /* degree list (but not at the head of a degree list) */ - } shared3 ; - union - { - Int degree_next ; /* next column, if col is in a degree list */ - Int hash_next ; /* next column, if col is in a hash list */ - } shared4 ; - - Int nextcol ; /* next column in this supercolumn */ - Int lastcol ; /* last column in this supercolumn */ - -} CColamd_Col ; - - -typedef struct CColamd_Row_struct -{ - /* size of this struct is 6 integers if no padding occurs */ - - Int start ; /* index for A of first col in this row */ - Int length ; /* number of principal columns in this row */ - union - { - Int degree ; /* number of principal & non-principal columns in row */ - Int p ; /* used as a row pointer in init_rows_cols () */ - } shared1 ; - union - { - Int mark ; /* for computing set differences and marking dead rows*/ - Int first_column ;/* first column in row (used in garbage collection) */ - } shared2 ; - - Int thickness ; /* number of original rows represented by this row */ - /* that are not yet pivotal */ - Int front ; /* -1 if an original row */ - /* k if this row represents the kth frontal matrix */ - /* where k goes from 0 to at most n_col-1 */ - -} CColamd_Row ; - -/* ========================================================================== */ -/* === basic definitions ==================================================== */ -/* ========================================================================== */ - -#define EMPTY (-1) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ -#define GLOBAL -#define PUBLIC -#define PRIVATE static - -#define DENSE_DEGREE(alpha,n) \ - ((Int) MAX (16.0, (alpha) * sqrt ((double) (n)))) - -#define CMEMBER(c) ((cmember == (Int *) NULL) ? (0) : (cmember [c])) - -/* True if x is NaN */ -#define SCALAR_IS_NAN(x) ((x) != (x)) - -/* true if an integer (stored in double x) would overflow (or if x is NaN) */ -#define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \ - || SCALAR_IS_NAN (x)) - -#define ONES_COMPLEMENT(r) (-(r)-1) -#undef TRUE -#undef FALSE -#define TRUE (1) -#define FALSE (0) - -/* Row and column status */ -#define ALIVE (0) -#define DEAD (-1) - -/* Column status */ -#define DEAD_PRINCIPAL (-1) -#define DEAD_NON_PRINCIPAL (-2) - -/* Macros for row and column status update and checking. */ -#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) -#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) -#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) -#define COL_IS_DEAD(c) (Col [c].start < ALIVE) -#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) -#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) -#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } -#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } -#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } - - -/* ========================================================================== */ -/* === ccolamd reporting mechanism ========================================== */ -/* ========================================================================== */ - -#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS) -/* In MATLAB, matrices are 1-based to the user, but 0-based internally */ -#define INDEX(i) ((i)+1) -#else -/* In C, matrices are 0-based and indices are reported as such in *_report */ -#define INDEX(i) (i) -#endif - -/* All output goes through the PRINTF macro. */ -#define PRINTF(params) { if (ccolamd_printf != NULL) (void) ccolamd_printf params ; } - - -/* ========================================================================== */ -/* === Debugging prototypes and definitions ================================= */ -/* ========================================================================== */ - -#ifndef SPQR_NDEBUG - -#include - -/* debug print level, present only when debugging */ -PRIVATE Int ccolamd_debug ; - -/* debug print statements */ -#define DEBUG0(params) { PRINTF (params) ; } -#define DEBUG1(params) { if (ccolamd_debug >= 1) PRINTF (params) ; } -#define DEBUG2(params) { if (ccolamd_debug >= 2) PRINTF (params) ; } -#define DEBUG3(params) { if (ccolamd_debug >= 3) PRINTF (params) ; } -#define DEBUG4(params) { if (ccolamd_debug >= 4) PRINTF (params) ; } - -#ifdef MATLAB_MEX_FILE -#define ASSERT(expression) (mxAssert ((expression), "")) -#else -#define ASSERT(expression) (assert (expression)) -#endif - -PRIVATE void ccolamd_get_debug -( - char *method -) ; - -PRIVATE void debug_mark -( - Int n_row, - CColamd_Row Row [], - Int tag_mark, - Int max_mark -) ; - -PRIVATE void debug_matrix -( - Int n_row, - Int n_col, - CColamd_Row Row [], - CColamd_Col Col [], - Int A [] -) ; - -PRIVATE void debug_structures -( - Int n_row, - Int n_col, - CColamd_Row Row [], - CColamd_Col Col [], - Int A [], - Int in_cset [], - Int cset_start [] -) ; - -PRIVATE void dump_super -( - Int super_c, - CColamd_Col Col [], - Int n_col -) ; - -PRIVATE void debug_deg_lists -( - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int head [ ], - Int min_score, - Int should, - Int max_deg -) ; - -#else - -/* === No debugging ========================================================= */ - -#define DEBUG0(params) ; -#define DEBUG1(params) ; -#define DEBUG2(params) ; -#define DEBUG3(params) ; -#define DEBUG4(params) ; - -#define ASSERT(expression) - -#endif - -/* ========================================================================== */ -/* === Prototypes of PRIVATE routines ======================================= */ -/* ========================================================================== */ - -PRIVATE Int init_rows_cols -( - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int A [ ], - Int p [ ], - Int stats [CCOLAMD_STATS] -) ; - -PRIVATE void init_scoring -( - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int A [ ], - Int head [ ], - double knobs [CCOLAMD_KNOBS], - Int *p_n_row2, - Int *p_n_col2, - Int *p_max_deg, - Int cmember [ ], - Int n_cset, - Int cset_start [ ], - Int dead_cols [ ], - Int *p_ndense_row, /* number of dense rows */ - Int *p_nempty_row, /* number of original empty rows */ - Int *p_nnewlyempty_row, /* number of newly empty rows */ - Int *p_ndense_col, /* number of dense cols (excl "empty" cols) */ - Int *p_nempty_col, /* number of original empty cols */ - Int *p_nnewlyempty_col /* number of newly empty cols */ -) ; - -PRIVATE Int find_ordering -( - Int n_row, - Int n_col, - Int Alen, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int A [ ], - Int head [ ], -#ifndef SPQR_NDEBUG - Int n_col2, -#endif - Int max_deg, - Int pfree, - Int cset [ ], - Int cset_start [ ], -#ifndef SPQR_NDEBUG - Int n_cset, -#endif - Int cmember [ ], - Int Front_npivcol [ ], - Int Front_nrows [ ], - Int Front_ncols [ ], - Int Front_parent [ ], - Int Front_cols [ ], - Int *p_nfr, - Int aggressive, - Int InFront [ ], - Int order_for_lu -) ; - -PRIVATE void detect_super_cols -( -#ifndef SPQR_NDEBUG - Int n_col, - CColamd_Row Row [ ], -#endif - CColamd_Col Col [ ], - Int A [ ], - Int head [ ], - Int row_start, - Int row_length, - Int in_set [ ] -) ; - -PRIVATE Int garbage_collection -( - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int A [ ], - Int *pfree -) ; - -PRIVATE Int clear_mark -( - Int tag_mark, - Int max_mark, - Int n_row, - CColamd_Row Row [ ] -) ; - -PRIVATE void print_report -( - char *method, - Int stats [CCOLAMD_STATS] -) ; - - -/* ========================================================================== */ -/* === USER-CALLABLE ROUTINES: ============================================== */ -/* ========================================================================== */ - - -/* ========================================================================== */ -/* === ccolamd_recommended ================================================== */ -/* ========================================================================== */ - -/* - * The ccolamd_recommended routine returns the suggested size for Alen. This - * value has been determined to provide good balance between the number of - * garbage collections and the memory requirements for ccolamd. If any - * argument is negative, or if integer overflow occurs, a 0 is returned as - * an error condition. - * - * 2*nnz space is required for the row and column indices of the matrix - * (or 4*n_col, which ever is larger). - * - * CCOLAMD_C (n_col) + CCOLAMD_R (n_row) space is required for the Col and Row - * arrays, respectively, which are internal to ccolamd. This is equal to - * 8*n_col + 6*n_row if the structures are not padded. - * - * An additional n_col space is the minimal amount of "elbow room", - * and nnz/5 more space is recommended for run time efficiency. - * - * The remaining (((3 * n_col) + 1) + 5 * (n_col + 1) + n_row) space is - * for other workspace used in ccolamd which did not appear in colamd. - */ - -/* add two values of type size_t, and check for integer overflow */ -static size_t t_add (size_t a, size_t b, int *ok) -{ - (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; - return ((*ok) ? (a + b) : 0) ; -} - -/* compute a*k where k is a small integer, and check for integer overflow */ -static size_t t_mult (size_t a, size_t k, int *ok) -{ - size_t i, s = 0 ; - for (i = 0 ; i < k ; i++) - { - s = t_add (s, a, ok) ; - } - return (s) ; -} - -/* size of the Col and Row structures */ -#define CCOLAMD_C(n_col,ok) \ - ((t_mult (t_add (n_col, 1, ok), sizeof (CColamd_Col), ok) / sizeof (Int))) - -#define CCOLAMD_R(n_row,ok) \ - ((t_mult (t_add (n_row, 1, ok), sizeof (CColamd_Row), ok) / sizeof (Int))) - -/* -#define CCOLAMD_RECOMMENDED(nnz, n_row, n_col) \ - MAX (2 * nnz, 4 * n_col) + \ - CCOLAMD_C (n_col) + CCOLAMD_R (n_row) + n_col + (nnz / 5) \ - + ((3 * n_col) + 1) + 5 * (n_col + 1) + n_row - */ - -static size_t ccolamd_need (Int nnz, Int n_row, Int n_col, int *ok) -{ - - /* ccolamd_need, compute the following, and check for integer overflow: - need = MAX (2*nnz, 4*n_col) + n_col + - Col_size + Row_size + - (3*n_col+1) + (5*(n_col+1)) + n_row ; - */ - size_t s, c, r, t ; - - /* MAX (2*nnz, 4*n_col) */ - s = t_mult (nnz, 2, ok) ; /* 2*nnz */ - t = t_mult (n_col, 4, ok) ; /* 4*n_col */ - s = MAX (s,t) ; - - s = t_add (s, n_col, ok) ; /* bare minimum elbow room */ - - /* Col and Row arrays */ - c = CCOLAMD_C (n_col, ok) ; /* size of column structures */ - r = CCOLAMD_R (n_row, ok) ; /* size of row structures */ - s = t_add (s, c, ok) ; - s = t_add (s, r, ok) ; - - c = t_mult (n_col, 3, ok) ; /* 3*n_col + 1 */ - c = t_add (c, 1, ok) ; - s = t_add (s, c, ok) ; - - c = t_add (n_col, 1, ok) ; /* 5 * (n_col + 1) */ - c = t_mult (c, 5, ok) ; - s = t_add (s, c, ok) ; - - s = t_add (s, n_row, ok) ; /* n_row */ - - return (ok ? s : 0) ; -} - -PUBLIC size_t CCOLAMD_recommended /* returns recommended value of Alen. */ -( - /* === Parameters ======================================================= */ - - Int nnz, /* number of nonzeros in A */ - Int n_row, /* number of rows in A */ - Int n_col /* number of columns in A */ -) -{ - size_t s ; - int ok = TRUE ; - if (nnz < 0 || n_row < 0 || n_col < 0) - { - return (0) ; - } - s = ccolamd_need (nnz, n_row, n_col, &ok) ; /* bare minimum needed */ - s = t_add (s, nnz/5, &ok) ; /* extra elbow room */ - ok = ok && (s < Int_MAX) ; - return (ok ? s : 0) ; -} - - -/* ========================================================================== */ -/* === ccolamd_set_defaults ================================================= */ -/* ========================================================================== */ - -/* - * The ccolamd_set_defaults routine sets the default values of the user- - * controllable parameters for ccolamd. - */ - -PUBLIC void CCOLAMD_set_defaults -( - /* === Parameters ======================================================= */ - - double knobs [CCOLAMD_KNOBS] /* knob array */ -) -{ - /* === Local variables ================================================== */ - - Int i ; - - if (!knobs) - { - return ; /* no knobs to initialize */ - } - for (i = 0 ; i < CCOLAMD_KNOBS ; i++) - { - knobs [i] = 0 ; - } - knobs [CCOLAMD_DENSE_ROW] = 10 ; - knobs [CCOLAMD_DENSE_COL] = 10 ; - knobs [CCOLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/ - knobs [CCOLAMD_LU] = FALSE ; /* default: order for Cholesky */ -} - - -/* ========================================================================== */ -/* === symamd =============================================================== */ -/* ========================================================================== */ - -PUBLIC Int CSYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */ -( - /* === Parameters ======================================================= */ - - Int n, /* number of rows and columns of A */ - Int A [ ], /* row indices of A */ - Int p [ ], /* column pointers of A */ - Int perm [ ], /* output permutation, size n+1 */ - double knobs [CCOLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - Int stats [CCOLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t),/* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *), /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ - Int cmember [ ], /* constraint set */ - Int stype /* stype of A */ -) -{ - /* === Local variables ================================================== */ - - double cknobs [CCOLAMD_KNOBS] ; - double default_knobs [CCOLAMD_KNOBS] ; - - Int *count ; /* length of each column of M, and col pointer*/ - Int *mark ; /* mark array for finding duplicate entries */ - Int *M ; /* row indices of matrix M */ - size_t Mlen ; /* length of M */ - Int n_row ; /* number of rows in M */ - Int nnz ; /* number of entries in A */ - Int i ; /* row index of A */ - Int j ; /* column index of A */ - Int k ; /* row index of M */ - Int mnz ; /* number of nonzeros in M */ - Int pp ; /* index into a column of A */ - Int last_row ; /* last row seen in the current column */ - Int length ; /* number of nonzeros in a column */ - Int both ; /* TRUE if ordering A+A' */ - Int upper ; /* TRUE if ordering triu(A)+triu(A)' */ - Int lower ; /* TRUE if ordering tril(A)+tril(A)' */ - -#ifndef SPQR_NDEBUG - ccolamd_get_debug ("csymamd") ; -#endif - - both = (stype == 0) ; - upper = (stype > 0) ; - lower = (stype < 0) ; - - /* === Check the input arguments ======================================== */ - - if (!stats) - { - DEBUG1 (("csymamd: stats not present\n")) ; - return (FALSE) ; - } - for (i = 0 ; i < CCOLAMD_STATS ; i++) - { - stats [i] = 0 ; - } - stats [CCOLAMD_STATUS] = CCOLAMD_OK ; - stats [CCOLAMD_INFO1] = -1 ; - stats [CCOLAMD_INFO2] = -1 ; - - if (!A) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_A_not_present ; - DEBUG1 (("csymamd: A not present\n")) ; - return (FALSE) ; - } - - if (!p) /* p is not present */ - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_p_not_present ; - DEBUG1 (("csymamd: p not present\n")) ; - return (FALSE) ; - } - - if (n < 0) /* n must be >= 0 */ - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_ncol_negative ; - stats [CCOLAMD_INFO1] = n ; - DEBUG1 (("csymamd: n negative "ID" \n", n)) ; - return (FALSE) ; - } - - nnz = p [n] ; - if (nnz < 0) /* nnz must be >= 0 */ - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_nnz_negative ; - stats [CCOLAMD_INFO1] = nnz ; - DEBUG1 (("csymamd: number of entries negative "ID" \n", nnz)) ; - return (FALSE) ; - } - - if (p [0] != 0) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_p0_nonzero ; - stats [CCOLAMD_INFO1] = p [0] ; - DEBUG1 (("csymamd: p[0] not zero "ID"\n", p [0])) ; - return (FALSE) ; - } - - /* === If no knobs, set default knobs =================================== */ - - if (!knobs) - { - CCOLAMD_set_defaults (default_knobs) ; - knobs = default_knobs ; - } - - /* === Allocate count and mark ========================================== */ - - count = (Int *) ((*allocate) (n+1, sizeof (Int))) ; - if (!count) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_out_of_memory ; - DEBUG1 (("csymamd: allocate count (size "ID") failed\n", n+1)) ; - return (FALSE) ; - } - - mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ; - if (!mark) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_out_of_memory ; - (*release) ((void *) count) ; - DEBUG1 (("csymamd: allocate mark (size "ID") failed\n", n+1)) ; - return (FALSE) ; - } - - /* === Compute column counts of M, check if A is valid ================== */ - - stats [CCOLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ - - for (i = 0 ; i < n ; i++) - { - mark [i] = -1 ; - } - - for (j = 0 ; j < n ; j++) - { - last_row = -1 ; - - length = p [j+1] - p [j] ; - if (length < 0) - { - /* column pointers must be non-decreasing */ - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_col_length_negative ; - stats [CCOLAMD_INFO1] = j ; - stats [CCOLAMD_INFO2] = length ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG1 (("csymamd: col "ID" negative length "ID"\n", j, length)) ; - return (FALSE) ; - } - - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - if (i < 0 || i >= n) - { - /* row index i, in column j, is out of bounds */ - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_row_index_out_of_bounds ; - stats [CCOLAMD_INFO1] = j ; - stats [CCOLAMD_INFO2] = i ; - stats [CCOLAMD_INFO3] = n ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG1 (("csymamd: row "ID" col "ID" out of bounds\n", i, j)) ; - return (FALSE) ; - } - - if (i <= last_row || mark [i] == j) - { - /* row index is unsorted or repeated (or both), thus col */ - /* is jumbled. This is a notice, not an error condition. */ - stats [CCOLAMD_STATUS] = CCOLAMD_OK_BUT_JUMBLED ; - stats [CCOLAMD_INFO1] = j ; - stats [CCOLAMD_INFO2] = i ; - (stats [CCOLAMD_INFO3]) ++ ; - DEBUG1 (("csymamd: row "ID" col "ID" unsorted/dupl.\n", i, j)) ; - } - - if (mark [i] != j) - { - if ((both && i != j) || (lower && i > j) || (upper && i < j)) - { - /* row k of M will contain column indices i and j */ - count [i]++ ; - count [j]++ ; - } - } - - /* mark the row as having been seen in this column */ - mark [i] = j ; - - last_row = i ; - } - } - - /* === Compute column pointers of M ===================================== */ - - /* use output permutation, perm, for column pointers of M */ - perm [0] = 0 ; - for (j = 1 ; j <= n ; j++) - { - perm [j] = perm [j-1] + count [j-1] ; - } - for (j = 0 ; j < n ; j++) - { - count [j] = perm [j] ; - } - - /* === Construct M ====================================================== */ - - mnz = perm [n] ; - n_row = mnz / 2 ; - Mlen = CCOLAMD_recommended (mnz, n_row, n) ; - M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ; - DEBUG1 (("csymamd: M is "ID"-by-"ID" with "ID" entries, Mlen = %g\n", - n_row, n, mnz, (double) Mlen)) ; - - if (!M) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_out_of_memory ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG1 (("csymamd: allocate M (size %g) failed\n", (double) Mlen)) ; - return (FALSE) ; - } - - k = 0 ; - - if (stats [CCOLAMD_STATUS] == CCOLAMD_OK) - { - /* Matrix is OK */ - for (j = 0 ; j < n ; j++) - { - ASSERT (p [j+1] - p [j] >= 0) ; - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - ASSERT (i >= 0 && i < n) ; - if ((both && i != j) || (lower && i > j) || (upper && i < j)) - { - /* row k of M contains column indices i and j */ - M [count [i]++] = k ; - M [count [j]++] = k ; - k++ ; - } - } - } - } - else - { - /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */ - DEBUG1 (("csymamd: Duplicates in A.\n")) ; - for (i = 0 ; i < n ; i++) - { - mark [i] = -1 ; - } - for (j = 0 ; j < n ; j++) - { - ASSERT (p [j+1] - p [j] >= 0) ; - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - ASSERT (i >= 0 && i < n) ; - if (mark [i] != j) - { - if ((both && i != j) || (lower && i > j) || (upper && i= 0 */ - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_nrow_negative ; - stats [CCOLAMD_INFO1] = n_row ; - DEBUG1 (("ccolamd: nrow negative "ID"\n", n_row)) ; - return (FALSE) ; - } - - if (n_col < 0) /* n_col must be >= 0 */ - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_ncol_negative ; - stats [CCOLAMD_INFO1] = n_col ; - DEBUG1 (("ccolamd: ncol negative "ID"\n", n_col)) ; - return (FALSE) ; - } - - nnz = p [n_col] ; - if (nnz < 0) /* nnz must be >= 0 */ - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_nnz_negative ; - stats [CCOLAMD_INFO1] = nnz ; - DEBUG1 (("ccolamd: number of entries negative "ID"\n", nnz)) ; - return (FALSE) ; - } - - if (p [0] != 0) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_p0_nonzero ; - stats [CCOLAMD_INFO1] = p [0] ; - DEBUG1 (("ccolamd: p[0] not zero "ID"\n", p [0])) ; - return (FALSE) ; - } - - /* === If no knobs, set default knobs =================================== */ - - if (!knobs) - { - CCOLAMD_set_defaults (default_knobs) ; - knobs = default_knobs ; - } - - aggressive = (knobs [CCOLAMD_AGGRESSIVE] != FALSE) ; - order_for_lu = (knobs [CCOLAMD_LU] != FALSE) ; - - /* === Allocate workspace from array A ================================== */ - - ok = TRUE ; - Col_size = CCOLAMD_C (n_col, &ok) ; - Row_size = CCOLAMD_R (n_row, &ok) ; - - /* min size of A is 2nnz+ncol. cset and cset_start are of size 2ncol+1 */ - /* Each of the 5 fronts is of size n_col + 1. InFront is of size nrow. */ - - /* - need = MAX (2*nnz, 4*n_col) + n_col + - Col_size + Row_size + - (3*n_col+1) + (5*(n_col+1)) + n_row ; - */ - need = ccolamd_need (nnz, n_row, n_col, &ok) ; - - if (!ok || need > (size_t) Alen || need > Int_MAX) - { - /* not enough space in array A to perform the ordering */ - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_A_too_small ; - stats [CCOLAMD_INFO1] = need ; - stats [CCOLAMD_INFO2] = Alen ; - DEBUG1 (("ccolamd: Need Alen >= "ID", given "ID"\n", need, Alen)) ; - return (FALSE) ; - } - - /* since integer overflow has been check, the following cannot overflow: */ - Alen -= Col_size + Row_size + (3*n_col + 1) + 5*(n_col+1) + n_row ; - - /* Size of A is now Alen >= MAX (2*nnz, 4*n_col) + n_col. The ordering - * requires Alen >= 2*nnz + n_col, and the postorder requires - * Alen >= 5*n_col. */ - - ap = Alen ; - - /* Front array workspace: 5*(n_col+1) + n_row */ - if (!Front_npivcol || !Front_nrows || !Front_ncols || !Front_parent || - !Front_cols || !Front_cols || !InFront) - { - Front_npivcol = &A [ap] ; ap += (n_col + 1) ; - Front_nrows = &A [ap] ; ap += (n_col + 1) ; - Front_ncols = &A [ap] ; ap += (n_col + 1) ; - Front_parent = &A [ap] ; ap += (n_col + 1) ; - Front_cols = &A [ap] ; ap += (n_col + 1) ; - InFront = &A [ap] ; ap += (n_row) ; - } - else - { - /* Fronts are present. Leave the additional space as elbow room. */ - ap += 5*(n_col+1) + n_row ; - ap = Alen ; - } - - /* Workspace for cset management: 3*n_col+1 */ - /* cset_start is of size n_col + 1 */ - cset_start = &A [ap] ; - ap += n_col + 1 ; - - /* dead_col is of size n_col */ - dead_cols = &A [ap] ; - ap += n_col ; - - /* cset is of size n_col */ - cset = &A [ap] ; - ap += n_col ; - - /* Col is of size Col_size. The space is shared by temp_cstart and csize */ - Col = (CColamd_Col *) &A [ap] ; - temp_cstart = (Int *) Col ; /* [ temp_cstart is of size n_col+1 */ - csize = temp_cstart + (n_col+1) ; /* csize is of size n_col+1 */ - ap += Col_size ; - ASSERT (Col_size >= 2*n_col+1) ; - - /* Row is of size Row_size */ - Row = (CColamd_Row *) &A [ap] ; - ap += Row_size ; - - /* Initialize csize & dead_cols to zero */ - for (i = 0 ; i < n_col ; i++) - { - csize [i] = 0 ; - dead_cols [i] = 0 ; - } - - /* === Construct the constraint set ===================================== */ - - if (n_col == 0) - { - n_cset = 0 ; - } - else if (cmember == (Int *) NULL) - { - /* no constraint set; all columns belong to set zero */ - n_cset = 1 ; - csize [0] = n_col ; - DEBUG1 (("no cmember present\n")) ; - } - else - { - n_cset = 0 ; - for (i = 0 ; i < n_col ; i++) - { - if (cmember [i] < 0 || cmember [i] > n_col) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_invalid_cmember ; - DEBUG1 (("ccolamd: malformed cmember \n")) ; - return (FALSE) ; - } - n_cset = MAX (n_cset, cmember [i]) ; - csize [cmember [i]]++ ; - } - /* cset is zero based */ - n_cset++ ; - } - - ASSERT ((n_cset >= 0) && (n_cset <= n_col)) ; - - cset_start [0] = temp_cstart [0] = 0 ; - for (i = 1 ; i <= n_cset ; i++) - { - cset_start [i] = cset_start [i-1] + csize [i-1] ; - DEBUG4 ((" cset_start ["ID"] = "ID" \n", i , cset_start [i])) ; - temp_cstart [i] = cset_start [i] ; - } - - /* do in reverse order to encourage natural tie-breaking */ - if (cmember == (Int *) NULL) - { - for (i = n_col-1 ; i >= 0 ; i--) - { - cset [temp_cstart [0]++] = i ; - } - } - else - { - for (i = n_col-1 ; i >= 0 ; i--) - { - cset [temp_cstart [cmember [i]]++] = i ; - } - } - - /* ] temp_cstart and csize are no longer used */ - - /* === Construct the row and column data structures ===================== */ - - if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats)) - { - /* input matrix is invalid */ - DEBUG1 (("ccolamd: Matrix invalid\n")) ; - return (FALSE) ; - } - - /* === Initialize front info ============================================ */ - - for (col = 0 ; col < n_col ; col++) - { - Front_npivcol [col] = 0 ; - Front_nrows [col] = 0 ; - Front_ncols [col] = 0 ; - Front_parent [col] = EMPTY ; - Front_cols [col] = EMPTY ; - } - - /* === Initialize scores, kill dense rows/columns ======================= */ - - init_scoring (n_row, n_col, Row, Col, A, p, knobs, - &n_row2, &n_col2, &max_deg, cmember, n_cset, cset_start, dead_cols, - &ndense_row, &nempty_row, &nnewlyempty_row, - &ndense_col, &nempty_col, &nnewlyempty_col) ; - - ASSERT (n_row2 == n_row - nempty_row - nnewlyempty_row - ndense_row) ; - ASSERT (n_col2 == n_col - nempty_col - nnewlyempty_col - ndense_col) ; - DEBUG1 (("# dense rows "ID" cols "ID"\n", ndense_row, ndense_col)) ; - - /* === Order the supercolumns =========================================== */ - - ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, -#ifndef SPQR_NDEBUG - n_col2, -#endif - max_deg, 2*nnz, cset, cset_start, -#ifndef SPQR_NDEBUG - n_cset, -#endif - cmember, Front_npivcol, Front_nrows, Front_ncols, Front_parent, - Front_cols, &nfr, aggressive, InFront, order_for_lu) ; - - ASSERT (Alen >= 5*n_col) ; - - /* === Postorder ======================================================== */ - - /* A is no longer needed, so use A [0..5*nfr-1] as workspace [ [ */ - /* This step requires Alen >= 5*n_col */ - Front_child = A ; - Front_sibling = Front_child + nfr ; - Front_stack = Front_sibling + nfr ; - Front_order = Front_stack + nfr ; - Front_size = Front_order + nfr ; - - CCOLAMD_fsize (nfr, Front_size, Front_nrows, Front_ncols, - Front_parent, Front_npivcol) ; - - CCOLAMD_postorder (nfr, Front_parent, Front_npivcol, Front_size, - Front_order, Front_child, Front_sibling, Front_stack, Front_cols, - cmember) ; - - /* Front_size, Front_stack, Front_child, Front_sibling no longer needed ] */ - - /* use A [0..nfr-1] as workspace */ - CCOLAMD_apply_order (Front_npivcol, Front_order, A, nfr, nfr) ; - CCOLAMD_apply_order (Front_nrows, Front_order, A, nfr, nfr) ; - CCOLAMD_apply_order (Front_ncols, Front_order, A, nfr, nfr) ; - CCOLAMD_apply_order (Front_parent, Front_order, A, nfr, nfr) ; - CCOLAMD_apply_order (Front_cols, Front_order, A, nfr, nfr) ; - - /* fix the parent to refer to the new numbering */ - for (i = 0 ; i < nfr ; i++) - { - parent = Front_parent [i] ; - if (parent != EMPTY) - { - Front_parent [i] = Front_order [parent] ; - } - } - - /* fix InFront to refer to the new numbering */ - for (row = 0 ; row < n_row ; row++) - { - i = InFront [row] ; - ASSERT (i >= EMPTY && i < nfr) ; - if (i != EMPTY) - { - InFront [row] = Front_order [i] ; - } - } - - /* Front_order longer needed ] */ - - /* === Order the columns in the fronts ================================== */ - - /* use A [0..n_col-1] as inverse permutation */ - for (i = 0 ; i < n_col ; i++) - { - A [i] = EMPTY ; - } - - k = 0 ; - set1 = 0 ; - for (i = 0 ; i < nfr ; i++) - { - ASSERT (Front_npivcol [i] > 0) ; - - set2 = CMEMBER (Front_cols [i]) ; - while (set1 < set2) - { - k += dead_cols [set1] ; - DEBUG3 (("Skip null/dense columns of set "ID"\n",set1)) ; - set1++ ; - } - set1 = set2 ; - - for (col = Front_cols [i] ; col != EMPTY ; col = Col [col].nextcol) - { - ASSERT (col >= 0 && col < n_col) ; - DEBUG1 (("ccolamd output ordering: k "ID" col "ID"\n", k, col)) ; - p [k] = col ; - ASSERT (A [col] == EMPTY) ; - - cs = CMEMBER (col) ; - ASSERT (k >= cset_start [cs] && k < cset_start [cs+1]) ; - - A [col] = k ; - k++ ; - } - } - - /* === Order the "dense" and null columns =============================== */ - - if (n_col2 < n_col) - { - for (col = 0 ; col < n_col ; col++) - { - if (A [col] == EMPTY) - { - k = Col [col].shared2.order ; - cs = CMEMBER (col) ; -#ifndef SPQR_NDEBUG - dead_cols [cs]-- ; -#endif - ASSERT (k >= cset_start [cs] && k < cset_start [cs+1]) ; - DEBUG1 (("ccolamd output ordering: k "ID" col "ID - " (dense or null col)\n", k, col)) ; - p [k] = col ; - A [col] = k ; - } - } - } - -#ifndef SPQR_NDEBUG - for (i = 0 ; i < n_cset ; i++) - { - ASSERT (dead_cols [i] == 0) ; - } -#endif - - /* === Return statistics in stats ======================================= */ - - stats [CCOLAMD_DENSE_ROW] = ndense_row ; - stats [CCOLAMD_DENSE_COL] = nempty_row ; - stats [CCOLAMD_NEWLY_EMPTY_ROW] = nnewlyempty_row ; - stats [CCOLAMD_DENSE_COL] = ndense_col ; - stats [CCOLAMD_EMPTY_COL] = nempty_col ; - stats [CCOLAMD_NEWLY_EMPTY_COL] = nnewlyempty_col ; - ASSERT (ndense_col + nempty_col + nnewlyempty_col == n_col - n_col2) ; - if (p_nfr) - { - *p_nfr = nfr ; - } - stats [CCOLAMD_DEFRAG_COUNT] = ngarbage ; - DEBUG1 (("ccolamd: done.\n")) ; - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === colamd_report ======================================================== */ -/* ========================================================================== */ - -PUBLIC void CCOLAMD_report -( - Int stats [CCOLAMD_STATS] -) -{ - print_report ("ccolamd", stats) ; -} - - -/* ========================================================================== */ -/* === symamd_report ======================================================== */ -/* ========================================================================== */ - -PUBLIC void CSYMAMD_report -( - Int stats [CCOLAMD_STATS] -) -{ - print_report ("csymamd", stats) ; -} - - -/* ========================================================================== */ -/* === NON-USER-CALLABLE ROUTINES: ========================================== */ -/* ========================================================================== */ - -/* There are no user-callable routines beyond this point in the file */ - - -/* ========================================================================== */ -/* === init_rows_cols ======================================================= */ -/* ========================================================================== */ - -/* - Takes the column form of the matrix in A and creates the row form of the - matrix. Also, row and column attributes are stored in the Col and Row - structs. If the columns are un-sorted or contain duplicate row indices, - this routine will also sort and remove duplicate row indices from the - column form of the matrix. Returns FALSE if the matrix is invalid, - TRUE otherwise. Not user-callable. -*/ - -PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - CColamd_Row Row [ ], /* of size n_row+1 */ - CColamd_Col Col [ ], /* of size n_col+1 */ - Int A [ ], /* row indices of A, of size Alen */ - Int p [ ], /* pointers to columns in A, of size n_col+1 */ - Int stats [CCOLAMD_STATS] /* colamd statistics */ -) -{ - /* === Local variables ================================================== */ - - Int col ; /* a column index */ - Int row ; /* a row index */ - Int *cp ; /* a column pointer */ - Int *cp_end ; /* a pointer to the end of a column */ - Int *rp ; /* a row pointer */ - Int *rp_end ; /* a pointer to the end of a row */ - Int last_row ; /* previous row */ - - /* === Initialize columns, and check column pointers ==================== */ - - for (col = 0 ; col < n_col ; col++) - { - Col [col].start = p [col] ; - Col [col].length = p [col+1] - p [col] ; - - if (Col [col].length < 0) - { - /* column pointers must be non-decreasing */ - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_col_length_negative ; - stats [CCOLAMD_INFO1] = col ; - stats [CCOLAMD_INFO2] = Col [col].length ; - DEBUG1 (("ccolamd: col "ID" length "ID" < 0\n", - col, Col [col].length)) ; - return (FALSE) ; - } - - Col [col].shared1.thickness = 1 ; - Col [col].shared2.score = 0 ; - Col [col].shared3.prev = EMPTY ; - Col [col].shared4.degree_next = EMPTY ; - Col [col].nextcol = EMPTY ; - Col [col].lastcol = col ; - } - - /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ - - /* === Scan columns, compute row degrees, and check row indices ========= */ - - stats [CCOLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ - - for (row = 0 ; row < n_row ; row++) - { - Row [row].length = 0 ; - Row [row].shared2.mark = -1 ; - Row [row].thickness = 1 ; - Row [row].front = EMPTY ; - } - - for (col = 0 ; col < n_col ; col++) - { - DEBUG1 (("\nCcolamd input column "ID":\n", col)) ; - last_row = -1 ; - - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - - while (cp < cp_end) - { - row = *cp++ ; - DEBUG1 (("row: "ID"\n", row)) ; - - /* make sure row indices within range */ - if (row < 0 || row >= n_row) - { - stats [CCOLAMD_STATUS] = CCOLAMD_ERROR_row_index_out_of_bounds ; - stats [CCOLAMD_INFO1] = col ; - stats [CCOLAMD_INFO2] = row ; - stats [CCOLAMD_INFO3] = n_row ; - DEBUG1 (("row "ID" col "ID" out of bounds\n", row, col)) ; - return (FALSE) ; - } - - if (row <= last_row || Row [row].shared2.mark == col) - { - /* row index are unsorted or repeated (or both), thus col */ - /* is jumbled. This is a notice, not an error condition. */ - stats [CCOLAMD_STATUS] = CCOLAMD_OK_BUT_JUMBLED ; - stats [CCOLAMD_INFO1] = col ; - stats [CCOLAMD_INFO2] = row ; - (stats [CCOLAMD_INFO3]) ++ ; - DEBUG1 (("row "ID" col "ID" unsorted/duplicate\n", row, col)) ; - } - - if (Row [row].shared2.mark != col) - { - Row [row].length++ ; - } - else - { - /* this is a repeated entry in the column, */ - /* it will be removed */ - Col [col].length-- ; - } - - /* mark the row as having been seen in this column */ - Row [row].shared2.mark = col ; - - last_row = row ; - } - } - - /* === Compute row pointers ============================================= */ - - /* row form of the matrix starts directly after the column */ - /* form of matrix in A */ - Row [0].start = p [n_col] ; - Row [0].shared1.p = Row [0].start ; - Row [0].shared2.mark = -1 ; - for (row = 1 ; row < n_row ; row++) - { - Row [row].start = Row [row-1].start + Row [row-1].length ; - Row [row].shared1.p = Row [row].start ; - Row [row].shared2.mark = -1 ; - } - - /* === Create row form ================================================== */ - - if (stats [CCOLAMD_STATUS] == CCOLAMD_OK_BUT_JUMBLED) - { - /* if cols jumbled, watch for repeated row indices */ - for (col = 0 ; col < n_col ; col++) - { - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - while (cp < cp_end) - { - row = *cp++ ; - if (Row [row].shared2.mark != col) - { - A [(Row [row].shared1.p)++] = col ; - Row [row].shared2.mark = col ; - } - } - } - } - else - { - /* if cols not jumbled, we don't need the mark (this is faster) */ - for (col = 0 ; col < n_col ; col++) - { - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - while (cp < cp_end) - { - A [(Row [*cp++].shared1.p)++] = col ; - } - } - } - - /* === Clear the row marks and set row degrees ========================== */ - - for (row = 0 ; row < n_row ; row++) - { - Row [row].shared2.mark = 0 ; - Row [row].shared1.degree = Row [row].length ; - } - - /* === See if we need to re-create columns ============================== */ - - if (stats [CCOLAMD_STATUS] == CCOLAMD_OK_BUT_JUMBLED) - { - DEBUG1 (("ccolamd: reconstructing column form, matrix jumbled\n")) ; - -#ifndef SPQR_NDEBUG - /* make sure column lengths are correct */ - for (col = 0 ; col < n_col ; col++) - { - p [col] = Col [col].length ; - } - for (row = 0 ; row < n_row ; row++) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - p [*rp++]-- ; - } - } - for (col = 0 ; col < n_col ; col++) - { - ASSERT (p [col] == 0) ; - } - /* now p is all zero (different than when debugging is turned off) */ -#endif - - /* === Compute col pointers ========================================= */ - - /* col form of the matrix starts at A [0]. */ - /* Note, we may have a gap between the col form and the row */ - /* form if there were duplicate entries, if so, it will be */ - /* removed upon the first garbage collection */ - Col [0].start = 0 ; - p [0] = Col [0].start ; - for (col = 1 ; col < n_col ; col++) - { - /* note that the lengths here are for pruned columns, i.e. */ - /* no duplicate row indices will exist for these columns */ - Col [col].start = Col [col-1].start + Col [col-1].length ; - p [col] = Col [col].start ; - } - - /* === Re-create col form =========================================== */ - - for (row = 0 ; row < n_row ; row++) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - A [(p [*rp++])++] = row ; - } - } - } - - /* === Done. Matrix is not (or no longer) jumbled ====================== */ - - - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === init_scoring ========================================================= */ -/* ========================================================================== */ - -/* - Kills dense or empty columns and rows, calculates an initial score for - each column, and places all columns in the degree lists. Not user-callable. -*/ - -PRIVATE void init_scoring -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - CColamd_Row Row [ ], /* of size n_row+1 */ - CColamd_Col Col [ ], /* of size n_col+1 */ - Int A [ ], /* column form and row form of A */ - Int head [ ], /* of size n_col+1 */ - double knobs [CCOLAMD_KNOBS],/* parameters */ - Int *p_n_row2, /* number of non-dense, non-empty rows */ - Int *p_n_col2, /* number of non-dense, non-empty columns */ - Int *p_max_deg, /* maximum row degree */ - Int cmember [ ], - Int n_cset, - Int cset_start [ ], - Int dead_cols [ ], - Int *p_ndense_row, /* number of dense rows */ - Int *p_nempty_row, /* number of original empty rows */ - Int *p_nnewlyempty_row, /* number of newly empty rows */ - Int *p_ndense_col, /* number of dense cols (excl "empty" cols) */ - Int *p_nempty_col, /* number of original empty cols */ - Int *p_nnewlyempty_col /* number of newly empty cols */ -) -{ -/* === Local variables ================================================== */ - - Int c ; /* a column index */ - Int r, row ; /* a row index */ - Int *cp ; /* a column pointer */ - Int deg ; /* degree of a row or column */ - Int *cp_end ; /* a pointer to the end of a column */ - Int *new_cp ; /* new column pointer */ - Int col_length ; /* length of pruned column */ - Int score ; /* current column score */ - Int n_col2 ; /* number of non-dense, non-empty columns */ - Int n_row2 ; /* number of non-dense, non-empty rows */ - Int dense_row_count ; /* remove rows with more entries than this */ - Int dense_col_count ; /* remove cols with more entries than this */ - Int max_deg ; /* maximum row degree */ - Int s ; /* a cset index */ - Int ndense_row ; /* number of dense rows */ - Int nempty_row ; /* number of empty rows */ - Int nnewlyempty_row ; /* number of newly empty rows */ - Int ndense_col ; /* number of dense cols (excl "empty" cols) */ - Int nempty_col ; /* number of original empty cols */ - Int nnewlyempty_col ; /* number of newly empty cols */ - Int ne ; - -#ifndef SPQR_NDEBUG - Int debug_count ; /* debug only. */ -#endif - - /* === Extract knobs ==================================================== */ - - /* Note: if knobs contains a NaN, this is undefined: */ - if (knobs [CCOLAMD_DENSE_ROW] < 0) - { - /* only remove completely dense rows */ - dense_row_count = n_col-1 ; - } - else - { - dense_row_count = DENSE_DEGREE (knobs [CCOLAMD_DENSE_ROW], n_col) ; - } - if (knobs [CCOLAMD_DENSE_COL] < 0) - { - /* only remove completely dense columns */ - dense_col_count = n_row-1 ; - } - else - { - dense_col_count = - DENSE_DEGREE (knobs [CCOLAMD_DENSE_COL], MIN (n_row, n_col)) ; - } - - DEBUG1 (("densecount: "ID" "ID"\n", dense_row_count, dense_col_count)) ; - max_deg = 0 ; - - n_col2 = n_col ; - n_row2 = n_row ; - - /* Set the head array for bookkeeping of dense and empty columns. */ - /* This will be used as hash buckets later. */ - for (s = 0 ; s < n_cset ; s++) - { - head [s] = cset_start [s+1] ; - } - - ndense_col = 0 ; - nempty_col = 0 ; - nnewlyempty_col = 0 ; - ndense_row = 0 ; - nempty_row = 0 ; - nnewlyempty_row = 0 ; - - /* === Kill empty columns =============================================== */ - - /* Put the empty columns at the end in their natural order, so that LU */ - /* factorization can proceed as far as possible. */ - for (c = n_col-1 ; c >= 0 ; c--) - { - deg = Col [c].length ; - if (deg == 0) - { - /* this is a empty column, kill and order it last of its cset */ - Col [c].shared2.order = --head [CMEMBER (c)] ; - --n_col2 ; - dead_cols [CMEMBER (c)] ++ ; - nempty_col++ ; - KILL_PRINCIPAL_COL (c) ; - } - } - DEBUG1 (("ccolamd: null columns killed: "ID"\n", n_col - n_col2)) ; - - /* === Kill dense columns =============================================== */ - - /* Put the dense columns at the end, in their natural order */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* skip any dead columns */ - if (COL_IS_DEAD (c)) - { - continue ; - } - deg = Col [c].length ; - if (deg > dense_col_count) - { - /* this is a dense column, kill and order it last of its cset */ - Col [c].shared2.order = --head [CMEMBER (c)] ; - --n_col2 ; - dead_cols [CMEMBER (c)] ++ ; - ndense_col++ ; - /* decrement the row degrees */ - cp = &A [Col [c].start] ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - Row [*cp++].shared1.degree-- ; - } - KILL_PRINCIPAL_COL (c) ; - } - } - DEBUG1 (("Dense and null columns killed: "ID"\n", n_col - n_col2)) ; - - /* === Kill dense and empty rows ======================================== */ - - /* Note that there can now be empty rows, since dense columns have - * been deleted. These are "newly" empty rows. */ - - ne = 0 ; - for (r = 0 ; r < n_row ; r++) - { - deg = Row [r].shared1.degree ; - ASSERT (deg >= 0 && deg <= n_col) ; - if (deg > dense_row_count) - { - /* There is at least one dense row. Continue ordering, but */ - /* symbolic factorization will be redone after ccolamd is done.*/ - ndense_row++ ; - } - if (deg == 0) - { - /* this is a newly empty row, or original empty row */ - ne++ ; - } - if (deg > dense_row_count || deg == 0) - { - /* kill a dense or empty row */ - KILL_ROW (r) ; - Row [r].thickness = 0 ; - --n_row2 ; - } - else - { - /* keep track of max degree of remaining rows */ - max_deg = MAX (max_deg, deg) ; - } - } - nnewlyempty_row = ne - nempty_row ; - DEBUG1 (("ccolamd: Dense and null rows killed: "ID"\n", n_row - n_row2)) ; - - /* === Compute initial column scores ==================================== */ - - /* At this point the row degrees are accurate. They reflect the number */ - /* of "live" (non-dense) columns in each row. No empty rows exist. */ - /* Some "live" columns may contain only dead rows, however. These are */ - /* pruned in the code below. */ - - /* now find the initial COLMMD score for each column */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* skip dead column */ - if (COL_IS_DEAD (c)) - { - continue ; - } - score = 0 ; - cp = &A [Col [c].start] ; - new_cp = cp ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - /* skip if dead */ - if (ROW_IS_DEAD (row)) - { - continue ; - } - /* compact the column */ - *new_cp++ = row ; - /* add row's external degree */ - score += Row [row].shared1.degree - 1 ; - /* guard against integer overflow */ - score = MIN (score, n_col) ; - } - /* determine pruned column length */ - col_length = (Int) (new_cp - &A [Col [c].start]) ; - if (col_length == 0) - { - /* a newly-made null column (all rows in this col are "dense" */ - /* and have already been killed) */ - DEBUG1 (("Newly null killed: "ID"\n", c)) ; - Col [c].shared2.order = -- head [CMEMBER (c)] ; - --n_col2 ; - dead_cols [CMEMBER (c)] ++ ; - nnewlyempty_col++ ; - KILL_PRINCIPAL_COL (c) ; - } - else - { - /* set column length and set score */ - ASSERT (score >= 0) ; - ASSERT (score <= n_col) ; - Col [c].length = col_length ; - Col [c].shared2.score = score ; - } - } - DEBUG1 (("ccolamd: Dense, null, and newly-null columns killed: "ID"\n", - n_col-n_col2)) ; - - /* At this point, all empty rows and columns are dead. All live columns */ - /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ - /* yet). Rows may contain dead columns, but all live rows contain at */ - /* least one live column. */ - -#ifndef SPQR_NDEBUG - debug_count = 0 ; -#endif - - /* clear the hash buckets */ - for (c = 0 ; c <= n_col ; c++) - { - head [c] = EMPTY ; - } - -#ifndef SPQR_NDEBUG - debug_structures (n_row, n_col, Row, Col, A, cmember, cset_start) ; -#endif - - /* === Return number of remaining columns, and max row degree =========== */ - - *p_n_col2 = n_col2 ; - *p_n_row2 = n_row2 ; - *p_max_deg = max_deg ; - *p_ndense_row = ndense_row ; - *p_nempty_row = nempty_row ; /* original empty rows */ - *p_nnewlyempty_row = nnewlyempty_row ; - *p_ndense_col = ndense_col ; - *p_nempty_col = nempty_col ; /* original empty cols */ - *p_nnewlyempty_col = nnewlyempty_col ; -} - - -/* ========================================================================== */ -/* === find_ordering ======================================================== */ -/* ========================================================================== */ - -/* - * Order the principal columns of the supercolumn form of the matrix - * (no supercolumns on input). Uses a minimum approximate column minimum - * degree ordering method. Not user-callable. - */ - -PRIVATE Int find_ordering /* return the number of garbage collections */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Int Alen, /* size of A, 2*nnz + n_col or larger */ - CColamd_Row Row [ ], /* of size n_row+1 */ - CColamd_Col Col [ ], /* of size n_col+1 */ - Int A [ ], /* column form and row form of A */ - Int head [ ], /* of size n_col+1 */ -#ifndef SPQR_NDEBUG - Int n_col2, /* Remaining columns to order */ -#endif - Int max_deg, /* Maximum row degree */ - Int pfree, /* index of first free slot (2*nnz on entry) */ - Int cset [ ], /* constraint set of A */ - Int cset_start [ ], /* pointer to the start of every cset */ -#ifndef SPQR_NDEBUG - Int n_cset, /* number of csets */ -#endif - Int cmember [ ], /* col -> cset mapping */ - Int Front_npivcol [ ], - Int Front_nrows [ ], - Int Front_ncols [ ], - Int Front_parent [ ], - Int Front_cols [ ], - Int *p_nfr, /* number of fronts */ - Int aggressive, - Int InFront [ ], - Int order_for_lu -) -{ - /* === Local variables ================================================== */ - - Int k ; /* current pivot ordering step */ - Int pivot_col ; /* current pivot column */ - Int *cp ; /* a column pointer */ - Int *rp ; /* a row pointer */ - Int pivot_row ; /* current pivot row */ - Int *new_cp ; /* modified column pointer */ - Int *new_rp ; /* modified row pointer */ - Int pivot_row_start ; /* pointer to start of pivot row */ - Int pivot_row_degree ; /* number of columns in pivot row */ - Int pivot_row_length ; /* number of supercolumns in pivot row */ - Int pivot_col_score ; /* score of pivot column */ - Int needed_memory ; /* free space needed for pivot row */ - Int *cp_end ; /* pointer to the end of a column */ - Int *rp_end ; /* pointer to the end of a row */ - Int row ; /* a row index */ - Int col ; /* a column index */ - Int max_score ; /* maximum possible score */ - Int cur_score ; /* score of current column */ - unsigned Int hash ; /* hash value for supernode detection */ - Int head_column ; /* head of hash bucket */ - Int first_col ; /* first column in hash bucket */ - Int tag_mark ; /* marker value for mark array */ - Int row_mark ; /* Row [row].shared2.mark */ - Int set_difference ; /* set difference size of row with pivot row */ - Int min_score ; /* smallest column score */ - Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ - Int max_mark ; /* maximum value of tag_mark */ - Int pivot_col_thickness ; /* number of columns represented by pivot col */ - Int prev_col ; /* Used by Dlist operations. */ - Int next_col ; /* Used by Dlist operations. */ - Int ngarbage ; /* number of garbage collections performed */ - Int current_set ; /* consraint set that is being ordered */ - Int score ; /* score of a column */ - Int colstart ; /* pointer to first column in current cset */ - Int colend ; /* pointer to last column in current cset */ - Int deadcol ; /* number of dense & null columns in a cset */ - -#ifndef SPQR_NDEBUG - Int debug_d ; /* debug loop counter */ - Int debug_step = 0 ; /* debug loop counter */ - Int cols_thickness = 0 ; /* the thickness of the columns in current */ - /* cset degreelist and in pivot row pattern. */ -#endif - - Int pivot_row_thickness ; /* number of rows represented by pivot row */ - Int nfr = 0 ; /* number of fronts */ - Int child ; - - /* === Initialization and clear mark ==================================== */ - - max_mark = Int_MAX - n_col ; /* Int_MAX defined in */ - tag_mark = clear_mark (0, max_mark, n_row, Row) ; - min_score = 0 ; - ngarbage = 0 ; - current_set = -1 ; - deadcol = 0 ; - DEBUG1 (("ccolamd: Ordering, n_col2="ID"\n", n_col2)) ; - - for (row = 0 ; row < n_row ; row++) - { - InFront [row] = EMPTY ; - } - - /* === Order the columns ================================================ */ - - for (k = 0 ; k < n_col ; /* 'k' is incremented below */) - { - - /* make sure degree list isn't empty */ - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (head [min_score] >= EMPTY) ; - -#ifndef SPQR_NDEBUG - for (debug_d = 0 ; debug_d < min_score ; debug_d++) - { - ASSERT (head [debug_d] == EMPTY) ; - } -#endif - - /* Initialize the degree list with columns from next non-empty cset */ - - while ((k+deadcol) == cset_start [current_set+1]) - { - current_set++ ; - DEBUG1 (("\n\n\n============ CSET: "ID"\n", current_set)) ; - k += deadcol ; /* jump to start of next cset */ - deadcol = 0 ; /* reset dead column count */ - - ASSERT ((current_set == n_cset) == (k == n_col)) ; - - /* return if all columns are ordered. */ - if (k == n_col) - { - *p_nfr = nfr ; - return (ngarbage) ; - } - -#ifndef SPQR_NDEBUG - for (col = 0 ; col <= n_col ; col++) - { - ASSERT (head [col] == EMPTY) ; - } -#endif - - min_score = n_col ; - colstart = cset_start [current_set] ; - colend = cset_start [current_set+1] ; - - while (colstart < colend) - { - col = cset [colstart++] ; - - if (COL_IS_DEAD(col)) - { - DEBUG1 (("Column "ID" is dead\n", col)) ; - /* count dense and null columns */ - if (Col [col].shared2.order != EMPTY) - { - deadcol++ ; - } - continue ; - } - - /* only add principal columns in current set to degree lists */ - ASSERT (CMEMBER (col) == current_set) ; - - score = Col [col].shared2.score ; - DEBUG1 (("Column "ID" is alive, score "ID"\n", col, score)) ; - - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (score >= 0) ; - ASSERT (score <= n_col) ; - ASSERT (head [score] >= EMPTY) ; - - /* now add this column to dList at proper score location */ - next_col = head [score] ; - Col [col].shared3.prev = EMPTY ; - Col [col].shared4.degree_next = next_col ; - - /* if there already was a column with the same score, set its */ - /* previous pointer to this new column */ - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = col ; - } - head [score] = col ; - - /* see if this score is less than current min */ - min_score = MIN (min_score, score) ; - } - -#ifndef SPQR_NDEBUG - DEBUG1 (("degree lists initialized \n")) ; - debug_deg_lists (n_row, n_col, Row, Col, head, min_score, - ((cset_start [current_set+1]-cset_start [current_set])-deadcol), - max_deg) ; -#endif - } - -#ifndef SPQR_NDEBUG - if (debug_step % 100 == 0) - { - DEBUG2 (("\n... Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ; - } - else - { - DEBUG3 (("\n------Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ; - } - debug_step++ ; - DEBUG1 (("start of step k="ID": ", k)) ; - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, cset_start [current_set+1]-(k+deadcol), max_deg) ; - debug_matrix (n_row, n_col, Row, Col, A) ; -#endif - - /* === Select pivot column, and order it ============================ */ - - while (head [min_score] == EMPTY && min_score < n_col) - { - min_score++ ; - } - - pivot_col = head [min_score] ; - - ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; - next_col = Col [pivot_col].shared4.degree_next ; - head [min_score] = next_col ; - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = EMPTY ; - } - - ASSERT (COL_IS_ALIVE (pivot_col)) ; - - /* remember score for defrag check */ - pivot_col_score = Col [pivot_col].shared2.score ; - - /* the pivot column is the kth column in the pivot order */ - Col [pivot_col].shared2.order = k ; - - /* increment order count by column thickness */ - pivot_col_thickness = Col [pivot_col].shared1.thickness ; - k += pivot_col_thickness ; - ASSERT (pivot_col_thickness > 0) ; - DEBUG3 (("Pivot col: "ID" thick "ID"\n", pivot_col, - pivot_col_thickness)) ; - - /* === Garbage_collection, if necessary ============================= */ - - needed_memory = MIN (pivot_col_score, n_col - k) ; - if (pfree + needed_memory >= Alen) - { - pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; - ngarbage++ ; - /* after garbage collection we will have enough */ - ASSERT (pfree + needed_memory < Alen) ; - /* garbage collection has wiped out Row [ ].shared2.mark array */ - tag_mark = clear_mark (0, max_mark, n_row, Row) ; - -#ifndef SPQR_NDEBUG - debug_matrix (n_row, n_col, Row, Col, A) ; -#endif - } - - /* === Compute pivot row pattern ==================================== */ - - /* get starting location for this new merged row */ - pivot_row_start = pfree ; - - /* initialize new row counts to zero */ - pivot_row_degree = 0 ; - pivot_row_thickness = 0 ; - - /* tag pivot column as having been visited so it isn't included */ - /* in merged pivot row */ - Col [pivot_col].shared1.thickness = -pivot_col_thickness ; - - /* pivot row is the union of all rows in the pivot column pattern */ - cp = &A [Col [pivot_col].start] ; - cp_end = cp + Col [pivot_col].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - ASSERT (row >= 0 && row < n_row) ; - DEBUG4 (("Pivcol pattern "ID" "ID"\n", ROW_IS_ALIVE (row), row)) ; - /* skip if row is dead */ - if (ROW_IS_ALIVE (row)) - { - /* sum the thicknesses of all the rows */ - pivot_row_thickness += Row [row].thickness ; - - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - /* get a column */ - col = *rp++ ; - /* add the column, if alive and untagged */ - col_thickness = Col [col].shared1.thickness ; - if (col_thickness > 0 && COL_IS_ALIVE (col)) - { - /* tag column in pivot row */ - Col [col].shared1.thickness = -col_thickness ; - ASSERT (pfree < Alen) ; - /* place column in pivot row */ - A [pfree++] = col ; - pivot_row_degree += col_thickness ; - DEBUG4 (("\t\t\tNew live col in pivrow: "ID"\n",col)) ; - } -#ifndef SPQR_NDEBUG - if (col_thickness < 0 && COL_IS_ALIVE (col)) - { - DEBUG4 (("\t\t\tOld live col in pivrow: "ID"\n",col)) ; - } -#endif - } - } - } - - /* pivot_row_thickness is the number of rows in frontal matrix */ - /* including both pivotal rows and nonpivotal rows */ - - /* clear tag on pivot column */ - Col [pivot_col].shared1.thickness = pivot_col_thickness ; - max_deg = MAX (max_deg, pivot_row_degree) ; - -#ifndef SPQR_NDEBUG - DEBUG3 (("check2\n")) ; - debug_mark (n_row, Row, tag_mark, max_mark) ; -#endif - - /* === Kill all rows used to construct pivot row ==================== */ - - /* also kill pivot row, temporarily */ - cp = &A [Col [pivot_col].start] ; - cp_end = cp + Col [pivot_col].length ; - while (cp < cp_end) - { - /* may be killing an already dead row */ - row = *cp++ ; - DEBUG3 (("Kill row in pivot col: "ID"\n", row)) ; - ASSERT (row >= 0 && row < n_row) ; - if (ROW_IS_ALIVE (row)) - { - if (Row [row].front != EMPTY) - { - /* This row represents a frontal matrix. */ - /* Row [row].front is a child of current front */ - child = Row [row].front ; - Front_parent [child] = nfr ; - DEBUG1 (("Front "ID" => front "ID", normal\n", child, nfr)); - } - else - { - /* This is an original row. Keep track of which front - * is its parent in the row-merge tree. */ - InFront [row] = nfr ; - DEBUG1 (("Row "ID" => front "ID", normal\n", row, nfr)) ; - } - } - - KILL_ROW (row) ; - Row [row].thickness = 0 ; - } - - /* === Select a row index to use as the new pivot row =============== */ - - pivot_row_length = pfree - pivot_row_start ; - if (pivot_row_length > 0) - { - /* pick the "pivot" row arbitrarily (first row in col) */ - pivot_row = A [Col [pivot_col].start] ; - DEBUG3 (("Pivotal row is "ID"\n", pivot_row)) ; - } - else - { - /* there is no pivot row, since it is of zero length */ - pivot_row = EMPTY ; - ASSERT (pivot_row_length == 0) ; - } - ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; - - /* === Approximate degree computation =============================== */ - - /* Here begins the computation of the approximate degree. The column */ - /* score is the sum of the pivot row "length", plus the size of the */ - /* set differences of each row in the column minus the pattern of the */ - /* pivot row itself. The column ("thickness") itself is also */ - /* excluded from the column score (we thus use an approximate */ - /* external degree). */ - - /* The time taken by the following code (compute set differences, and */ - /* add them up) is proportional to the size of the data structure */ - /* being scanned - that is, the sum of the sizes of each column in */ - /* the pivot row. Thus, the amortized time to compute a column score */ - /* is proportional to the size of that column (where size, in this */ - /* context, is the column "length", or the number of row indices */ - /* in that column). The number of row indices in a column is */ - /* monotonically non-decreasing, from the length of the original */ - /* column on input to colamd. */ - - /* === Compute set differences ====================================== */ - - DEBUG3 (("** Computing set differences phase. **\n")) ; - - /* pivot row is currently dead - it will be revived later. */ - - DEBUG3 (("Pivot row: ")) ; - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - col = *rp++ ; - ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; - DEBUG3 (("Col: "ID"\n", col)) ; - - /* clear tags used to construct pivot row pattern */ - col_thickness = -Col [col].shared1.thickness ; - ASSERT (col_thickness > 0) ; - Col [col].shared1.thickness = col_thickness ; - - /* === Remove column from degree list =========================== */ - - /* only columns in current_set will be in degree list */ - if (CMEMBER (col) == current_set) - { -#ifndef SPQR_NDEBUG - cols_thickness += col_thickness ; -#endif - cur_score = Col [col].shared2.score ; - prev_col = Col [col].shared3.prev ; - next_col = Col [col].shared4.degree_next ; - DEBUG3 ((" cur_score "ID" prev_col "ID" next_col "ID"\n", - cur_score, prev_col, next_col)) ; - ASSERT (cur_score >= 0) ; - ASSERT (cur_score <= n_col) ; - ASSERT (cur_score >= EMPTY) ; - if (prev_col == EMPTY) - { - head [cur_score] = next_col ; - } - else - { - Col [prev_col].shared4.degree_next = next_col ; - } - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = prev_col ; - } - } - - /* === Scan the column ========================================== */ - - cp = &A [Col [col].start] ; - cp_end = cp + Col [col].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - row_mark = Row [row].shared2.mark ; - /* skip if dead */ - if (ROW_IS_MARKED_DEAD (row_mark)) - { - continue ; - } - ASSERT (row != pivot_row) ; - set_difference = row_mark - tag_mark ; - /* check if the row has been seen yet */ - if (set_difference < 0) - { - ASSERT (Row [row].shared1.degree <= max_deg) ; - set_difference = Row [row].shared1.degree ; - } - /* subtract column thickness from this row's set difference */ - set_difference -= col_thickness ; - ASSERT (set_difference >= 0) ; - /* absorb this row if the set difference becomes zero */ - if (set_difference == 0 && aggressive) - { - DEBUG3 (("aggressive absorption. Row: "ID"\n", row)) ; - - if (Row [row].front != EMPTY) - { - /* Row [row].front is a child of current front. */ - child = Row [row].front ; - Front_parent [child] = nfr ; - DEBUG1 (("Front "ID" => front "ID", aggressive\n", - child, nfr)) ; - } - else - { - /* this is an original row. Keep track of which front - * assembles it, for the row-merge tree */ - InFront [row] = nfr ; - DEBUG1 (("Row "ID" => front "ID", aggressive\n", - row, nfr)) ; - } - - KILL_ROW (row) ; - - /* sum the thicknesses of all the rows */ - pivot_row_thickness += Row [row].thickness ; - Row [row].thickness = 0 ; - } - else - { - /* save the new mark */ - Row [row].shared2.mark = set_difference + tag_mark ; - } - } - } - -#ifndef SPQR_NDEBUG - debug_deg_lists (n_row, n_col, Row, Col, head, min_score, - cset_start [current_set+1]-(k+deadcol)-(cols_thickness), - max_deg) ; - cols_thickness = 0 ; -#endif - - /* === Add up set differences for each column ======================= */ - - DEBUG3 (("** Adding set differences phase. **\n")) ; - - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - /* get a column */ - col = *rp++ ; - ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; - hash = 0 ; - cur_score = 0 ; - cp = &A [Col [col].start] ; - /* compact the column */ - new_cp = cp ; - cp_end = cp + Col [col].length ; - - DEBUG4 (("Adding set diffs for Col: "ID".\n", col)) ; - - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - ASSERT (row >= 0 && row < n_row) ; - row_mark = Row [row].shared2.mark ; - /* skip if dead */ - if (ROW_IS_MARKED_DEAD (row_mark)) - { - DEBUG4 ((" Row "ID", dead\n", row)) ; - continue ; - } - DEBUG4 ((" Row "ID", set diff "ID"\n", row, row_mark-tag_mark)); - ASSERT (row_mark >= tag_mark) ; - /* compact the column */ - *new_cp++ = row ; - /* compute hash function */ - hash += row ; - /* add set difference */ - cur_score += row_mark - tag_mark ; - /* integer overflow... */ - cur_score = MIN (cur_score, n_col) ; - } - - /* recompute the column's length */ - Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; - - /* === Further mass elimination ================================= */ - - if (Col [col].length == 0 && CMEMBER (col) == current_set) - { - DEBUG4 (("further mass elimination. Col: "ID"\n", col)) ; - /* nothing left but the pivot row in this column */ - KILL_PRINCIPAL_COL (col) ; - pivot_row_degree -= Col [col].shared1.thickness ; - ASSERT (pivot_row_degree >= 0) ; - /* order it */ - Col [col].shared2.order = k ; - /* increment order count by column thickness */ - k += Col [col].shared1.thickness ; - pivot_col_thickness += Col [col].shared1.thickness ; - /* add to column list of front */ -#ifndef SPQR_NDEBUG - DEBUG1 (("Mass")) ; - dump_super (col, Col, n_col) ; -#endif - Col [Col [col].lastcol].nextcol = Front_cols [nfr] ; - Front_cols [nfr] = col ; - } - else - { - /* === Prepare for supercolumn detection ==================== */ - - DEBUG4 (("Preparing supercol detection for Col: "ID".\n", col)); - - /* save score so far */ - Col [col].shared2.score = cur_score ; - - /* add column to hash table, for supercolumn detection */ - hash %= n_col + 1 ; - - DEBUG4 ((" Hash = "ID", n_col = "ID".\n", hash, n_col)) ; - ASSERT (((Int) hash) <= n_col) ; - - head_column = head [hash] ; - if (head_column > EMPTY) - { - /* degree list "hash" is non-empty, use prev (shared3) of */ - /* first column in degree list as head of hash bucket */ - first_col = Col [head_column].shared3.headhash ; - Col [head_column].shared3.headhash = col ; - } - else - { - /* degree list "hash" is empty, use head as hash bucket */ - first_col = - (head_column + 2) ; - head [hash] = - (col + 2) ; - } - Col [col].shared4.hash_next = first_col ; - - /* save hash function in Col [col].shared3.hash */ - Col [col].shared3.hash = (Int) hash ; - ASSERT (COL_IS_ALIVE (col)) ; - } - } - - /* The approximate external column degree is now computed. */ - - /* === Supercolumn detection ======================================== */ - - DEBUG3 (("** Supercolumn detection phase. **\n")) ; - - detect_super_cols ( -#ifndef SPQR_NDEBUG - n_col, Row, -#endif - Col, A, head, pivot_row_start, pivot_row_length, cmember) ; - - /* === Kill the pivotal column ====================================== */ - - DEBUG1 ((" KILLING column detect supercols "ID" \n", pivot_col)) ; - KILL_PRINCIPAL_COL (pivot_col) ; - - /* add columns to column list of front */ -#ifndef SPQR_NDEBUG - DEBUG1 (("Pivot")) ; - dump_super (pivot_col, Col, n_col) ; -#endif - Col [Col [pivot_col].lastcol].nextcol = Front_cols [nfr] ; - Front_cols [nfr] = pivot_col ; - - /* === Clear mark =================================================== */ - - tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ; - -#ifndef SPQR_NDEBUG - DEBUG3 (("check3\n")) ; - debug_mark (n_row, Row, tag_mark, max_mark) ; -#endif - - /* === Finalize the new pivot row, and column scores ================ */ - - DEBUG3 (("** Finalize scores phase. **\n")) ; - - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - /* compact the pivot row */ - new_rp = rp ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - col = *rp++ ; - /* skip dead columns */ - if (COL_IS_DEAD (col)) - { - continue ; - } - *new_rp++ = col ; - /* add new pivot row to column */ - A [Col [col].start + (Col [col].length++)] = pivot_row ; - - /* retrieve score so far and add on pivot row's degree. */ - /* (we wait until here for this in case the pivot */ - /* row's degree was reduced due to mass elimination). */ - cur_score = Col [col].shared2.score + pivot_row_degree ; - - /* calculate the max possible score as the number of */ - /* external columns minus the 'k' value minus the */ - /* columns thickness */ - max_score = n_col - k - Col [col].shared1.thickness ; - - /* make the score the external degree of the union-of-rows */ - cur_score -= Col [col].shared1.thickness ; - - /* make sure score is less or equal than the max score */ - cur_score = MIN (cur_score, max_score) ; - ASSERT (cur_score >= 0) ; - - /* store updated score */ - Col [col].shared2.score = cur_score ; - - /* === Place column back in degree list ========================= */ - - if (CMEMBER (col) == current_set) - { - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (cur_score >= 0) ; - ASSERT (cur_score <= n_col) ; - ASSERT (head [cur_score] >= EMPTY) ; - next_col = head [cur_score] ; - Col [col].shared4.degree_next = next_col ; - Col [col].shared3.prev = EMPTY ; - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = col ; - } - head [cur_score] = col ; - /* see if this score is less than current min */ - min_score = MIN (min_score, cur_score) ; - } - else - { - Col [col].shared4.degree_next = EMPTY ; - Col [col].shared3.prev = EMPTY ; - } - } - -#ifndef SPQR_NDEBUG - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, cset_start [current_set+1]-(k+deadcol), max_deg) ; -#endif - - /* frontal matrix can have more pivot cols than pivot rows for */ - /* singular matrices. */ - - /* number of candidate pivot columns */ - Front_npivcol [nfr] = pivot_col_thickness ; - - /* all rows (not just size of contrib. block) */ - Front_nrows [nfr] = pivot_row_thickness ; - - /* all cols */ - Front_ncols [nfr] = pivot_col_thickness + pivot_row_degree ; - - Front_parent [nfr] = EMPTY ; - - pivot_row_thickness -= pivot_col_thickness ; - DEBUG1 (("Front "ID" Pivot_row_thickness after pivot cols elim: "ID"\n", - nfr, pivot_row_thickness)) ; - pivot_row_thickness = MAX (0, pivot_row_thickness) ; - - /* === Resurrect the new pivot row ================================== */ - - if ((pivot_row_degree > 0 && pivot_row_thickness > 0 && (order_for_lu)) - || (pivot_row_degree > 0 && (!order_for_lu))) - { - /* update pivot row length to reflect any cols that were killed */ - /* during super-col detection and mass elimination */ - Row [pivot_row].start = pivot_row_start ; - Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; - Row [pivot_row].shared1.degree = pivot_row_degree ; - Row [pivot_row].shared2.mark = 0 ; - Row [pivot_row].thickness = pivot_row_thickness ; - Row [pivot_row].front = nfr ; - /* pivot row is no longer dead */ - DEBUG1 (("Resurrect Pivot_row "ID" deg: "ID"\n", - pivot_row, pivot_row_degree)) ; - } - -#ifndef SPQR_NDEBUG - DEBUG1 (("Front "ID" : "ID" "ID" "ID" ", nfr, - Front_npivcol [nfr], Front_nrows [nfr], Front_ncols [nfr])) ; - DEBUG1 ((" cols:[ ")) ; - debug_d = 0 ; - for (col = Front_cols [nfr] ; col != EMPTY ; col = Col [col].nextcol) - { - DEBUG1 ((" "ID, col)) ; - ASSERT (col >= 0 && col < n_col) ; - ASSERT (COL_IS_DEAD (col)) ; - debug_d++ ; - ASSERT (debug_d <= pivot_col_thickness) ; - } - ASSERT (debug_d == pivot_col_thickness) ; - DEBUG1 ((" ]\n ")) ; -#endif - nfr++ ; /* one more front */ - } - - /* === All principal columns have now been ordered ====================== */ - - *p_nfr = nfr ; - return (ngarbage) ; -} - - -/* ========================================================================== */ -/* === detect_super_cols ==================================================== */ -/* ========================================================================== */ - -/* - * Detects supercolumns by finding matches between columns in the hash buckets. - * Check amongst columns in the set A [row_start ... row_start + row_length-1]. - * The columns under consideration are currently *not* in the degree lists, - * and have already been placed in the hash buckets. - * - * The hash bucket for columns whose hash function is equal to h is stored - * as follows: - * - * if head [h] is >= 0, then head [h] contains a degree list, so: - * - * head [h] is the first column in degree bucket h. - * Col [head [h]].headhash gives the first column in hash bucket h. - * - * otherwise, the degree list is empty, and: - * - * -(head [h] + 2) is the first column in hash bucket h. - * - * For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous - * column" pointer. Col [c].shared3.hash is used instead as the hash number - * for that column. The value of Col [c].shared4.hash_next is the next column - * in the same hash bucket. - * - * Assuming no, or "few" hash collisions, the time taken by this routine is - * linear in the sum of the sizes (lengths) of each column whose score has - * just been computed in the approximate degree computation. - * Not user-callable. - */ - -PRIVATE void detect_super_cols -( - /* === Parameters ======================================================= */ - -#ifndef SPQR_NDEBUG - /* these two parameters are only needed when debugging is enabled: */ - Int n_col, /* number of columns of A */ - CColamd_Row Row [ ], /* of size n_row+1 */ -#endif - - CColamd_Col Col [ ], /* of size n_col+1 */ - Int A [ ], /* row indices of A */ - Int head [ ], /* head of degree lists and hash buckets */ - Int row_start, /* pointer to set of columns to check */ - Int row_length, /* number of columns to check */ - Int cmember [ ] /* col -> cset mapping */ -) -{ - /* === Local variables ================================================== */ - - Int hash ; /* hash value for a column */ - Int *rp ; /* pointer to a row */ - Int c ; /* a column index */ - Int super_c ; /* column index of the column to absorb into */ - Int *cp1 ; /* column pointer for column super_c */ - Int *cp2 ; /* column pointer for column c */ - Int length ; /* length of column super_c */ - Int prev_c ; /* column preceding c in hash bucket */ - Int i ; /* loop counter */ - Int *rp_end ; /* pointer to the end of the row */ - Int col ; /* a column index in the row to check */ - Int head_column ; /* first column in hash bucket or degree list */ - Int first_col ; /* first column in hash bucket */ - - /* === Consider each column in the row ================================== */ - - rp = &A [row_start] ; - rp_end = rp + row_length ; - while (rp < rp_end) - { - col = *rp++ ; - if (COL_IS_DEAD (col)) - { - continue ; - } - - /* get hash number for this column */ - hash = Col [col].shared3.hash ; - ASSERT (hash <= n_col) ; - - /* === Get the first column in this hash bucket ===================== */ - - head_column = head [hash] ; - if (head_column > EMPTY) - { - first_col = Col [head_column].shared3.headhash ; - } - else - { - first_col = - (head_column + 2) ; - } - - /* === Consider each column in the hash bucket ====================== */ - - for (super_c = first_col ; super_c != EMPTY ; - super_c = Col [super_c].shared4.hash_next) - { - ASSERT (COL_IS_ALIVE (super_c)) ; - ASSERT (Col [super_c].shared3.hash == hash) ; - length = Col [super_c].length ; - - /* prev_c is the column preceding column c in the hash bucket */ - prev_c = super_c ; - - /* === Compare super_c with all columns after it ================ */ - - for (c = Col [super_c].shared4.hash_next ; - c != EMPTY ; c = Col [c].shared4.hash_next) - { - ASSERT (c != super_c) ; - ASSERT (COL_IS_ALIVE (c)) ; - ASSERT (Col [c].shared3.hash == hash) ; - - /* not identical if lengths or scores are different, */ - /* or if in different constraint sets */ - if (Col [c].length != length || - Col [c].shared2.score != Col [super_c].shared2.score - || CMEMBER (c) != CMEMBER (super_c)) - { - prev_c = c ; - continue ; - } - - /* compare the two columns */ - cp1 = &A [Col [super_c].start] ; - cp2 = &A [Col [c].start] ; - - for (i = 0 ; i < length ; i++) - { - /* the columns are "clean" (no dead rows) */ - ASSERT (ROW_IS_ALIVE (*cp1)) ; - ASSERT (ROW_IS_ALIVE (*cp2)) ; - /* row indices will same order for both supercols, */ - /* no gather scatter nessasary */ - if (*cp1++ != *cp2++) - { - break ; - } - } - - /* the two columns are different if the for-loop "broke" */ - /* super columns should belong to the same constraint set */ - if (i != length) - { - prev_c = c ; - continue ; - } - - /* === Got it! two columns are identical =================== */ - - ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; - - Col [super_c].shared1.thickness += Col [c].shared1.thickness ; - Col [c].shared1.parent = super_c ; - KILL_NON_PRINCIPAL_COL (c) ; - /* order c later, in order_children() */ - Col [c].shared2.order = EMPTY ; - /* remove c from hash bucket */ - Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; - - /* add c to end of list of super_c */ - ASSERT (Col [super_c].lastcol >= 0) ; - ASSERT (Col [super_c].lastcol < n_col) ; - Col [Col [super_c].lastcol].nextcol = c ; - Col [super_c].lastcol = Col [c].lastcol ; -#ifndef SPQR_NDEBUG - /* dump the supercolumn */ - DEBUG1 (("Super")) ; - dump_super (super_c, Col, n_col) ; -#endif - } - } - - /* === Empty this hash bucket ======================================= */ - - if (head_column > EMPTY) - { - /* corresponding degree list "hash" is not empty */ - Col [head_column].shared3.headhash = EMPTY ; - } - else - { - /* corresponding degree list "hash" is empty */ - head [hash] = EMPTY ; - } - } -} - - -/* ========================================================================== */ -/* === garbage_collection =================================================== */ -/* ========================================================================== */ - -/* - * Defragments and compacts columns and rows in the workspace A. Used when - * all avaliable memory has been used while performing row merging. Returns - * the index of the first free position in A, after garbage collection. The - * time taken by this routine is linear is the size of the array A, which is - * itself linear in the number of nonzeros in the input matrix. - * Not user-callable. - */ - -PRIVATE Int garbage_collection /* returns the new value of pfree */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows */ - Int n_col, /* number of columns */ - CColamd_Row Row [ ], /* row info */ - CColamd_Col Col [ ], /* column info */ - Int A [ ], /* A [0 ... Alen-1] holds the matrix */ - Int *pfree /* &A [0] ... pfree is in use */ -) -{ - /* === Local variables ================================================== */ - - Int *psrc ; /* source pointer */ - Int *pdest ; /* destination pointer */ - Int j ; /* counter */ - Int r ; /* a row index */ - Int c ; /* a column index */ - Int length ; /* length of a row or column */ - -#ifndef SPQR_NDEBUG - Int debug_rows ; - DEBUG2 (("Defrag..\n")) ; - for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; - debug_rows = 0 ; -#endif - - /* === Defragment the columns =========================================== */ - - pdest = &A[0] ; - for (c = 0 ; c < n_col ; c++) - { - if (COL_IS_ALIVE (c)) - { - psrc = &A [Col [c].start] ; - - /* move and compact the column */ - ASSERT (pdest <= psrc) ; - Col [c].start = (Int) (pdest - &A [0]) ; - length = Col [c].length ; - for (j = 0 ; j < length ; j++) - { - r = *psrc++ ; - if (ROW_IS_ALIVE (r)) - { - *pdest++ = r ; - } - } - Col [c].length = (Int) (pdest - &A [Col [c].start]) ; - } - } - - /* === Prepare to defragment the rows =================================== */ - - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_DEAD (r) || (Row [r].length == 0)) - { - /* This row is already dead, or is of zero length. Cannot compact - * a row of zero length, so kill it. NOTE: in the current version, - * there are no zero-length live rows. Kill the row (for the first - * time, or again) just to be safe. */ - KILL_ROW (r) ; - } - else - { - /* save first column index in Row [r].shared2.first_column */ - psrc = &A [Row [r].start] ; - Row [r].shared2.first_column = *psrc ; - ASSERT (ROW_IS_ALIVE (r)) ; - /* flag the start of the row with the one's complement of row */ - *psrc = ONES_COMPLEMENT (r) ; -#ifndef SPQR_NDEBUG - debug_rows++ ; -#endif - } - } - - /* === Defragment the rows ============================================== */ - - psrc = pdest ; - while (psrc < pfree) - { - /* find a negative number ... the start of a row */ - if (*psrc++ < 0) - { - psrc-- ; - /* get the row index */ - r = ONES_COMPLEMENT (*psrc) ; - ASSERT (r >= 0 && r < n_row) ; - /* restore first column index */ - *psrc = Row [r].shared2.first_column ; - ASSERT (ROW_IS_ALIVE (r)) ; - - /* move and compact the row */ - ASSERT (pdest <= psrc) ; - Row [r].start = (Int) (pdest - &A [0]) ; - length = Row [r].length ; - for (j = 0 ; j < length ; j++) - { - c = *psrc++ ; - if (COL_IS_ALIVE (c)) - { - *pdest++ = c ; - } - } - Row [r].length = (Int) (pdest - &A [Row [r].start]) ; -#ifndef SPQR_NDEBUG - debug_rows-- ; -#endif - } - } - - /* ensure we found all the rows */ - ASSERT (debug_rows == 0) ; - - /* === Return the new value of pfree ==================================== */ - - return ((Int) (pdest - &A [0])) ; -} - - -/* ========================================================================== */ -/* === clear_mark =========================================================== */ -/* ========================================================================== */ - -/* - * Clears the Row [ ].shared2.mark array, and returns the new tag_mark. - * Return value is the new tag_mark. Not user-callable. - */ - -PRIVATE Int clear_mark /* return the new value for tag_mark */ -( - /* === Parameters ======================================================= */ - - Int tag_mark, /* new value of tag_mark */ - Int max_mark, /* max allowed value of tag_mark */ - - Int n_row, /* number of rows in A */ - CColamd_Row Row [ ] /* Row [0 ... n_row-1].shared2.mark is set to zero */ -) -{ - /* === Local variables ================================================== */ - - Int r ; - - if (tag_mark <= 0 || tag_mark >= max_mark) - { - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_ALIVE (r)) - { - Row [r].shared2.mark = 0 ; - } - } - tag_mark = 1 ; - } - - return (tag_mark) ; -} - - -/* ========================================================================== */ -/* === print_report ========================================================= */ -/* ========================================================================== */ - -/* No printing occurs if NPRINT is defined at compile time. */ - -PRIVATE void print_report -( - char *method, - Int stats [CCOLAMD_STATS] -) -{ - - Int i1, i2, i3 ; - - PRINTF (("\n%s version %d.%d, %s: ", method, - CCOLAMD_MAIN_VERSION, CCOLAMD_SUB_VERSION, CCOLAMD_DATE)) ; - - if (!stats) - { - PRINTF (("No statistics available.\n")) ; - return ; - } - - i1 = stats [CCOLAMD_INFO1] ; - i2 = stats [CCOLAMD_INFO2] ; - i3 = stats [CCOLAMD_INFO3] ; - - if (stats [CCOLAMD_STATUS] >= 0) - { - PRINTF(("OK. ")) ; - } - else - { - PRINTF(("ERROR. ")) ; - } - - switch (stats [CCOLAMD_STATUS]) - { - - case CCOLAMD_OK_BUT_JUMBLED: - - PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ; - - PRINTF(("%s: duplicate or out-of-order row indices: "ID"\n", - method, i3)) ; - - PRINTF(("%s: last seen duplicate or out-of-order row: "ID"\n", - method, INDEX (i2))) ; - - PRINTF(("%s: last seen in column: "ID"", - method, INDEX (i1))) ; - - /* no break - fall through to next case instead */ - - case CCOLAMD_OK: - - PRINTF(("\n")) ; - - PRINTF(("%s: number of dense or empty rows ignored: "ID"\n", - method, stats [CCOLAMD_DENSE_ROW])) ; - - PRINTF(("%s: number of dense or empty columns ignored: "ID"\n", - method, stats [CCOLAMD_DENSE_COL])) ; - - PRINTF(("%s: number of garbage collections performed: "ID"\n", - method, stats [CCOLAMD_DEFRAG_COUNT])) ; - break ; - - case CCOLAMD_ERROR_A_not_present: - - PRINTF(("Array A (row indices of matrix) not present.\n")) ; - break ; - - case CCOLAMD_ERROR_p_not_present: - - PRINTF(("Array p (column pointers for matrix) not present.\n")) ; - break ; - - case CCOLAMD_ERROR_nrow_negative: - - PRINTF(("Invalid number of rows ("ID").\n", i1)) ; - break ; - - case CCOLAMD_ERROR_ncol_negative: - - PRINTF(("Invalid number of columns ("ID").\n", i1)) ; - break ; - - case CCOLAMD_ERROR_nnz_negative: - - PRINTF(("Invalid number of nonzero entries ("ID").\n", i1)) ; - break ; - - case CCOLAMD_ERROR_p0_nonzero: - - PRINTF(("Invalid column pointer, p [0] = "ID", must be 0.\n", i1)) ; - break ; - - case CCOLAMD_ERROR_A_too_small: - - PRINTF(("Array A too small.\n")) ; - PRINTF((" Need Alen >= "ID", but given only Alen = "ID".\n", - i1, i2)) ; - break ; - - case CCOLAMD_ERROR_col_length_negative: - - PRINTF(("Column "ID" has a negative number of entries ("ID").\n", - INDEX (i1), i2)) ; - break ; - - case CCOLAMD_ERROR_row_index_out_of_bounds: - - PRINTF(("Row index (row "ID") out of bounds ("ID" to "ID") in" - "column "ID".\n", INDEX (i2), INDEX (0), INDEX (i3-1), - INDEX (i1))) ; - break ; - - case CCOLAMD_ERROR_out_of_memory: - - PRINTF(("Out of memory.\n")) ; - break ; - - case CCOLAMD_ERROR_invalid_cmember: - - PRINTF(("cmember invalid\n")) ; - break ; - } -} - - -/* ========================================================================= */ -/* === "Expert" routines =================================================== */ -/* ========================================================================= */ - -/* The following routines are visible outside this routine, but are not meant - * to be called by the user. They are meant for a future version of UMFPACK, - * to replace UMFPACK internal routines with a similar name. - */ - - -/* ========================================================================== */ -/* === CCOLAMD_apply_order ================================================== */ -/* ========================================================================== */ - -/* - * Apply post-ordering of supernodal elimination tree. - */ - -GLOBAL void CCOLAMD_apply_order -( - Int Front [ ], /* of size nn on input, size nfr on output */ - const Int Order [ ], /* Order [i] = k, i in the range 0..nn-1, - * and k in the range 0..nfr-1, means that node - * i is the kth node in the postordered tree. */ - Int Temp [ ], /* workspace of size nfr */ - Int nn, /* nodes are numbered in the range 0..nn-1 */ - Int nfr /* the number of nodes actually in use */ -) -{ - Int i, k ; - for (i = 0 ; i < nn ; i++) - { - k = Order [i] ; - ASSERT (k >= EMPTY && k < nfr) ; - if (k != EMPTY) - { - Temp [k] = Front [i] ; - } - } - - for (k = 0 ; k < nfr ; k++) - { - Front [k] = Temp [k] ; - } -} - - -/* ========================================================================== */ -/* === CCOLAMD_fsize ======================================================== */ -/* ========================================================================== */ - -/* Determine the largest frontal matrix size for each subtree. - * Only required to sort the children of each - * node prior to postordering the column elimination tree. */ - -GLOBAL void CCOLAMD_fsize -( - Int nn, - Int Fsize [ ], - Int Fnrows [ ], - Int Fncols [ ], - Int Parent [ ], - Int Npiv [ ] -) -{ - double dr, dc ; - Int j, parent, frsize, r, c ; - - for (j = 0 ; j < nn ; j++) - { - Fsize [j] = EMPTY ; - } - - /* ---------------------------------------------------------------------- */ - /* find max front size for tree rooted at node j, for each front j */ - /* ---------------------------------------------------------------------- */ - - DEBUG1 (("\n\n========================================FRONTS:\n")) ; - for (j = 0 ; j < nn ; j++) - { - if (Npiv [j] > 0) - { - /* this is a frontal matrix */ - parent = Parent [j] ; - r = Fnrows [j] ; - c = Fncols [j] ; - /* avoid integer overflow */ - dr = (double) r ; - dc = (double) c ; - frsize = (INT_OVERFLOW (dr * dc)) ? Int_MAX : (r * c) ; - DEBUG1 ((""ID" : npiv "ID" size "ID" parent "ID" ", - j, Npiv [j], frsize, parent)) ; - Fsize [j] = MAX (Fsize [j], frsize) ; - DEBUG1 (("Fsize [j = "ID"] = "ID"\n", j, Fsize [j])) ; - if (parent != EMPTY) - { - /* find the maximum frontsize of self and children */ - ASSERT (Npiv [parent] > 0) ; - ASSERT (parent > j) ; - Fsize [parent] = MAX (Fsize [parent], Fsize [j]) ; - DEBUG1 (("Fsize [parent = "ID"] = "ID"\n", - parent, Fsize [parent])); - } - } - } - DEBUG1 (("fsize done\n")) ; -} - - -/* ========================================================================= */ -/* === CCOLAMD_postorder =================================================== */ -/* ========================================================================= */ - -/* Perform a postordering (via depth-first search) of an assembly tree. */ - -GLOBAL void CCOLAMD_postorder -( - /* inputs, not modified on output: */ - Int nn, /* nodes are in the range 0..nn-1 */ - Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */ - Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j, - * or zero if j is not a node. */ - Int Fsize [ ], /* Fsize [j]: size of node j */ - - /* output, not defined on input: */ - Int Order [ ], /* output post-order */ - - /* workspaces of size nn: */ - Int Child [ ], - Int Sibling [ ], - Int Stack [ ], - Int Front_cols [ ], - - /* input, not modified on output: */ - Int cmember [ ] -) -{ - Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ; - - for (j = 0 ; j < nn ; j++) - { - Child [j] = EMPTY ; - Sibling [j] = EMPTY ; - } - - /* --------------------------------------------------------------------- */ - /* place the children in link lists - bigger elements tend to be last */ - /* --------------------------------------------------------------------- */ - - for (j = nn-1 ; j >= 0 ; j--) - { - if (Nv [j] > 0) - { - /* this is an element */ - parent = Parent [j] ; - if (parent != EMPTY) - { - /* place the element in link list of the children its parent */ - /* bigger elements will tend to be at the end of the list */ - Sibling [j] = Child [parent] ; - if (CMEMBER (Front_cols[parent]) == CMEMBER (Front_cols[j])) - { - Child [parent] = j ; - } - } - } - } - -#ifndef SPQR_NDEBUG - { - Int nels, ff, nchild ; - DEBUG1 (("\n\n================================ ccolamd_postorder:\n")); - nels = 0 ; - for (j = 0 ; j < nn ; j++) - { - if (Nv [j] > 0) - { - DEBUG1 ((""ID" : nels "ID" npiv "ID" size "ID - " parent "ID" maxfr "ID"\n", j, nels, - Nv [j], Fsize [j], Parent [j], Fsize [j])) ; - /* this is an element */ - /* dump the link list of children */ - nchild = 0 ; - DEBUG1 ((" Children: ")) ; - for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff]) - { - DEBUG1 ((ID" ", ff)) ; - nchild++ ; - ASSERT (nchild < nn) ; - } - DEBUG1 (("\n")) ; - parent = Parent [j] ; - nels++ ; - } - } - } -#endif - - /* --------------------------------------------------------------------- */ - /* place the largest child last in the list of children for each node */ - /* --------------------------------------------------------------------- */ - - for (i = 0 ; i < nn ; i++) - { - if (Nv [i] > 0 && Child [i] != EMPTY) - { - -#ifndef SPQR_NDEBUG - Int nchild ; - DEBUG1 (("Before partial sort, element "ID"\n", i)) ; - nchild = 0 ; - for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) - { - DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ; - nchild++ ; - } -#endif - - /* find the biggest element in the child list */ - fprev = EMPTY ; - maxfrsize = EMPTY ; - bigfprev = EMPTY ; - bigf = EMPTY ; - for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) - { - frsize = Fsize [f] ; - if (frsize >= maxfrsize) - { - /* this is the biggest seen so far */ - maxfrsize = frsize ; - bigfprev = fprev ; - bigf = f ; - } - fprev = f ; - } - - fnext = Sibling [bigf] ; - - DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID - " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ; - - if (fnext != EMPTY) - { - /* if fnext is EMPTY then bigf is already at the end of list */ - - if (bigfprev == EMPTY) - { - /* delete bigf from the element of the list */ - Child [i] = fnext ; - } - else - { - /* delete bigf from the middle of the list */ - Sibling [bigfprev] = fnext ; - } - - /* put bigf at the end of the list */ - Sibling [bigf] = EMPTY ; - Sibling [fprev] = bigf ; - } - -#ifndef SPQR_NDEBUG - DEBUG1 (("After partial sort, element "ID"\n", i)) ; - for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) - { - DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ; - nchild-- ; - } -#endif - } - } - - /* --------------------------------------------------------------------- */ - /* postorder the assembly tree */ - /* --------------------------------------------------------------------- */ - - for (i = 0 ; i < nn ; i++) - { - Order [i] = EMPTY ; - } - - k = 0 ; - - for (i = 0 ; i < nn ; i++) - { - if ((Parent [i] == EMPTY - || (CMEMBER (Front_cols [Parent [i]]) != CMEMBER (Front_cols [i]))) - && Nv [i] > 0) - { - DEBUG1 (("Root of assembly tree "ID"\n", i)) ; - k = CCOLAMD_post_tree (i, k, Child, Sibling, Order, Stack) ; - } - } -} - - -/* ========================================================================= */ -/* === CCOLAMD_post_tree =================================================== */ -/* ========================================================================= */ - -/* Post-ordering of a supernodal column elimination tree. */ - -GLOBAL Int CCOLAMD_post_tree -( - Int root, /* root of the tree */ - Int k, /* start numbering at k */ - Int Child [ ], /* input argument of size nn, undefined on - * output. Child [i] is the head of a link - * list of all nodes that are children of node - * i in the tree. */ - const Int Sibling [ ], /* input argument of size nn, not modified. - * If f is a node in the link list of the - * children of node i, then Sibling [f] is the - * next child of node i. - */ - Int Order [ ], /* output order, of size nn. Order [i] = k - * if node i is the kth node of the reordered - * tree. */ - Int Stack [ ] /* workspace of size nn */ -) -{ - Int f, head, h, i ; - -#if 0 - /* --------------------------------------------------------------------- */ - /* recursive version (Stack [ ] is not used): */ - /* --------------------------------------------------------------------- */ - - /* this is simple, but can cause stack overflow if nn is large */ - i = root ; - for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) - { - k = CCOLAMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ; - } - Order [i] = k++ ; - return (k) ; -#endif - - /* --------------------------------------------------------------------- */ - /* non-recursive version, using an explicit stack */ - /* --------------------------------------------------------------------- */ - - /* push root on the stack */ - head = 0 ; - Stack [0] = root ; - - while (head >= 0) - { - /* get head of stack */ - i = Stack [head] ; - DEBUG1 (("head of stack "ID" \n", i)) ; - - if (Child [i] != EMPTY) - { - /* the children of i are not yet ordered */ - /* push each child onto the stack in reverse order */ - /* so that small ones at the head of the list get popped first */ - /* and the biggest one at the end of the list gets popped last */ - for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) - { - head++ ; - } - h = head ; - for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) - { - ASSERT (h > 0) ; - Stack [h--] = f ; - DEBUG1 (("push "ID" on stack\n", f)) ; - } - ASSERT (Stack [h] == i) ; - - /* delete child list so that i gets ordered next time we see it */ - Child [i] = EMPTY ; - } - else - { - /* the children of i (if there were any) are already ordered */ - /* remove i from the stack and order it. Front i is kth front */ - head-- ; - DEBUG1 (("pop "ID" order "ID"\n", i, k)) ; - Order [i] = k++ ; - } - -#ifndef SPQR_NDEBUG - DEBUG1 (("\nStack:")) ; - for (h = head ; h >= 0 ; h--) - { - Int j = Stack [h] ; - DEBUG1 ((" "ID, j)) ; - } - DEBUG1 (("\n\n")) ; -#endif - - } - return (k) ; -} - - - -/* ========================================================================== */ -/* === CCOLAMD debugging routines =========================================== */ -/* ========================================================================== */ - -/* When debugging is disabled, the remainder of this file is ignored. */ - -#ifndef SPQR_NDEBUG - - -/* ========================================================================== */ -/* === debug_structures ===================================================== */ -/* ========================================================================== */ - -/* - * At this point, all empty rows and columns are dead. All live columns - * are "clean" (containing no dead rows) and simplicial (no supercolumns - * yet). Rows may contain dead columns, but all live rows contain at - * least one live column. - */ - -PRIVATE void debug_structures -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int A [ ], - Int cmember [ ], - Int cset_start [ ] -) -{ - /* === Local variables ================================================== */ - - Int i ; - Int c ; - Int *cp ; - Int *cp_end ; - Int len ; - Int score ; - Int r ; - Int *rp ; - Int *rp_end ; - Int deg ; - Int cs ; - - /* === Check A, Row, and Col ============================================ */ - - for (c = 0 ; c < n_col ; c++) - { - if (COL_IS_ALIVE (c)) - { - len = Col [c].length ; - score = Col [c].shared2.score ; - DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; - ASSERT (len > 0) ; - ASSERT (score >= 0) ; - ASSERT (Col [c].shared1.thickness == 1) ; - cp = &A [Col [c].start] ; - cp_end = cp + len ; - while (cp < cp_end) - { - r = *cp++ ; - ASSERT (ROW_IS_ALIVE (r)) ; - } - } - else - { - i = Col [c].shared2.order ; - cs = CMEMBER (c) ; - ASSERT (i >= cset_start [cs] && i < cset_start [cs+1]) ; - } - } - - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_ALIVE (r)) - { - i = 0 ; - len = Row [r].length ; - deg = Row [r].shared1.degree ; - ASSERT (len > 0) ; - ASSERT (deg > 0) ; - rp = &A [Row [r].start] ; - rp_end = rp + len ; - while (rp < rp_end) - { - c = *rp++ ; - if (COL_IS_ALIVE (c)) - { - i++ ; - } - } - ASSERT (i > 0) ; - } - } -} - - -/* ========================================================================== */ -/* === debug_deg_lists ====================================================== */ -/* ========================================================================== */ - -/* - * Prints the contents of the degree lists. Counts the number of columns - * in the degree list and compares it to the total it should have. Also - * checks the row degrees. - */ - -PRIVATE void debug_deg_lists -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int head [ ], - Int min_score, - Int should, - Int max_deg -) - -{ - /* === Local variables ================================================== */ - - Int deg ; - Int col ; - Int have ; - Int row ; - - /* === Check the degree lists =========================================== */ - - if (n_col > 10000 && ccolamd_debug <= 0) - { - return ; - } - have = 0 ; - DEBUG4 (("Degree lists: "ID"\n", min_score)) ; - for (deg = 0 ; deg <= n_col ; deg++) - { - col = head [deg] ; - if (col == EMPTY) - { - continue ; - } - DEBUG4 (("%d:", deg)) ; - ASSERT (Col [col].shared3.prev == EMPTY) ; - while (col != EMPTY) - { - DEBUG4 ((" "ID"", col)) ; - have += Col [col].shared1.thickness ; - ASSERT (COL_IS_ALIVE (col)) ; - col = Col [col].shared4.degree_next ; - } - DEBUG4 (("\n")) ; - } - DEBUG4 (("should "ID" have "ID"\n", should, have)) ; - ASSERT (should == have) ; - - /* === Check the row degrees ============================================ */ - - if (n_row > 10000 && ccolamd_debug <= 0) - { - return ; - } - for (row = 0 ; row < n_row ; row++) - { - if (ROW_IS_ALIVE (row)) - { - ASSERT (Row [row].shared1.degree <= max_deg) ; - } - } -} - - -/* ========================================================================== */ -/* === debug_mark =========================================================== */ -/* ========================================================================== */ - -/* - * Ensures that the tag_mark is less that the maximum and also ensures that - * each entry in the mark array is less than the tag mark. - */ - -PRIVATE void debug_mark -( - /* === Parameters ======================================================= */ - - Int n_row, - CColamd_Row Row [ ], - Int tag_mark, - Int max_mark -) -{ - /* === Local variables ================================================== */ - - Int r ; - - /* === Check the Row marks ============================================== */ - - ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; - if (n_row > 10000 && ccolamd_debug <= 0) - { - return ; - } - for (r = 0 ; r < n_row ; r++) - { - ASSERT (Row [r].shared2.mark < tag_mark) ; - } -} - - -/* ========================================================================== */ -/* === debug_matrix ========================================================= */ -/* ========================================================================== */ - -/* Prints out the contents of the columns and the rows. */ - -PRIVATE void debug_matrix -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - CColamd_Row Row [ ], - CColamd_Col Col [ ], - Int A [ ] -) -{ - /* === Local variables ================================================== */ - - Int r ; - Int c ; - Int *rp ; - Int *rp_end ; - Int *cp ; - Int *cp_end ; - - /* === Dump the rows and columns of the matrix ========================== */ - - if (ccolamd_debug < 3) - { - return ; - } - DEBUG3 (("DUMP MATRIX:\n")) ; - for (r = 0 ; r < n_row ; r++) - { - DEBUG3 (("Row "ID" alive? "ID"\n", r, ROW_IS_ALIVE (r))) ; - if (ROW_IS_DEAD (r)) - { - continue ; - } - - DEBUG3 (("start "ID" length "ID" degree "ID"\nthickness "ID"\n", - Row [r].start, Row [r].length, Row [r].shared1.degree, - Row [r].thickness)) ; - - rp = &A [Row [r].start] ; - rp_end = rp + Row [r].length ; - while (rp < rp_end) - { - c = *rp++ ; - DEBUG4 ((" "ID" col "ID"\n", COL_IS_ALIVE (c), c)) ; - } - } - - for (c = 0 ; c < n_col ; c++) - { - DEBUG3 (("Col "ID" alive? "ID"\n", c, COL_IS_ALIVE (c))) ; - if (COL_IS_DEAD (c)) - { - continue ; - } - DEBUG3 (("start "ID" length "ID" shared1 "ID" shared2 "ID"\n", - Col [c].start, Col [c].length, - Col [c].shared1.thickness, Col [c].shared2.score)) ; - cp = &A [Col [c].start] ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - r = *cp++ ; - DEBUG4 ((" "ID" row "ID"\n", ROW_IS_ALIVE (r), r)) ; - } - } -} - - -/* ========================================================================== */ -/* === dump_super =========================================================== */ -/* ========================================================================== */ - -PRIVATE void dump_super -( - Int super_c, - CColamd_Col Col [ ], - Int n_col -) -{ - Int col, ncols ; - - DEBUG1 ((" =[ ")) ; - ncols = 0 ; - for (col = super_c ; col != EMPTY ; col = Col [col].nextcol) - { - DEBUG1 ((" "ID, col)) ; - ASSERT (col >= 0 && col < n_col) ; - if (col != super_c) - { - ASSERT (COL_IS_DEAD (col)) ; - } - if (Col [col].nextcol == EMPTY) - { - ASSERT (col == Col [super_c].lastcol) ; - } - ncols++ ; - ASSERT (ncols <= Col [super_c].shared1.thickness) ; - } - ASSERT (ncols == Col [super_c].shared1.thickness) ; - DEBUG1 (("]\n")) ; -} - - -/* ========================================================================== */ -/* === ccolamd_get_debug ==================================================== */ -/* ========================================================================== */ - -PRIVATE void ccolamd_get_debug -( - char *method -) -{ - FILE *debug_file ; - ccolamd_debug = 0 ; /* no debug printing */ - - /* Read debug info from the debug file. */ - debug_file = fopen ("debug", "r") ; - if (debug_file) - { - (void) fscanf (debug_file, ""ID"", &ccolamd_debug) ; - (void) fclose (debug_file) ; - } - - DEBUG0 ((":")) ; - DEBUG1 (("%s: debug version, D = "ID" (THIS WILL BE SLOW!)\n", - method, ccolamd_debug)) ; - DEBUG1 ((" Debug printing level: "ID"\n", ccolamd_debug)) ; -} - -#endif diff --git a/colamd/ccolamd.h b/colamd/ccolamd.h deleted file mode 100644 index 11a098741..000000000 --- a/colamd/ccolamd.h +++ /dev/null @@ -1,365 +0,0 @@ -/* ========================================================================== */ -/* === CCOLAMD/ccolamd.h ==================================================== */ -/* ========================================================================== */ - -/* ---------------------------------------------------------------------------- - * CCOLAMD Copyright (C), Univ. of Florida. Authors: Timothy A. Davis, - * Sivasankaran Rajamanickam, and Stefan Larimore - * See License.txt for the Version 2.1 of the GNU Lesser General Public License - * http://www.cise.ufl.edu/research/sparse - * -------------------------------------------------------------------------- */ - -/* - * You must include this file (ccolamd.h) in any routine that uses ccolamd, - * csymamd, or the related macros and definitions. - */ - -#ifndef CCOLAMD_H -#define CCOLAMD_H - -/* make it easy for C++ programs to include CCOLAMD */ -#ifdef __cplusplus -extern "C" { -#endif - -/* for size_t definition: */ -#include - -/* ========================================================================== */ -/* === CCOLAMD version ====================================================== */ -/* ========================================================================== */ - -/* All versions of CCOLAMD will include the following definitions. - * As an example, to test if the version you are using is 1.3 or later: - * - * if (CCOLAMD_VERSION >= CCOLAMD_VERSION_CODE (1,3)) ... - * - * This also works during compile-time: - * - * #if CCOLAMD_VERSION >= CCOLAMD_VERSION_CODE (1,3) - * printf ("This is version 1.3 or later\n") ; - * #else - * printf ("This is an early version\n") ; - * #endif - */ - -#define CCOLAMD_DATE "Nov 30, 2009" -#define CCOLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define CCOLAMD_MAIN_VERSION 2 -#define CCOLAMD_SUB_VERSION 7 -#define CCOLAMD_SUBSUB_VERSION 2 -#define CCOLAMD_VERSION \ - CCOLAMD_VERSION_CODE(CCOLAMD_MAIN_VERSION,CCOLAMD_SUB_VERSION) - -/* ========================================================================== */ -/* === Knob and statistics definitions ====================================== */ -/* ========================================================================== */ - -/* size of the knobs [ ] array. Only knobs [0..3] are currently used. */ -#define CCOLAMD_KNOBS 20 - -/* number of output statistics. Only stats [0..10] are currently used. */ -#define CCOLAMD_STATS 20 - -/* knobs [0] and stats [0]: dense row knob and output statistic. */ -#define CCOLAMD_DENSE_ROW 0 - -/* knobs [1] and stats [1]: dense column knob and output statistic. */ -#define CCOLAMD_DENSE_COL 1 - -/* knobs [2]: aggressive absorption option */ -#define CCOLAMD_AGGRESSIVE 2 - -/* knobs [3]: LU or Cholesky factorization option */ -#define CCOLAMD_LU 3 - -/* stats [2]: memory defragmentation count output statistic */ -#define CCOLAMD_DEFRAG_COUNT 2 - -/* stats [3]: ccolamd status: zero OK, > 0 warning or notice, < 0 error */ -#define CCOLAMD_STATUS 3 - -/* stats [4..6]: error info, or info on jumbled columns */ -#define CCOLAMD_INFO1 4 -#define CCOLAMD_INFO2 5 -#define CCOLAMD_INFO3 6 - -/* stats [7]: number of originally empty rows */ -#define CCOLAMD_EMPTY_ROW 7 -/* stats [8]: number of originally empty cols */ -#define CCOLAMD_EMPTY_COL 8 -/* stats [9]: number of rows with entries only in dense cols */ -#define CCOLAMD_NEWLY_EMPTY_ROW 9 -/* stats [10]: number of cols with entries only in dense rows */ -#define CCOLAMD_NEWLY_EMPTY_COL 10 - -/* error codes returned in stats [3]: */ -#define CCOLAMD_OK (0) -#define CCOLAMD_OK_BUT_JUMBLED (1) -#define CCOLAMD_ERROR_A_not_present (-1) -#define CCOLAMD_ERROR_p_not_present (-2) -#define CCOLAMD_ERROR_nrow_negative (-3) -#define CCOLAMD_ERROR_ncol_negative (-4) -#define CCOLAMD_ERROR_nnz_negative (-5) -#define CCOLAMD_ERROR_p0_nonzero (-6) -#define CCOLAMD_ERROR_A_too_small (-7) -#define CCOLAMD_ERROR_col_length_negative (-8) -#define CCOLAMD_ERROR_row_index_out_of_bounds (-9) -#define CCOLAMD_ERROR_out_of_memory (-10) -#define CCOLAMD_ERROR_invalid_cmember (-11) -#define CCOLAMD_ERROR_internal_error (-999) - -/* ========================================================================== */ -/* === Prototypes of user-callable routines ================================= */ -/* ========================================================================== */ - -/* define UF_long */ -#include "UFconfig.h" - -size_t ccolamd_recommended /* returns recommended value of Alen, */ - /* or 0 if input arguments are erroneous */ -( - int nnz, /* nonzeros in A */ - int n_row, /* number of rows in A */ - int n_col /* number of columns in A */ -) ; - -size_t ccolamd_l_recommended /* returns recommended value of Alen, */ - /* or 0 if input arguments are erroneous */ -( - UF_long nnz, /* nonzeros in A */ - UF_long n_row, /* number of rows in A */ - UF_long n_col /* number of columns in A */ -) ; - -void ccolamd_set_defaults /* sets default parameters */ -( /* knobs argument is modified on output */ - double knobs [CCOLAMD_KNOBS] /* parameter settings for ccolamd */ -) ; - -void ccolamd_l_set_defaults /* sets default parameters */ -( /* knobs argument is modified on output */ - double knobs [CCOLAMD_KNOBS] /* parameter settings for ccolamd */ -) ; - -int ccolamd /* returns (1) if successful, (0) otherwise*/ -( /* A and p arguments are modified on output */ - int n_row, /* number of rows in A */ - int n_col, /* number of columns in A */ - int Alen, /* size of the array A */ - int A [ ], /* row indices of A, of size Alen */ - int p [ ], /* column pointers of A, of size n_col+1 */ - double knobs [CCOLAMD_KNOBS],/* parameter settings for ccolamd */ - int stats [CCOLAMD_STATS], /* ccolamd output statistics and error codes */ - int cmember [ ] /* Constraint set of A, of size n_col */ -) ; - -UF_long ccolamd_l /* same as ccolamd, but with UF_long integers */ -( - UF_long n_row, - UF_long n_col, - UF_long Alen, - UF_long A [ ], - UF_long p [ ], - double knobs [CCOLAMD_KNOBS], - UF_long stats [CCOLAMD_STATS], - UF_long cmember [ ] -) ; - -int csymamd /* return (1) if OK, (0) otherwise */ -( - int n, /* number of rows and columns of A */ - int A [ ], /* row indices of A */ - int p [ ], /* column pointers of A */ - int perm [ ], /* output permutation, size n_col+1 */ - double knobs [CCOLAMD_KNOBS],/* parameters (uses defaults if NULL) */ - int stats [CCOLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *), /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ - int cmember [ ], /* Constraint set of A */ - int stype /* 0: use both parts, >0: upper, <0: lower */ -) ; - -UF_long csymamd_l /* same as csymamd, but with UF_long integers */ -( - UF_long n, - UF_long A [ ], - UF_long p [ ], - UF_long perm [ ], - double knobs [CCOLAMD_KNOBS], - UF_long stats [CCOLAMD_STATS], - void * (*allocate) (size_t, size_t), - void (*release) (void *), - UF_long cmember [ ], - UF_long stype -) ; - -void ccolamd_report -( - int stats [CCOLAMD_STATS] -) ; - -void ccolamd_l_report -( - UF_long stats [CCOLAMD_STATS] -) ; - -void csymamd_report -( - int stats [CCOLAMD_STATS] -) ; - -void csymamd_l_report -( - UF_long stats [CCOLAMD_STATS] -) ; - - -/* ========================================================================== */ -/* === Prototypes of "expert" routines ====================================== */ -/* ========================================================================== */ - -/* These routines are meant to be used internally, or in a future version of - * UMFPACK. They appear here so that UMFPACK can use them, but they should not - * be called directly by the user. - */ - -int ccolamd2 -( /* A and p arguments are modified on output */ - int n_row, /* number of rows in A */ - int n_col, /* number of columns in A */ - int Alen, /* size of the array A */ - int A [ ], /* row indices of A, of size Alen */ - int p [ ], /* column pointers of A, of size n_col+1 */ - double knobs [CCOLAMD_KNOBS],/* parameter settings for ccolamd */ - int stats [CCOLAMD_STATS], /* ccolamd output statistics and error codes */ - /* each Front_ array is of size n_col+1: */ - int Front_npivcol [ ], /* # pivot cols in each front */ - int Front_nrows [ ], /* # of rows in each front (incl. pivot rows) */ - int Front_ncols [ ], /* # of cols in each front (incl. pivot cols) */ - int Front_parent [ ], /* parent of each front */ - int Front_cols [ ], /* link list of pivot columns for each front */ - int *p_nfr, /* total number of frontal matrices */ - int InFront [ ], /* InFront [row] = f if row in front f */ - int cmember [ ] /* Constraint set of A */ -) ; - -UF_long ccolamd2_l /* same as ccolamd2, but with UF_long integers */ -( - UF_long n_row, - UF_long n_col, - UF_long Alen, - UF_long A [ ], - UF_long p [ ], - double knobs [CCOLAMD_KNOBS], - UF_long stats [CCOLAMD_STATS], - UF_long Front_npivcol [ ], - UF_long Front_nrows [ ], - UF_long Front_ncols [ ], - UF_long Front_parent [ ], - UF_long Front_cols [ ], - UF_long *p_nfr, - UF_long InFront [ ], - UF_long cmember [ ] -) ; - -void ccolamd_apply_order -( - int Front [ ], - const int Order [ ], - int Temp [ ], - int nn, - int nfr -) ; - -void ccolamd_l_apply_order -( - UF_long Front [ ], - const UF_long Order [ ], - UF_long Temp [ ], - UF_long nn, - UF_long nfr -) ; - - -void ccolamd_fsize -( - int nn, - int MaxFsize [ ], - int Fnrows [ ], - int Fncols [ ], - int Parent [ ], - int Npiv [ ] -) ; - -void ccolamd_l_fsize -( - UF_long nn, - UF_long MaxFsize [ ], - UF_long Fnrows [ ], - UF_long Fncols [ ], - UF_long Parent [ ], - UF_long Npiv [ ] -) ; - -void ccolamd_postorder -( - int nn, - int Parent [ ], - int Npiv [ ], - int Fsize [ ], - int Order [ ], - int Child [ ], - int Sibling [ ], - int Stack [ ], - int Front_cols [ ], - int cmember [ ] -) ; - -void ccolamd_l_postorder -( - UF_long nn, - UF_long Parent [ ], - UF_long Npiv [ ], - UF_long Fsize [ ], - UF_long Order [ ], - UF_long Child [ ], - UF_long Sibling [ ], - UF_long Stack [ ], - UF_long Front_cols [ ], - UF_long cmember [ ] -) ; - -int ccolamd_post_tree -( - int root, - int k, - int Child [ ], - const int Sibling [ ], - int Order [ ], - int Stack [ ] -) ; - -UF_long ccolamd_l_post_tree -( - UF_long root, - UF_long k, - UF_long Child [ ], - const UF_long Sibling [ ], - UF_long Order [ ], - UF_long Stack [ ] -) ; - -#ifndef EXTERN -#define EXTERN extern -#endif - -EXTERN int (*ccolamd_printf) (const char *, ...) ; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/colamd/ccolamd_global.c b/colamd/ccolamd_global.c deleted file mode 100644 index d43985126..000000000 --- a/colamd/ccolamd_global.c +++ /dev/null @@ -1,25 +0,0 @@ -/* ========================================================================== */ -/* === ccolamd_global.c ===================================================== */ -/* ========================================================================== */ - -/* ---------------------------------------------------------------------------- - * CCOLAMD Copyright (C), Univ. of Florida. Authors: Timothy A. Davis, - * Sivasankaran Rajamanickam, and Stefan Larimore - * See License.txt for the Version 2.1 of the GNU Lesser General Public License - * http://www.cise.ufl.edu/research/sparse - * -------------------------------------------------------------------------- */ - -/* Global variables for CCOLAMD */ - -#ifndef NPRINT -#ifdef MATLAB_MEX_FILE -#include "mex.h" -int (*ccolamd_printf) (const char *, ...) = mexPrintf ; -#else -#include -int (*ccolamd_printf) (const char *, ...) = printf ; -#endif -#else -int (*ccolamd_printf) (const char *, ...) = ((void *) 0) ; -#endif - diff --git a/colamd/colamd.c b/colamd/colamd.c deleted file mode 100755 index 79441dc91..000000000 --- a/colamd/colamd.c +++ /dev/null @@ -1,3611 +0,0 @@ -/* ========================================================================== */ -/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */ -/* ========================================================================== */ - -/* COLAMD / SYMAMD - - colamd: an approximate minimum degree column ordering algorithm, - for LU factorization of symmetric or unsymmetric matrices, - QR factorization, least squares, interior point methods for - linear programming problems, and other related problems. - - symamd: an approximate minimum degree ordering algorithm for Cholesky - factorization of symmetric matrices. - - Purpose: - - Colamd computes a permutation Q such that the Cholesky factorization of - (AQ)'(AQ) has less fill-in and requires fewer floating point operations - than A'A. This also provides a good ordering for sparse partial - pivoting methods, P(AQ) = LU, where Q is computed prior to numerical - factorization, and P is computed during numerical factorization via - conventional partial pivoting with row interchanges. Colamd is the - column ordering method used in SuperLU, part of the ScaLAPACK library. - It is also available as built-in function in MATLAB Version 6, - available from MathWorks, Inc. (http://www.mathworks.com). This - routine can be used in place of colmmd in MATLAB. - - Symamd computes a permutation P of a symmetric matrix A such that the - Cholesky factorization of PAP' has less fill-in and requires fewer - floating point operations than A. Symamd constructs a matrix M such - that M'M has the same nonzero pattern of A, and then orders the columns - of M using colmmd. The column ordering of M is then returned as the - row and column ordering P of A. - - Authors: - - The authors of the code itself are Stefan I. Larimore and Timothy A. - Davis (davis at cise.ufl.edu), University of Florida. The algorithm was - developed in collaboration with John Gilbert, Xerox PARC, and Esmond - Ng, Oak Ridge National Laboratory. - - Acknowledgements: - - This work was supported by the National Science Foundation, under - grants DMS-9504974 and DMS-9803599. - - Copyright and License: - - Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. - COLAMD is also available under alternate licenses, contact T. Davis - for details. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA - - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. - - Availability: - - The colamd/symamd library is available at - - http://www.cise.ufl.edu/research/sparse/colamd/ - - This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c - file. It requires the colamd.h file. It is required by the colamdmex.c - and symamdmex.c files, for the MATLAB interface to colamd and symamd. - Appears as ACM Algorithm 836. - - See the ChangeLog file for changes since Version 1.0. - - References: - - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column - minimum degree ordering algorithm, ACM Transactions on Mathematical - Software, vol. 30, no. 3., pp. 353-376, 2004. - - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, - an approximate column minimum degree ordering algorithm, ACM - Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, - 2004. - -*/ - -/* ========================================================================== */ -/* === Description of user-callable routines ================================ */ -/* ========================================================================== */ - -/* COLAMD includes both int and UF_long versions of all its routines. The - * description below is for the int version. For UF_long, all int arguments - * become UF_long. UF_long is normally defined as long, except for WIN64. - - ---------------------------------------------------------------------------- - colamd_recommended: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - size_t colamd_recommended (int nnz, int n_row, int n_col) ; - size_t colamd_l_recommended (UF_long nnz, UF_long n_row, - UF_long n_col) ; - - Purpose: - - Returns recommended value of Alen for use by colamd. Returns 0 - if any input argument is negative. The use of this routine - is optional. Not needed for symamd, which dynamically allocates - its own memory. - - Note that in v2.4 and earlier, these routines returned int or long. - They now return a value of type size_t. - - Arguments (all input arguments): - - int nnz ; Number of nonzeros in the matrix A. This must - be the same value as p [n_col] in the call to - colamd - otherwise you will get a wrong value - of the recommended memory to use. - - int n_row ; Number of rows in the matrix A. - - int n_col ; Number of columns in the matrix A. - - ---------------------------------------------------------------------------- - colamd_set_defaults: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - colamd_set_defaults (double knobs [COLAMD_KNOBS]) ; - colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ; - - Purpose: - - Sets the default parameters. The use of this routine is optional. - - Arguments: - - double knobs [COLAMD_KNOBS] ; Output only. - - NOTE: the meaning of the dense row/col knobs has changed in v2.4 - - knobs [0] and knobs [1] control dense row and col detection: - - Colamd: rows with more than - max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col)) - entries are removed prior to ordering. Columns with more than - max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col))) - entries are removed prior to - ordering, and placed last in the output column ordering. - - Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0]. - Rows and columns with more than - max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n)) - entries are removed prior to ordering, and placed last in the - output ordering. - - COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1, - respectively, in colamd.h. Default values of these two knobs - are both 10. Currently, only knobs [0] and knobs [1] are - used, but future versions may use more knobs. If so, they will - be properly set to their defaults by the future version of - colamd_set_defaults, so that the code that calls colamd will - not need to change, assuming that you either use - colamd_set_defaults, or pass a (double *) NULL pointer as the - knobs array to colamd or symamd. - - knobs [2]: aggressive absorption - - knobs [COLAMD_AGGRESSIVE] controls whether or not to do - aggressive absorption during the ordering. Default is TRUE. - - - ---------------------------------------------------------------------------- - colamd: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - int colamd (int n_row, int n_col, int Alen, int *A, int *p, - double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ; - UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen, - UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS], - UF_long stats [COLAMD_STATS]) ; - - Purpose: - - Computes a column ordering (Q) of A such that P(AQ)=LU or - (AQ)'AQ=LL' have less fill-in and require fewer floating point - operations than factorizing the unpermuted matrix A or A'A, - respectively. - - Returns: - - TRUE (1) if successful, FALSE (0) otherwise. - - Arguments: - - int n_row ; Input argument. - - Number of rows in the matrix A. - Restriction: n_row >= 0. - Colamd returns FALSE if n_row is negative. - - int n_col ; Input argument. - - Number of columns in the matrix A. - Restriction: n_col >= 0. - Colamd returns FALSE if n_col is negative. - - int Alen ; Input argument. - - Restriction (see note): - Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col - Colamd returns FALSE if these conditions are not met. - - Note: this restriction makes an modest assumption regarding - the size of the two typedef's structures in colamd.h. - We do, however, guarantee that - - Alen >= colamd_recommended (nnz, n_row, n_col) - - will be sufficient. Note: the macro version does not check - for integer overflow, and thus is not recommended. Use - the colamd_recommended routine instead. - - int A [Alen] ; Input argument, undefined on output. - - A is an integer array of size Alen. Alen must be at least as - large as the bare minimum value given above, but this is very - low, and can result in excessive run time. For best - performance, we recommend that Alen be greater than or equal to - colamd_recommended (nnz, n_row, n_col), which adds - nnz/5 to the bare minimum value given above. - - On input, the row indices of the entries in column c of the - matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices - in a given column c need not be in ascending order, and - duplicate row indices may be be present. However, colamd will - work a little faster if both of these conditions are met - (Colamd puts the matrix into this format, if it finds that the - the conditions are not met). - - The matrix is 0-based. That is, rows are in the range 0 to - n_row-1, and columns are in the range 0 to n_col-1. Colamd - returns FALSE if any row index is out of range. - - The contents of A are modified during ordering, and are - undefined on output. - - int p [n_col+1] ; Both input and output argument. - - p is an integer array of size n_col+1. On input, it holds the - "pointers" for the column form of the matrix A. Column c of - the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first - entry, p [0], must be zero, and p [c] <= p [c+1] must hold - for all c in the range 0 to n_col-1. The value p [n_col] is - thus the total number of entries in the pattern of the matrix A. - Colamd returns FALSE if these conditions are not met. - - On output, if colamd returns TRUE, the array p holds the column - permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is - the first column index in the new ordering, and p [n_col-1] is - the last. That is, p [k] = j means that column j of A is the - kth pivot column, in AQ, where k is in the range 0 to n_col-1 - (p [0] = j means that column j of A is the first column in AQ). - - If colamd returns FALSE, then no permutation is returned, and - p is undefined on output. - - double knobs [COLAMD_KNOBS] ; Input argument. - - See colamd_set_defaults for a description. - - int stats [COLAMD_STATS] ; Output argument. - - Statistics on the ordering, and error status. - See colamd.h for related definitions. - Colamd returns FALSE if stats is not present. - - stats [0]: number of dense or empty rows ignored. - - stats [1]: number of dense or empty columns ignored (and - ordered last in the output permutation p) - Note that a row can become "empty" if it - contains only "dense" and/or "empty" columns, - and similarly a column can become "empty" if it - only contains "dense" and/or "empty" rows. - - stats [2]: number of garbage collections performed. - This can be excessively high if Alen is close - to the minimum required value. - - stats [3]: status code. < 0 is an error code. - > 1 is a warning or notice. - - 0 OK. Each column of the input matrix contained - row indices in increasing order, with no - duplicates. - - 1 OK, but columns of input matrix were jumbled - (unsorted columns or duplicate entries). Colamd - had to do some extra work to sort the matrix - first and remove duplicate entries, but it - still was able to return a valid permutation - (return value of colamd was TRUE). - - stats [4]: highest numbered column that - is unsorted or has duplicate - entries. - stats [5]: last seen duplicate or - unsorted row index. - stats [6]: number of duplicate or - unsorted row indices. - - -1 A is a null pointer - - -2 p is a null pointer - - -3 n_row is negative - - stats [4]: n_row - - -4 n_col is negative - - stats [4]: n_col - - -5 number of nonzeros in matrix is negative - - stats [4]: number of nonzeros, p [n_col] - - -6 p [0] is nonzero - - stats [4]: p [0] - - -7 A is too small - - stats [4]: required size - stats [5]: actual size (Alen) - - -8 a column has a negative number of entries - - stats [4]: column with < 0 entries - stats [5]: number of entries in col - - -9 a row index is out of bounds - - stats [4]: column with bad row index - stats [5]: bad row index - stats [6]: n_row, # of rows of matrx - - -10 (unused; see symamd.c) - - -999 (unused; see symamd.c) - - Future versions may return more statistics in the stats array. - - Example: - - See http://www.cise.ufl.edu/research/sparse/colamd/example.c - for a complete example. - - To order the columns of a 5-by-4 matrix with 11 nonzero entries in - the following nonzero pattern - - x 0 x 0 - x 0 x x - 0 x x 0 - 0 0 x x - x x 0 0 - - with default knobs and no output statistics, do the following: - - #include "colamd.h" - #define ALEN 100 - int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; - int p [ ] = {0, 3, 5, 9, 11} ; - int stats [COLAMD_STATS] ; - colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; - - The permutation is returned in the array p, and A is destroyed. - - ---------------------------------------------------------------------------- - symamd: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - int symamd (int n, int *A, int *p, int *perm, - double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS], - void (*allocate) (size_t, size_t), void (*release) (void *)) ; - UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm, - double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS], - void (*allocate) (size_t, size_t), void (*release) (void *)) ; - - Purpose: - - The symamd routine computes an ordering P of a symmetric sparse - matrix A such that the Cholesky factorization PAP' = LL' remains - sparse. It is based on a column ordering of a matrix M constructed - so that the nonzero pattern of M'M is the same as A. The matrix A - is assumed to be symmetric; only the strictly lower triangular part - is accessed. You must pass your selected memory allocator (usually - calloc/free or mxCalloc/mxFree) to symamd, for it to allocate - memory for the temporary matrix M. - - Returns: - - TRUE (1) if successful, FALSE (0) otherwise. - - Arguments: - - int n ; Input argument. - - Number of rows and columns in the symmetrix matrix A. - Restriction: n >= 0. - Symamd returns FALSE if n is negative. - - int A [nnz] ; Input argument. - - A is an integer array of size nnz, where nnz = p [n]. - - The row indices of the entries in column c of the matrix are - held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a - given column c need not be in ascending order, and duplicate - row indices may be present. However, symamd will run faster - if the columns are in sorted order with no duplicate entries. - - The matrix is 0-based. That is, rows are in the range 0 to - n-1, and columns are in the range 0 to n-1. Symamd - returns FALSE if any row index is out of range. - - The contents of A are not modified. - - int p [n+1] ; Input argument. - - p is an integer array of size n+1. On input, it holds the - "pointers" for the column form of the matrix A. Column c of - the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first - entry, p [0], must be zero, and p [c] <= p [c+1] must hold - for all c in the range 0 to n-1. The value p [n] is - thus the total number of entries in the pattern of the matrix A. - Symamd returns FALSE if these conditions are not met. - - The contents of p are not modified. - - int perm [n+1] ; Output argument. - - On output, if symamd returns TRUE, the array perm holds the - permutation P, where perm [0] is the first index in the new - ordering, and perm [n-1] is the last. That is, perm [k] = j - means that row and column j of A is the kth column in PAP', - where k is in the range 0 to n-1 (perm [0] = j means - that row and column j of A are the first row and column in - PAP'). The array is used as a workspace during the ordering, - which is why it must be of length n+1, not just n. - - double knobs [COLAMD_KNOBS] ; Input argument. - - See colamd_set_defaults for a description. - - int stats [COLAMD_STATS] ; Output argument. - - Statistics on the ordering, and error status. - See colamd.h for related definitions. - Symamd returns FALSE if stats is not present. - - stats [0]: number of dense or empty row and columns ignored - (and ordered last in the output permutation - perm). Note that a row/column can become - "empty" if it contains only "dense" and/or - "empty" columns/rows. - - stats [1]: (same as stats [0]) - - stats [2]: number of garbage collections performed. - - stats [3]: status code. < 0 is an error code. - > 1 is a warning or notice. - - 0 OK. Each column of the input matrix contained - row indices in increasing order, with no - duplicates. - - 1 OK, but columns of input matrix were jumbled - (unsorted columns or duplicate entries). Symamd - had to do some extra work to sort the matrix - first and remove duplicate entries, but it - still was able to return a valid permutation - (return value of symamd was TRUE). - - stats [4]: highest numbered column that - is unsorted or has duplicate - entries. - stats [5]: last seen duplicate or - unsorted row index. - stats [6]: number of duplicate or - unsorted row indices. - - -1 A is a null pointer - - -2 p is a null pointer - - -3 (unused, see colamd.c) - - -4 n is negative - - stats [4]: n - - -5 number of nonzeros in matrix is negative - - stats [4]: # of nonzeros (p [n]). - - -6 p [0] is nonzero - - stats [4]: p [0] - - -7 (unused) - - -8 a column has a negative number of entries - - stats [4]: column with < 0 entries - stats [5]: number of entries in col - - -9 a row index is out of bounds - - stats [4]: column with bad row index - stats [5]: bad row index - stats [6]: n_row, # of rows of matrx - - -10 out of memory (unable to allocate temporary - workspace for M or count arrays using the - "allocate" routine passed into symamd). - - Future versions may return more statistics in the stats array. - - void * (*allocate) (size_t, size_t) - - A pointer to a function providing memory allocation. The - allocated memory must be returned initialized to zero. For a - C application, this argument should normally be a pointer to - calloc. For a MATLAB mexFunction, the routine mxCalloc is - passed instead. - - void (*release) (size_t, size_t) - - A pointer to a function that frees memory allocated by the - memory allocation routine above. For a C application, this - argument should normally be a pointer to free. For a MATLAB - mexFunction, the routine mxFree is passed instead. - - - ---------------------------------------------------------------------------- - colamd_report: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - colamd_report (int stats [COLAMD_STATS]) ; - colamd_l_report (UF_long stats [COLAMD_STATS]) ; - - Purpose: - - Prints the error status and statistics recorded in the stats - array on the standard error output (for a standard C routine) - or on the MATLAB output (for a mexFunction). - - Arguments: - - int stats [COLAMD_STATS] ; Input only. Statistics from colamd. - - - ---------------------------------------------------------------------------- - symamd_report: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - symamd_report (int stats [COLAMD_STATS]) ; - symamd_l_report (UF_long stats [COLAMD_STATS]) ; - - Purpose: - - Prints the error status and statistics recorded in the stats - array on the standard error output (for a standard C routine) - or on the MATLAB output (for a mexFunction). - - Arguments: - - int stats [COLAMD_STATS] ; Input only. Statistics from symamd. - - -*/ - -/* ========================================================================== */ -/* === Scaffolding code definitions ======================================== */ -/* ========================================================================== */ - -/* Ensure that debugging is turned off: */ -#ifndef SPQR_NDEBUG -#define SPQR_NDEBUG -#endif - -/* turn on debugging by uncommenting the following line - #undef SPQR_NDEBUG -*/ - -/* - Our "scaffolding code" philosophy: In our opinion, well-written library - code should keep its "debugging" code, and just normally have it turned off - by the compiler so as not to interfere with performance. This serves - several purposes: - - (1) assertions act as comments to the reader, telling you what the code - expects at that point. All assertions will always be true (unless - there really is a bug, of course). - - (2) leaving in the scaffolding code assists anyone who would like to modify - the code, or understand the algorithm (by reading the debugging output, - one can get a glimpse into what the code is doing). - - (3) (gasp!) for actually finding bugs. This code has been heavily tested - and "should" be fully functional and bug-free ... but you never know... - - The code will become outrageously slow when debugging is - enabled. To control the level of debugging output, set an environment - variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging, - you should see the following message on the standard output: - - colamd: debug version, D = 1 (THIS WILL BE SLOW!) - - or a similar message for symamd. If you don't, then debugging has not - been enabled. - -*/ - -/* ========================================================================== */ -/* === Include files ======================================================== */ -/* ========================================================================== */ - -#include "colamd.h" -#include -#include - -#ifdef MATLAB_MEX_FILE -#include "mex.h" -#include "matrix.h" -#endif /* MATLAB_MEX_FILE */ - -#if !defined (NPRINT) || !defined (SPQR_NDEBUG) -#include -#endif - -#ifndef NULL -#define NULL ((void *) 0) -#endif - -/* ========================================================================== */ -/* === int or UF_long ======================================================= */ -/* ========================================================================== */ - -/* define UF_long */ -#include "UFconfig.h" - -#ifdef DLONG - -#define Int UF_long -#define ID UF_long_id -#define Int_MAX UF_long_max - -#define COLAMD_recommended colamd_l_recommended -#define COLAMD_set_defaults colamd_l_set_defaults -#define COLAMD_MAIN colamd_l -#define SYMAMD_MAIN symamd_l -#define COLAMD_report colamd_l_report -#define SYMAMD_report symamd_l_report - -#else - -#define Int int -#define ID "%d" -#define Int_MAX INT_MAX - -#define COLAMD_recommended colamd_recommended -#define COLAMD_set_defaults colamd_set_defaults -#define COLAMD_MAIN colamd -#define SYMAMD_MAIN symamd -#define COLAMD_report colamd_report -#define SYMAMD_report symamd_report - -#endif - -/* ========================================================================== */ -/* === Row and Column structures ============================================ */ -/* ========================================================================== */ - -/* User code that makes use of the colamd/symamd routines need not directly */ -/* reference these structures. They are used only for colamd_recommended. */ - -typedef struct Colamd_Col_struct -{ - Int start ; /* index for A of first row in this column, or DEAD */ - /* if column is dead */ - Int length ; /* number of rows in this column */ - union - { - Int thickness ; /* number of original columns represented by this */ - /* col, if the column is alive */ - Int parent ; /* parent in parent tree super-column structure, if */ - /* the column is dead */ - } shared1 ; - union - { - Int score ; /* the score used to maintain heap, if col is alive */ - Int order ; /* pivot ordering of this column, if col is dead */ - } shared2 ; - union - { - Int headhash ; /* head of a hash bucket, if col is at the head of */ - /* a degree list */ - Int hash ; /* hash value, if col is not in a degree list */ - Int prev ; /* previous column in degree list, if col is in a */ - /* degree list (but not at the head of a degree list) */ - } shared3 ; - union - { - Int degree_next ; /* next column, if col is in a degree list */ - Int hash_next ; /* next column, if col is in a hash list */ - } shared4 ; - -} Colamd_Col ; - -typedef struct Colamd_Row_struct -{ - Int start ; /* index for A of first col in this row */ - Int length ; /* number of principal columns in this row */ - union - { - Int degree ; /* number of principal & non-principal columns in row */ - Int p ; /* used as a row pointer in init_rows_cols () */ - } shared1 ; - union - { - Int mark ; /* for computing set differences and marking dead rows*/ - Int first_column ;/* first column in row (used in garbage collection) */ - } shared2 ; - -} Colamd_Row ; - -/* ========================================================================== */ -/* === Definitions ========================================================== */ -/* ========================================================================== */ - -/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ -#define PUBLIC -#define PRIVATE static - -#define DENSE_DEGREE(alpha,n) \ - ((Int) MAX (16.0, (alpha) * sqrt ((double) (n)))) - -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#define ONES_COMPLEMENT(r) (-(r)-1) - -/* -------------------------------------------------------------------------- */ -/* Change for version 2.1: define TRUE and FALSE only if not yet defined */ -/* -------------------------------------------------------------------------- */ - -#ifndef TRUE -#define TRUE (1) -#endif - -#ifndef FALSE -#define FALSE (0) -#endif - -/* -------------------------------------------------------------------------- */ - -#define EMPTY (-1) - -/* Row and column status */ -#define ALIVE (0) -#define DEAD (-1) - -/* Column status */ -#define DEAD_PRINCIPAL (-1) -#define DEAD_NON_PRINCIPAL (-2) - -/* Macros for row and column status update and checking. */ -#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) -#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) -#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) -#define COL_IS_DEAD(c) (Col [c].start < ALIVE) -#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) -#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) -#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } -#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } -#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } - -/* ========================================================================== */ -/* === Colamd reporting mechanism =========================================== */ -/* ========================================================================== */ - -#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS) -/* In MATLAB, matrices are 1-based to the user, but 0-based internally */ -#define INDEX(i) ((i)+1) -#else -/* In C, matrices are 0-based and indices are reported as such in *_report */ -#define INDEX(i) (i) -#endif - -/* All output goes through the PRINTF macro. */ -#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; } - -/* ========================================================================== */ -/* === Prototypes of PRIVATE routines ======================================= */ -/* ========================================================================== */ - -PRIVATE Int init_rows_cols -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int p [], - Int stats [COLAMD_STATS] -) ; - -PRIVATE void init_scoring -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int head [], - double knobs [COLAMD_KNOBS], - Int *p_n_row2, - Int *p_n_col2, - Int *p_max_deg -) ; - -PRIVATE Int find_ordering -( - Int n_row, - Int n_col, - Int Alen, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int head [], - Int n_col2, - Int max_deg, - Int pfree, - Int aggressive -) ; - -PRIVATE void order_children -( - Int n_col, - Colamd_Col Col [], - Int p [] -) ; - -PRIVATE void detect_super_cols -( - -#ifndef SPQR_NDEBUG - Int n_col, - Colamd_Row Row [], -#endif /* SPQR_NDEBUG */ - - Colamd_Col Col [], - Int A [], - Int head [], - Int row_start, - Int row_length -) ; - -PRIVATE Int garbage_collection -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int *pfree -) ; - -PRIVATE Int clear_mark -( - Int tag_mark, - Int max_mark, - Int n_row, - Colamd_Row Row [] -) ; - -PRIVATE void print_report -( - char *method, - Int stats [COLAMD_STATS] -) ; - -/* ========================================================================== */ -/* === Debugging prototypes and definitions ================================= */ -/* ========================================================================== */ - -#ifndef SPQR_NDEBUG - -#include - -/* colamd_debug is the *ONLY* global variable, and is only */ -/* present when debugging */ - -PRIVATE Int colamd_debug = 0 ; /* debug print level */ - -#define DEBUG0(params) { PRINTF (params) ; } -#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; } -#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; } -#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; } -#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; } - -#ifdef MATLAB_MEX_FILE -#define ASSERT(expression) (mxAssert ((expression), "")) -#else -#define ASSERT(expression) (assert (expression)) -#endif /* MATLAB_MEX_FILE */ - -PRIVATE void colamd_get_debug /* gets the debug print level from getenv */ -( - char *method -) ; - -PRIVATE void debug_deg_lists -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int head [], - Int min_score, - Int should, - Int max_deg -) ; - -PRIVATE void debug_mark -( - Int n_row, - Colamd_Row Row [], - Int tag_mark, - Int max_mark -) ; - -PRIVATE void debug_matrix -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [] -) ; - -PRIVATE void debug_structures -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int n_col2 -) ; - -#else /* SPQR_NDEBUG */ - -/* === No debugging ========================================================= */ - -#define DEBUG0(params) ; -#define DEBUG1(params) ; -#define DEBUG2(params) ; -#define DEBUG3(params) ; -#define DEBUG4(params) ; - -#define ASSERT(expression) - -#endif /* SPQR_NDEBUG */ - -/* ========================================================================== */ -/* === USER-CALLABLE ROUTINES: ============================================== */ -/* ========================================================================== */ - -/* ========================================================================== */ -/* === colamd_recommended =================================================== */ -/* ========================================================================== */ - -/* - The colamd_recommended routine returns the suggested size for Alen. This - value has been determined to provide good balance between the number of - garbage collections and the memory requirements for colamd. If any - argument is negative, or if integer overflow occurs, a 0 is returned as an - error condition. 2*nnz space is required for the row and column - indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is - required for the Col and Row arrays, respectively, which are internal to - colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the - minimal amount of "elbow room", and nnz/5 more space is recommended for - run time efficiency. - - Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10. - - This function is not needed when using symamd. -*/ - -/* add two values of type size_t, and check for integer overflow */ -static size_t t_add (size_t a, size_t b, int *ok) -{ - (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; - return ((*ok) ? (a + b) : 0) ; -} - -/* compute a*k where k is a small integer, and check for integer overflow */ -static size_t t_mult (size_t a, size_t k, int *ok) -{ - size_t i, s = 0 ; - for (i = 0 ; i < k ; i++) - { - s = t_add (s, a, ok) ; - } - return (s) ; -} - -/* size of the Col and Row structures */ -#define COLAMD_C(n_col,ok) \ - ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int))) - -#define COLAMD_R(n_row,ok) \ - ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int))) - - -PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */ -( - /* === Parameters ======================================================= */ - - Int nnz, /* number of nonzeros in A */ - Int n_row, /* number of rows in A */ - Int n_col /* number of columns in A */ -) -{ - size_t s, c, r ; - int ok = TRUE ; - if (nnz < 0 || n_row < 0 || n_col < 0) - { - return (0) ; - } - s = t_mult (nnz, 2, &ok) ; /* 2*nnz */ - c = COLAMD_C (n_col, &ok) ; /* size of column structures */ - r = COLAMD_R (n_row, &ok) ; /* size of row structures */ - s = t_add (s, c, &ok) ; - s = t_add (s, r, &ok) ; - s = t_add (s, n_col, &ok) ; /* elbow room */ - s = t_add (s, nnz/5, &ok) ; /* elbow room */ - ok = ok && (s < Int_MAX) ; - return (ok ? s : 0) ; -} - - -/* ========================================================================== */ -/* === colamd_set_defaults ================================================== */ -/* ========================================================================== */ - -/* - The colamd_set_defaults routine sets the default values of the user- - controllable parameters for colamd and symamd: - - Colamd: rows with more than max (16, knobs [0] * sqrt (n_col)) - entries are removed prior to ordering. Columns with more than - max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed - prior to ordering, and placed last in the output column ordering. - - Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n)) - entries are removed prior to ordering, and placed last in the - output ordering. - - knobs [0] dense row control - - knobs [1] dense column control - - knobs [2] if nonzero, do aggresive absorption - - knobs [3..19] unused, but future versions might use this - -*/ - -PUBLIC void COLAMD_set_defaults -( - /* === Parameters ======================================================= */ - - double knobs [COLAMD_KNOBS] /* knob array */ -) -{ - /* === Local variables ================================================== */ - - Int i ; - - if (!knobs) - { - return ; /* no knobs to initialize */ - } - for (i = 0 ; i < COLAMD_KNOBS ; i++) - { - knobs [i] = 0 ; - } - knobs [COLAMD_DENSE_ROW] = 10 ; - knobs [COLAMD_DENSE_COL] = 10 ; - knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/ -} - - -/* ========================================================================== */ -/* === symamd =============================================================== */ -/* ========================================================================== */ - -PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */ -( - /* === Parameters ======================================================= */ - - Int n, /* number of rows and columns of A */ - Int A [], /* row indices of A */ - Int p [], /* column pointers of A */ - Int perm [], /* output permutation, size n+1 */ - double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - Int stats [COLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), - /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *) - /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ -) -{ - /* === Local variables ================================================== */ - - Int *count ; /* length of each column of M, and col pointer*/ - Int *mark ; /* mark array for finding duplicate entries */ - Int *M ; /* row indices of matrix M */ - size_t Mlen ; /* length of M */ - Int n_row ; /* number of rows in M */ - Int nnz ; /* number of entries in A */ - Int i ; /* row index of A */ - Int j ; /* column index of A */ - Int k ; /* row index of M */ - Int mnz ; /* number of nonzeros in M */ - Int pp ; /* index into a column of A */ - Int last_row ; /* last row seen in the current column */ - Int length ; /* number of nonzeros in a column */ - - double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */ - double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */ - -#ifndef SPQR_NDEBUG - colamd_get_debug ("symamd") ; -#endif /* SPQR_NDEBUG */ - - /* === Check the input arguments ======================================== */ - - if (!stats) - { - DEBUG0 (("symamd: stats not present\n")) ; - return (FALSE) ; - } - for (i = 0 ; i < COLAMD_STATS ; i++) - { - stats [i] = 0 ; - } - stats [COLAMD_STATUS] = COLAMD_OK ; - stats [COLAMD_INFO1] = -1 ; - stats [COLAMD_INFO2] = -1 ; - - if (!A) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; - DEBUG0 (("symamd: A not present\n")) ; - return (FALSE) ; - } - - if (!p) /* p is not present */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; - DEBUG0 (("symamd: p not present\n")) ; - return (FALSE) ; - } - - if (n < 0) /* n must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; - stats [COLAMD_INFO1] = n ; - DEBUG0 (("symamd: n negative %d\n", n)) ; - return (FALSE) ; - } - - nnz = p [n] ; - if (nnz < 0) /* nnz must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; - stats [COLAMD_INFO1] = nnz ; - DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ; - return (FALSE) ; - } - - if (p [0] != 0) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; - stats [COLAMD_INFO1] = p [0] ; - DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ; - return (FALSE) ; - } - - /* === If no knobs, set default knobs =================================== */ - - if (!knobs) - { - COLAMD_set_defaults (default_knobs) ; - knobs = default_knobs ; - } - - /* === Allocate count and mark ========================================== */ - - count = (Int *) ((*allocate) (n+1, sizeof (Int))) ; - if (!count) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; - DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ; - return (FALSE) ; - } - - mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ; - if (!mark) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; - (*release) ((void *) count) ; - DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ; - return (FALSE) ; - } - - /* === Compute column counts of M, check if A is valid ================== */ - - stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ - - for (i = 0 ; i < n ; i++) - { - mark [i] = -1 ; - } - - for (j = 0 ; j < n ; j++) - { - last_row = -1 ; - - length = p [j+1] - p [j] ; - if (length < 0) - { - /* column pointers must be non-decreasing */ - stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; - stats [COLAMD_INFO1] = j ; - stats [COLAMD_INFO2] = length ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ; - return (FALSE) ; - } - - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - if (i < 0 || i >= n) - { - /* row index i, in column j, is out of bounds */ - stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; - stats [COLAMD_INFO1] = j ; - stats [COLAMD_INFO2] = i ; - stats [COLAMD_INFO3] = n ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ; - return (FALSE) ; - } - - if (i <= last_row || mark [i] == j) - { - /* row index is unsorted or repeated (or both), thus col */ - /* is jumbled. This is a notice, not an error condition. */ - stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; - stats [COLAMD_INFO1] = j ; - stats [COLAMD_INFO2] = i ; - (stats [COLAMD_INFO3]) ++ ; - DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ; - } - - if (i > j && mark [i] != j) - { - /* row k of M will contain column indices i and j */ - count [i]++ ; - count [j]++ ; - } - - /* mark the row as having been seen in this column */ - mark [i] = j ; - - last_row = i ; - } - } - - /* v2.4: removed free(mark) */ - - /* === Compute column pointers of M ===================================== */ - - /* use output permutation, perm, for column pointers of M */ - perm [0] = 0 ; - for (j = 1 ; j <= n ; j++) - { - perm [j] = perm [j-1] + count [j-1] ; - } - for (j = 0 ; j < n ; j++) - { - count [j] = perm [j] ; - } - - /* === Construct M ====================================================== */ - - mnz = perm [n] ; - n_row = mnz / 2 ; - Mlen = COLAMD_recommended (mnz, n_row, n) ; - M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ; - DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n", - n_row, n, mnz, (double) Mlen)) ; - - if (!M) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ; - return (FALSE) ; - } - - k = 0 ; - - if (stats [COLAMD_STATUS] == COLAMD_OK) - { - /* Matrix is OK */ - for (j = 0 ; j < n ; j++) - { - ASSERT (p [j+1] - p [j] >= 0) ; - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - ASSERT (i >= 0 && i < n) ; - if (i > j) - { - /* row k of M contains column indices i and j */ - M [count [i]++] = k ; - M [count [j]++] = k ; - k++ ; - } - } - } - } - else - { - /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */ - DEBUG0 (("symamd: Duplicates in A.\n")) ; - for (i = 0 ; i < n ; i++) - { - mark [i] = -1 ; - } - for (j = 0 ; j < n ; j++) - { - ASSERT (p [j+1] - p [j] >= 0) ; - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - ASSERT (i >= 0 && i < n) ; - if (i > j && mark [i] != j) - { - /* row k of M contains column indices i and j */ - M [count [i]++] = k ; - M [count [j]++] = k ; - k++ ; - mark [i] = j ; - } - } - } - /* v2.4: free(mark) moved below */ - } - - /* count and mark no longer needed */ - (*release) ((void *) count) ; - (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */ - ASSERT (k == n_row) ; - - /* === Adjust the knobs for M =========================================== */ - - for (i = 0 ; i < COLAMD_KNOBS ; i++) - { - cknobs [i] = knobs [i] ; - } - - /* there are no dense rows in M */ - cknobs [COLAMD_DENSE_ROW] = -1 ; - cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ; - - /* === Order the columns of M =========================================== */ - - /* v2.4: colamd cannot fail here, so the error check is removed */ - (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ; - - /* Note that the output permutation is now in perm */ - - /* === get the statistics for symamd from colamd ======================== */ - - /* a dense column in colamd means a dense row and col in symamd */ - stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ; - - /* === Free M =========================================================== */ - - (*release) ((void *) M) ; - DEBUG0 (("symamd: done.\n")) ; - return (TRUE) ; - -} - -/* ========================================================================== */ -/* === colamd =============================================================== */ -/* ========================================================================== */ - -/* - The colamd routine computes a column ordering Q of a sparse matrix - A such that the LU factorization P(AQ) = LU remains sparse, where P is - selected via partial pivoting. The routine can also be viewed as - providing a permutation Q such that the Cholesky factorization - (AQ)'(AQ) = LL' remains sparse. -*/ - -PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows in A */ - Int n_col, /* number of columns in A */ - Int Alen, /* length of A */ - Int A [], /* row indices of A */ - Int p [], /* pointers to columns in A */ - double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */ - Int stats [COLAMD_STATS] /* output statistics and error codes */ -) -{ - /* === Local variables ================================================== */ - - Int i ; /* loop index */ - Int nnz ; /* nonzeros in A */ - size_t Row_size ; /* size of Row [], in integers */ - size_t Col_size ; /* size of Col [], in integers */ - size_t need ; /* minimum required length of A */ - Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */ - Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */ - Int n_col2 ; /* number of non-dense, non-empty columns */ - Int n_row2 ; /* number of non-dense, non-empty rows */ - Int ngarbage ; /* number of garbage collections performed */ - Int max_deg ; /* maximum row degree */ - double default_knobs [COLAMD_KNOBS] ; /* default knobs array */ - Int aggressive ; /* do aggressive absorption */ - int ok ; - -#ifndef SPQR_NDEBUG - colamd_get_debug ("colamd") ; -#endif /* SPQR_NDEBUG */ - - /* === Check the input arguments ======================================== */ - - if (!stats) - { - DEBUG0 (("colamd: stats not present\n")) ; - return (FALSE) ; - } - for (i = 0 ; i < COLAMD_STATS ; i++) - { - stats [i] = 0 ; - } - stats [COLAMD_STATUS] = COLAMD_OK ; - stats [COLAMD_INFO1] = -1 ; - stats [COLAMD_INFO2] = -1 ; - - if (!A) /* A is not present */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; - DEBUG0 (("colamd: A not present\n")) ; - return (FALSE) ; - } - - if (!p) /* p is not present */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; - DEBUG0 (("colamd: p not present\n")) ; - return (FALSE) ; - } - - if (n_row < 0) /* n_row must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ; - stats [COLAMD_INFO1] = n_row ; - DEBUG0 (("colamd: nrow negative %d\n", n_row)) ; - return (FALSE) ; - } - - if (n_col < 0) /* n_col must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; - stats [COLAMD_INFO1] = n_col ; - DEBUG0 (("colamd: ncol negative %d\n", n_col)) ; - return (FALSE) ; - } - - nnz = p [n_col] ; - if (nnz < 0) /* nnz must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; - stats [COLAMD_INFO1] = nnz ; - DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ; - return (FALSE) ; - } - - if (p [0] != 0) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; - stats [COLAMD_INFO1] = p [0] ; - DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ; - return (FALSE) ; - } - - /* === If no knobs, set default knobs =================================== */ - - if (!knobs) - { - COLAMD_set_defaults (default_knobs) ; - knobs = default_knobs ; - } - - aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ; - - /* === Allocate the Row and Col arrays from array A ===================== */ - - ok = TRUE ; - Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */ - Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */ - - /* need = 2*nnz + n_col + Col_size + Row_size ; */ - need = t_mult (nnz, 2, &ok) ; - need = t_add (need, n_col, &ok) ; - need = t_add (need, Col_size, &ok) ; - need = t_add (need, Row_size, &ok) ; - - if (!ok || need > (size_t) Alen || need > Int_MAX) - { - /* not enough space in array A to perform the ordering */ - stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ; - stats [COLAMD_INFO1] = need ; - stats [COLAMD_INFO2] = Alen ; - DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen)); - return (FALSE) ; - } - - Alen -= Col_size + Row_size ; - Col = (Colamd_Col *) &A [Alen] ; - Row = (Colamd_Row *) &A [Alen + Col_size] ; - - /* === Construct the row and column data structures ===================== */ - - if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats)) - { - /* input matrix is invalid */ - DEBUG0 (("colamd: Matrix invalid\n")) ; - return (FALSE) ; - } - - /* === Initialize scores, kill dense rows/columns ======================= */ - - init_scoring (n_row, n_col, Row, Col, A, p, knobs, - &n_row2, &n_col2, &max_deg) ; - - /* === Order the supercolumns =========================================== */ - - ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, - n_col2, max_deg, 2*nnz, aggressive) ; - - /* === Order the non-principal columns ================================== */ - - order_children (n_col, Col, p) ; - - /* === Return statistics in stats ======================================= */ - - stats [COLAMD_DENSE_ROW] = n_row - n_row2 ; - stats [COLAMD_DENSE_COL] = n_col - n_col2 ; - stats [COLAMD_DEFRAG_COUNT] = ngarbage ; - DEBUG0 (("colamd: done.\n")) ; - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === colamd_report ======================================================== */ -/* ========================================================================== */ - -PUBLIC void COLAMD_report -( - Int stats [COLAMD_STATS] -) -{ - print_report ("colamd", stats) ; -} - - -/* ========================================================================== */ -/* === symamd_report ======================================================== */ -/* ========================================================================== */ - -PUBLIC void SYMAMD_report -( - Int stats [COLAMD_STATS] -) -{ - print_report ("symamd", stats) ; -} - - - -/* ========================================================================== */ -/* === NON-USER-CALLABLE ROUTINES: ========================================== */ -/* ========================================================================== */ - -/* There are no user-callable routines beyond this point in the file */ - - -/* ========================================================================== */ -/* === init_rows_cols ======================================================= */ -/* ========================================================================== */ - -/* - Takes the column form of the matrix in A and creates the row form of the - matrix. Also, row and column attributes are stored in the Col and Row - structs. If the columns are un-sorted or contain duplicate row indices, - this routine will also sort and remove duplicate row indices from the - column form of the matrix. Returns FALSE if the matrix is invalid, - TRUE otherwise. Not user-callable. -*/ - -PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Colamd_Row Row [], /* of size n_row+1 */ - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* row indices of A, of size Alen */ - Int p [], /* pointers to columns in A, of size n_col+1 */ - Int stats [COLAMD_STATS] /* colamd statistics */ -) -{ - /* === Local variables ================================================== */ - - Int col ; /* a column index */ - Int row ; /* a row index */ - Int *cp ; /* a column pointer */ - Int *cp_end ; /* a pointer to the end of a column */ - Int *rp ; /* a row pointer */ - Int *rp_end ; /* a pointer to the end of a row */ - Int last_row ; /* previous row */ - - /* === Initialize columns, and check column pointers ==================== */ - - for (col = 0 ; col < n_col ; col++) - { - Col [col].start = p [col] ; - Col [col].length = p [col+1] - p [col] ; - - if (Col [col].length < 0) - { - /* column pointers must be non-decreasing */ - stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; - stats [COLAMD_INFO1] = col ; - stats [COLAMD_INFO2] = Col [col].length ; - DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ; - return (FALSE) ; - } - - Col [col].shared1.thickness = 1 ; - Col [col].shared2.score = 0 ; - Col [col].shared3.prev = EMPTY ; - Col [col].shared4.degree_next = EMPTY ; - } - - /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ - - /* === Scan columns, compute row degrees, and check row indices ========= */ - - stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ - - for (row = 0 ; row < n_row ; row++) - { - Row [row].length = 0 ; - Row [row].shared2.mark = -1 ; - } - - for (col = 0 ; col < n_col ; col++) - { - last_row = -1 ; - - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - - while (cp < cp_end) - { - row = *cp++ ; - - /* make sure row indices within range */ - if (row < 0 || row >= n_row) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; - stats [COLAMD_INFO1] = col ; - stats [COLAMD_INFO2] = row ; - stats [COLAMD_INFO3] = n_row ; - DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ; - return (FALSE) ; - } - - if (row <= last_row || Row [row].shared2.mark == col) - { - /* row index are unsorted or repeated (or both), thus col */ - /* is jumbled. This is a notice, not an error condition. */ - stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; - stats [COLAMD_INFO1] = col ; - stats [COLAMD_INFO2] = row ; - (stats [COLAMD_INFO3]) ++ ; - DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col)); - } - - if (Row [row].shared2.mark != col) - { - Row [row].length++ ; - } - else - { - /* this is a repeated entry in the column, */ - /* it will be removed */ - Col [col].length-- ; - } - - /* mark the row as having been seen in this column */ - Row [row].shared2.mark = col ; - - last_row = row ; - } - } - - /* === Compute row pointers ============================================= */ - - /* row form of the matrix starts directly after the column */ - /* form of matrix in A */ - Row [0].start = p [n_col] ; - Row [0].shared1.p = Row [0].start ; - Row [0].shared2.mark = -1 ; - for (row = 1 ; row < n_row ; row++) - { - Row [row].start = Row [row-1].start + Row [row-1].length ; - Row [row].shared1.p = Row [row].start ; - Row [row].shared2.mark = -1 ; - } - - /* === Create row form ================================================== */ - - if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) - { - /* if cols jumbled, watch for repeated row indices */ - for (col = 0 ; col < n_col ; col++) - { - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - while (cp < cp_end) - { - row = *cp++ ; - if (Row [row].shared2.mark != col) - { - A [(Row [row].shared1.p)++] = col ; - Row [row].shared2.mark = col ; - } - } - } - } - else - { - /* if cols not jumbled, we don't need the mark (this is faster) */ - for (col = 0 ; col < n_col ; col++) - { - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - while (cp < cp_end) - { - A [(Row [*cp++].shared1.p)++] = col ; - } - } - } - - /* === Clear the row marks and set row degrees ========================== */ - - for (row = 0 ; row < n_row ; row++) - { - Row [row].shared2.mark = 0 ; - Row [row].shared1.degree = Row [row].length ; - } - - /* === See if we need to re-create columns ============================== */ - - if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) - { - DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ; - -#ifndef SPQR_NDEBUG - /* make sure column lengths are correct */ - for (col = 0 ; col < n_col ; col++) - { - p [col] = Col [col].length ; - } - for (row = 0 ; row < n_row ; row++) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - p [*rp++]-- ; - } - } - for (col = 0 ; col < n_col ; col++) - { - ASSERT (p [col] == 0) ; - } - /* now p is all zero (different than when debugging is turned off) */ -#endif /* SPQR_NDEBUG */ - - /* === Compute col pointers ========================================= */ - - /* col form of the matrix starts at A [0]. */ - /* Note, we may have a gap between the col form and the row */ - /* form if there were duplicate entries, if so, it will be */ - /* removed upon the first garbage collection */ - Col [0].start = 0 ; - p [0] = Col [0].start ; - for (col = 1 ; col < n_col ; col++) - { - /* note that the lengths here are for pruned columns, i.e. */ - /* no duplicate row indices will exist for these columns */ - Col [col].start = Col [col-1].start + Col [col-1].length ; - p [col] = Col [col].start ; - } - - /* === Re-create col form =========================================== */ - - for (row = 0 ; row < n_row ; row++) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - A [(p [*rp++])++] = row ; - } - } - } - - /* === Done. Matrix is not (or no longer) jumbled ====================== */ - - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === init_scoring ========================================================= */ -/* ========================================================================== */ - -/* - Kills dense or empty columns and rows, calculates an initial score for - each column, and places all columns in the degree lists. Not user-callable. -*/ - -PRIVATE void init_scoring -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Colamd_Row Row [], /* of size n_row+1 */ - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* column form and row form of A */ - Int head [], /* of size n_col+1 */ - double knobs [COLAMD_KNOBS],/* parameters */ - Int *p_n_row2, /* number of non-dense, non-empty rows */ - Int *p_n_col2, /* number of non-dense, non-empty columns */ - Int *p_max_deg /* maximum row degree */ -) -{ - /* === Local variables ================================================== */ - - Int c ; /* a column index */ - Int r, row ; /* a row index */ - Int *cp ; /* a column pointer */ - Int deg ; /* degree of a row or column */ - Int *cp_end ; /* a pointer to the end of a column */ - Int *new_cp ; /* new column pointer */ - Int col_length ; /* length of pruned column */ - Int score ; /* current column score */ - Int n_col2 ; /* number of non-dense, non-empty columns */ - Int n_row2 ; /* number of non-dense, non-empty rows */ - Int dense_row_count ; /* remove rows with more entries than this */ - Int dense_col_count ; /* remove cols with more entries than this */ - Int min_score ; /* smallest column score */ - Int max_deg ; /* maximum row degree */ - Int next_col ; /* Used to add to degree list.*/ - -#ifndef SPQR_NDEBUG - Int debug_count ; /* debug only. */ -#endif /* SPQR_NDEBUG */ - - /* === Extract knobs ==================================================== */ - - /* Note: if knobs contains a NaN, this is undefined: */ - if (knobs [COLAMD_DENSE_ROW] < 0) - { - /* only remove completely dense rows */ - dense_row_count = n_col-1 ; - } - else - { - dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ; - } - if (knobs [COLAMD_DENSE_COL] < 0) - { - /* only remove completely dense columns */ - dense_col_count = n_row-1 ; - } - else - { - dense_col_count = - DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ; - } - - DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ; - max_deg = 0 ; - n_col2 = n_col ; - n_row2 = n_row ; - - /* === Kill empty columns =============================================== */ - - /* Put the empty columns at the end in their natural order, so that LU */ - /* factorization can proceed as far as possible. */ - for (c = n_col-1 ; c >= 0 ; c--) - { - deg = Col [c].length ; - if (deg == 0) - { - /* this is a empty column, kill and order it last */ - Col [c].shared2.order = --n_col2 ; - KILL_PRINCIPAL_COL (c) ; - } - } - DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ; - - /* === Kill dense columns =============================================== */ - - /* Put the dense columns at the end, in their natural order */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* skip any dead columns */ - if (COL_IS_DEAD (c)) - { - continue ; - } - deg = Col [c].length ; - if (deg > dense_col_count) - { - /* this is a dense column, kill and order it last */ - Col [c].shared2.order = --n_col2 ; - /* decrement the row degrees */ - cp = &A [Col [c].start] ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - Row [*cp++].shared1.degree-- ; - } - KILL_PRINCIPAL_COL (c) ; - } - } - DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ; - - /* === Kill dense and empty rows ======================================== */ - - for (r = 0 ; r < n_row ; r++) - { - deg = Row [r].shared1.degree ; - ASSERT (deg >= 0 && deg <= n_col) ; - if (deg > dense_row_count || deg == 0) - { - /* kill a dense or empty row */ - KILL_ROW (r) ; - --n_row2 ; - } - else - { - /* keep track of max degree of remaining rows */ - max_deg = MAX (max_deg, deg) ; - } - } - DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ; - - /* === Compute initial column scores ==================================== */ - - /* At this point the row degrees are accurate. They reflect the number */ - /* of "live" (non-dense) columns in each row. No empty rows exist. */ - /* Some "live" columns may contain only dead rows, however. These are */ - /* pruned in the code below. */ - - /* now find the initial matlab score for each column */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* skip dead column */ - if (COL_IS_DEAD (c)) - { - continue ; - } - score = 0 ; - cp = &A [Col [c].start] ; - new_cp = cp ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - /* skip if dead */ - if (ROW_IS_DEAD (row)) - { - continue ; - } - /* compact the column */ - *new_cp++ = row ; - /* add row's external degree */ - score += Row [row].shared1.degree - 1 ; - /* guard against integer overflow */ - score = MIN (score, n_col) ; - } - /* determine pruned column length */ - col_length = (Int) (new_cp - &A [Col [c].start]) ; - if (col_length == 0) - { - /* a newly-made null column (all rows in this col are "dense" */ - /* and have already been killed) */ - DEBUG2 (("Newly null killed: %d\n", c)) ; - Col [c].shared2.order = --n_col2 ; - KILL_PRINCIPAL_COL (c) ; - } - else - { - /* set column length and set score */ - ASSERT (score >= 0) ; - ASSERT (score <= n_col) ; - Col [c].length = col_length ; - Col [c].shared2.score = score ; - } - } - DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n", - n_col-n_col2)) ; - - /* At this point, all empty rows and columns are dead. All live columns */ - /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ - /* yet). Rows may contain dead columns, but all live rows contain at */ - /* least one live column. */ - -#ifndef SPQR_NDEBUG - debug_structures (n_row, n_col, Row, Col, A, n_col2) ; -#endif /* SPQR_NDEBUG */ - - /* === Initialize degree lists ========================================== */ - -#ifndef SPQR_NDEBUG - debug_count = 0 ; -#endif /* SPQR_NDEBUG */ - - /* clear the hash buckets */ - for (c = 0 ; c <= n_col ; c++) - { - head [c] = EMPTY ; - } - min_score = n_col ; - /* place in reverse order, so low column indices are at the front */ - /* of the lists. This is to encourage natural tie-breaking */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* only add principal columns to degree lists */ - if (COL_IS_ALIVE (c)) - { - DEBUG4 (("place %d score %d minscore %d ncol %d\n", - c, Col [c].shared2.score, min_score, n_col)) ; - - /* === Add columns score to DList =============================== */ - - score = Col [c].shared2.score ; - - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (score >= 0) ; - ASSERT (score <= n_col) ; - ASSERT (head [score] >= EMPTY) ; - - /* now add this column to dList at proper score location */ - next_col = head [score] ; - Col [c].shared3.prev = EMPTY ; - Col [c].shared4.degree_next = next_col ; - - /* if there already was a column with the same score, set its */ - /* previous pointer to this new column */ - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = c ; - } - head [score] = c ; - - /* see if this score is less than current min */ - min_score = MIN (min_score, score) ; - -#ifndef SPQR_NDEBUG - debug_count++ ; -#endif /* SPQR_NDEBUG */ - - } - } - -#ifndef SPQR_NDEBUG - DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n", - debug_count, n_col, n_col-debug_count)) ; - ASSERT (debug_count == n_col2) ; - debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; -#endif /* SPQR_NDEBUG */ - - /* === Return number of remaining columns, and max row degree =========== */ - - *p_n_col2 = n_col2 ; - *p_n_row2 = n_row2 ; - *p_max_deg = max_deg ; -} - - -/* ========================================================================== */ -/* === find_ordering ======================================================== */ -/* ========================================================================== */ - -/* - Order the principal columns of the supercolumn form of the matrix - (no supercolumns on input). Uses a minimum approximate column minimum - degree ordering method. Not user-callable. -*/ - -PRIVATE Int find_ordering /* return the number of garbage collections */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Int Alen, /* size of A, 2*nnz + n_col or larger */ - Colamd_Row Row [], /* of size n_row+1 */ - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* column form and row form of A */ - Int head [], /* of size n_col+1 */ - Int n_col2, /* Remaining columns to order */ - Int max_deg, /* Maximum row degree */ - Int pfree, /* index of first free slot (2*nnz on entry) */ - Int aggressive -) -{ - /* === Local variables ================================================== */ - - Int k ; /* current pivot ordering step */ - Int pivot_col ; /* current pivot column */ - Int *cp ; /* a column pointer */ - Int *rp ; /* a row pointer */ - Int pivot_row ; /* current pivot row */ - Int *new_cp ; /* modified column pointer */ - Int *new_rp ; /* modified row pointer */ - Int pivot_row_start ; /* pointer to start of pivot row */ - Int pivot_row_degree ; /* number of columns in pivot row */ - Int pivot_row_length ; /* number of supercolumns in pivot row */ - Int pivot_col_score ; /* score of pivot column */ - Int needed_memory ; /* free space needed for pivot row */ - Int *cp_end ; /* pointer to the end of a column */ - Int *rp_end ; /* pointer to the end of a row */ - Int row ; /* a row index */ - Int col ; /* a column index */ - Int max_score ; /* maximum possible score */ - Int cur_score ; /* score of current column */ - unsigned Int hash ; /* hash value for supernode detection */ - Int head_column ; /* head of hash bucket */ - Int first_col ; /* first column in hash bucket */ - Int tag_mark ; /* marker value for mark array */ - Int row_mark ; /* Row [row].shared2.mark */ - Int set_difference ; /* set difference size of row with pivot row */ - Int min_score ; /* smallest column score */ - Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ - Int max_mark ; /* maximum value of tag_mark */ - Int pivot_col_thickness ; /* number of columns represented by pivot col */ - Int prev_col ; /* Used by Dlist operations. */ - Int next_col ; /* Used by Dlist operations. */ - Int ngarbage ; /* number of garbage collections performed */ - -#ifndef SPQR_NDEBUG - Int debug_d ; /* debug loop counter */ - Int debug_step = 0 ; /* debug loop counter */ -#endif /* SPQR_NDEBUG */ - - /* === Initialization and clear mark ==================================== */ - - max_mark = INT_MAX - n_col ; /* INT_MAX defined in */ - tag_mark = clear_mark (0, max_mark, n_row, Row) ; - min_score = 0 ; - ngarbage = 0 ; - DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ; - - /* === Order the columns ================================================ */ - - for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) - { - -#ifndef SPQR_NDEBUG - if (debug_step % 100 == 0) - { - DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; - } - else - { - DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; - } - debug_step++ ; - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, n_col2-k, max_deg) ; - debug_matrix (n_row, n_col, Row, Col, A) ; -#endif /* SPQR_NDEBUG */ - - /* === Select pivot column, and order it ============================ */ - - /* make sure degree list isn't empty */ - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (head [min_score] >= EMPTY) ; - -#ifndef SPQR_NDEBUG - for (debug_d = 0 ; debug_d < min_score ; debug_d++) - { - ASSERT (head [debug_d] == EMPTY) ; - } -#endif /* SPQR_NDEBUG */ - - /* get pivot column from head of minimum degree list */ - while (head [min_score] == EMPTY && min_score < n_col) - { - min_score++ ; - } - pivot_col = head [min_score] ; - ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; - next_col = Col [pivot_col].shared4.degree_next ; - head [min_score] = next_col ; - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = EMPTY ; - } - - ASSERT (COL_IS_ALIVE (pivot_col)) ; - - /* remember score for defrag check */ - pivot_col_score = Col [pivot_col].shared2.score ; - - /* the pivot column is the kth column in the pivot order */ - Col [pivot_col].shared2.order = k ; - - /* increment order count by column thickness */ - pivot_col_thickness = Col [pivot_col].shared1.thickness ; - k += pivot_col_thickness ; - ASSERT (pivot_col_thickness > 0) ; - DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ; - - /* === Garbage_collection, if necessary ============================= */ - - needed_memory = MIN (pivot_col_score, n_col - k) ; - if (pfree + needed_memory >= Alen) - { - pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; - ngarbage++ ; - /* after garbage collection we will have enough */ - ASSERT (pfree + needed_memory < Alen) ; - /* garbage collection has wiped out the Row[].shared2.mark array */ - tag_mark = clear_mark (0, max_mark, n_row, Row) ; - -#ifndef SPQR_NDEBUG - debug_matrix (n_row, n_col, Row, Col, A) ; -#endif /* SPQR_NDEBUG */ - } - - /* === Compute pivot row pattern ==================================== */ - - /* get starting location for this new merged row */ - pivot_row_start = pfree ; - - /* initialize new row counts to zero */ - pivot_row_degree = 0 ; - - /* tag pivot column as having been visited so it isn't included */ - /* in merged pivot row */ - Col [pivot_col].shared1.thickness = -pivot_col_thickness ; - - /* pivot row is the union of all rows in the pivot column pattern */ - cp = &A [Col [pivot_col].start] ; - cp_end = cp + Col [pivot_col].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; - /* skip if row is dead */ - if (ROW_IS_ALIVE (row)) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - /* get a column */ - col = *rp++ ; - /* add the column, if alive and untagged */ - col_thickness = Col [col].shared1.thickness ; - if (col_thickness > 0 && COL_IS_ALIVE (col)) - { - /* tag column in pivot row */ - Col [col].shared1.thickness = -col_thickness ; - ASSERT (pfree < Alen) ; - /* place column in pivot row */ - A [pfree++] = col ; - pivot_row_degree += col_thickness ; - } - } - } - } - - /* clear tag on pivot column */ - Col [pivot_col].shared1.thickness = pivot_col_thickness ; - max_deg = MAX (max_deg, pivot_row_degree) ; - -#ifndef SPQR_NDEBUG - DEBUG3 (("check2\n")) ; - debug_mark (n_row, Row, tag_mark, max_mark) ; -#endif /* SPQR_NDEBUG */ - - /* === Kill all rows used to construct pivot row ==================== */ - - /* also kill pivot row, temporarily */ - cp = &A [Col [pivot_col].start] ; - cp_end = cp + Col [pivot_col].length ; - while (cp < cp_end) - { - /* may be killing an already dead row */ - row = *cp++ ; - DEBUG3 (("Kill row in pivot col: %d\n", row)) ; - KILL_ROW (row) ; - } - - /* === Select a row index to use as the new pivot row =============== */ - - pivot_row_length = pfree - pivot_row_start ; - if (pivot_row_length > 0) - { - /* pick the "pivot" row arbitrarily (first row in col) */ - pivot_row = A [Col [pivot_col].start] ; - DEBUG3 (("Pivotal row is %d\n", pivot_row)) ; - } - else - { - /* there is no pivot row, since it is of zero length */ - pivot_row = EMPTY ; - ASSERT (pivot_row_length == 0) ; - } - ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; - - /* === Approximate degree computation =============================== */ - - /* Here begins the computation of the approximate degree. The column */ - /* score is the sum of the pivot row "length", plus the size of the */ - /* set differences of each row in the column minus the pattern of the */ - /* pivot row itself. The column ("thickness") itself is also */ - /* excluded from the column score (we thus use an approximate */ - /* external degree). */ - - /* The time taken by the following code (compute set differences, and */ - /* add them up) is proportional to the size of the data structure */ - /* being scanned - that is, the sum of the sizes of each column in */ - /* the pivot row. Thus, the amortized time to compute a column score */ - /* is proportional to the size of that column (where size, in this */ - /* context, is the column "length", or the number of row indices */ - /* in that column). The number of row indices in a column is */ - /* monotonically non-decreasing, from the length of the original */ - /* column on input to colamd. */ - - /* === Compute set differences ====================================== */ - - DEBUG3 (("** Computing set differences phase. **\n")) ; - - /* pivot row is currently dead - it will be revived later. */ - - DEBUG3 (("Pivot row: ")) ; - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - col = *rp++ ; - ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; - DEBUG3 (("Col: %d\n", col)) ; - - /* clear tags used to construct pivot row pattern */ - col_thickness = -Col [col].shared1.thickness ; - ASSERT (col_thickness > 0) ; - Col [col].shared1.thickness = col_thickness ; - - /* === Remove column from degree list =========================== */ - - cur_score = Col [col].shared2.score ; - prev_col = Col [col].shared3.prev ; - next_col = Col [col].shared4.degree_next ; - ASSERT (cur_score >= 0) ; - ASSERT (cur_score <= n_col) ; - ASSERT (cur_score >= EMPTY) ; - if (prev_col == EMPTY) - { - head [cur_score] = next_col ; - } - else - { - Col [prev_col].shared4.degree_next = next_col ; - } - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = prev_col ; - } - - /* === Scan the column ========================================== */ - - cp = &A [Col [col].start] ; - cp_end = cp + Col [col].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - row_mark = Row [row].shared2.mark ; - /* skip if dead */ - if (ROW_IS_MARKED_DEAD (row_mark)) - { - continue ; - } - ASSERT (row != pivot_row) ; - set_difference = row_mark - tag_mark ; - /* check if the row has been seen yet */ - if (set_difference < 0) - { - ASSERT (Row [row].shared1.degree <= max_deg) ; - set_difference = Row [row].shared1.degree ; - } - /* subtract column thickness from this row's set difference */ - set_difference -= col_thickness ; - ASSERT (set_difference >= 0) ; - /* absorb this row if the set difference becomes zero */ - if (set_difference == 0 && aggressive) - { - DEBUG3 (("aggressive absorption. Row: %d\n", row)) ; - KILL_ROW (row) ; - } - else - { - /* save the new mark */ - Row [row].shared2.mark = set_difference + tag_mark ; - } - } - } - -#ifndef SPQR_NDEBUG - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, n_col2-k-pivot_row_degree, max_deg) ; -#endif /* SPQR_NDEBUG */ - - /* === Add up set differences for each column ======================= */ - - DEBUG3 (("** Adding set differences phase. **\n")) ; - - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - /* get a column */ - col = *rp++ ; - ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; - hash = 0 ; - cur_score = 0 ; - cp = &A [Col [col].start] ; - /* compact the column */ - new_cp = cp ; - cp_end = cp + Col [col].length ; - - DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ; - - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - ASSERT(row >= 0 && row < n_row) ; - row_mark = Row [row].shared2.mark ; - /* skip if dead */ - if (ROW_IS_MARKED_DEAD (row_mark)) - { - DEBUG4 ((" Row %d, dead\n", row)) ; - continue ; - } - DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark)); - ASSERT (row_mark >= tag_mark) ; - /* compact the column */ - *new_cp++ = row ; - /* compute hash function */ - hash += row ; - /* add set difference */ - cur_score += row_mark - tag_mark ; - /* integer overflow... */ - cur_score = MIN (cur_score, n_col) ; - } - - /* recompute the column's length */ - Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; - - /* === Further mass elimination ================================= */ - - if (Col [col].length == 0) - { - DEBUG4 (("further mass elimination. Col: %d\n", col)) ; - /* nothing left but the pivot row in this column */ - KILL_PRINCIPAL_COL (col) ; - pivot_row_degree -= Col [col].shared1.thickness ; - ASSERT (pivot_row_degree >= 0) ; - /* order it */ - Col [col].shared2.order = k ; - /* increment order count by column thickness */ - k += Col [col].shared1.thickness ; - } - else - { - /* === Prepare for supercolumn detection ==================== */ - - DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ; - - /* save score so far */ - Col [col].shared2.score = cur_score ; - - /* add column to hash table, for supercolumn detection */ - hash %= n_col + 1 ; - - DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; - ASSERT (((Int) hash) <= n_col) ; - - head_column = head [hash] ; - if (head_column > EMPTY) - { - /* degree list "hash" is non-empty, use prev (shared3) of */ - /* first column in degree list as head of hash bucket */ - first_col = Col [head_column].shared3.headhash ; - Col [head_column].shared3.headhash = col ; - } - else - { - /* degree list "hash" is empty, use head as hash bucket */ - first_col = - (head_column + 2) ; - head [hash] = - (col + 2) ; - } - Col [col].shared4.hash_next = first_col ; - - /* save hash function in Col [col].shared3.hash */ - Col [col].shared3.hash = (Int) hash ; - ASSERT (COL_IS_ALIVE (col)) ; - } - } - - /* The approximate external column degree is now computed. */ - - /* === Supercolumn detection ======================================== */ - - DEBUG3 (("** Supercolumn detection phase. **\n")) ; - - detect_super_cols ( - -#ifndef SPQR_NDEBUG - n_col, Row, -#endif /* SPQR_NDEBUG */ - - Col, A, head, pivot_row_start, pivot_row_length) ; - - /* === Kill the pivotal column ====================================== */ - - KILL_PRINCIPAL_COL (pivot_col) ; - - /* === Clear mark =================================================== */ - - tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ; - -#ifndef SPQR_NDEBUG - DEBUG3 (("check3\n")) ; - debug_mark (n_row, Row, tag_mark, max_mark) ; -#endif /* SPQR_NDEBUG */ - - /* === Finalize the new pivot row, and column scores ================ */ - - DEBUG3 (("** Finalize scores phase. **\n")) ; - - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - /* compact the pivot row */ - new_rp = rp ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - col = *rp++ ; - /* skip dead columns */ - if (COL_IS_DEAD (col)) - { - continue ; - } - *new_rp++ = col ; - /* add new pivot row to column */ - A [Col [col].start + (Col [col].length++)] = pivot_row ; - - /* retrieve score so far and add on pivot row's degree. */ - /* (we wait until here for this in case the pivot */ - /* row's degree was reduced due to mass elimination). */ - cur_score = Col [col].shared2.score + pivot_row_degree ; - - /* calculate the max possible score as the number of */ - /* external columns minus the 'k' value minus the */ - /* columns thickness */ - max_score = n_col - k - Col [col].shared1.thickness ; - - /* make the score the external degree of the union-of-rows */ - cur_score -= Col [col].shared1.thickness ; - - /* make sure score is less or equal than the max score */ - cur_score = MIN (cur_score, max_score) ; - ASSERT (cur_score >= 0) ; - - /* store updated score */ - Col [col].shared2.score = cur_score ; - - /* === Place column back in degree list ========================= */ - - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (cur_score >= 0) ; - ASSERT (cur_score <= n_col) ; - ASSERT (head [cur_score] >= EMPTY) ; - next_col = head [cur_score] ; - Col [col].shared4.degree_next = next_col ; - Col [col].shared3.prev = EMPTY ; - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = col ; - } - head [cur_score] = col ; - - /* see if this score is less than current min */ - min_score = MIN (min_score, cur_score) ; - - } - -#ifndef SPQR_NDEBUG - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, n_col2-k, max_deg) ; -#endif /* SPQR_NDEBUG */ - - /* === Resurrect the new pivot row ================================== */ - - if (pivot_row_degree > 0) - { - /* update pivot row length to reflect any cols that were killed */ - /* during super-col detection and mass elimination */ - Row [pivot_row].start = pivot_row_start ; - Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; - ASSERT (Row [pivot_row].length > 0) ; - Row [pivot_row].shared1.degree = pivot_row_degree ; - Row [pivot_row].shared2.mark = 0 ; - /* pivot row is no longer dead */ - - DEBUG1 (("Resurrect Pivot_row %d deg: %d\n", - pivot_row, pivot_row_degree)) ; - } - } - - /* === All principal columns have now been ordered ====================== */ - - return (ngarbage) ; -} - - -/* ========================================================================== */ -/* === order_children ======================================================= */ -/* ========================================================================== */ - -/* - The find_ordering routine has ordered all of the principal columns (the - representatives of the supercolumns). The non-principal columns have not - yet been ordered. This routine orders those columns by walking up the - parent tree (a column is a child of the column which absorbed it). The - final permutation vector is then placed in p [0 ... n_col-1], with p [0] - being the first column, and p [n_col-1] being the last. It doesn't look - like it at first glance, but be assured that this routine takes time linear - in the number of columns. Although not immediately obvious, the time - taken by this routine is O (n_col), that is, linear in the number of - columns. Not user-callable. -*/ - -PRIVATE void order_children -( - /* === Parameters ======================================================= */ - - Int n_col, /* number of columns of A */ - Colamd_Col Col [], /* of size n_col+1 */ - Int p [] /* p [0 ... n_col-1] is the column permutation*/ -) -{ - /* === Local variables ================================================== */ - - Int i ; /* loop counter for all columns */ - Int c ; /* column index */ - Int parent ; /* index of column's parent */ - Int order ; /* column's order */ - - /* === Order each non-principal column ================================== */ - - for (i = 0 ; i < n_col ; i++) - { - /* find an un-ordered non-principal column */ - ASSERT (COL_IS_DEAD (i)) ; - if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) - { - parent = i ; - /* once found, find its principal parent */ - do - { - parent = Col [parent].shared1.parent ; - } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; - - /* now, order all un-ordered non-principal columns along path */ - /* to this parent. collapse tree at the same time */ - c = i ; - /* get order of parent */ - order = Col [parent].shared2.order ; - - do - { - ASSERT (Col [c].shared2.order == EMPTY) ; - - /* order this column */ - Col [c].shared2.order = order++ ; - /* collaps tree */ - Col [c].shared1.parent = parent ; - - /* get immediate parent of this column */ - c = Col [c].shared1.parent ; - - /* continue until we hit an ordered column. There are */ - /* guarranteed not to be anymore unordered columns */ - /* above an ordered column */ - } while (Col [c].shared2.order == EMPTY) ; - - /* re-order the super_col parent to largest order for this group */ - Col [parent].shared2.order = order ; - } - } - - /* === Generate the permutation ========================================= */ - - for (c = 0 ; c < n_col ; c++) - { - p [Col [c].shared2.order] = c ; - } -} - - -/* ========================================================================== */ -/* === detect_super_cols ==================================================== */ -/* ========================================================================== */ - -/* - Detects supercolumns by finding matches between columns in the hash buckets. - Check amongst columns in the set A [row_start ... row_start + row_length-1]. - The columns under consideration are currently *not* in the degree lists, - and have already been placed in the hash buckets. - - The hash bucket for columns whose hash function is equal to h is stored - as follows: - - if head [h] is >= 0, then head [h] contains a degree list, so: - - head [h] is the first column in degree bucket h. - Col [head [h]].headhash gives the first column in hash bucket h. - - otherwise, the degree list is empty, and: - - -(head [h] + 2) is the first column in hash bucket h. - - For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous - column" pointer. Col [c].shared3.hash is used instead as the hash number - for that column. The value of Col [c].shared4.hash_next is the next column - in the same hash bucket. - - Assuming no, or "few" hash collisions, the time taken by this routine is - linear in the sum of the sizes (lengths) of each column whose score has - just been computed in the approximate degree computation. - Not user-callable. -*/ - -PRIVATE void detect_super_cols -( - /* === Parameters ======================================================= */ - -#ifndef SPQR_NDEBUG - /* these two parameters are only needed when debugging is enabled: */ - Int n_col, /* number of columns of A */ - Colamd_Row Row [], /* of size n_row+1 */ -#endif /* SPQR_NDEBUG */ - - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* row indices of A */ - Int head [], /* head of degree lists and hash buckets */ - Int row_start, /* pointer to set of columns to check */ - Int row_length /* number of columns to check */ -) -{ - /* === Local variables ================================================== */ - - Int hash ; /* hash value for a column */ - Int *rp ; /* pointer to a row */ - Int c ; /* a column index */ - Int super_c ; /* column index of the column to absorb into */ - Int *cp1 ; /* column pointer for column super_c */ - Int *cp2 ; /* column pointer for column c */ - Int length ; /* length of column super_c */ - Int prev_c ; /* column preceding c in hash bucket */ - Int i ; /* loop counter */ - Int *rp_end ; /* pointer to the end of the row */ - Int col ; /* a column index in the row to check */ - Int head_column ; /* first column in hash bucket or degree list */ - Int first_col ; /* first column in hash bucket */ - - /* === Consider each column in the row ================================== */ - - rp = &A [row_start] ; - rp_end = rp + row_length ; - while (rp < rp_end) - { - col = *rp++ ; - if (COL_IS_DEAD (col)) - { - continue ; - } - - /* get hash number for this column */ - hash = Col [col].shared3.hash ; - ASSERT (hash <= n_col) ; - - /* === Get the first column in this hash bucket ===================== */ - - head_column = head [hash] ; - if (head_column > EMPTY) - { - first_col = Col [head_column].shared3.headhash ; - } - else - { - first_col = - (head_column + 2) ; - } - - /* === Consider each column in the hash bucket ====================== */ - - for (super_c = first_col ; super_c != EMPTY ; - super_c = Col [super_c].shared4.hash_next) - { - ASSERT (COL_IS_ALIVE (super_c)) ; - ASSERT (Col [super_c].shared3.hash == hash) ; - length = Col [super_c].length ; - - /* prev_c is the column preceding column c in the hash bucket */ - prev_c = super_c ; - - /* === Compare super_c with all columns after it ================ */ - - for (c = Col [super_c].shared4.hash_next ; - c != EMPTY ; c = Col [c].shared4.hash_next) - { - ASSERT (c != super_c) ; - ASSERT (COL_IS_ALIVE (c)) ; - ASSERT (Col [c].shared3.hash == hash) ; - - /* not identical if lengths or scores are different */ - if (Col [c].length != length || - Col [c].shared2.score != Col [super_c].shared2.score) - { - prev_c = c ; - continue ; - } - - /* compare the two columns */ - cp1 = &A [Col [super_c].start] ; - cp2 = &A [Col [c].start] ; - - for (i = 0 ; i < length ; i++) - { - /* the columns are "clean" (no dead rows) */ - ASSERT (ROW_IS_ALIVE (*cp1)) ; - ASSERT (ROW_IS_ALIVE (*cp2)) ; - /* row indices will same order for both supercols, */ - /* no gather scatter nessasary */ - if (*cp1++ != *cp2++) - { - break ; - } - } - - /* the two columns are different if the for-loop "broke" */ - if (i != length) - { - prev_c = c ; - continue ; - } - - /* === Got it! two columns are identical =================== */ - - ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; - - Col [super_c].shared1.thickness += Col [c].shared1.thickness ; - Col [c].shared1.parent = super_c ; - KILL_NON_PRINCIPAL_COL (c) ; - /* order c later, in order_children() */ - Col [c].shared2.order = EMPTY ; - /* remove c from hash bucket */ - Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; - } - } - - /* === Empty this hash bucket ======================================= */ - - if (head_column > EMPTY) - { - /* corresponding degree list "hash" is not empty */ - Col [head_column].shared3.headhash = EMPTY ; - } - else - { - /* corresponding degree list "hash" is empty */ - head [hash] = EMPTY ; - } - } -} - - -/* ========================================================================== */ -/* === garbage_collection =================================================== */ -/* ========================================================================== */ - -/* - Defragments and compacts columns and rows in the workspace A. Used when - all avaliable memory has been used while performing row merging. Returns - the index of the first free position in A, after garbage collection. The - time taken by this routine is linear is the size of the array A, which is - itself linear in the number of nonzeros in the input matrix. - Not user-callable. -*/ - -PRIVATE Int garbage_collection /* returns the new value of pfree */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows */ - Int n_col, /* number of columns */ - Colamd_Row Row [], /* row info */ - Colamd_Col Col [], /* column info */ - Int A [], /* A [0 ... Alen-1] holds the matrix */ - Int *pfree /* &A [0] ... pfree is in use */ -) -{ - /* === Local variables ================================================== */ - - Int *psrc ; /* source pointer */ - Int *pdest ; /* destination pointer */ - Int j ; /* counter */ - Int r ; /* a row index */ - Int c ; /* a column index */ - Int length ; /* length of a row or column */ - -#ifndef SPQR_NDEBUG - Int debug_rows ; - DEBUG2 (("Defrag..\n")) ; - for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; - debug_rows = 0 ; -#endif /* SPQR_NDEBUG */ - - /* === Defragment the columns =========================================== */ - - pdest = &A[0] ; - for (c = 0 ; c < n_col ; c++) - { - if (COL_IS_ALIVE (c)) - { - psrc = &A [Col [c].start] ; - - /* move and compact the column */ - ASSERT (pdest <= psrc) ; - Col [c].start = (Int) (pdest - &A [0]) ; - length = Col [c].length ; - for (j = 0 ; j < length ; j++) - { - r = *psrc++ ; - if (ROW_IS_ALIVE (r)) - { - *pdest++ = r ; - } - } - Col [c].length = (Int) (pdest - &A [Col [c].start]) ; - } - } - - /* === Prepare to defragment the rows =================================== */ - - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_DEAD (r) || (Row [r].length == 0)) - { - /* This row is already dead, or is of zero length. Cannot compact - * a row of zero length, so kill it. NOTE: in the current version, - * there are no zero-length live rows. Kill the row (for the first - * time, or again) just to be safe. */ - KILL_ROW (r) ; - } - else - { - /* save first column index in Row [r].shared2.first_column */ - psrc = &A [Row [r].start] ; - Row [r].shared2.first_column = *psrc ; - ASSERT (ROW_IS_ALIVE (r)) ; - /* flag the start of the row with the one's complement of row */ - *psrc = ONES_COMPLEMENT (r) ; -#ifndef SPQR_NDEBUG - debug_rows++ ; -#endif /* SPQR_NDEBUG */ - } - } - - /* === Defragment the rows ============================================== */ - - psrc = pdest ; - while (psrc < pfree) - { - /* find a negative number ... the start of a row */ - if (*psrc++ < 0) - { - psrc-- ; - /* get the row index */ - r = ONES_COMPLEMENT (*psrc) ; - ASSERT (r >= 0 && r < n_row) ; - /* restore first column index */ - *psrc = Row [r].shared2.first_column ; - ASSERT (ROW_IS_ALIVE (r)) ; - ASSERT (Row [r].length > 0) ; - /* move and compact the row */ - ASSERT (pdest <= psrc) ; - Row [r].start = (Int) (pdest - &A [0]) ; - length = Row [r].length ; - for (j = 0 ; j < length ; j++) - { - c = *psrc++ ; - if (COL_IS_ALIVE (c)) - { - *pdest++ = c ; - } - } - Row [r].length = (Int) (pdest - &A [Row [r].start]) ; - ASSERT (Row [r].length > 0) ; -#ifndef SPQR_NDEBUG - debug_rows-- ; -#endif /* SPQR_NDEBUG */ - } - } - /* ensure we found all the rows */ - ASSERT (debug_rows == 0) ; - - /* === Return the new value of pfree ==================================== */ - - return ((Int) (pdest - &A [0])) ; -} - - -/* ========================================================================== */ -/* === clear_mark =========================================================== */ -/* ========================================================================== */ - -/* - Clears the Row [].shared2.mark array, and returns the new tag_mark. - Return value is the new tag_mark. Not user-callable. -*/ - -PRIVATE Int clear_mark /* return the new value for tag_mark */ -( - /* === Parameters ======================================================= */ - - Int tag_mark, /* new value of tag_mark */ - Int max_mark, /* max allowed value of tag_mark */ - - Int n_row, /* number of rows in A */ - Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ -) -{ - /* === Local variables ================================================== */ - - Int r ; - - if (tag_mark <= 0 || tag_mark >= max_mark) - { - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_ALIVE (r)) - { - Row [r].shared2.mark = 0 ; - } - } - tag_mark = 1 ; - } - - return (tag_mark) ; -} - - -/* ========================================================================== */ -/* === print_report ========================================================= */ -/* ========================================================================== */ - -PRIVATE void print_report -( - char *method, - Int stats [COLAMD_STATS] -) -{ - - Int i1, i2, i3 ; - - PRINTF (("\n%s version %d.%d, %s: ", method, - COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ; - - if (!stats) - { - PRINTF (("No statistics available.\n")) ; - return ; - } - - i1 = stats [COLAMD_INFO1] ; - i2 = stats [COLAMD_INFO2] ; - i3 = stats [COLAMD_INFO3] ; - - if (stats [COLAMD_STATUS] >= 0) - { - PRINTF (("OK. ")) ; - } - else - { - PRINTF (("ERROR. ")) ; - } - - switch (stats [COLAMD_STATUS]) - { - - case COLAMD_OK_BUT_JUMBLED: - - PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ; - - PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n", - method, i3)) ; - - PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n", - method, INDEX (i2))) ; - - PRINTF(("%s: last seen in column: %d", - method, INDEX (i1))) ; - - /* no break - fall through to next case instead */ - - case COLAMD_OK: - - PRINTF(("\n")) ; - - PRINTF(("%s: number of dense or empty rows ignored: %d\n", - method, stats [COLAMD_DENSE_ROW])) ; - - PRINTF(("%s: number of dense or empty columns ignored: %d\n", - method, stats [COLAMD_DENSE_COL])) ; - - PRINTF(("%s: number of garbage collections performed: %d\n", - method, stats [COLAMD_DEFRAG_COUNT])) ; - break ; - - case COLAMD_ERROR_A_not_present: - - PRINTF(("Array A (row indices of matrix) not present.\n")) ; - break ; - - case COLAMD_ERROR_p_not_present: - - PRINTF(("Array p (column pointers for matrix) not present.\n")) ; - break ; - - case COLAMD_ERROR_nrow_negative: - - PRINTF(("Invalid number of rows (%d).\n", i1)) ; - break ; - - case COLAMD_ERROR_ncol_negative: - - PRINTF(("Invalid number of columns (%d).\n", i1)) ; - break ; - - case COLAMD_ERROR_nnz_negative: - - PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ; - break ; - - case COLAMD_ERROR_p0_nonzero: - - PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1)); - break ; - - case COLAMD_ERROR_A_too_small: - - PRINTF(("Array A too small.\n")) ; - PRINTF((" Need Alen >= %d, but given only Alen = %d.\n", - i1, i2)) ; - break ; - - case COLAMD_ERROR_col_length_negative: - - PRINTF - (("Column %d has a negative number of nonzero entries (%d).\n", - INDEX (i1), i2)) ; - break ; - - case COLAMD_ERROR_row_index_out_of_bounds: - - PRINTF - (("Row index (row %d) out of bounds (%d to %d) in column %d.\n", - INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ; - break ; - - case COLAMD_ERROR_out_of_memory: - - PRINTF(("Out of memory.\n")) ; - break ; - - /* v2.4: internal-error case deleted */ - } -} - - - - -/* ========================================================================== */ -/* === colamd debugging routines ============================================ */ -/* ========================================================================== */ - -/* When debugging is disabled, the remainder of this file is ignored. */ - -#ifndef SPQR_NDEBUG - - -/* ========================================================================== */ -/* === debug_structures ===================================================== */ -/* ========================================================================== */ - -/* - At this point, all empty rows and columns are dead. All live columns - are "clean" (containing no dead rows) and simplicial (no supercolumns - yet). Rows may contain dead columns, but all live rows contain at - least one live column. -*/ - -PRIVATE void debug_structures -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int n_col2 -) -{ - /* === Local variables ================================================== */ - - Int i ; - Int c ; - Int *cp ; - Int *cp_end ; - Int len ; - Int score ; - Int r ; - Int *rp ; - Int *rp_end ; - Int deg ; - - /* === Check A, Row, and Col ============================================ */ - - for (c = 0 ; c < n_col ; c++) - { - if (COL_IS_ALIVE (c)) - { - len = Col [c].length ; - score = Col [c].shared2.score ; - DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; - ASSERT (len > 0) ; - ASSERT (score >= 0) ; - ASSERT (Col [c].shared1.thickness == 1) ; - cp = &A [Col [c].start] ; - cp_end = cp + len ; - while (cp < cp_end) - { - r = *cp++ ; - ASSERT (ROW_IS_ALIVE (r)) ; - } - } - else - { - i = Col [c].shared2.order ; - ASSERT (i >= n_col2 && i < n_col) ; - } - } - - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_ALIVE (r)) - { - i = 0 ; - len = Row [r].length ; - deg = Row [r].shared1.degree ; - ASSERT (len > 0) ; - ASSERT (deg > 0) ; - rp = &A [Row [r].start] ; - rp_end = rp + len ; - while (rp < rp_end) - { - c = *rp++ ; - if (COL_IS_ALIVE (c)) - { - i++ ; - } - } - ASSERT (i > 0) ; - } - } -} - - -/* ========================================================================== */ -/* === debug_deg_lists ====================================================== */ -/* ========================================================================== */ - -/* - Prints the contents of the degree lists. Counts the number of columns - in the degree list and compares it to the total it should have. Also - checks the row degrees. -*/ - -PRIVATE void debug_deg_lists -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int head [], - Int min_score, - Int should, - Int max_deg -) -{ - /* === Local variables ================================================== */ - - Int deg ; - Int col ; - Int have ; - Int row ; - - /* === Check the degree lists =========================================== */ - - if (n_col > 10000 && colamd_debug <= 0) - { - return ; - } - have = 0 ; - DEBUG4 (("Degree lists: %d\n", min_score)) ; - for (deg = 0 ; deg <= n_col ; deg++) - { - col = head [deg] ; - if (col == EMPTY) - { - continue ; - } - DEBUG4 (("%d:", deg)) ; - while (col != EMPTY) - { - DEBUG4 ((" %d", col)) ; - have += Col [col].shared1.thickness ; - ASSERT (COL_IS_ALIVE (col)) ; - col = Col [col].shared4.degree_next ; - } - DEBUG4 (("\n")) ; - } - DEBUG4 (("should %d have %d\n", should, have)) ; - ASSERT (should == have) ; - - /* === Check the row degrees ============================================ */ - - if (n_row > 10000 && colamd_debug <= 0) - { - return ; - } - for (row = 0 ; row < n_row ; row++) - { - if (ROW_IS_ALIVE (row)) - { - ASSERT (Row [row].shared1.degree <= max_deg) ; - } - } -} - - -/* ========================================================================== */ -/* === debug_mark =========================================================== */ -/* ========================================================================== */ - -/* - Ensures that the tag_mark is less that the maximum and also ensures that - each entry in the mark array is less than the tag mark. -*/ - -PRIVATE void debug_mark -( - /* === Parameters ======================================================= */ - - Int n_row, - Colamd_Row Row [], - Int tag_mark, - Int max_mark -) -{ - /* === Local variables ================================================== */ - - Int r ; - - /* === Check the Row marks ============================================== */ - - ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; - if (n_row > 10000 && colamd_debug <= 0) - { - return ; - } - for (r = 0 ; r < n_row ; r++) - { - ASSERT (Row [r].shared2.mark < tag_mark) ; - } -} - - -/* ========================================================================== */ -/* === debug_matrix ========================================================= */ -/* ========================================================================== */ - -/* - Prints out the contents of the columns and the rows. -*/ - -PRIVATE void debug_matrix -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [] -) -{ - /* === Local variables ================================================== */ - - Int r ; - Int c ; - Int *rp ; - Int *rp_end ; - Int *cp ; - Int *cp_end ; - - /* === Dump the rows and columns of the matrix ========================== */ - - if (colamd_debug < 3) - { - return ; - } - DEBUG3 (("DUMP MATRIX:\n")) ; - for (r = 0 ; r < n_row ; r++) - { - DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; - if (ROW_IS_DEAD (r)) - { - continue ; - } - DEBUG3 (("start %d length %d degree %d\n", - Row [r].start, Row [r].length, Row [r].shared1.degree)) ; - rp = &A [Row [r].start] ; - rp_end = rp + Row [r].length ; - while (rp < rp_end) - { - c = *rp++ ; - DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; - } - } - - for (c = 0 ; c < n_col ; c++) - { - DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; - if (COL_IS_DEAD (c)) - { - continue ; - } - DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", - Col [c].start, Col [c].length, - Col [c].shared1.thickness, Col [c].shared2.score)) ; - cp = &A [Col [c].start] ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - r = *cp++ ; - DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; - } - } -} - -PRIVATE void colamd_get_debug -( - char *method -) -{ - FILE *f ; - colamd_debug = 0 ; /* no debug printing */ - f = fopen ("debug", "r") ; - if (f == (FILE *) NULL) - { - colamd_debug = 0 ; - } - else - { - fscanf (f, "%d", &colamd_debug) ; - fclose (f) ; - } - DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n", - method, colamd_debug)) ; -} - -#endif /* SPQR_NDEBUG */ diff --git a/colamd/colamd.h b/colamd/colamd.h deleted file mode 100755 index 26372d8fa..000000000 --- a/colamd/colamd.h +++ /dev/null @@ -1,255 +0,0 @@ -/* ========================================================================== */ -/* === colamd/symamd prototypes and definitions ============================= */ -/* ========================================================================== */ - -/* COLAMD / SYMAMD include file - - You must include this file (colamd.h) in any routine that uses colamd, - symamd, or the related macros and definitions. - - Authors: - - The authors of the code itself are Stefan I. Larimore and Timothy A. - Davis (davis at cise.ufl.edu), University of Florida. The algorithm was - developed in collaboration with John Gilbert, Xerox PARC, and Esmond - Ng, Oak Ridge National Laboratory. - - Acknowledgements: - - This work was supported by the National Science Foundation, under - grants DMS-9504974 and DMS-9803599. - - Notice: - - Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. - - THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY - EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - - Permission is hereby granted to use, copy, modify, and/or distribute - this program, provided that the Copyright, this License, and the - Availability of the original version is retained on all copies and made - accessible to the end-user of any code or package that includes COLAMD - or any modified version of COLAMD. - - Availability: - - The colamd/symamd library is available at - - http://www.cise.ufl.edu/research/sparse/colamd/ - - This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h - file. It is required by the colamd.c, colamdmex.c, and symamdmex.c - files, and by any C code that calls the routines whose prototypes are - listed below, or that uses the colamd/symamd definitions listed below. - -*/ - -#ifndef COLAMD_H -#define COLAMD_H - -/* make it easy for C++ programs to include COLAMD */ -#ifdef __cplusplus -extern "C" { -#endif - -/* ========================================================================== */ -/* === Include files ======================================================== */ -/* ========================================================================== */ - -#include - -/* ========================================================================== */ -/* === COLAMD version ======================================================= */ -/* ========================================================================== */ - -/* COLAMD Version 2.4 and later will include the following definitions. - * As an example, to test if the version you are using is 2.4 or later: - * - * #ifdef COLAMD_VERSION - * if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ... - * #endif - * - * This also works during compile-time: - * - * #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) - * printf ("This is version 2.4 or later\n") ; - * #else - * printf ("This is an early version\n") ; - * #endif - * - * Versions 2.3 and earlier of COLAMD do not include a #define'd version number. - */ - -#define COLAMD_DATE "Nov 1, 2007" -#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define COLAMD_MAIN_VERSION 2 -#define COLAMD_SUB_VERSION 7 -#define COLAMD_SUBSUB_VERSION 1 -#define COLAMD_VERSION \ - COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) - -/* ========================================================================== */ -/* === Knob and statistics definitions ====================================== */ -/* ========================================================================== */ - -/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ -#define COLAMD_KNOBS 20 - -/* number of output statistics. Only stats [0..6] are currently used. */ -#define COLAMD_STATS 20 - -/* knobs [0] and stats [0]: dense row knob and output statistic. */ -#define COLAMD_DENSE_ROW 0 - -/* knobs [1] and stats [1]: dense column knob and output statistic. */ -#define COLAMD_DENSE_COL 1 - -/* knobs [2]: aggressive absorption */ -#define COLAMD_AGGRESSIVE 2 - -/* stats [2]: memory defragmentation count output statistic */ -#define COLAMD_DEFRAG_COUNT 2 - -/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */ -#define COLAMD_STATUS 3 - -/* stats [4..6]: error info, or info on jumbled columns */ -#define COLAMD_INFO1 4 -#define COLAMD_INFO2 5 -#define COLAMD_INFO3 6 - -/* error codes returned in stats [3]: */ -#define COLAMD_OK (0) -#define COLAMD_OK_BUT_JUMBLED (1) -#define COLAMD_ERROR_A_not_present (-1) -#define COLAMD_ERROR_p_not_present (-2) -#define COLAMD_ERROR_nrow_negative (-3) -#define COLAMD_ERROR_ncol_negative (-4) -#define COLAMD_ERROR_nnz_negative (-5) -#define COLAMD_ERROR_p0_nonzero (-6) -#define COLAMD_ERROR_A_too_small (-7) -#define COLAMD_ERROR_col_length_negative (-8) -#define COLAMD_ERROR_row_index_out_of_bounds (-9) -#define COLAMD_ERROR_out_of_memory (-10) -#define COLAMD_ERROR_internal_error (-999) - - -/* ========================================================================== */ -/* === Prototypes of user-callable routines ================================= */ -/* ========================================================================== */ - -/* define UF_long */ -#include "UFconfig.h" - -size_t colamd_recommended /* returns recommended value of Alen, */ - /* or 0 if input arguments are erroneous */ -( - int nnz, /* nonzeros in A */ - int n_row, /* number of rows in A */ - int n_col /* number of columns in A */ -) ; - -size_t colamd_l_recommended /* returns recommended value of Alen, */ - /* or 0 if input arguments are erroneous */ -( - UF_long nnz, /* nonzeros in A */ - UF_long n_row, /* number of rows in A */ - UF_long n_col /* number of columns in A */ -) ; - -void colamd_set_defaults /* sets default parameters */ -( /* knobs argument is modified on output */ - double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ -) ; - -void colamd_l_set_defaults /* sets default parameters */ -( /* knobs argument is modified on output */ - double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ -) ; - -int colamd /* returns (1) if successful, (0) otherwise*/ -( /* A and p arguments are modified on output */ - int n_row, /* number of rows in A */ - int n_col, /* number of columns in A */ - int Alen, /* size of the array A */ - int A [], /* row indices of A, of size Alen */ - int p [], /* column pointers of A, of size n_col+1 */ - double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ - int stats [COLAMD_STATS] /* colamd output statistics and error codes */ -) ; - -UF_long colamd_l /* returns (1) if successful, (0) otherwise*/ -( /* A and p arguments are modified on output */ - UF_long n_row, /* number of rows in A */ - UF_long n_col, /* number of columns in A */ - UF_long Alen, /* size of the array A */ - UF_long A [], /* row indices of A, of size Alen */ - UF_long p [], /* column pointers of A, of size n_col+1 */ - double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ - UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */ -) ; - -int symamd /* return (1) if OK, (0) otherwise */ -( - int n, /* number of rows and columns of A */ - int A [], /* row indices of A */ - int p [], /* column pointers of A */ - int perm [], /* output permutation, size n_col+1 */ - double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - int stats [COLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), - /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *) - /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ -) ; - -UF_long symamd_l /* return (1) if OK, (0) otherwise */ -( - UF_long n, /* number of rows and columns of A */ - UF_long A [], /* row indices of A */ - UF_long p [], /* column pointers of A */ - UF_long perm [], /* output permutation, size n_col+1 */ - double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - UF_long stats [COLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), - /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *) - /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ -) ; - -void colamd_report -( - int stats [COLAMD_STATS] -) ; - -void colamd_l_report -( - UF_long stats [COLAMD_STATS] -) ; - -void symamd_report -( - int stats [COLAMD_STATS] -) ; - -void symamd_l_report -( - UF_long stats [COLAMD_STATS] -) ; - -#ifndef EXTERN -#define EXTERN extern -#endif - -EXTERN int (*colamd_printf) (const char *, ...) ; - -#ifdef __cplusplus -} -#endif - -#endif /* COLAMD_H */ diff --git a/colamd/colamd_global.c b/colamd/colamd_global.c deleted file mode 100755 index 4d1ae2230..000000000 --- a/colamd/colamd_global.c +++ /dev/null @@ -1,24 +0,0 @@ -/* ========================================================================== */ -/* === colamd_global.c ====================================================== */ -/* ========================================================================== */ - -/* ---------------------------------------------------------------------------- - * COLAMD, Copyright (C) 2007, Timothy A. Davis. - * See License.txt for the Version 2.1 of the GNU Lesser General Public License - * http://www.cise.ufl.edu/research/sparse - * -------------------------------------------------------------------------- */ - -/* Global variables for COLAMD */ - -#ifndef NPRINT -#ifdef MATLAB_MEX_FILE -#include "mex.h" -int (*colamd_printf) (const char *, ...) = mexPrintf ; -#else -#include -int (*colamd_printf) (const char *, ...) = printf ; -#endif -#else -int (*colamd_printf) (const char *, ...) = ((void *) 0) ; -#endif - diff --git a/colamd/main.cpp b/colamd/main.cpp deleted file mode 100755 index da728b446..000000000 --- a/colamd/main.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "iostream" -#include "colamd.h" - -using namespace std; - -#define ALEN 100 - -void use_colamd() -{ - int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; - int p [ ] = {0, 3, 5, 9, 11} ; - int stats [COLAMD_STATS] ; - colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; - for(int i = 0; i < 5; i++) - printf("%d ", p[i]); - printf("\n"); - for(int i = 0; i < COLAMD_STATS; i++) - printf("%d ", stats[i]); - printf("\n"); -} - -int main() -{ - /* - A: - [0 x x 0 x - x x 0 0 x - x 0 0 x x - 0 0 x 0 0 - x x x 0 x - ] - */ - //int A [ALEN] = {0, 3, 2, 3, 1, 2, 0, 1, 3, 4, 3} ; - //int p [ ] = {0, 2, 4, 6, 10, 11} ; - - use_colamd(); - return 0; -} diff --git a/configure.ac b/configure.ac index 5c9864b2e..e6769389c 100644 --- a/configure.ac +++ b/configure.ac @@ -4,12 +4,10 @@ AC_PREREQ(2.59) AC_INIT(gtsam, 0.0.0, dellaert@cc.gatech.edu) AM_INIT_AUTOMAKE(gtsam, 0.0.0) -AC_OUTPUT(Makefile CppUnitLite/Makefile colamd/Makefile spqr_mini/Makefile base/Makefile inference/Makefile linear/Makefile geometry/Makefile nonlinear/Makefile slam/Makefile tests/Makefile wrap/Makefile examples/Makefile) +AC_OUTPUT(Makefile CppUnitLite/Makefile base/Makefile inference/Makefile linear/Makefile geometry/Makefile nonlinear/Makefile slam/Makefile tests/Makefile wrap/Makefile examples/Makefile) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_SRCDIR([CppUnitLite/Test.cpp]) -AC_CONFIG_SRCDIR([colamd/colamd.c]) -AC_CONFIG_SRCDIR([spqr_mini/spqr_front.cpp]) AC_CONFIG_SRCDIR([base/DSFVector.cpp]) AC_CONFIG_SRCDIR([geometry/Cal3_S2.cpp]) AC_CONFIG_SRCDIR([inference/SymbolicFactorGraph.cpp]) @@ -151,5 +149,25 @@ AC_ARG_WITH([boost], [--with-boost has to be specified]) ]) AC_SUBST([boost]) + +# ask for sparse library include directory +AC_ARG_WITH([sparse-inc], + [AS_HELP_STRING([--with-sparse-inc], + [specify the sparse library include directory (mandatory)])], + [SparseInc=$withval], + [AC_MSG_FAILURE( + [--with-sparse-inc has to be specified]) + ]) +AC_SUBST([SparseInc]) + +# ask for sparse library lib directory +AC_ARG_WITH([sparse-lib], + [AS_HELP_STRING([--with-sparse-lib], + [specify the sparse library lib directory (mandatory)])], + [SparseLib=$withval], + [AC_MSG_FAILURE( + [--with-sparse-lib has to be specified]) + ]) +AC_SUBST([SparseLib]) AC_OUTPUT diff --git a/examples/Makefile.am b/examples/Makefile.am index fe1adefc9..a0b0f4621 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,7 +20,7 @@ noinst_PROGRAMS += PlanarSLAMSelfContained # Solves SLAM example from tutorial # rules to build local programs #---------------------------------------------------------------------------------------------------- AM_LDFLAGS = $(BOOST_LDFLAGS) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. LDADD = ../libgtsam.la AM_DEFAULT_SOURCE_EXT = .cpp diff --git a/inference/FactorGraph-inl.h b/inference/FactorGraph-inl.h index ccadadc31..e1ffb66e7 100644 --- a/inference/FactorGraph-inl.h +++ b/inference/FactorGraph-inl.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/inference/Makefile.am b/inference/Makefile.am index 618e874d8..b6a17320c 100644 --- a/inference/Makefile.am +++ b/inference/Makefile.am @@ -63,16 +63,16 @@ inferencedir = $(pkgincludedir)/inference inference_HEADERS = $(headers) noinst_LTLIBRARIES = libinference.la libinference_la_SOURCES = $(sources) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. AM_CXXFLAGS = #---------------------------------------------------------------------------------------------------- # rules to build local programs #---------------------------------------------------------------------------------------------------- TESTS = $(check_PROGRAMS) -AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) +AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) -L$(SparseLib) -lcolamd -lccolamd LDADD = libinference.la ../base/libbase.la -LDADD += ../CppUnitLite/libCppUnitLite.a ../colamd/libcolamd.la +LDADD += ../CppUnitLite/libCppUnitLite.a AM_DEFAULT_SOURCE_EXT = .cpp if USE_ACCELERATE_MACOS @@ -89,6 +89,5 @@ endif if USE_LAPACK AM_CXXFLAGS += -DGT_USE_LAPACK -LDADD += ../spqr_mini/libspqr_mini.la endif diff --git a/inference/SymbolMap.h b/inference/SymbolMap.h index f31c1bdb7..54b18c701 100644 --- a/inference/SymbolMap.h +++ b/inference/SymbolMap.h @@ -11,7 +11,7 @@ #define GTSAM_SYMBOL_BINARY #define GTSAM_SYMBOL_SPECIAL -#include +#include #include #include diff --git a/inference/inference-inl.h b/inference/inference-inl.h index 45d2d7c55..08163986a 100644 --- a/inference/inference-inl.h +++ b/inference/inference-inl.h @@ -10,7 +10,8 @@ #include #include #include -#include + +#include #include #include diff --git a/linear/Makefile.am b/linear/Makefile.am index 2a767b20a..b2ecbb940 100644 --- a/linear/Makefile.am +++ b/linear/Makefile.am @@ -49,16 +49,16 @@ lineardir = $(pkgincludedir)/linear linear_HEADERS = $(headers) noinst_LTLIBRARIES = liblinear.la liblinear_la_SOURCES = $(sources) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. AM_CXXFLAGS = #---------------------------------------------------------------------------------------------------- # rules to build local programs #---------------------------------------------------------------------------------------------------- TESTS = $(check_PROGRAMS) -AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) +AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) -L$(SparseLib) -lcolamd -lccolamd LDADD = liblinear.la ../inference/libinference.la ../base/libbase.la -LDADD += ../CppUnitLite/libCppUnitLite.a ../colamd/libcolamd.la +LDADD += ../CppUnitLite/libCppUnitLite.a AM_DEFAULT_SOURCE_EXT = .cpp if USE_ACCELERATE_MACOS @@ -75,6 +75,5 @@ endif if USE_LAPACK AM_CXXFLAGS += -DGT_USE_LAPACK -LDADD += ../spqr_mini/libspqr_mini.la endif diff --git a/nonlinear/Makefile.am b/nonlinear/Makefile.am index 5abd05a6f..d4bf683ea 100644 --- a/nonlinear/Makefile.am +++ b/nonlinear/Makefile.am @@ -39,16 +39,16 @@ nonlineardir = $(pkgincludedir)/nonlinear nonlinear_HEADERS = $(headers) noinst_LTLIBRARIES = libnonlinear.la libnonlinear_la_SOURCES = $(sources) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. AM_CXXFLAGS = #---------------------------------------------------------------------------------------------------- # rules to build local programs #---------------------------------------------------------------------------------------------------- TESTS = $(check_PROGRAMS) -AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) +AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) -L$(SparseLib) -lcolamd -lccolamd LDADD = libnonlinear.la ../linear/liblinear.la ../inference/libinference.la ../base/libbase.la -LDADD += ../CppUnitLite/libCppUnitLite.a ../colamd/libcolamd.la +LDADD += ../CppUnitLite/libCppUnitLite.a AM_DEFAULT_SOURCE_EXT = .cpp if USE_ACCELERATE_MACOS @@ -65,6 +65,5 @@ endif if USE_LAPACK AM_CXXFLAGS += -DGT_USE_LAPACK -LDADD += ../spqr_mini/libspqr_mini.la endif diff --git a/slam/Makefile.am b/slam/Makefile.am index 5e47e40dd..d6e5bdeeb 100644 --- a/slam/Makefile.am +++ b/slam/Makefile.am @@ -65,25 +65,21 @@ slamdir = $(pkgincludedir)/slam slam_HEADERS = $(headers) noinst_LTLIBRARIES = libslam.la libslam_la_SOURCES = $(sources) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. #---------------------------------------------------------------------------------------------------- # rules to build local programs #---------------------------------------------------------------------------------------------------- TESTS = $(check_PROGRAMS) AM_DEFAULT_SOURCE_EXT = .cpp -AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) +AM_LDFLAGS = $(BOOST_LDFLAGS) $(boost_serialization) -L$(SparseLib) -lcolamd -lccolamd LDADD = libslam.la ../geometry/libgeometry.la ../nonlinear/libnonlinear.la ../linear/liblinear.la ../inference/libinference.la ../base/libbase.la -LDADD += ../CppUnitLite/libCppUnitLite.a ../colamd/libcolamd.la +LDADD += ../CppUnitLite/libCppUnitLite.a if USE_ACCELERATE_MACOS AM_LDFLAGS += -Wl,/System/Library/Frameworks/Accelerate.framework/Accelerate endif -if USE_LAPACK -LDADD += ../spqr_mini/libspqr_mini.la -endif - # rule to run an executable %.run: % $(LDADD) ./$^ diff --git a/spqr_mini/Makefile.am b/spqr_mini/Makefile.am deleted file mode 100644 index a58e79639..000000000 --- a/spqr_mini/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -# Only install if LAPACK enabled - -if USE_LAPACK - -sources = cholmod_error.c cholmod_common.c cholmod_memory.c spqr_front.cpp spqr_larftb.cpp -headers = UFconfig.h cholmod_common.h cholmod_internal.h cholmod_blas.h cholmod_core.h -headers += SuiteSparseQR_definitions.h SuiteSparseQR_subset.hpp spqr_subset.hpp spqr_larftb.h spqr_front.h - -# Create a libtool library that is not installed -# It will be packaged in the toplevel libgtsam.la as specfied in ../Makefile.am -# The headers are not installed either -noinst_LTLIBRARIES = libspqr_mini.la -libspqr_mini_la_SOURCES = $(sources) -noinst_HEADERS = $(headers) - -AM_CPPFLAGS = -DDLONG # Compiles cholmod in double/long mode - -# On Mac, we compile using the BLAS/LAPACK headers in the Accelerate framework -if USE_ACCELERATE_MACOS -AM_CPPFLAGS += -I/System/Library/Frameworks/Accelerate.framework/Headers -endif - -endif - - diff --git a/spqr_mini/SuiteSparseQR_definitions.h b/spqr_mini/SuiteSparseQR_definitions.h deleted file mode 100644 index 0e903cdb4..000000000 --- a/spqr_mini/SuiteSparseQR_definitions.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ========================================================================== */ -/* === SuiteSparseQR_definitions.h ========================================== */ -/* ========================================================================== */ - -/* Core definitions for both C and C++ programs. */ - -#ifndef SUITESPARSEQR_DEFINITIONS_H -#define SUITESPARSEQR_DEFINITIONS_H - -/* ordering options */ -#define SPQR_ORDERING_FIXED 0 -#define SPQR_ORDERING_NATURAL 1 -#define SPQR_ORDERING_COLAMD 2 -#define SPQR_ORDERING_GIVEN 3 /* only used for C/C++ interface */ -#define SPQR_ORDERING_CHOLMOD 4 /* CHOLMOD best-effort (COLAMD, METIS,...)*/ -#define SPQR_ORDERING_AMD 5 /* AMD(A'*A) */ -#define SPQR_ORDERING_METIS 6 /* metis(A'*A) */ -#define SPQR_ORDERING_DEFAULT 7 /* SuiteSparseQR default ordering */ -#define SPQR_ORDERING_BEST 8 /* try COLAMD, AMD, and METIS; pick best */ -#define SPQR_ORDERING_BESTAMD 9 /* try COLAMD and AMD; pick best */ - -/* Let [m n] = size of the matrix after pruning singletons. The default - * ordering strategy is to use COLAMD if m <= 2*n. Otherwise, AMD(A'A) is - * tried. If there is a high fill-in with AMD then try METIS(A'A) and take - * the best of AMD and METIS. METIS is not tried if it isn't installed. */ - -/* tol options */ -#define SPQR_DEFAULT_TOL (-2) /* if tol <= -2, the default tol is used */ -#define SPQR_NO_TOL (-1) /* if -2 < tol < 0, then no tol is used */ - -/* for qmult, method can be 0,1,2,3: */ -#define SPQR_QTX 0 -#define SPQR_QX 1 -#define SPQR_XQT 2 -#define SPQR_XQ 3 - -/* system can be 0,1,2,3: Given Q*R=A*E from SuiteSparseQR_factorize: */ -#define SPQR_RX_EQUALS_B 0 /* solve R*X=B or X = R\B */ -#define SPQR_RETX_EQUALS_B 1 /* solve R*E'*X=B or X = E*(R\B) */ -#define SPQR_RTX_EQUALS_B 2 /* solve R'*X=B or X = R'\B */ -#define SPQR_RTX_EQUALS_ETB 3 /* solve R'*X=E'*B or X = R'\(E'*B) */ - -/* ========================================================================== */ -/* === SuiteSparseQR version ================================================ */ -/* ========================================================================== */ - -/* - All versions of SuiteSparseQR will include the following definitions. - As an example, to test if the version you are using is 1.3 or later: - - if (SPQR_VERSION >= SPQR_VER_CODE (1,3)) ... - - This also works during compile-time: - - #if SPQR_VERSION >= SPQR_VER_CODE (1,3) - printf ("This is version 1.3 or later\n") ; - #else - printf ("This is version is earlier than 1.3\n") ; - #endif - */ - -#define SPQR_DATE "Nov 30, 2009" -#define SPQR_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SPQR_MAIN_VERSION 1 -#define SPQR_SUB_VERSION 2 -#define SPQR_SUBSUB_VERSION 0 -#define SPQR_VERSION SPQR_VER_CODE(SPQR_MAIN_VERSION,SPQR_SUB_VERSION) - -#endif diff --git a/spqr_mini/SuiteSparseQR_subset.hpp b/spqr_mini/SuiteSparseQR_subset.hpp deleted file mode 100644 index 5bb99a00e..000000000 --- a/spqr_mini/SuiteSparseQR_subset.hpp +++ /dev/null @@ -1,604 +0,0 @@ -// ============================================================================= -// === SuiteSparseQR.hpp ======================================================= -// ============================================================================= - -// User include file for C++ programs. - -#ifndef SUITESPARSEQR_H -#define SUITESPARSEQR_H - -// ----------------------------------------------------------------------------- -// include files -// ----------------------------------------------------------------------------- - -#include "cholmod.h" -#include "UFconfig.h" -#include "SuiteSparseQR_definitions.h" - -// ============================================================================= -// === spqr_symbolic =========================================================== -// ============================================================================= - -// The contents of this object do not change during numeric factorization. The -// Symbolic object depends only on the pattern of the input matrix, and not its -// values. These contents also do not change with column pivoting for rank -// detection. This makes parallelism easier to manage, since all threads can -// have access to this object without synchronization. -// -// The total size of the Symbolic object is (10 + 2*m + anz + 2*n + 5*nf + rnz) -// Int's, where the user's input A matrix is m-by-n with anz nonzeros, nf <= -// MIN(m,n) is the number of frontal matrices, and rnz <= nnz(R) is the number -// of column indices used to represent the supernodal form of R (one Int per -// non-pivotal column index in the leading row of each block of R). - -struct spqr_symbolic -{ - - // ------------------------------------------------------------------------- - // row-form of the input matrix and its permutations - // ------------------------------------------------------------------------- - - // During symbolic analysis, the nonzero pattern of S = A(P,Q) is - // constructed, where A is the user's input matrix. Its numerical values - // are also constructed, but they do not become part of the Symbolic - // object. The matrix S is stored in row-oriented form. The rows of S are - // sorted according to their leftmost column index (via PLinv). Column - // indices in each row of S are in strictly ascending order, even though - // the input matrix A need not be sorted. - - UF_long m, n, anz ; // S is m-by-n with anz entries - - UF_long *Sp ; // size m+1, row pointers of S - - UF_long *Sj ; // size anz = Sp [n], column indices of S - - UF_long *Qfill ; // size n, fill-reducing column permutation. - // Qfill [k] = j if column k of A is column j of S. - - UF_long *PLinv ; // size m, inverse row permutation that places S=A(P,Q) - // in increasing order of leftmost column index. - // PLinv [i] = k if row i of A is row k of S. - - UF_long *Sleft ; // size n+2. The list of rows of S whose leftmost - // column index is j is given by - // Sleft [j] ... Sleft [j+1]-1. This can be empty (that is, Sleft - // [j] can equal Sleft [j+1]). Sleft [n] is the number of - // non-empty rows of S, and Sleft [n+1] == m. That is, Sleft [n] - // ... Sleft [n+1]-1 gives the empty rows of S, if any. - - // ------------------------------------------------------------------------- - // frontal matrices: pattern and tree - // ------------------------------------------------------------------------- - - // Each frontal matrix is fm-by-fn, with fnpiv pivot columns. The fn - // column indices are given by a set of size fnpiv pivot columns, defined - // by Super, followed by the pattern Rj [ Rp[f] ... Rp[f+1]-1 ]. - - // The row indices of the front are not kept. If the Householder vectors - // are not kept, the row indices are not needed. If the Householder - // vectors are kept, the row indices are computed dynamically during - // numerical factorization. - - UF_long nf ; // number of frontal matrices; nf <= MIN (m,n) - UF_long maxfn ; // max # of columns in any front - - // parent, child, and childp define the row merge tree or etree (A'A) - UF_long *Parent ; // size nf+1 - UF_long *Child ; // size nf+1 - UF_long *Childp ; // size nf+2 - - // The parent of a front f is Parent [f], or EMPTY if f=nf. - // A list of children of f can be obtained in the list - // Child [Childp [f] ... Childp [f+1]-1]. - - // Node nf in the tree is a placeholder; it does not represent a frontal - // matrix. All roots of the frontal "tree" (may be a forest) have the - // placeholder node nf as their parent. Thus, the tree of nodes 0:nf is - // truly a tree, with just one parent (node nf). - - UF_long *Super ; // size nf+1. Super [f] gives the first pivot column - // in the front F. This refers to a column of S. The - // number of expected pivot columns in F is thus - // Super [f+1] - Super [f]. - - UF_long *Rp ; // size nf+1 - UF_long *Rj ; // size rjsize; compressed supernodal form of R - - UF_long *Post ; // size nf+1, post ordering of frontal tree. f=Post[k] - // gives the kth node in the postordered tree - - UF_long rjsize ; // size of Rj - - UF_long do_rank_detection ; // TRUE: allow for tol >= 0. FALSE: ignore tol - - // the rest depends on whether or not rank-detection is allowed: - UF_long maxstack ; // max stack size (sequential case) - UF_long hisize ; // size of Hii - - UF_long keepH ; // TRUE if H is present - - UF_long *Hip ; // size nf+1. If H is kept, the row indices of frontal - // matrix f are in Hii [Hip [f] ... Hip [f] + Hm [f]], - // where Hii and Hm are stored in the numeric object. - - // There is one block row of R per frontal matrix. - // The fn column indices of R are given by Rj [Rp [f] ... Rp [f+1]-1], - // where the first fp column indices are Super [f] ... Super [f+1]-1. - // The remaining column indices in Rj [...] are non-pivotal, and are - // in the range Super [f+1] to n. The number of rows of R is at - // most fp, but can be less if dead columns appear in the matrix. - // The number of columns in the contribution block C is always - // cn = fn - fp, where fn = Rp [f+1] - Rp [f]. - - UF_long ntasks ; // number of tasks in task graph - UF_long ns ; // number of stacks - - // ------------------------------------------------------------------------- - // the rest of the QR symbolic object is present only if ntasks > 1 - // ------------------------------------------------------------------------- - - // Task tree (nodes 0:ntasks), including placeholder node - UF_long *TaskChildp ; // size ntasks+2 - UF_long *TaskChild ; // size ntasks+1 - - UF_long *TaskStack ; // size ntasks+1 - - // list of fronts for each task - UF_long *TaskFront ; // size nf+1 - UF_long *TaskFrontp ; // size ntasks+2 - - UF_long *On_stack ; // size nf+1, front f is on stack On_stack [f] - - // size of each stack - UF_long *Stack_maxstack ; // size ns+2 - -} ; - - -// ============================================================================= -// === spqr_numeric ============================================================ -// ============================================================================= - -// The Numeric object contains the numerical values of the triangular/ -// trapezoidal factor R, and optionally the Householder vectors H if they -// are kept. - -template struct spqr_numeric -{ - - // ------------------------------------------------------------------------- - // Numeric R factor - // ------------------------------------------------------------------------- - - Entry **Rblock ; // size nf. R [f] is an (Entry *) pointer to the - // R block for front F. It is an upper trapezoidal - // of size Rm(f)-by-Rn(f), but only the upper - // triangular part is stored in column-packed format. - - Entry **Stacks ; // size ns; an array of stacks holding the R and H - // factors and the current frontal matrix F at the head. - // This is followed by empty space, then the C blocks of - // prior frontal matrices at the bottom. When the - // factorization is complete, only the R and H part at - // the head of each stack is left. - - UF_long *Stack_size ; // size ns; Stack_size [s] is the size of Stacks [s] - - UF_long hisize ; // size of Hii - - UF_long n ; // A is m-by-n - UF_long m ; - UF_long nf ; // number of frontal matrices - UF_long ntasks ; // number of tasks in task graph actually used - UF_long ns ; // number of stacks actually used - UF_long maxstack ; // size of sequential stack, if used - - // ------------------------------------------------------------------------- - // for rank detection and m < n case - // ------------------------------------------------------------------------- - - char *Rdead ; // size n, Rdead [k] = 1 if k is a dead pivot column, - // Rdead [k] = 0 otherwise. If no columns are dead, - // this is NULL. If m < n, then at least m-n columns - // will be dead. - - UF_long rank ; // number of live pivot columns - UF_long rank1 ; // number of live pivot columns in first ntol columns - // of A - - UF_long maxfrank ; // max number of rows in any R block - - double norm_E_fro ; // 2-norm of w, the vector of dead column 2-norms - - // ------------------------------------------------------------------------- - // for keeping Householder vectors - // ------------------------------------------------------------------------- - - // The factorization is R = (H_s * ... * H_2 * H_1) * P_H - // where P_H is the permutation HPinv, and H_1, ... H_s are the Householder - // vectors (s = rjsize). - - UF_long keepH ; // TRUE if H is present - - UF_long rjsize ; // size of Hstair and HTau - - UF_long *HStair ; // size rjsize. The list Hstair [Rp [f] ... Rp [f+1]-1] - // gives the staircase for front F - - Entry *HTau ; // size rjsize. The list HTau [Rp [f] ... Rp [f+1]-1] - // gives the Householder coefficients for front F - - UF_long *Hii ; // size hisize, row indices of H. - - UF_long *HPinv ; // size m. HPinv [i] = k if row i of A and H is row k - // of R. This permutation includes QRsym->PLinv, and - // the permutation constructed via pivotal row ordering - // during factorization. - - UF_long *Hm ; // size nf, Hm [f] = # of rows in front F - UF_long *Hr ; // size nf, Hr [f] = # of rows in R block of front F - UF_long maxfm ; // max (Hm [0:nf-1]), computed only if H kept - -} ; - - -// ============================================================================= -// === SuiteSparseQR_factorization ============================================= -// ============================================================================= - -// A combined symbolic+numeric QR factorization of A or [A B], -// with singletons - -template struct SuiteSparseQR_factorization -{ - - // QR factorization of A or [A Binput] after singletons have been removed - double tol ; // tol used - spqr_symbolic *QRsym ; - spqr_numeric *QRnum ; - - // singletons, in compressed-row form; R is n1rows-by-n - UF_long *R1p ; // size n1rows+1 - UF_long *R1j ; - Entry *R1x ; - UF_long r1nz ; // nnz (R1) - - // combined singleton and fill-reducing permutation - UF_long *Q1fill ; - UF_long *P1inv ; - UF_long *HP1inv ; // NULL if n1cols == 0, in which case QRnum->HPinv - // serves in its place. - - // Rmap and RmapInv are NULL if QR->rank == A->ncol - UF_long *Rmap ; // size n. Rmap [j] = k if column j of R is the kth - // live column and where k < QR->rank; otherwise, if - // j is a dead column, then k >= QR->rank. - UF_long *RmapInv ; - - UF_long n1rows ; // number of singleton rows of [A B] - UF_long n1cols ; // number of singleton columns of [A B] - - UF_long narows ; // number of rows of A - UF_long nacols ; // number of columns of A - UF_long bncols ; // number of columns of B - UF_long rank ; // rank estimate of A (n1rows + QRnum->rank1), ranges - // from 0 to min(m,n) - - int allow_tol ; // if TRUE, do rank detection -} ; - - -// ============================================================================= -// === Simple user-callable SuiteSparseQR functions ============================ -// ============================================================================= - -// SuiteSparseQR Sparse QR factorization and solve -// SuiteSparseQR_qmult Q*X, Q'*X, X*Q, or X*Q' for X full or sparse - -// returns rank(A) estimate, or EMPTY on failure -template UF_long SuiteSparseQR -( - // inputs, not modified - int ordering, // all, except 3:given treated as 0:fixed - double tol, // only accept singletons above tol - - UF_long econ, // number of rows of C and R to return; a value - // less than the rank r of A is treated as r, and - // a value greater than m is treated as m. - - int getCTX, // if 0: return Z = C of size econ-by-bncols - // if 1: return Z = C' of size bncols-by-econ - // if 2: return Z = X of size econ-by-bncols - - cholmod_sparse *A, // m-by-n sparse matrix - - // B is either sparse or dense. If Bsparse is non-NULL, B is sparse and - // Bdense is ignored. If Bsparse is NULL and Bdense is non-NULL, then B is - // dense. B is not present if both are NULL. - cholmod_sparse *Bsparse, - cholmod_dense *Bdense, - - // output arrays, neither allocated nor defined on input. - - // Z is the matrix C, C', or X - cholmod_sparse **Zsparse, - cholmod_dense **Zdense, - cholmod_sparse **R, // the R factor - UF_long **E, // size n; fill-reducing ordering of A. - cholmod_sparse **H, // the Householder vectors (m-by-nh) - UF_long **HPinv, // size m; row permutation for H - cholmod_dense **HTau, // size nh, Householder coefficients - - // workspace and parameters - cholmod_common *cc -) ; - -// X = A\dense(B) -template cholmod_dense *SuiteSparseQR -( - int ordering, // all, except 3:given treated as 0:fixed - double tol, - cholmod_sparse *A, // m-by-n sparse matrix - cholmod_dense *B, // m-by-nrhs - cholmod_common *cc // workspace and parameters -) ; - -// X = A\dense(B) using default ordering and tolerance -template cholmod_dense *SuiteSparseQR -( - cholmod_sparse *A, // m-by-n sparse matrix - cholmod_dense *B, // m-by-nrhs - cholmod_common *cc // workspace and parameters -) ; - -// X = A\sparse(B) -template cholmod_sparse *SuiteSparseQR -( - int ordering, // all, except 3:given treated as 0:fixed - double tol, - cholmod_sparse *A, // m-by-n sparse matrix - cholmod_sparse *B, // m-by-nrhs - cholmod_common *cc // workspace and parameters -) ; - -// [Q,R,E] = qr(A), returning Q as a sparse matrix -template UF_long SuiteSparseQR // returns rank(A) estimate -( - int ordering, // all, except 3:given treated as 0:fixed - double tol, - UF_long econ, - cholmod_sparse *A, // m-by-n sparse matrix - // outputs - cholmod_sparse **Q, // m-by-e sparse matrix where e=max(econ,rank(A)) - cholmod_sparse **R, // e-by-n sparse matrix - UF_long **E, // permutation of 0:n-1, NULL if identity - cholmod_common *cc // workspace and parameters -) ; - -// [Q,R,E] = qr(A), discarding Q -template UF_long SuiteSparseQR // returns rank(A) estimate -( - int ordering, // all, except 3:given treated as 0:fixed - double tol, - UF_long econ, - cholmod_sparse *A, // m-by-n sparse matrix - // outputs - cholmod_sparse **R, // e-by-n sparse matrix - UF_long **E, // permutation of 0:n-1, NULL if identity - cholmod_common *cc // workspace and parameters -) ; - -// [C,R,E] = qr(A,B), where C and B are dense -template UF_long SuiteSparseQR -( - // inputs, not modified - int ordering, // all, except 3:given treated as 0:fixed - double tol, // only accept singletons above tol - UF_long econ, // number of rows of C and R to return - cholmod_sparse *A, // m-by-n sparse matrix - cholmod_dense *B, // m-by-nrhs dense matrix - // outputs - cholmod_dense **C, // C = Q'*B, an e-by-nrhs dense matrix - cholmod_sparse **R, // e-by-n sparse matrix where e=max(econ,rank(A)) - UF_long **E, // permutation of 0:n-1, NULL if identity - cholmod_common *cc // workspace and parameters -) ; - -// [C,R,E] = qr(A,B), where C and B are sparse -template UF_long SuiteSparseQR -( - // inputs, not modified - int ordering, // all, except 3:given treated as 0:fixed - double tol, // only accept singletons above tol - UF_long econ, // number of rows of C and R to return - cholmod_sparse *A, // m-by-n sparse matrix - cholmod_sparse *B, // m-by-nrhs sparse matrix - // outputs - cholmod_sparse **C, // C = Q'*B, an e-by-nrhs sparse matrix - cholmod_sparse **R, // e-by-n sparse matrix where e=max(econ,rank(A)) - UF_long **E, // permutation of 0:n-1, NULL if identity - cholmod_common *cc // workspace and parameters -) ; - -// [Q,R,E] = qr(A) where Q is returned in Householder form -template UF_long SuiteSparseQR -( - // inputs, not modified - int ordering, // all, except 3:given treated as 0:fixed - double tol, // only accept singletons above tol - UF_long econ, // number of rows of C and R to return - cholmod_sparse *A, // m-by-n sparse matrix - // outputs - cholmod_sparse **R, // the R factor - UF_long **E, // permutation of 0:n-1, NULL if identity - cholmod_sparse **H, // the Householder vectors (m-by-nh) - UF_long **HPinv, // size m; row permutation for H - cholmod_dense **HTau, // size nh, Householder coefficients - cholmod_common *cc // workspace and parameters -) ; - -// ============================================================================= -// === SuiteSparseQR_qmult ===================================================== -// ============================================================================= - -// This function takes as input the matrix Q in Householder form, as returned -// by SuiteSparseQR (... H, HPinv, HTau, cc) above. - -// returns Y of size m-by-n (NULL on failure) -template cholmod_dense *SuiteSparseQR_qmult -( - // inputs, no modified - int method, // 0,1,2,3 - cholmod_sparse *H, // either m-by-nh or n-by-nh - cholmod_dense *HTau, // size 1-by-nh - UF_long *HPinv, // size mh - cholmod_dense *Xdense, // size m-by-n - - // workspace and parameters - cholmod_common *cc -) ; - -template cholmod_sparse *SuiteSparseQR_qmult -( - // inputs, no modified - int method, // 0,1,2,3 - cholmod_sparse *H, // either m-by-nh or n-by-nh - cholmod_dense *HTau, // size 1-by-nh - UF_long *HPinv, // size mh - cholmod_sparse *X, - - // workspace and parameters - cholmod_common *cc -) ; - -// ============================================================================= -// === Expert user-callable SuiteSparseQR functions ============================ -// ============================================================================= - -#ifndef NEXPERT - -// These functions are "expert" routines, allowing reuse of the QR -// factorization for different right-hand-sides. They also allow the user to -// find the minimum 2-norm solution to an undertermined system of equations. - -template -SuiteSparseQR_factorization *SuiteSparseQR_factorize -( - // inputs, not modified: - int ordering, // all, except 3:given treated as 0:fixed - double tol, // treat columns with 2-norm <= tol as zero - cholmod_sparse *A, // sparse matrix to factorize - // workspace and parameters - cholmod_common *cc -) ; - -template cholmod_dense *SuiteSparseQR_solve // returns X -( - // inputs, not modified: - int system, // which system to solve - SuiteSparseQR_factorization *QR, // of an m-by-n sparse matrix A - cholmod_dense *B, // right-hand-side, m-by-nrhs or n-by-nrhs - // workspace and parameters - cholmod_common *cc -) ; - -template cholmod_sparse *SuiteSparseQR_solve // returns X -( - // inputs, not modified: - int system, // which system to solve (0,1,2,3) - SuiteSparseQR_factorization *QR, // of an m-by-n sparse matrix A - cholmod_sparse *Bsparse, // right-hand-side, m-by-nrhs or n-by-nrhs - // workspace and parameters - cholmod_common *cc -) ; - -// returns Y of size m-by-n, or NULL on failure -template cholmod_dense *SuiteSparseQR_qmult -( - // inputs, not modified - int method, // 0,1,2,3 (same as SuiteSparseQR_qmult) - SuiteSparseQR_factorization *QR, // of an m-by-n sparse matrix A - cholmod_dense *Xdense, // size m-by-n with leading dimension ldx - // workspace and parameters - cholmod_common *cc -) ; - -// returns Y of size m-by-n, or NULL on failure -template cholmod_sparse *SuiteSparseQR_qmult -( - // inputs, not modified - int method, // 0,1,2,3 - SuiteSparseQR_factorization *QR, // of an m-by-n sparse matrix A - cholmod_sparse *Xsparse, // size m-by-n - // workspace and parameters - cholmod_common *cc -) ; - -// free the QR object -template int SuiteSparseQR_free -( - SuiteSparseQR_factorization **QR, // of an m-by-n sparse matrix A - cholmod_common *cc -) ; - -// find the min 2-norm solution to a sparse linear system -template cholmod_dense *SuiteSparseQR_min2norm -( - int ordering, // all, except 3:given treated as 0:fixed - double tol, - cholmod_sparse *A, - cholmod_dense *B, - cholmod_common *cc -) ; - -template cholmod_sparse *SuiteSparseQR_min2norm -( - int ordering, // all, except 3:given treated as 0:fixed - double tol, - cholmod_sparse *A, - cholmod_sparse *B, - cholmod_common *cc -) ; - -// symbolic QR factorization; no singletons exploited -template -SuiteSparseQR_factorization *SuiteSparseQR_symbolic -( - // inputs: - int ordering, // all, except 3:given treated as 0:fixed - int allow_tol, // if FALSE, tol is ignored by the numeric - // factorization, and no rank detection is performed - cholmod_sparse *A, // sparse matrix to factorize (A->x ignored) - cholmod_common *cc // workspace and parameters -) ; - -// numeric QR factorization; -template int SuiteSparseQR_numeric -( - // inputs: - double tol, // treat columns with 2-norm <= tol as zero - cholmod_sparse *A, // sparse matrix to factorize - // input/output - SuiteSparseQR_factorization *QR, - cholmod_common *cc // workspace and parameters -) ; - -#endif - -// ============================================================================= -// === high-resolution timing ================================================== -// ============================================================================= - -#ifdef TIMING - -extern "C" { - -#include -#include - -double spqr_time ( ) ; // returns current time in seconds - -} -#endif - -#endif diff --git a/spqr_mini/UFconfig.h b/spqr_mini/UFconfig.h deleted file mode 100644 index 5b39627a3..000000000 --- a/spqr_mini/UFconfig.h +++ /dev/null @@ -1,151 +0,0 @@ -/* ========================================================================== */ -/* === UFconfig.h =========================================================== */ -/* ========================================================================== */ - -/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages - * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others). - * - * UFconfig.h provides the definition of the long integer. On most systems, - * a C program can be compiled in LP64 mode, in which long's and pointers are - * both 64-bits, and int's are 32-bits. Windows 64, however, uses the LLP64 - * model, in which int's and long's are 32-bits, and long long's and pointers - * are 64-bits. - * - * SuiteSparse packages that include long integer versions are - * intended for the LP64 mode. However, as a workaround for Windows 64 - * (and perhaps other systems), the long integer can be redefined. - * - * If _WIN64 is defined, then the __int64 type is used instead of long. - * - * The long integer can also be defined at compile time. For example, this - * could be added to UFconfig.mk: - * - * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \ - * -D'UF_long_idd="lld"' - * - * This file defines UF_long as either long (on all but _WIN64) or - * __int64 on Windows 64. The intent is that a UF_long is always a 64-bit - * integer in a 64-bit code. ptrdiff_t might be a better choice than long; - * it is always the same size as a pointer. - * - * This file also defines the SUITESPARSE_VERSION and related definitions. - * - * Copyright (c) 2007, University of Florida. No licensing restrictions - * apply to this file or to the UFconfig directory. Author: Timothy A. Davis. - */ - -#ifndef _UFCONFIG_H -#define _UFCONFIG_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* ========================================================================== */ -/* === UF_long ============================================================== */ -/* ========================================================================== */ - -#ifndef UF_long - -#ifdef _WIN64 - -#define UF_long __int64 -#define UF_long_max _I64_MAX -#define UF_long_idd "I64d" - -#else - -#define UF_long long -#define UF_long_max LONG_MAX -#define UF_long_idd "ld" - -#endif -#define UF_long_id "%" UF_long_idd -#endif - -/* ========================================================================== */ -/* === UFconfig parameters and functions ==================================== */ -/* ========================================================================== */ - -/* SuiteSparse-wide parameters will be placed in this struct. So far, they - are only used by RBio. */ - -typedef struct UFconfig_struct -{ - void *(*malloc_memory) (size_t) ; /* pointer to malloc */ - void *(*realloc_memory) (void *, size_t) ; /* pointer to realloc */ - void (*free_memory) (void *) ; /* pointer to free */ - void *(*calloc_memory) (size_t, size_t) ; /* pointer to calloc */ - -} UFconfig ; - -void *UFmalloc /* pointer to allocated block of memory */ -( - size_t nitems, /* number of items to malloc (>=1 is enforced) */ - size_t size_of_item, /* sizeof each item */ - int *ok, /* TRUE if successful, FALSE otherwise */ - UFconfig *config /* SuiteSparse-wide configuration */ -) ; - -void *UFfree /* always returns NULL */ -( - void *p, /* block to free */ - UFconfig *config /* SuiteSparse-wide configuration */ -) ; - - -/* ========================================================================== */ -/* === SuiteSparse version ================================================== */ -/* ========================================================================== */ - -/* SuiteSparse is not a package itself, but a collection of packages, some of - * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD, - * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the - * collection itself. The versions of packages within each version of - * SuiteSparse are meant to work together. Combining one packge from one - * version of SuiteSparse, with another package from another version of - * SuiteSparse, may or may not work. - * - * SuiteSparse Version 3.5.0 contains the following packages: - * - * AMD version 2.2.1 - * BTF version 1.1.1 - * CAMD version 2.2.1 - * CCOLAMD version 2.7.2 - * CHOLMOD version 1.7.2 - * COLAMD version 2.7.2 - * CSparse version 2.2.4 - * CXSparse version 2.2.4 - * KLU version 1.1.1 - * LDL version 2.0.2 - * RBio version 2.0.0 - * SuiteSparseQR version 1.2.0 - * UFcollection version 1.3.0 - * UFconfig version number is the same as SuiteSparse - * UMFPACK version 5.5.0 - * LINFACTOR version 1.1.0 - * MESHND version 1.1.1 - * SSMULT version 2.0.2 - * MATLAB_Tools no specific version number - * - * Other package dependencies: - * BLAS required by CHOLMOD and UMFPACK - * LAPACK required by CHOLMOD - * METIS 4.0.1 required by CHOLMOD (optional) and KLU (optional) - */ - -#define SUITESPARSE_DATE "Nov 30, 2009" -#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_MAIN_VERSION 3 -#define SUITESPARSE_SUB_VERSION 5 -#define SUITESPARSE_SUBSUB_VERSION 1 -#define SUITESPARSE_VERSION \ - SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/spqr_mini/cholmod_blas.h b/spqr_mini/cholmod_blas.h deleted file mode 100644 index b03de64fe..000000000 --- a/spqr_mini/cholmod_blas.h +++ /dev/null @@ -1,456 +0,0 @@ -/* ========================================================================== */ -/* === Include/cholmod_blas.h =============================================== */ -/* ========================================================================== */ - -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_blas.h. - * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis - * CHOLMOD/Include/cholmod_blas.h 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 - * -------------------------------------------------------------------------- */ - -/* This does not need to be included in the user's program. */ - -#ifndef CHOLMOD_BLAS_H -#define CHOLMOD_BLAS_H - -/* ========================================================================== */ -/* === Architecture ========================================================= */ -/* ========================================================================== */ - -#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2) -#define CHOLMOD_SOL2 -#define CHOLMOD_ARCHITECTURE "Sun Solaris" - -#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI) -#define CHOLMOD_SGI -#define CHOLMOD_ARCHITECTURE "SGI Irix" - -#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86) -#define CHOLMOD_LINUX -#define CHOLMOD_ARCHITECTURE "Linux" - -#elif defined (__APPLE__) -#define CHOLMOD_MAC -#define CHOLMOD_ARCHITECTURE "Mac" - -#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS) -#define CHOLMOD_AIX -#define CHOLMOD_ARCHITECTURE "IBM AIX" -/* recent reports from IBM AIX seem to indicate that this is not needed: */ -/* #define BLAS_NO_UNDERSCORE */ - -#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA) -#define CHOLMOD_ALPHA -#define CHOLMOD_ARCHITECTURE "Compaq Alpha" - -#elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64) -#if defined (__MINGW32__) || defined (__MINGW32__) -#define CHOLMOD_MINGW -#elif defined (__CYGWIN32__) || defined (__CYGWIN32__) -#define CHOLMOD_CYGWIN -#else -#define CHOLMOD_WINDOWS -#define BLAS_NO_UNDERSCORE -#endif -#define CHOLMOD_ARCHITECTURE "Microsoft Windows" - -#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX) -#define CHOLMOD_HP -#define CHOLMOD_ARCHITECTURE "HP Unix" -#define BLAS_NO_UNDERSCORE - -#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700) -#define CHOLMOD_HP -#define CHOLMOD_ARCHITECTURE "HP 700 Unix" -#define BLAS_NO_UNDERSCORE - -#else -/* If the architecture is unknown, and you call the BLAS, you may need to */ -/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */ -#define CHOLMOD_ARCHITECTURE "unknown" -#endif - -/* ========================================================================== */ -/* === BLAS and LAPACK names ================================================ */ -/* ========================================================================== */ - -/* Prototypes for the various versions of the BLAS. */ - -/* Determine if the 64-bit Sun Performance BLAS is to be used */ -#if defined(CHOLMOD_SOL2) && !defined(NSUNPERF) && defined(BLAS64) -#define SUN64 -#endif - -#ifdef SUN64 - -#define BLAS_DTRSV dtrsv_64_ -#define BLAS_DGEMV dgemv_64_ -#define BLAS_DTRSM dtrsm_64_ -#define BLAS_DGEMM dgemm_64_ -#define BLAS_DSYRK dsyrk_64_ -#define BLAS_DGER dger_64_ -#define BLAS_DSCAL dscal_64_ -#define LAPACK_DPOTRF dpotrf_64_ - -#define BLAS_ZTRSV ztrsv_64_ -#define BLAS_ZGEMV zgemv_64_ -#define BLAS_ZTRSM ztrsm_64_ -#define BLAS_ZGEMM zgemm_64_ -#define BLAS_ZHERK zherk_64_ -#define BLAS_ZGER zgeru_64_ -#define BLAS_ZSCAL zscal_64_ -#define LAPACK_ZPOTRF zpotrf_64_ - -#elif defined (BLAS_NO_UNDERSCORE) - -#define BLAS_DTRSV dtrsv -#define BLAS_DGEMV dgemv -#define BLAS_DTRSM dtrsm -#define BLAS_DGEMM dgemm -#define BLAS_DSYRK dsyrk -#define BLAS_DGER dger -#define BLAS_DSCAL dscal -#define LAPACK_DPOTRF dpotrf - -#define BLAS_ZTRSV ztrsv -#define BLAS_ZGEMV zgemv -#define BLAS_ZTRSM ztrsm -#define BLAS_ZGEMM zgemm -#define BLAS_ZHERK zherk -#define BLAS_ZGER zgeru -#define BLAS_ZSCAL zscal -#define LAPACK_ZPOTRF zpotrf - -#else - -#define BLAS_DTRSV dtrsv_ -#define BLAS_DGEMV dgemv_ -#define BLAS_DTRSM dtrsm_ -#define BLAS_DGEMM dgemm_ -#define BLAS_DSYRK dsyrk_ -#define BLAS_DGER dger_ -#define BLAS_DSCAL dscal_ -#define LAPACK_DPOTRF dpotrf_ - -#define BLAS_ZTRSV ztrsv_ -#define BLAS_ZGEMV zgemv_ -#define BLAS_ZTRSM ztrsm_ -#define BLAS_ZGEMM zgemm_ -#define BLAS_ZHERK zherk_ -#define BLAS_ZGER zgeru_ -#define BLAS_ZSCAL zscal_ -#define LAPACK_ZPOTRF zpotrf_ - -#endif - -/* ========================================================================== */ -/* === BLAS and LAPACK integer arguments ==================================== */ -/* ========================================================================== */ - -/* Compile CHOLMOD, UMFPACK, and SPQR with -DBLAS64 if you have a BLAS that - * uses 64-bit integers */ - -#if defined (LONGBLAS) || defined (BLAS64) -#define BLAS_INT UF_long -#else -#define BLAS_INT int -#endif - -/* If the BLAS integer is smaller than the basic CHOLMOD integer, then we need - * to check for integer overflow when converting from Int to BLAS_INT. If - * any integer overflows, the externally-defined BLAS_OK variable is - * set to FALSE. BLAS_OK should be set to TRUE before calling any - * BLAS_* macro. - */ - -#define CHECK_BLAS_INT (sizeof (BLAS_INT) < sizeof (Int)) -#define EQ(K,k) (((BLAS_INT) K) == ((Int) k)) - -/* ========================================================================== */ -/* === BLAS and LAPACK prototypes and macros ================================ */ -/* ========================================================================== */ - -void BLAS_DGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha, - double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta, - double *Y, BLAS_INT *incy) ; - -#define BLAS_dgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \ -{ \ - BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ - EQ (INCX,incx) && EQ (INCY,incy))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \ - } \ -} - -void BLAS_ZGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha, - double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta, - double *Y, BLAS_INT *incy) ; - -#define BLAS_zgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \ -{ \ - BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ - EQ (INCX,incx) && EQ (INCY,incy))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \ - } \ -} - -void BLAS_DTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A, - BLAS_INT *lda, double *X, BLAS_INT *incx) ; - -#define BLAS_dtrsv(uplo,trans,diag,n,A,lda,X,incx) \ -{ \ - BLAS_INT N = n, LDA = lda, INCX = incx ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \ - } \ -} - -void BLAS_ZTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A, - BLAS_INT *lda, double *X, BLAS_INT *incx) ; - -#define BLAS_ztrsv(uplo,trans,diag,n,A,lda,X,incx) \ -{ \ - BLAS_INT N = n, LDA = lda, INCX = incx ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \ - } \ -} - -void BLAS_DTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m, - BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B, - BLAS_INT *ldb) ; - -#define BLAS_dtrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \ -{ \ - BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ - EQ (LDB,ldb))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\ - } \ -} - -void BLAS_ZTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m, - BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B, - BLAS_INT *ldb) ; - -#define BLAS_ztrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \ -{ \ - BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ - EQ (LDB,ldb))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\ - } \ -} - -void BLAS_DGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n, - BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B, - BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ; - -#define BLAS_dgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \ -{ \ - BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (K,k) && \ - EQ (LDA,lda) && EQ (LDB,ldb) && EQ (LDC,ldc))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \ - C, &LDC) ; \ - } \ -} - -void BLAS_ZGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n, - BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B, - BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ; - -#define BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \ -{ \ - BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (K,k) && \ - EQ (LDA,lda) && EQ (LDB,ldb) && EQ (LDC,ldc))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \ - C, &LDC) ; \ - } \ -} - -void BLAS_DSYRK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k, - double *alpha, double *A, BLAS_INT *lda, double *beta, double *C, - BLAS_INT *ldc) ; - -#define BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \ -{ \ - BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && \ - EQ (LDC,ldc))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DSYRK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \ - } \ -} \ - -void BLAS_ZHERK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k, - double *alpha, double *A, BLAS_INT *lda, double *beta, double *C, - BLAS_INT *ldc) ; - -#define BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \ -{ \ - BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && \ - EQ (LDC,ldc))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZHERK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \ - } \ -} \ - -void LAPACK_DPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda, - BLAS_INT *info) ; - -#define LAPACK_dpotrf(uplo,n,A,lda,info) \ -{ \ - BLAS_INT N = n, LDA = lda, INFO = 1 ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - LAPACK_DPOTRF (uplo, &N, A, &LDA, &INFO) ; \ - } \ - info = INFO ; \ -} - -void LAPACK_ZPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda, - BLAS_INT *info) ; - -#define LAPACK_zpotrf(uplo,n,A,lda,info) \ -{ \ - BLAS_INT N = n, LDA = lda, INFO = 1 ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - LAPACK_ZPOTRF (uplo, &N, A, &LDA, &INFO) ; \ - } \ - info = INFO ; \ -} - -/* ========================================================================== */ - -void BLAS_DSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ; - -#define BLAS_dscal(n,alpha,Y,incy) \ -{ \ - BLAS_INT N = n, INCY = incy ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (INCY,incy))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DSCAL (&N, alpha, Y, &INCY) ; \ - } \ -} - -void BLAS_ZSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ; - -#define BLAS_zscal(n,alpha,Y,incy) \ -{ \ - BLAS_INT N = n, INCY = incy ; \ - if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (INCY,incy))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZSCAL (&N, alpha, Y, &INCY) ; \ - } \ -} - -void BLAS_DGER (BLAS_INT *m, BLAS_INT *n, double *alpha, - double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy, - double *A, BLAS_INT *lda) ; - -#define BLAS_dger(m,n,alpha,X,incx,Y,incy,A,lda) \ -{ \ - BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ - EQ (INCX,incx) && EQ (INCY,incy))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_DGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \ - } \ -} - -void BLAS_ZGER (BLAS_INT *m, BLAS_INT *n, double *alpha, - double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy, - double *A, BLAS_INT *lda) ; - -#define BLAS_zgeru(m,n,alpha,X,incx,Y,incy,A,lda) \ -{ \ - BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ - EQ (INCX,incx) && EQ (INCY,incy))) \ - { \ - BLAS_OK = FALSE ; \ - } \ - if (!CHECK_BLAS_INT || BLAS_OK) \ - { \ - BLAS_ZGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \ - } \ -} - -#endif diff --git a/spqr_mini/cholmod_common.c b/spqr_mini/cholmod_common.c deleted file mode 100644 index 06e873b26..000000000 --- a/spqr_mini/cholmod_common.c +++ /dev/null @@ -1,672 +0,0 @@ -/* ========================================================================== */ -/* === Core/cholmod_common ================================================== */ -/* ========================================================================== */ - -/* ----------------------------------------------------------------------------- - * CHOLMOD/Core Module. Copyright (C) 2005-2006, - * Univ. of Florida. Author: Timothy A. Davis - * The CHOLMOD/Core 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 - * -------------------------------------------------------------------------- */ - -/* Core utility routines for the cholmod_common object: - * - * Primary routines: - * ----------------- - * cholmod_start the first call to CHOLMOD - * cholmod_finish the last call to CHOLMOD - * - * Secondary routines: - * ------------------- - * cholmod_defaults restore (most) default control parameters - * cholmod_allocate_work allocate (or reallocate) workspace in Common - * cholmod_free_work free workspace in Common - * cholmod_clear_flag clear Common->Flag in workspace - * cholmod_maxrank column dimension of Common->Xwork workspace - * - * The Common object is unique. It cannot be allocated or deallocated by - * CHOLMOD, since it contains the definition of the memory management routines - * used (pointers to malloc, free, realloc, and calloc, or their equivalent). - * The Common object contains workspace that is used between calls to - * CHOLMOD routines. This workspace allocated by CHOLMOD as needed, by - * cholmod_allocate_work and cholmod_free_work. - */ - -#include "cholmod_internal.h" -#include "cholmod_core.h" - -/* ========================================================================== */ -/* === cholmod_start ======================================================== */ -/* ========================================================================== */ - -/* Initialize Common default parameters and statistics. Sets workspace - * pointers to NULL. - * - * This routine must be called just once, prior to calling any other CHOLMOD - * routine. Do not call this routine after any other CHOLMOD routine (except - * cholmod_finish, to start a new CHOLMOD session), or a memory leak will - * occur. - * - * workspace: none - */ - -int CHOLMOD(start) -( - cholmod_common *Common -) -{ - int k ; - - if (Common == NULL) - { - return (FALSE) ; - } - - /* ---------------------------------------------------------------------- */ - /* user error handling routine */ - /* ---------------------------------------------------------------------- */ - - Common->error_handler = NULL ; - - /* ---------------------------------------------------------------------- */ - /* integer and numerical types */ - /* ---------------------------------------------------------------------- */ - - Common->itype = ITYPE ; - Common->dtype = DTYPE ; - - /* ---------------------------------------------------------------------- */ - /* default control parameters */ - /* ---------------------------------------------------------------------- */ - - cholmod_l_defaults(Common) ; - Common->try_catch = FALSE ; - - /* ---------------------------------------------------------------------- */ - /* memory management routines */ - /* ---------------------------------------------------------------------- */ - - /* The user can replace cholmod's memory management routines by redefining - * these function pointers. */ - -#ifndef NMALLOC - /* stand-alone ANSI C program */ - Common->malloc_memory = malloc ; - Common->free_memory = free ; - Common->realloc_memory = realloc ; - Common->calloc_memory = calloc ; -#else - /* no memory manager defined at compile-time; MUST define one at run-time */ - Common->malloc_memory = NULL ; - Common->free_memory = NULL ; - Common->realloc_memory = NULL ; - Common->calloc_memory = NULL ; -#endif - - /* ---------------------------------------------------------------------- */ - /* complex arithmetic routines */ - /* ---------------------------------------------------------------------- */ - -// Common->complex_divide = CHOLMOD(divcomplex) ; -// Common->hypotenuse = CHOLMOD(hypot) ; - - /* ---------------------------------------------------------------------- */ - /* print routine */ - /* ---------------------------------------------------------------------- */ - -#ifndef NPRINT - /* stand-alone ANSI C program */ - Common->print_function = printf ; -#else - /* printing disabled */ - Common->print_function = NULL ; -#endif - - /* ---------------------------------------------------------------------- */ - /* workspace */ - /* ---------------------------------------------------------------------- */ - - /* This code assumes the workspace held in Common is not initialized. If - * it is, then a memory leak will occur because the pointers are - * overwritten with NULL. */ - - Common->nrow = 0 ; - Common->mark = EMPTY ; - Common->xworksize = 0 ; - Common->iworksize = 0 ; - Common->Flag = NULL ; - Common->Head = NULL ; - Common->Iwork = NULL ; - Common->Xwork = NULL ; - Common->no_workspace_reallocate = FALSE ; - - /* ---------------------------------------------------------------------- */ - /* statistics */ - /* ---------------------------------------------------------------------- */ - - /* fl and lnz are computed in cholmod_analyze and cholmod_rowcolcounts */ - Common->fl = EMPTY ; - Common->lnz = EMPTY ; - - /* modfl is computed in cholmod_updown, cholmod_rowadd, and cholmod_rowdel*/ - Common->modfl = EMPTY ; - - /* all routines use status as their error-report code */ - Common->status = CHOLMOD_OK ; - - Common->malloc_count = 0 ; /* # calls to malloc minus # calls to free */ - Common->memory_usage = 0 ; /* peak memory usage (in bytes) */ - Common->memory_inuse = 0 ; /* current memory in use (in bytes) */ - - Common->nrealloc_col = 0 ; - Common->nrealloc_factor = 0 ; - Common->ndbounds_hit = 0 ; - Common->rowfacfl = 0 ; - Common->aatfl = EMPTY ; - - /* Common->called_nd is TRUE if cholmod_analyze called or NESDIS */ - Common->called_nd = FALSE ; - - Common->blas_ok = TRUE ; /* false if BLAS int overflow occurs */ - - /* ---------------------------------------------------------------------- */ - /* default SuiteSparseQR knobs and statististics */ - /* ---------------------------------------------------------------------- */ - - for (k = 0 ; k < 4 ; k++) Common->SPQR_xstat [k] = 0 ; - for (k = 0 ; k < 10 ; k++) Common->SPQR_istat [k] = 0 ; - Common->SPQR_grain = 1 ; /* no Intel TBB multitasking, by default */ - Common->SPQR_small = 1e6 ; /* target min task size for TBB */ - Common->SPQR_shrink = 1 ; /* controls SPQR shrink realloc */ - Common->SPQR_nthreads = 0 ; /* 0: let TBB decide how many threads to use */ - - DEBUG_INIT ("cholmod start", Common) ; - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === cholmod_defaults ===================================================== */ -/* ========================================================================== */ - -/* Set Common default parameters, except for the function pointers. - * - * workspace: none - */ - -int CHOLMOD(defaults) -( - cholmod_common *Common -) -{ - Int i ; - - RETURN_IF_NULL_COMMON (FALSE) ; - - /* ---------------------------------------------------------------------- */ - /* default control parameters */ - /* ---------------------------------------------------------------------- */ - - Common->dbound = 0.0 ; - Common->grow0 = 1.2 ; - Common->grow1 = 1.2 ; - Common->grow2 = 5 ; - Common->maxrank = 8 ; - - Common->final_asis = TRUE ; - Common->final_super = TRUE ; - Common->final_ll = FALSE ; - Common->final_pack = TRUE ; - Common->final_monotonic = TRUE ; - Common->final_resymbol = FALSE ; - - /* use simplicial factorization if flop/nnz(L) < 40, supernodal otherwise */ - Common->supernodal = CHOLMOD_AUTO ; - Common->supernodal_switch = 40 ; - - Common->nrelax [0] = 4 ; - Common->nrelax [1] = 16 ; - Common->nrelax [2] = 48 ; - Common->zrelax [0] = 0.8 ; - Common->zrelax [1] = 0.1 ; - Common->zrelax [2] = 0.05 ; - - Common->prefer_zomplex = FALSE ; - Common->prefer_upper = TRUE ; - Common->prefer_binary = FALSE ; - Common->quick_return_if_not_posdef = FALSE ; - - /* METIS workarounds */ - Common->metis_memory = 0.0 ; /* > 0 for memory guard (2 is reasonable) */ - Common->metis_nswitch = 3000 ; - Common->metis_dswitch = 0.66 ; - - Common->print = 3 ; - Common->precise = FALSE ; - - /* ---------------------------------------------------------------------- */ - /* default ordering methods */ - /* ---------------------------------------------------------------------- */ - - /* Note that if the Partition module is not installed, the CHOLMOD_METIS - * and CHOLMOD_NESDIS methods will not be available. cholmod_analyze will - * report the CHOLMOD_NOT_INSTALLED error, and safely skip over them. - */ - -#if (CHOLMOD_MAXMETHODS < 9) -#error "CHOLMOD_MAXMETHODS must be 9 or more (defined in cholmod_core.h)." -#endif - - /* default strategy: try given, AMD, and then METIS if AMD reports high - * fill-in. NESDIS can be used instead, if Common->default_nesdis is TRUE. - */ - Common->nmethods = 0 ; /* use default strategy */ - Common->default_nesdis = FALSE ; /* use METIS in default strategy */ - - Common->current = 0 ; /* current method being tried */ - Common->selected = 0 ; /* the best method selected */ - - /* first, fill each method with default parameters */ - for (i = 0 ; i <= CHOLMOD_MAXMETHODS ; i++) - { - /* CHOLMOD's default method is AMD for A or AA' */ - Common->method [i].ordering = CHOLMOD_AMD ; - - /* CHOLMOD nested dissection and minimum degree parameter */ - Common->method [i].prune_dense = 10.0 ; /* dense row/col control */ - - /* min degree parameters (AMD, COLAMD, SYMAMD, CAMD, CCOLAMD, CSYMAMD)*/ - Common->method [i].prune_dense2 = -1 ; /* COLAMD dense row control */ - Common->method [i].aggressive = TRUE ; /* aggressive absorption */ - Common->method [i].order_for_lu = FALSE ;/* order for Cholesky not LU */ - - /* CHOLMOD's nested dissection (METIS + constrained AMD) */ - Common->method [i].nd_small = 200 ; /* small graphs aren't cut */ - Common->method [i].nd_compress = TRUE ; /* compress graph & subgraphs */ - Common->method [i].nd_camd = 1 ; /* use CAMD */ - Common->method [i].nd_components = FALSE ; /* lump connected comp. */ - Common->method [i].nd_oksep = 1.0 ; /* sep ok if < oksep*n */ - - /* statistics for each method are not yet computed */ - Common->method [i].fl = EMPTY ; - Common->method [i].lnz = EMPTY ; - } - - Common->postorder = TRUE ; /* follow ordering with weighted postorder */ - - /* Next, define some methods. The first five use default parameters. */ - Common->method [0].ordering = CHOLMOD_GIVEN ; /* skip if UserPerm NULL */ - Common->method [1].ordering = CHOLMOD_AMD ; - Common->method [2].ordering = CHOLMOD_METIS ; - Common->method [3].ordering = CHOLMOD_NESDIS ; - Common->method [4].ordering = CHOLMOD_NATURAL ; - - /* CHOLMOD's nested dissection with large leaves of separator tree */ - Common->method [5].ordering = CHOLMOD_NESDIS ; - Common->method [5].nd_small = 20000 ; - - /* CHOLMOD's nested dissection with tiny leaves, and no AMD ordering */ - Common->method [6].ordering = CHOLMOD_NESDIS ; - Common->method [6].nd_small = 4 ; - Common->method [6].nd_camd = 0 ; /* no CSYMAMD or CAMD */ - - /* CHOLMOD's nested dissection with no dense node removal */ - Common->method [7].ordering = CHOLMOD_NESDIS ; - Common->method [7].prune_dense = -1. ; - - /* COLAMD for A*A', AMD for A */ - Common->method [8].ordering = CHOLMOD_COLAMD ; - - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === cholmod_finish ======================================================= */ -/* ========================================================================== */ - -/* The last call to CHOLMOD must be cholmod_finish. You may call this routine - * more than once, and can safely call any other CHOLMOD routine after calling - * it (including cholmod_start). - * - * The statistics and parameter settings in Common are preserved. The - * workspace in Common is freed. This routine is just another name for - * cholmod_free_work. - */ - -int CHOLMOD(finish) -( - cholmod_common *Common -) -{ - return (CHOLMOD(free_work) (Common)) ; -} - - -/* ========================================================================== */ -/* === cholmod_allocate_work ================================================ */ -/* ========================================================================== */ - -/* Allocate and initialize workspace for CHOLMOD routines, or increase the size - * of already-allocated workspace. If enough workspace is already allocated, - * then nothing happens. - * - * workspace: Flag (nrow), Head (nrow+1), Iwork (iworksize), Xwork (xworksize) - */ - -int CHOLMOD(allocate_work) -( - /* ---- input ---- */ - size_t nrow, /* # of rows in the matrix A */ - size_t iworksize, /* size of Iwork */ - size_t xworksize, /* size of Xwork */ - /* --------------- */ - cholmod_common *Common -) -{ - double *W ; - Int *Head ; - Int i ; - size_t nrow1 ; - int ok = TRUE ; - - /* ---------------------------------------------------------------------- */ - /* get inputs */ - /* ---------------------------------------------------------------------- */ - - RETURN_IF_NULL_COMMON (FALSE) ; - Common->status = CHOLMOD_OK ; - - /* ---------------------------------------------------------------------- */ - /* Allocate Flag (nrow) and Head (nrow+1) */ - /* ---------------------------------------------------------------------- */ - - nrow = MAX (1, nrow) ; - - /* nrow1 = nrow + 1 */ - nrow1 = CHOLMOD(add_size_t) (nrow, 1, &ok) ; - if (!ok) - { - /* nrow+1 causes size_t overflow ; problem is too large */ - Common->status = CHOLMOD_TOO_LARGE ; - CHOLMOD(free_work) (Common) ; - return (FALSE) ; - } - - if (nrow > Common->nrow) - { - - if (Common->no_workspace_reallocate) - { - /* CHOLMOD is not allowed to change the workspace here */ - Common->status = CHOLMOD_INVALID ; - return (FALSE) ; - } - - /* free the old workspace (if any) and allocate new space */ - Common->Flag = CHOLMOD(free) (Common->nrow, sizeof (Int), Common->Flag, - Common) ; - Common->Head = CHOLMOD(free) (Common->nrow+1,sizeof (Int), Common->Head, - Common) ; - Common->Flag = CHOLMOD(malloc) (nrow, sizeof (Int), Common) ; - Common->Head = CHOLMOD(malloc) (nrow1, sizeof (Int), Common) ; - - /* record the new size of Flag and Head */ - Common->nrow = nrow ; - - if (Common->status < CHOLMOD_OK) - { - CHOLMOD(free_work) (Common) ; - return (FALSE) ; - } - - /* initialize Flag and Head */ - Common->mark = EMPTY ; - CHOLMOD(clear_flag) (Common) ; - Head = Common->Head ; - for (i = 0 ; i <= (Int) (nrow) ; i++) - { - Head [i] = EMPTY ; - } - } - - /* ---------------------------------------------------------------------- */ - /* Allocate Iwork (iworksize) */ - /* ---------------------------------------------------------------------- */ - - iworksize = MAX (1, iworksize) ; - if (iworksize > Common->iworksize) - { - - if (Common->no_workspace_reallocate) - { - /* CHOLMOD is not allowed to change the workspace here */ - Common->status = CHOLMOD_INVALID ; - return (FALSE) ; - } - - /* free the old workspace (if any) and allocate new space. - * integer overflow safely detected in cholmod_malloc */ - CHOLMOD(free) (Common->iworksize, sizeof (Int), Common->Iwork, Common) ; - Common->Iwork = CHOLMOD(malloc) (iworksize, sizeof (Int), Common) ; - - /* record the new size of Iwork */ - Common->iworksize = iworksize ; - - if (Common->status < CHOLMOD_OK) - { - CHOLMOD(free_work) (Common) ; - return (FALSE) ; - } - - /* note that Iwork does not need to be initialized */ - } - - /* ---------------------------------------------------------------------- */ - /* Allocate Xwork (xworksize) and set it to ((double) 0.) */ - /* ---------------------------------------------------------------------- */ - - /* make sure xworksize is >= 1 */ - xworksize = MAX (1, xworksize) ; - if (xworksize > Common->xworksize) - { - - if (Common->no_workspace_reallocate) - { - /* CHOLMOD is not allowed to change the workspace here */ - Common->status = CHOLMOD_INVALID ; - return (FALSE) ; - } - - /* free the old workspace (if any) and allocate new space */ - CHOLMOD(free) (Common->xworksize, sizeof (double), Common->Xwork, - Common) ; - Common->Xwork = CHOLMOD(malloc) (xworksize, sizeof (double), Common) ; - - /* record the new size of Xwork */ - Common->xworksize = xworksize ; - - if (Common->status < CHOLMOD_OK) - { - CHOLMOD(free_work) (Common) ; - return (FALSE) ; - } - - /* initialize Xwork */ - W = Common->Xwork ; - for (i = 0 ; i < (Int) xworksize ; i++) - { - W [i] = 0. ; - } - } - - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === cholmod_free_work ==================================================== */ -/* ========================================================================== */ - -/* Deallocate the CHOLMOD workspace. - * - * workspace: deallocates all workspace in Common - */ - -int CHOLMOD(free_work) -( - cholmod_common *Common -) -{ - RETURN_IF_NULL_COMMON (FALSE) ; - Common->Flag = CHOLMOD(free) (Common->nrow, sizeof (Int), - Common->Flag, Common) ; - Common->Head = CHOLMOD(free) (Common->nrow+1, sizeof (Int), - Common->Head, Common) ; - Common->Iwork = CHOLMOD(free) (Common->iworksize, sizeof (Int), - Common->Iwork, Common) ; - Common->Xwork = CHOLMOD(free) (Common->xworksize, sizeof (double), - Common->Xwork, Common) ; - Common->nrow = 0 ; - Common->iworksize = 0 ; - Common->xworksize = 0 ; - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === cholmod_clear_flag =================================================== */ -/* ========================================================================== */ - -/* Increment mark to ensure Flag [0..nrow-1] < mark. If integer overflow - * occurs, or mark was initially negative, reset the entire array. This is - * not an error condition, but an intended function of the Flag workspace. - * - * workspace: Flag (nrow). Does not modify Flag if nrow is zero. - */ - -UF_long cholmod_l_clear_flag -( - cholmod_common *Common -) -{ - Int i, nrow, *Flag ; - - RETURN_IF_NULL_COMMON (-1) ; - - Common->mark++ ; - if (Common->mark <= 0) - { - nrow = Common->nrow ; - Flag = Common->Flag ; - PRINT2 (("reset Flag: nrow "ID"\n", nrow)) ; - PRINT2 (("reset Flag: mark %ld\n", Common->mark)) ; - for (i = 0 ; i < nrow ; i++) - { - Flag [i] = EMPTY ; - } - Common->mark = 0 ; - } - return (Common->mark) ; -} - - -/* ========================================================================== */ -/* ==== cholmod_maxrank ===================================================== */ -/* ========================================================================== */ - -/* Find a valid value of Common->maxrank. Returns 0 if error, or 2, 4, or 8 - * if successful. */ - -size_t cholmod_l_maxrank /* returns validated value of Common->maxrank */ -( - /* ---- input ---- */ - size_t n, /* A and L will have n rows */ - /* --------------- */ - cholmod_common *Common -) -{ - size_t maxrank ; - RETURN_IF_NULL_COMMON (0) ; - maxrank = Common->maxrank ; - if (n > 0) - { - /* Ensure maxrank*n*sizeof(double) does not result in integer overflow. - * If n is so large that 2*n*sizeof(double) results in integer overflow - * (n = 268,435,455 if an Int is 32 bits), then maxrank will be 0 or 1, - * but maxrank will be set to 2 below. 2*n will not result in integer - * overflow, and CHOLMOD will run out of memory or safely detect integer - * overflow elsewhere. - */ - maxrank = MIN (maxrank, Size_max / (n * sizeof (double))) ; - } - if (maxrank <= 2) - { - maxrank = 2 ; - } - else if (maxrank <= 4) - { - maxrank = 4 ; - } - else - { - maxrank = 8 ; - } - return (maxrank) ; -} - - -/* ========================================================================== */ -/* === cholmod_dbound ======================================================= */ -/* ========================================================================== */ - -/* Ensure the absolute value of a diagonal entry, D (j,j), is greater than - * Common->dbound. This routine is not meant for the user to call. It is used - * by the various LDL' factorization and update/downdate routines. The - * default value of Common->dbound is zero, and in that case this routine is not - * called at all. No change is made if D (j,j) is NaN. CHOLMOD does not call - * this routine if Common->dbound is NaN. - */ - -double cholmod_l_dbound /* returns modified diagonal entry of D */ -( - /* ---- input ---- */ - double dj, /* diagonal entry of D, for LDL' factorization */ - /* --------------- */ - cholmod_common *Common -) -{ - double dbound ; - RETURN_IF_NULL_COMMON (0) ; - if (!IS_NAN (dj)) - { - dbound = Common->dbound ; - if (dj < 0) - { - if (dj > -dbound) - { - dj = -dbound ; - Common->ndbounds_hit++ ; - if (Common->status == CHOLMOD_OK) - { - ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ; - } - } - } - else - { - if (dj < dbound) - { - dj = dbound ; - Common->ndbounds_hit++ ; - if (Common->status == CHOLMOD_OK) - { - ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ; - } - } - } - } - return (dj) ; -} diff --git a/spqr_mini/cholmod_common.h b/spqr_mini/cholmod_common.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/spqr_mini/cholmod_core.h b/spqr_mini/cholmod_core.h deleted file mode 100644 index 1637b8267..000000000 --- a/spqr_mini/cholmod_core.h +++ /dev/null @@ -1,2290 +0,0 @@ -/* ========================================================================== */ -/* === Include/cholmod_core.h =============================================== */ -/* ========================================================================== */ - -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_core.h. - * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis - * CHOLMOD/Include/cholmod_core.h 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 - * -------------------------------------------------------------------------- */ - -/* CHOLMOD Core module: basic CHOLMOD objects and routines. - * Required by all CHOLMOD modules. Requires no other module or package. - * - * The CHOLMOD modules are: - * - * Core basic data structures and definitions - * Check check/print the 5 CHOLMOD objects, & 3 types of integer vectors - * Cholesky sparse Cholesky factorization - * Modify sparse Cholesky update/downdate/row-add/row-delete - * MatrixOps sparse matrix functions (add, multiply, norm, ...) - * Supernodal supernodal sparse Cholesky factorization - * Partition graph-partitioning based orderings - * - * The CHOLMOD objects: - * -------------------- - * - * cholmod_common parameters, statistics, and workspace - * cholmod_sparse a sparse matrix in compressed column form - * cholmod_factor an LL' or LDL' factorization - * cholmod_dense a dense matrix - * cholmod_triplet a sparse matrix in "triplet" form - * - * The Core module described here defines the CHOLMOD data structures, and - * basic operations on them. To create and solve a sparse linear system Ax=b, - * the user must create A and b, populate them with values, and then pass them - * to the routines in the CHOLMOD Cholesky module. There are two primary - * methods for creating A: (1) allocate space for a column-oriented sparse - * matrix and fill it with pattern and values, or (2) create a triplet form - * matrix and convert it to a sparse matrix. The latter option is simpler. - * - * The matrices b and x are typically dense matrices, but can also be sparse. - * You can allocate and free them as dense matrices with the - * cholmod_allocate_dense and cholmod_free_dense routines. - * - * The cholmod_factor object contains the symbolic and numeric LL' or LDL' - * factorization of sparse symmetric matrix. The matrix must be positive - * definite for an LL' factorization. It need only be symmetric and have well- - * conditioned leading submatrices for it to have an LDL' factorization - * (CHOLMOD does not pivot for numerical stability). It is typically created - * with the cholmod_factorize routine in the Cholesky module, but can also - * be initialized to L=D=I in the Core module and then modified by the Modify - * module. It must be freed with cholmod_free_factor, defined below. - * - * The Core routines for each object are described below. Each list is split - * into two parts: the primary routines and secondary routines. - * - * ============================================================================ - * === cholmod_common ========================================================= - * ============================================================================ - * - * The Common object contains control parameters, statistics, and - * You must call cholmod_start before calling any other CHOLMOD routine, and - * must call cholmod_finish as your last call to CHOLMOD, with two exceptions: - * you may call cholmod_print_common and cholmod_check_common in the Check - * module after calling cholmod_finish. - * - * cholmod_start first call to CHOLMOD - * cholmod_finish last call to CHOLMOD - * ----------------------------- - * cholmod_defaults restore default parameters - * cholmod_maxrank maximum rank for update/downdate - * cholmod_allocate_work allocate workspace in Common - * cholmod_free_work free workspace in Common - * cholmod_clear_flag clear Flag workspace in Common - * cholmod_error called when CHOLMOD encounters an error - * cholmod_dbound for internal use in CHOLMOD only - * cholmod_hypot compute sqrt (x*x + y*y) accurately - * cholmod_divcomplex complex division, c = a/b - * - * ============================================================================ - * === cholmod_sparse ========================================================= - * ============================================================================ - * - * A sparse matrix is held in compressed column form. In the basic type - * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix - * with nz entries is held in three arrays: p of size n+1, i of size nz, and x - * of size nz. Row indices of column j are held in i [p [j] ... p [j+1]-1] and - * in the same locations in x. There may be no duplicate entries in a column. - * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track). - * A->stype determines the storage mode: 0 if both upper/lower parts are stored, - * -1 if A is symmetric and just tril(A) is stored, +1 if symmetric and triu(A) - * is stored. - * - * cholmod_allocate_sparse allocate a sparse matrix - * cholmod_free_sparse free a sparse matrix - * ----------------------------- - * cholmod_reallocate_sparse change the size (# entries) of sparse matrix - * cholmod_nnz number of nonzeros in a sparse matrix - * cholmod_speye sparse identity matrix - * cholmod_spzeros sparse zero matrix - * cholmod_transpose transpose a sparse matrix - * cholmod_ptranspose transpose/permute a sparse matrix - * cholmod_transpose_unsym transpose/permute an unsymmetric sparse matrix - * cholmod_transpose_sym transpose/permute a symmetric sparse matrix - * cholmod_sort sort row indices in each column of sparse matrix - * cholmod_band C = tril (triu (A,k1), k2) - * cholmod_band_inplace A = tril (triu (A,k1), k2) - * cholmod_aat C = A*A' - * cholmod_copy_sparse C = A, create an exact copy of a sparse matrix - * cholmod_copy C = A, with possible change of stype - * cholmod_add C = alpha*A + beta*B - * cholmod_sparse_xtype change the xtype of a sparse matrix - * - * ============================================================================ - * === cholmod_factor ========================================================= - * ============================================================================ - * - * The data structure for an LL' or LDL' factorization is too complex to - * describe in one sentence. This object can hold the symbolic analysis alone, - * or in combination with a "simplicial" (similar to a sparse matrix) or - * "supernodal" form of the numerical factorization. Only the routine to free - * a factor is primary, since a factor object is created by the factorization - * routine (cholmod_factorize). It must be freed with cholmod_free_factor. - * - * cholmod_free_factor free a factor - * ----------------------------- - * cholmod_allocate_factor allocate a factor (LL' or LDL') - * cholmod_reallocate_factor change the # entries in a factor - * cholmod_change_factor change the type of factor (e.g., LDL' to LL') - * cholmod_pack_factor pack the columns of a factor - * cholmod_reallocate_column resize a single column of a factor - * cholmod_factor_to_sparse create a sparse matrix copy of a factor - * cholmod_copy_factor create a copy of a factor - * cholmod_factor_xtype change the xtype of a factor - * - * Note that there is no cholmod_sparse_to_factor routine to create a factor - * as a copy of a sparse matrix. It could be done, after a fashion, but a - * lower triangular sparse matrix would not necessarily have a chordal graph, - * which would break the many CHOLMOD routines that rely on this property. - * - * ============================================================================ - * === cholmod_dense ========================================================== - * ============================================================================ - * - * The solve routines and some of the MatrixOps and Modify routines use dense - * matrices as inputs. These are held in column-major order. With a leading - * dimension of d, the entry in row i and column j is held in x [i+j*d]. - * - * cholmod_allocate_dense allocate a dense matrix - * cholmod_free_dense free a dense matrix - * ----------------------------- - * cholmod_zeros allocate a dense matrix of all zeros - * cholmod_ones allocate a dense matrix of all ones - * cholmod_eye allocate a dense identity matrix - * cholmod_sparse_to_dense create a dense matrix copy of a sparse matrix - * cholmod_dense_to_sparse create a sparse matrix copy of a dense matrix - * cholmod_copy_dense create a copy of a dense matrix - * cholmod_copy_dense2 copy a dense matrix (pre-allocated) - * cholmod_dense_xtype change the xtype of a dense matrix - * - * ============================================================================ - * === cholmod_triplet ======================================================== - * ============================================================================ - * - * A sparse matrix held in triplet form is the simplest one for a user to - * create. It consists of a list of nz entries in arbitrary order, held in - * three arrays: i, j, and x, each of length nk. The kth entry is in row i[k], - * column j[k], with value x[k]. There may be duplicate values; if A(i,j) - * appears more than once, its value is the sum of the entries with those row - * and column indices. - * - * cholmod_allocate_triplet allocate a triplet matrix - * cholmod_triplet_to_sparse create a sparse matrix copy of a triplet matrix - * cholmod_free_triplet free a triplet matrix - * ----------------------------- - * cholmod_reallocate_triplet change the # of entries in a triplet matrix - * cholmod_sparse_to_triplet create a triplet matrix copy of a sparse matrix - * cholmod_copy_triplet create a copy of a triplet matrix - * cholmod_triplet_xtype change the xtype of a triplet matrix - * - * ============================================================================ - * === memory management ====================================================== - * ============================================================================ - * - * cholmod_malloc malloc wrapper - * cholmod_calloc calloc wrapper - * cholmod_free free wrapper - * cholmod_realloc realloc wrapper - * cholmod_realloc_multiple realloc wrapper for multiple objects - * - * ============================================================================ - * === Core CHOLMOD prototypes ================================================ - * ============================================================================ - * - * All CHOLMOD routines (in all modules) use the following protocol for return - * values, with one exception: - * - * int TRUE (1) if successful, or FALSE (0) otherwise. - * (exception: cholmod_divcomplex) - * UF_long a value >= 0 if successful, or -1 otherwise. - * double a value >= 0 if successful, or -1 otherwise. - * size_t a value > 0 if successful, or 0 otherwise. - * void * a non-NULL pointer to newly allocated memory if - * successful, or NULL otherwise. - * cholmod_sparse * a non-NULL pointer to a newly allocated matrix - * if successful, or NULL otherwise. - * cholmod_factor * a non-NULL pointer to a newly allocated factor - * if successful, or NULL otherwise. - * cholmod_triplet * a non-NULL pointer to a newly allocated triplet - * matrix if successful, or NULL otherwise. - * cholmod_dense * a non-NULL pointer to a newly allocated triplet - * matrix if successful, or NULL otherwise. - * - * The last parameter to all routines is always a pointer to the CHOLMOD - * Common object. - * - * TRUE and FALSE are not defined here, since they may conflict with the user - * program. A routine that described here returning TRUE or FALSE returns 1 - * or 0, respectively. Any TRUE/FALSE parameter is true if nonzero, false if - * zero. - */ - -#ifndef CHOLMOD_CORE_H -#define CHOLMOD_CORE_H - -/* ========================================================================== */ -/* === CHOLMOD version ====================================================== */ -/* ========================================================================== */ - -/* All versions of CHOLMOD will include the following definitions. - * As an example, to test if the version you are using is 1.3 or later: - * - * if (CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3)) ... - * - * This also works during compile-time: - * - * #if CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3) - * printf ("This is version 1.3 or later\n") ; - * #else - * printf ("This is version is earlier than 1.3\n") ; - * #endif - */ - -#define CHOLMOD_DATE "Nov 30, 2009" -#define CHOLMOD_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define CHOLMOD_MAIN_VERSION 1 -#define CHOLMOD_SUB_VERSION 7 -#define CHOLMOD_SUBSUB_VERSION 2 -#define CHOLMOD_VERSION \ - CHOLMOD_VER_CODE(CHOLMOD_MAIN_VERSION,CHOLMOD_SUB_VERSION) - - -/* ========================================================================== */ -/* === non-CHOLMOD include files ============================================ */ -/* ========================================================================== */ - -/* This is the only non-CHOLMOD include file imposed on the user program. - * It required for size_t definition used here. CHOLMOD itself includes other - * ANSI C89 standard #include files, but does not expose them to the user. - * - * CHOLMOD assumes that your C compiler is ANSI C89 compliant. It does not make - * use of ANSI C99 features. - */ - -#include -#include - -/* ========================================================================== */ -/* === CHOLMOD objects ====================================================== */ -/* ========================================================================== */ - -/* Each CHOLMOD object has its own type code. */ - -#define CHOLMOD_COMMON 0 -#define CHOLMOD_SPARSE 1 -#define CHOLMOD_FACTOR 2 -#define CHOLMOD_DENSE 3 -#define CHOLMOD_TRIPLET 4 - -/* ========================================================================== */ -/* === CHOLMOD Common ======================================================= */ -/* ========================================================================== */ - -/* itype defines the types of integer used: */ -#define CHOLMOD_INT 0 /* all integer arrays are int */ -#define CHOLMOD_INTLONG 1 /* most are int, some are UF_long */ -#define CHOLMOD_LONG 2 /* all integer arrays are UF_long */ - -/* The itype of all parameters for all CHOLMOD routines must match. - * FUTURE WORK: CHOLMOD_INTLONG is not yet supported. - */ - -/* dtype defines what the numerical type is (double or float): */ -#define CHOLMOD_DOUBLE 0 /* all numerical values are double */ -#define CHOLMOD_SINGLE 1 /* all numerical values are float */ - -/* The dtype of all parameters for all CHOLMOD routines must match. - * - * Scalar floating-point values are always passed as double arrays of size 2 - * (for the real and imaginary parts). They are typecast to float as needed. - * FUTURE WORK: the float case is not supported yet. - */ - -/* xtype defines the kind of numerical values used: */ -#define CHOLMOD_PATTERN 0 /* pattern only, no numerical values */ -#define CHOLMOD_REAL 1 /* a real matrix */ -#define CHOLMOD_COMPLEX 2 /* a complex matrix (ANSI C99 compatible) */ -#define CHOLMOD_ZOMPLEX 3 /* a complex matrix (MATLAB compatible) */ - -/* The xtype of all parameters for all CHOLMOD routines must match. - * - * CHOLMOD_PATTERN: x and z are ignored. - * CHOLMOD_DOUBLE: x is non-null of size nzmax, z is ignored. - * CHOLMOD_COMPLEX: x is non-null of size 2*nzmax doubles, z is ignored. - * CHOLMOD_ZOMPLEX: x and z are non-null of size nzmax - * - * In the real case, z is ignored. The kth entry in the matrix is x [k]. - * There are two methods for the complex case. In the ANSI C99-compatible - * CHOLMOD_COMPLEX case, the real and imaginary parts of the kth entry - * are in x [2*k] and x [2*k+1], respectively. z is ignored. In the - * MATLAB-compatible CHOLMOD_ZOMPLEX case, the real and imaginary - * parts of the kth entry are in x [k] and z [k]. - * - * Scalar floating-point values are always passed as double arrays of size 2 - * (real and imaginary parts). The imaginary part of a scalar is ignored if - * the routine operates on a real matrix. - * - * These Modules support complex and zomplex matrices, with a few exceptions: - * - * Check all routines - * Cholesky all routines - * Core all except cholmod_aat, add, band, copy - * Demo all routines - * Partition all routines - * Supernodal all routines support any real, complex, or zomplex input. - * There will never be a supernodal zomplex L; a complex - * supernodal L is created if A is zomplex. - * Tcov all routines - * Valgrind all routines - * - * These Modules provide partial support for complex and zomplex matrices: - * - * MATLAB all routines support real and zomplex only, not complex, - * with the exception of ldlupdate, which supports - * real matrices only. This is a minor constraint since - * MATLAB's matrices are all real or zomplex. - * MatrixOps only norm_dense, norm_sparse, and sdmult support complex - * and zomplex - * - * These Modules do not support complex and zomplex matrices at all: - * - * Modify all routines support real matrices only - */ - -/* Definitions for cholmod_common: */ -#define CHOLMOD_MAXMETHODS 9 /* maximum number of different methods that */ - /* cholmod_analyze can try. Must be >= 9. */ - -/* Common->status values. zero means success, negative means a fatal error, - * positive is a warning. */ -#define CHOLMOD_OK 0 /* success */ -#define CHOLMOD_NOT_INSTALLED (-1) /* failure: method not installed */ -#define CHOLMOD_OUT_OF_MEMORY (-2) /* failure: out of memory */ -#define CHOLMOD_TOO_LARGE (-3) /* failure: integer overflow occured */ -#define CHOLMOD_INVALID (-4) /* failure: invalid input */ -#define CHOLMOD_NOT_POSDEF (1) /* warning: matrix not pos. def. */ -#define CHOLMOD_DSMALL (2) /* warning: D for LDL' or diag(L) or */ - /* LL' has tiny absolute value */ - -/* ordering method (also used for L->ordering) */ -#define CHOLMOD_NATURAL 0 /* use natural ordering */ -#define CHOLMOD_GIVEN 1 /* use given permutation */ -#define CHOLMOD_AMD 2 /* use minimum degree (AMD) */ -#define CHOLMOD_METIS 3 /* use METIS' nested dissection */ -#define CHOLMOD_NESDIS 4 /* use CHOLMOD's version of nested dissection:*/ - /* node bisector applied recursively, followed - * by constrained minimum degree (CSYMAMD or - * CCOLAMD) */ -#define CHOLMOD_COLAMD 5 /* use AMD for A, COLAMD for A*A' */ - -/* POSTORDERED is not a method, but a result of natural ordering followed by a - * weighted postorder. It is used for L->ordering, not method [ ].ordering. */ -#define CHOLMOD_POSTORDERED 6 /* natural ordering, postordered. */ - -/* supernodal strategy (for Common->supernodal) */ -#define CHOLMOD_SIMPLICIAL 0 /* always do simplicial */ -#define CHOLMOD_AUTO 1 /* select simpl/super depending on matrix */ -#define CHOLMOD_SUPERNODAL 2 /* always do supernodal */ - -typedef struct cholmod_common_struct -{ - /* ---------------------------------------------------------------------- */ - /* parameters for symbolic/numeric factorization and update/downdate */ - /* ---------------------------------------------------------------------- */ - - double dbound ; /* Smallest absolute value of diagonal entries of D - * for LDL' factorization and update/downdate/rowadd/ - * rowdel, or the diagonal of L for an LL' factorization. - * Entries in the range 0 to dbound are replaced with dbound. - * Entries in the range -dbound to 0 are replaced with -dbound. No - * changes are made to the diagonal if dbound <= 0. Default: zero */ - - double grow0 ; /* For a simplicial factorization, L->i and L->x can - * grow if necessary. grow0 is the factor by which - * it grows. For the initial space, L is of size MAX (1,grow0) times - * the required space. If L runs out of space, the new size of L is - * MAX(1.2,grow0) times the new required space. If you do not plan on - * modifying the LDL' factorization in the Modify module, set grow0 to - * zero (or set grow2 to 0, see below). Default: 1.2 */ - - double grow1 ; - - size_t grow2 ; /* For a simplicial factorization, each column j of L - * is initialized with space equal to - * grow1*L->ColCount[j] + grow2. If grow0 < 1, grow1 < 1, or grow2 == 0, - * then the space allocated is exactly equal to L->ColCount[j]. If the - * column j runs out of space, it increases to grow1*need + grow2 in - * size, where need is the total # of nonzeros in that column. If you do - * not plan on modifying the factorization in the Modify module, set - * grow2 to zero. Default: grow1 = 1.2, grow2 = 5. */ - - size_t maxrank ; /* rank of maximum update/downdate. Valid values: - * 2, 4, or 8. A value < 2 is set to 2, and a - * value > 8 is set to 8. It is then rounded up to the next highest - * power of 2, if not already a power of 2. Workspace (Xwork, below) of - * size nrow-by-maxrank double's is allocated for the update/downdate. - * If an update/downdate of rank-k is requested, with k > maxrank, - * it is done in steps of maxrank. Default: 8, which is fastest. - * Memory usage can be reduced by setting maxrank to 2 or 4. - */ - - double supernodal_switch ; /* supernodal vs simplicial factorization */ - int supernodal ; /* If Common->supernodal <= CHOLMOD_SIMPLICIAL - * (0) then cholmod_analyze performs a - * simplicial analysis. If >= CHOLMOD_SUPERNODAL (2), then a supernodal - * analysis is performed. If == CHOLMOD_AUTO (1) and - * flop/nnz(L) < Common->supernodal_switch, then a simplicial analysis - * is done. A supernodal analysis done otherwise. - * Default: CHOLMOD_AUTO. Default supernodal_switch = 40 */ - - int final_asis ; /* If TRUE, then ignore the other final_* parameters - * (except for final_pack). - * The factor is left as-is when done. Default: TRUE.*/ - - int final_super ; /* If TRUE, leave a factor in supernodal form when - * supernodal factorization is finished. If FALSE, - * then convert to a simplicial factor when done. - * Default: TRUE */ - - int final_ll ; /* If TRUE, leave factor in LL' form when done. - * Otherwise, leave in LDL' form. Default: FALSE */ - - int final_pack ; /* If TRUE, pack the columns when done. If TRUE, and - * cholmod_factorize is called with a symbolic L, L is - * allocated with exactly the space required, using L->ColCount. If you - * plan on modifying the factorization, set Common->final_pack to FALSE, - * and each column will be given a little extra slack space for future - * growth in fill-in due to updates. Default: TRUE */ - - int final_monotonic ; /* If TRUE, ensure columns are monotonic when done. - * Default: TRUE */ - - int final_resymbol ;/* if cholmod_factorize performed a supernodal - * factorization, final_resymbol is true, and - * final_super is FALSE (convert a simplicial numeric factorization), - * then numerically zero entries that resulted from relaxed supernodal - * amalgamation are removed. This does not remove entries that are zero - * due to exact numeric cancellation, since doing so would break the - * update/downdate rowadd/rowdel routines. Default: FALSE. */ - - /* supernodal relaxed amalgamation parameters: */ - double zrelax [3] ; - size_t nrelax [3] ; - - /* Let ns be the total number of columns in two adjacent supernodes. - * Let z be the fraction of zero entries in the two supernodes if they - * are merged (z includes zero entries from prior amalgamations). The - * two supernodes are merged if: - * (ns <= nrelax [0]) || (no new zero entries added) || - * (ns <= nrelax [1] && z < zrelax [0]) || - * (ns <= nrelax [2] && z < zrelax [1]) || (z < zrelax [2]) - * - * Default parameters result in the following rule: - * (ns <= 4) || (no new zero entries added) || - * (ns <= 16 && z < 0.8) || (ns <= 48 && z < 0.1) || (z < 0.05) - */ - - int prefer_zomplex ; /* X = cholmod_solve (sys, L, B, Common) computes - * x=A\b or solves a related system. If L and B are - * both real, then X is real. Otherwise, X is returned as - * CHOLMOD_COMPLEX if Common->prefer_zomplex is FALSE, or - * CHOLMOD_ZOMPLEX if Common->prefer_zomplex is TRUE. This parameter - * is needed because there is no supernodal zomplex L. Suppose the - * caller wants all complex matrices to be stored in zomplex form - * (MATLAB, for example). A supernodal L is returned in complex form - * if A is zomplex. B can be real, and thus X = cholmod_solve (L,B) - * should return X as zomplex. This cannot be inferred from the input - * arguments L and B. Default: FALSE, since all data types are - * supported in CHOLMOD_COMPLEX form and since this is the native type - * of LAPACK and the BLAS. Note that the MATLAB/cholmod.c mexFunction - * sets this parameter to TRUE, since MATLAB matrices are in - * CHOLMOD_ZOMPLEX form. - */ - - int prefer_upper ; /* cholmod_analyze and cholmod_factorize work - * fastest when a symmetric matrix is stored in - * upper triangular form when a fill-reducing ordering is used. In - * MATLAB, this corresponds to how x=A\b works. When the matrix is - * ordered as-is, they work fastest when a symmetric matrix is in lower - * triangular form. In MATLAB, R=chol(A) does the opposite. This - * parameter affects only how cholmod_read returns a symmetric matrix. - * If TRUE (the default case), a symmetric matrix is always returned in - * upper-triangular form (A->stype = 1). */ - - int quick_return_if_not_posdef ; /* if TRUE, the supernodal numeric - * factorization will return quickly if - * the matrix is not positive definite. Default: FALSE. */ - - /* ---------------------------------------------------------------------- */ - /* printing and error handling options */ - /* ---------------------------------------------------------------------- */ - - int print ; /* print level. Default: 3 */ - int precise ; /* if TRUE, print 16 digits. Otherwise print 5 */ - int (*print_function) (const char *, ...) ; /* pointer to printf */ - - int try_catch ; /* if TRUE, then ignore errors; CHOLMOD is in the middle - * of a try/catch block. No error message is printed - * and the Common->error_handler function is not called. */ - - void (*error_handler) (int status, const char *file, - int line, const char *message) ; - - /* Common->error_handler is the user's error handling routine. If not - * NULL, this routine is called if an error occurs in CHOLMOD. status - * can be CHOLMOD_OK (0), negative for a fatal error, and positive for - * a warning. file is a string containing the name of the source code - * file where the error occured, and line is the line number in that - * file. message is a string describing the error in more detail. */ - - /* ---------------------------------------------------------------------- */ - /* ordering options */ - /* ---------------------------------------------------------------------- */ - - /* The cholmod_analyze routine can try many different orderings and select - * the best one. It can also try one ordering method multiple times, with - * different parameter settings. The default is to use three orderings, - * the user's permutation (if provided), AMD which is the fastest ordering - * and generally gives good fill-in, and METIS. CHOLMOD's nested dissection - * (METIS with a constrained AMD) usually gives a better ordering than METIS - * alone (by about 5% to 10%) but it takes more time. - * - * If you know the method that is best for your matrix, set Common->nmethods - * to 1 and set Common->method [0] to the set of parameters for that method. - * If you set it to 1 and do not provide a permutation, then only AMD will - * be called. - * - * If METIS is not available, the default # of methods tried is 2 (the user - * permutation, if any, and AMD). - * - * To try other methods, set Common->nmethods to the number of methods you - * want to try. The suite of default methods and their parameters is - * described in the cholmod_defaults routine, and summarized here: - * - * Common->method [i]: - * i = 0: user-provided ordering (cholmod_analyze_p only) - * i = 1: AMD (for both A and A*A') - * i = 2: METIS - * i = 3: CHOLMOD's nested dissection (NESDIS), default parameters - * i = 4: natural - * i = 5: NESDIS with nd_small = 20000 - * i = 6: NESDIS with nd_small = 4, no constrained minimum degree - * i = 7: NESDIS with no dense node removal - * i = 8: AMD for A, COLAMD for A*A' - * - * You can modify the suite of methods you wish to try by modifying - * Common.method [...] after calling cholmod_start or cholmod_defaults. - * - * For example, to use AMD, followed by a weighted postordering: - * - * Common->nmethods = 1 ; - * Common->method [0].ordering = CHOLMOD_AMD ; - * Common->postorder = TRUE ; - * - * To use the natural ordering (with no postordering): - * - * Common->nmethods = 1 ; - * Common->method [0].ordering = CHOLMOD_NATURAL ; - * Common->postorder = FALSE ; - * - * If you are going to factorize hundreds or more matrices with the same - * nonzero pattern, you may wish to spend a great deal of time finding a - * good permutation. In this case, try setting Common->nmethods to 9. - * The time spent in cholmod_analysis will be very high, but you need to - * call it only once. - * - * cholmod_analyze sets Common->current to a value between 0 and nmethods-1. - * Each ordering method uses the set of options defined by this parameter. - */ - - int nmethods ; /* The number of ordering methods to try. Default: 0. - * nmethods = 0 is a special case. cholmod_analyze - * will try the user-provided ordering (if given) and AMD. Let fl and - * lnz be the flop count and nonzeros in L from AMD's ordering. Let - * anz be the number of nonzeros in the upper or lower triangular part - * of the symmetric matrix A. If fl/lnz < 500 or lnz/anz < 5, then this - * is a good ordering, and METIS is not attempted. Otherwise, METIS is - * tried. The best ordering found is used. If nmethods > 0, the - * methods used are given in the method[ ] array, below. The first - * three methods in the default suite of orderings is (1) use the given - * permutation (if provided), (2) use AMD, and (3) use METIS. Maximum - * allowed value is CHOLMOD_MAXMETHODS. */ - - int current ; /* The current method being tried. Default: 0. Valid - * range is 0 to nmethods-1. */ - - int selected ; /* The best method found. */ - - /* The suite of ordering methods and parameters: */ - - struct cholmod_method_struct - { - /* statistics for this method */ - double lnz ; /* nnz(L) excl. zeros from supernodal amalgamation, - * for a "pure" L */ - - double fl ; /* flop count for a "pure", real simplicial LL' - * factorization, with no extra work due to - * amalgamation. Subtract n to get the LDL' flop count. Multiply - * by about 4 if the matrix is complex or zomplex. */ - - /* ordering method parameters */ - double prune_dense ;/* dense row/col control for AMD, SYMAMD, CSYMAMD, - * and NESDIS (cholmod_nested_dissection). For a - * symmetric n-by-n matrix, rows/columns with more than - * MAX (16, prune_dense * sqrt (n)) entries are removed prior to - * ordering. They appear at the end of the re-ordered matrix. - * - * If prune_dense < 0, only completely dense rows/cols are removed. - * - * This paramater is also the dense column control for COLAMD and - * CCOLAMD. For an m-by-n matrix, columns with more than - * MAX (16, prune_dense * sqrt (MIN (m,n))) entries are removed prior - * to ordering. They appear at the end of the re-ordered matrix. - * CHOLMOD factorizes A*A', so it calls COLAMD and CCOLAMD with A', - * not A. Thus, this parameter affects the dense *row* control for - * CHOLMOD's matrix, and the dense *column* control for COLAMD and - * CCOLAMD. - * - * Removing dense rows and columns improves the run-time of the - * ordering methods. It has some impact on ordering quality - * (usually minimal, sometimes good, sometimes bad). - * - * Default: 10. */ - - double prune_dense2 ;/* dense row control for COLAMD and CCOLAMD. - * Rows with more than MAX (16, dense2 * sqrt (n)) - * for an m-by-n matrix are removed prior to ordering. CHOLMOD's - * matrix is transposed before ordering it with COLAMD or CCOLAMD, - * so this controls the dense *columns* of CHOLMOD's matrix, and - * the dense *rows* of COLAMD's or CCOLAMD's matrix. - * - * If prune_dense2 < 0, only completely dense rows/cols are removed. - * - * Default: -1. Note that this is not the default for COLAMD and - * CCOLAMD. -1 is best for Cholesky. 10 is best for LU. */ - - double nd_oksep ; /* in NESDIS, when a node separator is computed, it - * discarded if nsep >= nd_oksep*n, where nsep is - * the number of nodes in the separator, and n is the size of the - * graph being cut. Valid range is 0 to 1. If 1 or greater, the - * separator is discarded if it consists of the entire graph. - * Default: 1 */ - - double other1 [4] ; /* future expansion */ - - size_t nd_small ; /* do not partition graphs with fewer nodes than - * nd_small, in NESDIS. Default: 200 (same as - * METIS) */ - - size_t other2 [4] ; /* future expansion */ - - int aggressive ; /* Aggresive absorption in AMD, COLAMD, SYMAMD, - * CCOLAMD, and CSYMAMD. Default: TRUE */ - - int order_for_lu ; /* CCOLAMD can be optimized to produce an ordering - * for LU or Cholesky factorization. CHOLMOD only - * performs a Cholesky factorization. However, you may wish to use - * CHOLMOD as an interface for CCOLAMD but use it for your own LU - * factorization. In this case, order_for_lu should be set to FALSE. - * When factorizing in CHOLMOD itself, you should *** NEVER *** set - * this parameter FALSE. Default: TRUE. */ - - int nd_compress ; /* If TRUE, compress the graph and subgraphs before - * partitioning them in NESDIS. Default: TRUE */ - - int nd_camd ; /* If 1, follow the nested dissection ordering - * with a constrained minimum degree ordering that - * respects the partitioning just found (using CAMD). If 2, use - * CSYMAMD instead. If you set nd_small very small, you may not need - * this ordering, and can save time by setting it to zero (no - * constrained minimum degree ordering). Default: 1. */ - - int nd_components ; /* The nested dissection ordering finds a node - * separator that splits the graph into two parts, - * which may be unconnected. If nd_components is TRUE, each of - * these connected components is split independently. If FALSE, - * each part is split as a whole, even if it consists of more than - * one connected component. Default: FALSE */ - - /* fill-reducing ordering to use */ - int ordering ; - - size_t other3 [4] ; /* future expansion */ - - } method [CHOLMOD_MAXMETHODS + 1] ; - - int postorder ; /* If TRUE, cholmod_analyze follows the ordering with a - * weighted postorder of the elimination tree. Improves - * supernode amalgamation. Does not affect fundamental nnz(L) and - * flop count. Default: TRUE. */ - - /* ---------------------------------------------------------------------- */ - /* memory management routines */ - /* ---------------------------------------------------------------------- */ - - void *(*malloc_memory) (size_t) ; /* pointer to malloc */ - void *(*realloc_memory) (void *, size_t) ; /* pointer to realloc */ - void (*free_memory) (void *) ; /* pointer to free */ - void *(*calloc_memory) (size_t, size_t) ; /* pointer to calloc */ - - /* ---------------------------------------------------------------------- */ - /* routines for complex arithmetic */ - /* ---------------------------------------------------------------------- */ - - int (*complex_divide) (double ax, double az, double bx, double bz, - double *cx, double *cz) ; - - /* flag = complex_divide (ax, az, bx, bz, &cx, &cz) computes the complex - * division c = a/b, where ax and az hold the real and imaginary part - * of a, and b and c are stored similarly. flag is returned as 1 if - * a divide-by-zero occurs, or 0 otherwise. By default, the function - * pointer Common->complex_divide is set equal to cholmod_divcomplex. - */ - - double (*hypotenuse) (double x, double y) ; - - /* s = hypotenuse (x,y) computes s = sqrt (x*x + y*y), but does so more - * accurately. By default, the function pointer Common->hypotenuse is - * set equal to cholmod_hypot. See also the hypot function in the C99 - * standard, which has an identical syntax and function. If you have - * a C99-compliant compiler, you can set Common->hypotenuse = hypot. */ - - /* ---------------------------------------------------------------------- */ - /* METIS workarounds */ - /* ---------------------------------------------------------------------- */ - - double metis_memory ; /* This is a parameter for CHOLMOD's interface to - * METIS, not a parameter to METIS itself. METIS - * uses an amount of memory that is difficult to estimate precisely - * beforehand. If it runs out of memory, it terminates your program. - * All routines in CHOLMOD except for CHOLMOD's interface to METIS - * return an error status and safely return to your program if they run - * out of memory. To mitigate this problem, the CHOLMOD interface - * can allocate a single block of memory equal in size to an empirical - * upper bound of METIS's memory usage times the Common->metis_memory - * parameter, and then immediately free it. It then calls METIS. If - * this pre-allocation fails, it is possible that METIS will fail as - * well, and so CHOLMOD returns with an out-of-memory condition without - * calling METIS. - * - * METIS_NodeND (used in the CHOLMOD_METIS ordering option) with its - * default parameter settings typically uses about (4*nz+40n+4096) - * times sizeof(int) memory, where nz is equal to the number of entries - * in A for the symmetric case or AA' if an unsymmetric matrix is - * being ordered (where nz includes both the upper and lower parts - * of A or AA'). The observed "upper bound" (with 2 exceptions), - * measured in an instrumented copy of METIS 4.0.1 on thousands of - * matrices, is (10*nz+50*n+4096) * sizeof(int). Two large matrices - * exceeded this bound, one by almost a factor of 2 (Gupta/gupta2). - * - * If your program is terminated by METIS, try setting metis_memory to - * 2.0, or even higher if needed. By default, CHOLMOD assumes that METIS - * does not have this problem (so that CHOLMOD will work correctly when - * this issue is fixed in METIS). Thus, the default value is zero. - * This work-around is not guaranteed anyway. - * - * If a matrix exceeds this predicted memory usage, AMD is attempted - * instead. It, too, may run out of memory, but if it does so it will - * not terminate your program. - */ - - double metis_dswitch ; /* METIS_NodeND in METIS 4.0.1 gives a seg */ - size_t metis_nswitch ; /* fault with one matrix of order n = 3005 and - * nz = 6,036,025. This is a very dense graph. - * The workaround is to use AMD instead of METIS for matrices of dimension - * greater than Common->metis_nswitch (default 3000) or more and with - * density of Common->metis_dswitch (default 0.66) or more. - * cholmod_nested_dissection has no problems with the same matrix, even - * though it uses METIS_NodeComputeSeparator on this matrix. If this - * seg fault does not affect you, set metis_nswitch to zero or less, - * and CHOLMOD will not switch to AMD based just on the density of the - * matrix (it will still switch to AMD if the metis_memory parameter - * causes the switch). - */ - - /* ---------------------------------------------------------------------- */ - /* workspace */ - /* ---------------------------------------------------------------------- */ - - /* CHOLMOD has several routines that take less time than the size of - * workspace they require. Allocating and initializing the workspace would - * dominate the run time, unless workspace is allocated and initialized - * just once. CHOLMOD allocates this space when needed, and holds it here - * between calls to CHOLMOD. cholmod_start sets these pointers to NULL - * (which is why it must be the first routine called in CHOLMOD). - * cholmod_finish frees the workspace (which is why it must be the last - * call to CHOLMOD). - */ - - size_t nrow ; /* size of Flag and Head */ - UF_long mark ; /* mark value for Flag array */ - size_t iworksize ; /* size of Iwork. Upper bound: 6*nrow+ncol */ - size_t xworksize ; /* size of Xwork, in bytes. - * maxrank*nrow*sizeof(double) for update/downdate. - * 2*nrow*sizeof(double) otherwise */ - - /* initialized workspace: contents needed between calls to CHOLMOD */ - void *Flag ; /* size nrow, an integer array. Kept cleared between - * calls to cholmod rouines (Flag [i] < mark) */ - - void *Head ; /* size nrow+1, an integer array. Kept cleared between - * calls to cholmod routines (Head [i] = EMPTY) */ - - void *Xwork ; /* a double array. Its size varies. It is nrow for - * most routines (cholmod_rowfac, cholmod_add, - * cholmod_aat, cholmod_norm, cholmod_ssmult) for the real case, twice - * that when the input matrices are complex or zomplex. It is of size - * 2*nrow for cholmod_rowadd and cholmod_rowdel. For cholmod_updown, - * its size is maxrank*nrow where maxrank is 2, 4, or 8. Kept cleared - * between calls to cholmod (set to zero). */ - - /* uninitialized workspace, contents not needed between calls to CHOLMOD */ - void *Iwork ; /* size iworksize, 2*nrow+ncol for most routines, - * up to 6*nrow+ncol for cholmod_analyze. */ - - int itype ; /* If CHOLMOD_LONG, Flag, Head, and Iwork are UF_long. - * Otherwise all three arrays are int. */ - - int dtype ; /* double or float */ - - /* Common->itype and Common->dtype are used to define the types of all - * sparse matrices, triplet matrices, dense matrices, and factors - * created using this Common struct. The itypes and dtypes of all - * parameters to all CHOLMOD routines must match. */ - - int no_workspace_reallocate ; /* this is an internal flag, used as a - * precaution by cholmod_analyze. It is normally false. If true, - * cholmod_allocate_work is not allowed to reallocate any workspace; - * they must use the existing workspace in Common (Iwork, Flag, Head, - * and Xwork). Added for CHOLMOD v1.1 */ - - /* ---------------------------------------------------------------------- */ - /* statistics */ - /* ---------------------------------------------------------------------- */ - - /* fl and lnz are set only in cholmod_analyze and cholmod_rowcolcounts, - * in the Cholesky modudle. modfl is set only in the Modify module. */ - - int status ; /* error code */ - double fl ; /* LL' flop count from most recent analysis */ - double lnz ; /* fundamental nz in L */ - double anz ; /* nonzeros in tril(A) if A is symmetric/lower, - * triu(A) if symmetric/upper, or tril(A*A') if - * unsymmetric, in last call to cholmod_analyze. */ - double modfl ; /* flop count from most recent update/downdate/ - * rowadd/rowdel (excluding flops to modify the - * solution to Lx=b, if computed) */ - size_t malloc_count ; /* # of objects malloc'ed minus the # free'd*/ - size_t memory_usage ; /* peak memory usage in bytes */ - size_t memory_inuse ; /* current memory usage in bytes */ - - double nrealloc_col ; /* # of column reallocations */ - double nrealloc_factor ;/* # of factor reallocations due to col. reallocs */ - double ndbounds_hit ; /* # of times diagonal modified by dbound */ - - double rowfacfl ; /* # of flops in last call to cholmod_rowfac */ - double aatfl ; /* # of flops to compute A(:,f)*A(:,f)' */ - - /* ---------------------------------------------------------------------- */ - /* future expansion */ - /* ---------------------------------------------------------------------- */ - - /* To allow CHOLMOD to be updated without recompiling the user application, - * additional space is set aside here for future statistics, parameters, - * and workspace. Note: additional entries were added in v1.1 to the - * method array, above, and thus v1.0 and v1.1 are not binary compatible. - * - * v1.1 to the current version are binary compatible. - */ - - /* ---------------------------------------------------------------------- */ - double other1 [10] ; - - double SPQR_xstat [4] ; /* for SuiteSparseQR statistics */ - - /* SuiteSparseQR control parameters: */ - double SPQR_grain ; /* task size is >= max (total flops / grain) */ - double SPQR_small ; /* task size is >= small */ - - /* ---------------------------------------------------------------------- */ - UF_long SPQR_istat [10] ; /* for SuiteSparseQR statistics */ - UF_long other2 [6] ; /* reduced from size 16 in v1.6 */ - - /* ---------------------------------------------------------------------- */ - int other3 [10] ; /* reduced from size 16 in v1.1. */ - - int prefer_binary ; /* cholmod_read_triplet converts a symmetric - * pattern-only matrix into a real matrix. If - * prefer_binary is FALSE, the diagonal entries are set to 1 + the degree - * of the row/column, and off-diagonal entries are set to -1 (resulting - * in a positive definite matrix if the diagonal is zero-free). Most - * symmetric patterns are the pattern a positive definite matrix. If - * this parameter is TRUE, then the matrix is returned with a 1 in each - * entry, instead. Default: FALSE. Added in v1.3. */ - - /* control parameter (added for v1.2): */ - int default_nesdis ; /* Default: FALSE. If FALSE, then the default - * ordering strategy (when Common->nmethods == 0) - * is to try the given ordering (if present), AMD, and then METIS if AMD - * reports high fill-in. If Common->default_nesdis is TRUE then NESDIS - * is used instead in the default strategy. */ - - /* statistic (added for v1.2): */ - int called_nd ; /* TRUE if the last call to - * cholmod_analyze called NESDIS or METIS. */ - - int blas_ok ; /* FALSE if BLAS int overflow; TRUE otherwise */ - - /* SuiteSparseQR control parameters: */ - int SPQR_shrink ; /* controls stack realloc method */ - int SPQR_nthreads ; /* number of TBB threads, 0 = auto */ - - /* ---------------------------------------------------------------------- */ - size_t other4 [16] ; - - /* ---------------------------------------------------------------------- */ - void *other5 [16] ; - -} cholmod_common ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_start: first call to CHOLMOD */ -/* -------------------------------------------------------------------------- */ - -int cholmod_start -( - cholmod_common *Common -) ; - -int cholmod_l_start (cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_finish: last call to CHOLMOD */ -/* -------------------------------------------------------------------------- */ - -int cholmod_finish -( - cholmod_common *Common -) ; - -int cholmod_l_finish (cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_defaults: restore default parameters */ -/* -------------------------------------------------------------------------- */ - -int cholmod_defaults -( - cholmod_common *Common -) ; - -int cholmod_l_defaults (cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_maxrank: return valid maximum rank for update/downdate */ -/* -------------------------------------------------------------------------- */ - -size_t cholmod_maxrank /* returns validated value of Common->maxrank */ -( - /* ---- input ---- */ - size_t n, /* A and L will have n rows */ - /* --------------- */ - cholmod_common *Common -) ; - -size_t cholmod_l_maxrank (size_t, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_allocate_work: allocate workspace in Common */ -/* -------------------------------------------------------------------------- */ - -int cholmod_allocate_work -( - /* ---- input ---- */ - size_t nrow, /* size: Common->Flag (nrow), Common->Head (nrow+1) */ - size_t iworksize, /* size of Common->Iwork */ - size_t xworksize, /* size of Common->Xwork */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_allocate_work (size_t, size_t, size_t, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_free_work: free workspace in Common */ -/* -------------------------------------------------------------------------- */ - -int cholmod_free_work -( - cholmod_common *Common -) ; - -int cholmod_l_free_work (cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_clear_flag: clear Flag workspace in Common */ -/* -------------------------------------------------------------------------- */ - -/* use a macro for speed */ -#define CHOLMOD_CLEAR_FLAG(Common) \ -{ \ - Common->mark++ ; \ - if (Common->mark <= 0) \ - { \ - Common->mark = EMPTY ; \ - CHOLMOD (clear_flag) (Common) ; \ - } \ -} - -UF_long cholmod_clear_flag -( - cholmod_common *Common -) ; - -UF_long cholmod_l_clear_flag (cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_error: called when CHOLMOD encounters an error */ -/* -------------------------------------------------------------------------- */ - -int cholmod_error -( - /* ---- input ---- */ - int status, /* error status */ - const char *file, /* name of source code file where error occured */ - int line, /* line number in source code file where error occured*/ - const char *message,/* error message */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_error (int, const char *, int, const char *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_dbound: for internal use in CHOLMOD only */ -/* -------------------------------------------------------------------------- */ - -double cholmod_dbound /* returns modified diagonal entry of D or L */ -( - /* ---- input ---- */ - double dj, /* diagonal entry of D for LDL' or L for LL' */ - /* --------------- */ - cholmod_common *Common -) ; - -double cholmod_l_dbound (double, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_hypot: compute sqrt (x*x + y*y) accurately */ -/* -------------------------------------------------------------------------- */ - -double cholmod_hypot -( - /* ---- input ---- */ - double x, double y -) ; - -double cholmod_l_hypot (double, double) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_divcomplex: complex division, c = a/b */ -/* -------------------------------------------------------------------------- */ - -int cholmod_divcomplex /* return 1 if divide-by-zero, 0 otherise */ -( - /* ---- input ---- */ - double ar, double ai, /* real and imaginary parts of a */ - double br, double bi, /* real and imaginary parts of b */ - /* ---- output --- */ - double *cr, double *ci /* real and imaginary parts of c */ -) ; - -int cholmod_l_divcomplex (double, double, double, double, double *, double *) ; - - -/* ========================================================================== */ -/* === Core/cholmod_sparse ================================================== */ -/* ========================================================================== */ - -/* A sparse matrix stored in compressed-column form. */ - -typedef struct cholmod_sparse_struct -{ - size_t nrow ; /* the matrix is nrow-by-ncol */ - size_t ncol ; - size_t nzmax ; /* maximum number of entries in the matrix */ - - /* pointers to int or UF_long: */ - void *p ; /* p [0..ncol], the column pointers */ - void *i ; /* i [0..nzmax-1], the row indices */ - - /* for unpacked matrices only: */ - void *nz ; /* nz [0..ncol-1], the # of nonzeros in each col. In - * packed form, the nonzero pattern of column j is in - * A->i [A->p [j] ... A->p [j+1]-1]. In unpacked form, column j is in - * A->i [A->p [j] ... A->p [j]+A->nz[j]-1] instead. In both cases, the - * numerical values (if present) are in the corresponding locations in - * the array x (or z if A->xtype is CHOLMOD_ZOMPLEX). */ - - /* pointers to double or float: */ - void *x ; /* size nzmax or 2*nzmax, if present */ - void *z ; /* size nzmax, if present */ - - int stype ; /* Describes what parts of the matrix are considered: - * - * 0: matrix is "unsymmetric": use both upper and lower triangular parts - * (the matrix may actually be symmetric in pattern and value, but - * both parts are explicitly stored and used). May be square or - * rectangular. - * >0: matrix is square and symmetric, use upper triangular part. - * Entries in the lower triangular part are ignored. - * <0: matrix is square and symmetric, use lower triangular part. - * Entries in the upper triangular part are ignored. - * - * Note that stype>0 and stype<0 are different for cholmod_sparse and - * cholmod_triplet. See the cholmod_triplet data structure for more - * details. - */ - - int itype ; /* CHOLMOD_INT: p, i, and nz are int. - * CHOLMOD_INTLONG: p is UF_long, i and nz are int. - * CHOLMOD_LONG: p, i, and nz are UF_long. */ - - int xtype ; /* pattern, real, complex, or zomplex */ - int dtype ; /* x and z are double or float */ - int sorted ; /* TRUE if columns are sorted, FALSE otherwise */ - int packed ; /* TRUE if packed (nz ignored), FALSE if unpacked - * (nz is required) */ - -} cholmod_sparse ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_allocate_sparse: allocate a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_allocate_sparse -( - /* ---- input ---- */ - size_t nrow, /* # of rows of A */ - size_t ncol, /* # of columns of A */ - size_t nzmax, /* max # of nonzeros of A */ - int sorted, /* TRUE if columns of A sorted, FALSE otherwise */ - int packed, /* TRUE if A will be packed, FALSE otherwise */ - int stype, /* stype of A */ - int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_allocate_sparse (size_t, size_t, size_t, int, int, - int, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_free_sparse: free a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_free_sparse -( - /* ---- in/out --- */ - cholmod_sparse **A, /* matrix to deallocate, NULL on output */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_free_sparse (cholmod_sparse **, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_reallocate_sparse: change the size (# entries) of sparse matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_reallocate_sparse -( - /* ---- input ---- */ - size_t nznew, /* new # of entries in A */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to reallocate */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_reallocate_sparse ( size_t, cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_nnz: return number of nonzeros in a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -UF_long cholmod_nnz -( - /* ---- input ---- */ - cholmod_sparse *A, - /* --------------- */ - cholmod_common *Common -) ; - -UF_long cholmod_l_nnz (cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_speye: sparse identity matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_speye -( - /* ---- input ---- */ - size_t nrow, /* # of rows of A */ - size_t ncol, /* # of columns of A */ - int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_speye (size_t, size_t, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_spzeros: sparse zero matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_spzeros -( - /* ---- input ---- */ - size_t nrow, /* # of rows of A */ - size_t ncol, /* # of columns of A */ - size_t nzmax, /* max # of nonzeros of A */ - int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_spzeros (size_t, size_t, size_t, int, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_transpose: transpose a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -/* Return A' or A.' The "values" parameter is 0, 1, or 2 to denote the pattern - * transpose, the array transpose (A.'), and the complex conjugate transpose - * (A'). - */ - -cholmod_sparse *cholmod_transpose -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to transpose */ - int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_transpose_unsym: transpose an unsymmetric sparse matrix */ -/* -------------------------------------------------------------------------- */ - -/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is - * already allocated. See cholmod_transpose for a simpler routine. */ - -int cholmod_transpose_unsym -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to transpose */ - int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ - int *Perm, /* size nrow, if present (can be NULL) */ - int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* ---- output --- */ - cholmod_sparse *F, /* F = A', A(:,f)', or A(p,f)' */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_transpose_unsym (cholmod_sparse *, int, UF_long *, UF_long *, - size_t, cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_transpose_sym: transpose a symmetric sparse matrix */ -/* -------------------------------------------------------------------------- */ - -/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated. - * See cholmod_transpose for a simpler routine. */ - -int cholmod_transpose_sym -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to transpose */ - int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ - int *Perm, /* size nrow, if present (can be NULL) */ - /* ---- output --- */ - cholmod_sparse *F, /* F = A' or A(p,p)' */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_transpose_sym (cholmod_sparse *, int, UF_long *, cholmod_sparse *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_ptranspose: transpose a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -/* Return A' or A(p,p)' if A is symmetric. Return A', A(:,f)', or A(p,f)' if - * A is unsymmetric. */ - -cholmod_sparse *cholmod_ptranspose -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to transpose */ - int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ - int *Perm, /* if non-NULL, F = A(p,f) or A(p,p) */ - int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_ptranspose (cholmod_sparse *, int, UF_long *, - UF_long *, size_t, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_sort: sort row indices in each column of sparse matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_sort -( - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix to sort */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_sort (cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_band: C = tril (triu (A,k1), k2) */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_band -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to extract band matrix from */ - UF_long k1, /* ignore entries below the k1-st diagonal */ - UF_long k2, /* ignore entries above the k2-nd diagonal */ - int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_band (cholmod_sparse *, UF_long, UF_long, int, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_band_inplace: A = tril (triu (A,k1), k2) */ -/* -------------------------------------------------------------------------- */ - -int cholmod_band_inplace -( - /* ---- input ---- */ - UF_long k1, /* ignore entries below the k1-st diagonal */ - UF_long k2, /* ignore entries above the k2-nd diagonal */ - int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ - /* ---- in/out --- */ - cholmod_sparse *A, /* matrix from which entries not in band are removed */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_band_inplace (UF_long, UF_long, int, cholmod_sparse *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_aat: C = A*A' or A(:,f)*A(:,f)' */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_aat -( - /* ---- input ---- */ - cholmod_sparse *A, /* input matrix; C=A*A' is constructed */ - int *fset, /* subset of 0:(A->ncol)-1 */ - size_t fsize, /* size of fset */ - int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag), - * -2: pattern only, no diagonal, add 50%+n extra - * space to C */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_aat (cholmod_sparse *, UF_long *, size_t, int, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_copy_sparse: C = A, create an exact copy of a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_copy_sparse -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to copy */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_copy_sparse (cholmod_sparse *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_copy: C = A, with possible change of stype */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_copy -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to copy */ - int stype, /* requested stype of C */ - int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_copy (cholmod_sparse *, int, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_add: C = alpha*A + beta*B */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_add -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to add */ - cholmod_sparse *B, /* matrix to add */ - double alpha [2], /* scale factor for A */ - double beta [2], /* scale factor for B */ - int values, /* if TRUE compute the numerical values of C */ - int sorted, /* if TRUE, sort columns of C */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_add (cholmod_sparse *, cholmod_sparse *, double *, - double *, int, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_sparse_xtype: change the xtype of a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_sparse_xtype -( - /* ---- input ---- */ - int to_xtype, /* requested xtype (pattern, real, complex, zomplex) */ - /* ---- in/out --- */ - cholmod_sparse *A, /* sparse matrix to change */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_sparse_xtype (int, cholmod_sparse *, cholmod_common *) ; - - -/* ========================================================================== */ -/* === Core/cholmod_factor ================================================== */ -/* ========================================================================== */ - -/* A symbolic and numeric factorization, either simplicial or supernodal. - * In all cases, the row indices in the columns of L are kept sorted. */ - -typedef struct cholmod_factor_struct -{ - /* ---------------------------------------------------------------------- */ - /* for both simplicial and supernodal factorizations */ - /* ---------------------------------------------------------------------- */ - - size_t n ; /* L is n-by-n */ - - size_t minor ; /* If the factorization failed, L->minor is the column - * at which it failed (in the range 0 to n-1). A value - * of n means the factorization was successful or - * the matrix has not yet been factorized. */ - - /* ---------------------------------------------------------------------- */ - /* symbolic ordering and analysis */ - /* ---------------------------------------------------------------------- */ - - void *Perm ; /* size n, permutation used */ - void *ColCount ; /* size n, column counts for simplicial L */ - - /* ---------------------------------------------------------------------- */ - /* simplicial factorization */ - /* ---------------------------------------------------------------------- */ - - size_t nzmax ; /* size of i and x */ - - void *p ; /* p [0..ncol], the column pointers */ - void *i ; /* i [0..nzmax-1], the row indices */ - void *x ; /* x [0..nzmax-1], the numerical values */ - void *z ; - void *nz ; /* nz [0..ncol-1], the # of nonzeros in each column. - * i [p [j] ... p [j]+nz[j]-1] contains the row indices, - * and the numerical values are in the same locatins - * in x. The value of i [p [k]] is always k. */ - - void *next ; /* size ncol+2. next [j] is the next column in i/x */ - void *prev ; /* size ncol+2. prev [j] is the prior column in i/x. - * head of the list is ncol+1, and the tail is ncol. */ - - /* ---------------------------------------------------------------------- */ - /* supernodal factorization */ - /* ---------------------------------------------------------------------- */ - - /* Note that L->x is shared with the simplicial data structure. L->x has - * size L->nzmax for a simplicial factor, and size L->xsize for a supernodal - * factor. */ - - size_t nsuper ; /* number of supernodes */ - size_t ssize ; /* size of s, integer part of supernodes */ - size_t xsize ; /* size of x, real part of supernodes */ - size_t maxcsize ; /* size of largest update matrix */ - size_t maxesize ; /* max # of rows in supernodes, excl. triangular part */ - - void *super ; /* size nsuper+1, first col in each supernode */ - void *pi ; /* size nsuper+1, pointers to integer patterns */ - void *px ; /* size nsuper+1, pointers to real parts */ - void *s ; /* size ssize, integer part of supernodes */ - - /* ---------------------------------------------------------------------- */ - /* factorization type */ - /* ---------------------------------------------------------------------- */ - - int ordering ; /* ordering method used */ - - int is_ll ; /* TRUE if LL', FALSE if LDL' */ - int is_super ; /* TRUE if supernodal, FALSE if simplicial */ - int is_monotonic ; /* TRUE if columns of L appear in order 0..n-1. - * Only applicable to simplicial numeric types. */ - - /* There are 8 types of factor objects that cholmod_factor can represent - * (only 6 are used): - * - * Numeric types (xtype is not CHOLMOD_PATTERN) - * -------------------------------------------- - * - * simplicial LDL': (is_ll FALSE, is_super FALSE). Stored in compressed - * column form, using the simplicial components above (nzmax, p, i, - * x, z, nz, next, and prev). The unit diagonal of L is not stored, - * and D is stored in its place. There are no supernodes. - * - * simplicial LL': (is_ll TRUE, is_super FALSE). Uses the same storage - * scheme as the simplicial LDL', except that D does not appear. - * The first entry of each column of L is the diagonal entry of - * that column of L. - * - * supernodal LDL': (is_ll FALSE, is_super TRUE). Not used. - * FUTURE WORK: add support for supernodal LDL' - * - * supernodal LL': (is_ll TRUE, is_super TRUE). A supernodal factor, - * using the supernodal components described above (nsuper, ssize, - * xsize, maxcsize, maxesize, super, pi, px, s, x, and z). - * - * - * Symbolic types (xtype is CHOLMOD_PATTERN) - * ----------------------------------------- - * - * simplicial LDL': (is_ll FALSE, is_super FALSE). Nothing is present - * except Perm and ColCount. - * - * simplicial LL': (is_ll TRUE, is_super FALSE). Identical to the - * simplicial LDL', except for the is_ll flag. - * - * supernodal LDL': (is_ll FALSE, is_super TRUE). Not used. - * FUTURE WORK: add support for supernodal LDL' - * - * supernodal LL': (is_ll TRUE, is_super TRUE). A supernodal symbolic - * factorization. The simplicial symbolic information is present - * (Perm and ColCount), as is all of the supernodal factorization - * except for the numerical values (x and z). - */ - - int itype ; /* The integer arrays are Perm, ColCount, p, i, nz, - * next, prev, super, pi, px, and s. If itype is - * CHOLMOD_INT, all of these are int arrays. - * CHOLMOD_INTLONG: p, pi, px are UF_long, others int. - * CHOLMOD_LONG: all integer arrays are UF_long. */ - int xtype ; /* pattern, real, complex, or zomplex */ - int dtype ; /* x and z double or float */ - -} cholmod_factor ; - - -/* -------------------------------------------------------------------------- */ -/* cholmod_allocate_factor: allocate a factor (symbolic LL' or LDL') */ -/* -------------------------------------------------------------------------- */ - -cholmod_factor *cholmod_allocate_factor -( - /* ---- input ---- */ - size_t n, /* L is n-by-n */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_factor *cholmod_l_allocate_factor (size_t, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_free_factor: free a factor */ -/* -------------------------------------------------------------------------- */ - -int cholmod_free_factor -( - /* ---- in/out --- */ - cholmod_factor **L, /* factor to free, NULL on output */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_free_factor (cholmod_factor **, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_reallocate_factor: change the # entries in a factor */ -/* -------------------------------------------------------------------------- */ - -int cholmod_reallocate_factor -( - /* ---- input ---- */ - size_t nznew, /* new # of entries in L */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_reallocate_factor (size_t, cholmod_factor *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_change_factor: change the type of factor (e.g., LDL' to LL') */ -/* -------------------------------------------------------------------------- */ - -int cholmod_change_factor -( - /* ---- input ---- */ - int to_xtype, /* to CHOLMOD_PATTERN, _REAL, _COMPLEX, _ZOMPLEX */ - int to_ll, /* TRUE: convert to LL', FALSE: LDL' */ - int to_super, /* TRUE: convert to supernodal, FALSE: simplicial */ - int to_packed, /* TRUE: pack simplicial columns, FALSE: do not pack */ - int to_monotonic, /* TRUE: put simplicial columns in order, FALSE: not */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_change_factor ( int, int, int, int, int, cholmod_factor *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_pack_factor: pack the columns of a factor */ -/* -------------------------------------------------------------------------- */ - -/* Pack the columns of a simplicial factor. Unlike cholmod_change_factor, - * it can pack the columns of a factor even if they are not stored in their - * natural order (non-monotonic). */ - -int cholmod_pack_factor -( - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_pack_factor (cholmod_factor *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_reallocate_column: resize a single column of a factor */ -/* -------------------------------------------------------------------------- */ - -int cholmod_reallocate_column -( - /* ---- input ---- */ - size_t j, /* the column to reallocate */ - size_t need, /* required size of column j */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to modify */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_reallocate_column (size_t, size_t, cholmod_factor *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_factor_to_sparse: create a sparse matrix copy of a factor */ -/* -------------------------------------------------------------------------- */ - -/* Only operates on numeric factors, not symbolic ones */ - -cholmod_sparse *cholmod_factor_to_sparse -( - /* ---- in/out --- */ - cholmod_factor *L, /* factor to copy, converted to symbolic on output */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_factor_to_sparse (cholmod_factor *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_copy_factor: create a copy of a factor */ -/* -------------------------------------------------------------------------- */ - -cholmod_factor *cholmod_copy_factor -( - /* ---- input ---- */ - cholmod_factor *L, /* factor to copy */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_factor *cholmod_l_copy_factor (cholmod_factor *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_factor_xtype: change the xtype of a factor */ -/* -------------------------------------------------------------------------- */ - -int cholmod_factor_xtype -( - /* ---- input ---- */ - int to_xtype, /* requested xtype (real, complex, or zomplex) */ - /* ---- in/out --- */ - cholmod_factor *L, /* factor to change */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_factor_xtype (int, cholmod_factor *, cholmod_common *) ; - - -/* ========================================================================== */ -/* === Core/cholmod_dense =================================================== */ -/* ========================================================================== */ - -/* A dense matrix in column-oriented form. It has no itype since it contains - * no integers. Entry in row i and column j is located in x [i+j*d]. - */ - -typedef struct cholmod_dense_struct -{ - size_t nrow ; /* the matrix is nrow-by-ncol */ - size_t ncol ; - size_t nzmax ; /* maximum number of entries in the matrix */ - size_t d ; /* leading dimension (d >= nrow must hold) */ - void *x ; /* size nzmax or 2*nzmax, if present */ - void *z ; /* size nzmax, if present */ - int xtype ; /* pattern, real, complex, or zomplex */ - int dtype ; /* x and z double or float */ - -} cholmod_dense ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_allocate_dense: allocate a dense matrix (contents uninitialized) */ -/* -------------------------------------------------------------------------- */ - -cholmod_dense *cholmod_allocate_dense -( - /* ---- input ---- */ - size_t nrow, /* # of rows of matrix */ - size_t ncol, /* # of columns of matrix */ - size_t d, /* leading dimension */ - int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_dense *cholmod_l_allocate_dense (size_t, size_t, size_t, int, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_zeros: allocate a dense matrix and set it to zero */ -/* -------------------------------------------------------------------------- */ - -cholmod_dense *cholmod_zeros -( - /* ---- input ---- */ - size_t nrow, /* # of rows of matrix */ - size_t ncol, /* # of columns of matrix */ - int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_dense *cholmod_l_zeros (size_t, size_t, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_ones: allocate a dense matrix and set it to all ones */ -/* -------------------------------------------------------------------------- */ - -cholmod_dense *cholmod_ones -( - /* ---- input ---- */ - size_t nrow, /* # of rows of matrix */ - size_t ncol, /* # of columns of matrix */ - int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_dense *cholmod_l_ones (size_t, size_t, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_eye: allocate a dense matrix and set it to the identity matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_dense *cholmod_eye -( - /* ---- input ---- */ - size_t nrow, /* # of rows of matrix */ - size_t ncol, /* # of columns of matrix */ - int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_dense *cholmod_l_eye (size_t, size_t, int, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_free_dense: free a dense matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_free_dense -( - /* ---- in/out --- */ - cholmod_dense **X, /* dense matrix to deallocate, NULL on output */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_free_dense (cholmod_dense **, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_sparse_to_dense: create a dense matrix copy of a sparse matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_dense *cholmod_sparse_to_dense -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to copy */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_dense *cholmod_l_sparse_to_dense (cholmod_sparse *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_dense_to_sparse: create a sparse matrix copy of a dense matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_dense_to_sparse -( - /* ---- input ---- */ - cholmod_dense *X, /* matrix to copy */ - int values, /* TRUE if values to be copied, FALSE otherwise */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_copy_dense: create a copy of a dense matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_dense *cholmod_copy_dense -( - /* ---- input ---- */ - cholmod_dense *X, /* matrix to copy */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_dense *cholmod_l_copy_dense (cholmod_dense *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_copy_dense2: copy a dense matrix (pre-allocated) */ -/* -------------------------------------------------------------------------- */ - -int cholmod_copy_dense2 -( - /* ---- input ---- */ - cholmod_dense *X, /* matrix to copy */ - /* ---- output --- */ - cholmod_dense *Y, /* copy of matrix X */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_copy_dense2 (cholmod_dense *, cholmod_dense *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_dense_xtype: change the xtype of a dense matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_dense_xtype -( - /* ---- input ---- */ - int to_xtype, /* requested xtype (real, complex,or zomplex) */ - /* ---- in/out --- */ - cholmod_dense *X, /* dense matrix to change */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_dense_xtype (int, cholmod_dense *, cholmod_common *) ; - - -/* ========================================================================== */ -/* === Core/cholmod_triplet ================================================= */ -/* ========================================================================== */ - -/* A sparse matrix stored in triplet form. */ - -typedef struct cholmod_triplet_struct -{ - size_t nrow ; /* the matrix is nrow-by-ncol */ - size_t ncol ; - size_t nzmax ; /* maximum number of entries in the matrix */ - size_t nnz ; /* number of nonzeros in the matrix */ - - void *i ; /* i [0..nzmax-1], the row indices */ - void *j ; /* j [0..nzmax-1], the column indices */ - void *x ; /* size nzmax or 2*nzmax, if present */ - void *z ; /* size nzmax, if present */ - - int stype ; /* Describes what parts of the matrix are considered: - * - * 0: matrix is "unsymmetric": use both upper and lower triangular parts - * (the matrix may actually be symmetric in pattern and value, but - * both parts are explicitly stored and used). May be square or - * rectangular. - * >0: matrix is square and symmetric. Entries in the lower triangular - * part are transposed and added to the upper triangular part when - * the matrix is converted to cholmod_sparse form. - * <0: matrix is square and symmetric. Entries in the upper triangular - * part are transposed and added to the lower triangular part when - * the matrix is converted to cholmod_sparse form. - * - * Note that stype>0 and stype<0 are different for cholmod_sparse and - * cholmod_triplet. The reason is simple. You can permute a symmetric - * triplet matrix by simply replacing a row and column index with their - * new row and column indices, via an inverse permutation. Suppose - * P = L->Perm is your permutation, and Pinv is an array of size n. - * Suppose a symmetric matrix A is represent by a triplet matrix T, with - * entries only in the upper triangular part. Then the following code: - * - * Ti = T->i ; - * Tj = T->j ; - * for (k = 0 ; k < n ; k++) Pinv [P [k]] = k ; - * for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ; - * for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ; - * - * creates the triplet form of C=P*A*P'. However, if T initially - * contains just the upper triangular entries (T->stype = 1), after - * permutation it has entries in both the upper and lower triangular - * parts. These entries should be transposed when constructing the - * cholmod_sparse form of A, which is what cholmod_triplet_to_sparse - * does. Thus: - * - * C = cholmod_triplet_to_sparse (T, 0, &Common) ; - * - * will return the matrix C = P*A*P'. - * - * Since the triplet matrix T is so simple to generate, it's quite easy - * to remove entries that you do not want, prior to converting T to the - * cholmod_sparse form. So if you include these entries in T, CHOLMOD - * assumes that there must be a reason (such as the one above). Thus, - * no entry in a triplet matrix is ever ignored. - */ - - int itype ; /* CHOLMOD_LONG: i and j are UF_long. Otherwise int. */ - int xtype ; /* pattern, real, complex, or zomplex */ - int dtype ; /* x and z are double or float */ - -} cholmod_triplet ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_allocate_triplet: allocate a triplet matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_triplet *cholmod_allocate_triplet -( - /* ---- input ---- */ - size_t nrow, /* # of rows of T */ - size_t ncol, /* # of columns of T */ - size_t nzmax, /* max # of nonzeros of T */ - int stype, /* stype of T */ - int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_triplet *cholmod_l_allocate_triplet (size_t, size_t, size_t, int, int, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_free_triplet: free a triplet matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_free_triplet -( - /* ---- in/out --- */ - cholmod_triplet **T, /* triplet matrix to deallocate, NULL on output */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_free_triplet (cholmod_triplet **, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_reallocate_triplet: change the # of entries in a triplet matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_reallocate_triplet -( - /* ---- input ---- */ - size_t nznew, /* new # of entries in T */ - /* ---- in/out --- */ - cholmod_triplet *T, /* triplet matrix to modify */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_reallocate_triplet (size_t, cholmod_triplet *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_sparse_to_triplet: create a triplet matrix copy of a sparse matrix*/ -/* -------------------------------------------------------------------------- */ - -cholmod_triplet *cholmod_sparse_to_triplet -( - /* ---- input ---- */ - cholmod_sparse *A, /* matrix to copy */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_triplet *cholmod_l_sparse_to_triplet (cholmod_sparse *, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_triplet_to_sparse: create a sparse matrix copy of a triplet matrix*/ -/* -------------------------------------------------------------------------- */ - -cholmod_sparse *cholmod_triplet_to_sparse -( - /* ---- input ---- */ - cholmod_triplet *T, /* matrix to copy */ - size_t nzmax, /* allocate at least this much space in output matrix */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_sparse *cholmod_l_triplet_to_sparse (cholmod_triplet *, size_t, - cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_copy_triplet: create a copy of a triplet matrix */ -/* -------------------------------------------------------------------------- */ - -cholmod_triplet *cholmod_copy_triplet -( - /* ---- input ---- */ - cholmod_triplet *T, /* matrix to copy */ - /* --------------- */ - cholmod_common *Common -) ; - -cholmod_triplet *cholmod_l_copy_triplet (cholmod_triplet *, cholmod_common *) ; - -/* -------------------------------------------------------------------------- */ -/* cholmod_triplet_xtype: change the xtype of a triplet matrix */ -/* -------------------------------------------------------------------------- */ - -int cholmod_triplet_xtype -( - /* ---- input ---- */ - int to_xtype, /* requested xtype (pattern, real, complex,or zomplex)*/ - /* ---- in/out --- */ - cholmod_triplet *T, /* triplet matrix to change */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ; - - -/* ========================================================================== */ -/* === Core/cholmod_memory ================================================== */ -/* ========================================================================== */ - -/* The user may make use of these, just like malloc and free. You can even - * malloc an object and safely free it with cholmod_free, and visa versa - * (except that the memory usage statistics will be corrupted). These routines - * do differ from malloc and free. If cholmod_free is given a NULL pointer, - * for example, it does nothing (unlike the ANSI free). cholmod_realloc does - * not return NULL if given a non-NULL pointer and a nonzero size, even if it - * fails (it returns the original pointer and sets an error code in - * Common->status instead). - * - * CHOLMOD keeps track of the amount of memory it has allocated, and so the - * cholmod_free routine also takes the size of the object being freed. This - * is only used for statistics. If you, the user of CHOLMOD, pass the wrong - * size, the only consequence is that the memory usage statistics will be - * corrupted. - */ - -void *cholmod_malloc /* returns pointer to the newly malloc'd block */ -( - /* ---- input ---- */ - size_t n, /* number of items */ - size_t size, /* size of each item */ - /* --------------- */ - cholmod_common *Common -) ; - -void *cholmod_l_malloc (size_t, size_t, cholmod_common *) ; - -void *cholmod_calloc /* returns pointer to the newly calloc'd block */ -( - /* ---- input ---- */ - size_t n, /* number of items */ - size_t size, /* size of each item */ - /* --------------- */ - cholmod_common *Common -) ; - -void *cholmod_l_calloc (size_t, size_t, cholmod_common *) ; - -void *cholmod_free /* always returns NULL */ -( - /* ---- input ---- */ - size_t n, /* number of items */ - size_t size, /* size of each item */ - /* ---- in/out --- */ - void *p, /* block of memory to free */ - /* --------------- */ - cholmod_common *Common -) ; - -void *cholmod_l_free (size_t, size_t, void *, cholmod_common *) ; - -void *cholmod_realloc /* returns pointer to reallocated block */ -( - /* ---- input ---- */ - size_t nnew, /* requested # of items in reallocated block */ - size_t size, /* size of each item */ - /* ---- in/out --- */ - void *p, /* block of memory to realloc */ - size_t *n, /* current size on input, nnew on output if successful*/ - /* --------------- */ - cholmod_common *Common -) ; - -void *cholmod_l_realloc (size_t, size_t, void *, size_t *, cholmod_common *) ; - -int cholmod_realloc_multiple -( - /* ---- input ---- */ - size_t nnew, /* requested # of items in reallocated blocks */ - int nint, /* number of int/UF_long blocks */ - int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ - /* ---- in/out --- */ - void **I, /* int or UF_long block */ - void **J, /* int or UF_long block */ - void **X, /* complex, double, or float block */ - void **Z, /* zomplex case only: double or float block */ - size_t *n, /* current size of the I,J,X,Z blocks on input, - * nnew on output if successful */ - /* --------------- */ - cholmod_common *Common -) ; - -int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **, - void **, size_t *, cholmod_common *) ; - -/* ========================================================================== */ -/* === symmetry types ======================================================= */ -/* ========================================================================== */ - -#define CHOLMOD_MM_RECTANGULAR 1 -#define CHOLMOD_MM_UNSYMMETRIC 2 -#define CHOLMOD_MM_SYMMETRIC 3 -#define CHOLMOD_MM_HERMITIAN 4 -#define CHOLMOD_MM_SKEW_SYMMETRIC 5 -#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 -#define CHOLMOD_MM_HERMITIAN_POSDIAG 7 - -/* ========================================================================== */ -/* === Numerical relop macros =============================================== */ -/* ========================================================================== */ - -/* These macros correctly handle the NaN case. - * - * CHOLMOD_IS_NAN(x): - * True if x is NaN. False otherwise. The commonly-existing isnan(x) - * function could be used, but it's not in Kernighan & Ritchie 2nd edition - * (ANSI C89). It may appear in , but I'm not certain about - * portability. The expression x != x is true if and only if x is NaN, - * according to the IEEE 754 floating-point standard. - * - * CHOLMOD_IS_ZERO(x): - * True if x is zero. False if x is nonzero, NaN, or +/- Inf. - * This is (x == 0) if the compiler is IEEE 754 compliant. - * - * CHOLMOD_IS_NONZERO(x): - * True if x is nonzero, NaN, or +/- Inf. False if x zero. - * This is (x != 0) if the compiler is IEEE 754 compliant. - * - * CHOLMOD_IS_LT_ZERO(x): - * True if x is < zero or -Inf. False if x is >= 0, NaN, or +Inf. - * This is (x < 0) if the compiler is IEEE 754 compliant. - * - * CHOLMOD_IS_GT_ZERO(x): - * True if x is > zero or +Inf. False if x is <= 0, NaN, or -Inf. - * This is (x > 0) if the compiler is IEEE 754 compliant. - * - * CHOLMOD_IS_LE_ZERO(x): - * True if x is <= zero or -Inf. False if x is > 0, NaN, or +Inf. - * This is (x <= 0) if the compiler is IEEE 754 compliant. - */ - -#ifdef CHOLMOD_WINDOWS - -/* Yes, this is exceedingly ugly. Blame Microsoft, which hopelessly */ -/* violates the IEEE 754 floating-point standard in a bizarre way. */ -/* If you're using an IEEE 754-compliant compiler, then x != x is true */ -/* iff x is NaN. For Microsoft, (x < x) is true iff x is NaN. */ -/* So either way, this macro safely detects a NaN. */ -#define CHOLMOD_IS_NAN(x) (((x) != (x)) || (((x) < (x)))) -#define CHOLMOD_IS_ZERO(x) (((x) == 0.) && !CHOLMOD_IS_NAN(x)) -#define CHOLMOD_IS_NONZERO(x) (((x) != 0.) || CHOLMOD_IS_NAN(x)) -#define CHOLMOD_IS_LT_ZERO(x) (((x) < 0.) && !CHOLMOD_IS_NAN(x)) -#define CHOLMOD_IS_GT_ZERO(x) (((x) > 0.) && !CHOLMOD_IS_NAN(x)) -#define CHOLMOD_IS_LE_ZERO(x) (((x) <= 0.) && !CHOLMOD_IS_NAN(x)) - -#else - -/* These all work properly, according to the IEEE 754 standard ... except on */ -/* a PC with windows. Works fine in Linux on the same PC... */ -#define CHOLMOD_IS_NAN(x) ((x) != (x)) -#define CHOLMOD_IS_ZERO(x) ((x) == 0.) -#define CHOLMOD_IS_NONZERO(x) ((x) != 0.) -#define CHOLMOD_IS_LT_ZERO(x) ((x) < 0.) -#define CHOLMOD_IS_GT_ZERO(x) ((x) > 0.) -#define CHOLMOD_IS_LE_ZERO(x) ((x) <= 0.) - -#endif - -#endif diff --git a/spqr_mini/cholmod_error.c b/spqr_mini/cholmod_error.c deleted file mode 100644 index 193598c14..000000000 --- a/spqr_mini/cholmod_error.c +++ /dev/null @@ -1,80 +0,0 @@ -/* ========================================================================== */ -/* === Core/cholmod_error =================================================== */ -/* ========================================================================== */ - -/* ----------------------------------------------------------------------------- - * CHOLMOD/Core Module. Copyright (C) 2005-2006, - * Univ. of Florida. Author: Timothy A. Davis - * The CHOLMOD/Core 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 - * -------------------------------------------------------------------------- */ - -/* CHOLMOD error-handling routine. */ - -#include "cholmod_internal.h" -#include "cholmod_core.h" - -/* ========================================================================== */ -/* ==== cholmod_error ======================================================= */ -/* ========================================================================== */ - -/* An error has occurred. Set the status, optionally print an error message, - * and call the user error-handling routine (if it exists). If - * Common->try_catch is TRUE, then CHOLMOD is inside a try/catch block. - * The status is set, but no message is printed and the user error handler - * is not called. This is not (yet) an error, since CHOLMOD may recover. - * - * In the current version, this try/catch mechanism is used internally only in - * cholmod_analyze, which tries multiple ordering methods and picks the best - * one. If one or more ordering method fails, it keeps going. Only one - * ordering needs to succeed for cholmod_analyze to succeed. - */ - -int CHOLMOD(error) -( - /* ---- input ---- */ - int status, /* error status */ - const char *file, /* name of source code file where error occured */ - int line, /* line number in source code file where error occured*/ - const char *message, /* error message */ - /* --------------- */ - cholmod_common *Common -) -{ - RETURN_IF_NULL_COMMON (FALSE) ; - - Common->status = status ; - - if (!(Common->try_catch)) - { - -#ifndef NPRINT - /* print a warning or error message */ - if (Common->print_function != NULL) - { - if (status > 0 && Common->print > 1) - { - (Common->print_function) ("CHOLMOD warning: %s\n", message) ; - fflush (stdout) ; - fflush (stderr) ; - } - else if (Common->print > 0) - { - (Common->print_function) ("CHOLMOD error: %s\n", message) ; - fflush (stdout) ; - fflush (stderr) ; - } - } -#endif - - /* call the user error handler, if it exists */ - if (Common->error_handler != NULL) - { - Common->error_handler (status, file, line, message) ; - } - } - - return (TRUE) ; -} diff --git a/spqr_mini/cholmod_internal.h b/spqr_mini/cholmod_internal.h deleted file mode 100644 index 7edfc2a1c..000000000 --- a/spqr_mini/cholmod_internal.h +++ /dev/null @@ -1,400 +0,0 @@ -/* ========================================================================== */ -/* === Include/cholmod_internal.h =========================================== */ -/* ========================================================================== */ - -/* ----------------------------------------------------------------------------- - * CHOLMOD/Include/cholmod_internal.h. - * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis - * CHOLMOD/Include/cholmod_internal.h 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 - * -------------------------------------------------------------------------- */ - -/* CHOLMOD internal include file. - * - * This file contains internal definitions for CHOLMOD, not meant to be included - * in user code. They define macros that are not prefixed with CHOLMOD_. This - * file can safely #include'd in user code if you want to make use of the - * macros defined here, and don't mind the possible name conflicts with your - * code, however. - * - * Required by all CHOLMOD routines. Not required by any user routine that - * uses CHOLMOMD. Unless debugging is enabled, this file does not require any - * CHOLMOD module (not even the Core module). - * - * If debugging is enabled, all CHOLMOD modules require the Check module. - * Enabling debugging requires that this file be editted. Debugging cannot be - * enabled with a compiler flag. This is because CHOLMOD is exceedingly slow - * when debugging is enabled. Debugging is meant for development of CHOLMOD - * itself, not by users of CHOLMOD. - */ - -#ifndef CHOLMOD_INTERNAL_H -#define CHOLMOD_INTERNAL_H - -/* ========================================================================== */ -/* === large file I/O ======================================================= */ -/* ========================================================================== */ - -/* Definitions for large file I/O must come before any other #includes. If - * this causes problems (may not be portable to all platforms), then compile - * CHOLMOD with -DNLARGEFILE. You must do this for MATLAB 6.5 and earlier, - * for example. */ - -//#include "cholmod_io64.h" - -/* ========================================================================== */ -/* === debugging and basic includes ========================================= */ -/* ========================================================================== */ - -/* turn off debugging */ -#ifndef SPQR_NDEBUG -#define SPQR_NDEBUG -#endif - -/* Uncomment this line to enable debugging. CHOLMOD will be very slow. -#undef SPQR_NDEBUG - */ - -#ifdef MATLAB_MEX_FILE -#include "mex.h" -#endif - -#if !defined(NPRINT) || !defined(SPQR_NDEBUG) -#include -#endif - -#include -#include -#include -#include -#include - -/* ========================================================================== */ -/* === basic definitions ==================================================== */ -/* ========================================================================== */ - -/* Some non-conforming compilers insist on defining TRUE and FALSE. */ -#undef TRUE -#undef FALSE -#define TRUE 1 -#define FALSE 0 -#define BOOLEAN(x) ((x) ? TRUE : FALSE) - -/* NULL should already be defined, but ensure it is here. */ -#ifndef NULL -#define NULL ((void *) 0) -#endif - -/* FLIP is a "negation about -1", and is used to mark an integer i that is - * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY - * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i - * for all integers i. UNFLIP (i) is >= EMPTY. */ -#define EMPTY (-1) -#define FLIP(i) (-(i)-2) -#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i)) - -/* MAX and MIN are not safe to use for NaN's */ -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MAX3(a,b,c) (((a) > (b)) ? (MAX (a,c)) : (MAX (b,c))) -#define MAX4(a,b,c,d) (((a) > (b)) ? (MAX3 (a,c,d)) : (MAX3 (b,c,d))) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define IMPLIES(p,q) (!(p) || (q)) - -/* find the sign: -1 if x < 0, 1 if x > 0, zero otherwise. - * Not safe for NaN's */ -#define SIGN(x) (((x) < 0) ? (-1) : (((x) > 0) ? 1 : 0)) - -/* round up an integer x to a multiple of s */ -#define ROUNDUP(x,s) ((s) * (((x) + ((s) - 1)) / (s))) - -#define ERROR(status,msg) \ - CHOLMOD(error) (status, __FILE__, __LINE__, msg, Common) - -/* Check a pointer and return if null. Set status to invalid, unless the - * status is already "out of memory" */ -#define RETURN_IF_NULL(A,result) \ -{ \ - if ((A) == NULL) \ - { \ - if (Common->status != CHOLMOD_OUT_OF_MEMORY) \ - { \ - ERROR (CHOLMOD_INVALID, "argument missing") ; \ - } \ - return (result) ; \ - } \ -} - -/* Return if Common is NULL or invalid */ -#define RETURN_IF_NULL_COMMON(result) \ -{ \ - if (Common == NULL) \ - { \ - return (result) ; \ - } \ - if (Common->itype != ITYPE || Common->dtype != DTYPE) \ - { \ - Common->status = CHOLMOD_INVALID ; \ - return (result) ; \ - } \ -} - -#define IS_NAN(x) CHOLMOD_IS_NAN(x) -#define IS_ZERO(x) CHOLMOD_IS_ZERO(x) -#define IS_NONZERO(x) CHOLMOD_IS_NONZERO(x) -#define IS_LT_ZERO(x) CHOLMOD_IS_LT_ZERO(x) -#define IS_GT_ZERO(x) CHOLMOD_IS_GT_ZERO(x) -#define IS_LE_ZERO(x) CHOLMOD_IS_LE_ZERO(x) - -/* 1e308 is a huge number that doesn't take many characters to print in a - * file, in CHOLMOD/Check/cholmod_read and _write. Numbers larger than this - * are interpretted as Inf, since sscanf doesn't read in Inf's properly. - * This assumes IEEE double precision arithmetic. DBL_MAX would be a little - * better, except that it takes too many digits to print in a file. */ -#define HUGE_DOUBLE 1e308 - -/* ========================================================================== */ -/* === int/UF_long and double/float definitions ============================= */ -/* ========================================================================== */ - -/* CHOLMOD is designed for 3 types of integer variables: - * - * (1) all integers are int - * (2) most integers are int, some are UF_long - * (3) all integers are UF_long - * - * and two kinds of floating-point values: - * - * (1) double - * (2) float - * - * the complex types (ANSI-compatible complex, and MATLAB-compatable zomplex) - * are based on the double or float type, and are not selected here. They - * are typically selected via template routines. - * - * This gives 6 different modes in which CHOLMOD can be compiled (only the - * first two are currently supported): - * - * DINT double, int prefix: cholmod_ - * DLONG double, UF_long prefix: cholmod_l_ - * DMIX double, mixed int/UF_long prefix: cholmod_m_ - * SINT float, int prefix: cholmod_si_ - * SLONG float, UF_long prefix: cholmod_sl_ - * SMIX float, mixed int/log prefix: cholmod_sm_ - * - * These are selected with compile time flags (-DDLONG, for example). If no - * flag is selected, the default is DINT. - * - * All six versions use the same include files. The user-visible include files - * are completely independent of which int/UF_long/double/float version is being - * used. The integer / real types in all data structures (sparse, triplet, - * dense, common, and triplet) are defined at run-time, not compile-time, so - * there is only one "cholmod_sparse" data type. Void pointers are used inside - * that data structure to point to arrays of the proper type. Each data - * structure has an itype and dtype field which determines the kind of basic - * types used. These are defined in Include/cholmod_core.h. - * - * FUTURE WORK: support all six types (float, and mixed int/UF_long) - * - * UF_long is normally defined as long. However, for WIN64 it is __int64. - * It can also be redefined for other platforms, by modifying UFconfig.h. - */ - -#include "UFconfig.h" - -/* -------------------------------------------------------------------------- */ -/* Size_max: the largest value of size_t */ -/* -------------------------------------------------------------------------- */ - -#define Size_max ((size_t) (-1)) - -/* routines for doing arithmetic on size_t, and checking for overflow */ -size_t cholmod_add_size_t (size_t a, size_t b, int *ok) ; -size_t cholmod_mult_size_t (size_t a, size_t k, int *ok) ; -size_t cholmod_l_add_size_t (size_t a, size_t b, int *ok) ; -size_t cholmod_l_mult_size_t (size_t a, size_t k, int *ok) ; - -/* -------------------------------------------------------------------------- */ -/* double (also complex double), UF_long */ -/* -------------------------------------------------------------------------- */ - -#ifdef DLONG -#define Real double -#define Int UF_long -#define Int_max UF_long_max -#define CHOLMOD(name) cholmod_l_ ## name -#define LONG -#define DOUBLE -#define ITYPE CHOLMOD_LONG -#define DTYPE CHOLMOD_DOUBLE -#define ID UF_long_id - -/* -------------------------------------------------------------------------- */ -/* double, int/UF_long */ -/* -------------------------------------------------------------------------- */ - -#elif defined (DMIX) -#error "mixed int/UF_long not yet supported" - -/* -------------------------------------------------------------------------- */ -/* single, int */ -/* -------------------------------------------------------------------------- */ - -#elif defined (SINT) -#error "single-precision not yet supported" - -/* -------------------------------------------------------------------------- */ -/* single, UF_long */ -/* -------------------------------------------------------------------------- */ - -#elif defined (SLONG) -#error "single-precision not yet supported" - -/* -------------------------------------------------------------------------- */ -/* single, int/UF_long */ -/* -------------------------------------------------------------------------- */ - -#elif defined (SMIX) -#error "single-precision not yet supported" - -/* -------------------------------------------------------------------------- */ -/* double (also complex double), int: this is the default */ -/* -------------------------------------------------------------------------- */ - -#else - -#ifndef DINT -#define DINT -#endif -#define INT -#define DOUBLE - -#define Real double -#define Int int -#define Int_max INT_MAX -#define CHOLMOD(name) cholmod_ ## name -#define ITYPE CHOLMOD_INT -#define DTYPE CHOLMOD_DOUBLE -#define ID "%d" - -#endif - - -/* ========================================================================== */ -/* === real/complex arithmetic ============================================== */ -/* ========================================================================== */ - -//#include "cholmod_complexity.h" - -/* ========================================================================== */ -/* === Architecture and BLAS ================================================ */ -/* ========================================================================== */ - -#define BLAS_OK Common->blas_ok -#include "cholmod_blas.h" - -/* ========================================================================== */ -/* === debugging definitions ================================================ */ -/* ========================================================================== */ - -#ifndef SPQR_NDEBUG - -#include -#include "cholmod.h" - -/* The cholmod_dump routines are in the Check module. No CHOLMOD routine - * calls the cholmod_check_* or cholmod_print_* routines in the Check module, - * since they use Common workspace that may already be in use. Instead, they - * use the cholmod_dump_* routines defined there, which allocate their own - * workspace if they need it. */ - -#ifndef EXTERN -#define EXTERN extern -#endif - -/* double, int */ -EXTERN int cholmod_dump ; -EXTERN int cholmod_dump_malloc ; -UF_long cholmod_dump_sparse (cholmod_sparse *, const char *, cholmod_common *); -int cholmod_dump_factor (cholmod_factor *, const char *, cholmod_common *) ; -int cholmod_dump_triplet (cholmod_triplet *, const char *, cholmod_common *) ; -int cholmod_dump_dense (cholmod_dense *, const char *, cholmod_common *) ; -int cholmod_dump_subset (int *, size_t, size_t, const char *, - cholmod_common *) ; -int cholmod_dump_perm (int *, size_t, size_t, const char *, cholmod_common *) ; -int cholmod_dump_parent (int *, size_t, const char *, cholmod_common *) ; -void cholmod_dump_init (const char *, cholmod_common *) ; -int cholmod_dump_mem (const char *, UF_long, cholmod_common *) ; -void cholmod_dump_real (const char *, Real *, UF_long, UF_long, int, int, - cholmod_common *) ; -void cholmod_dump_super (UF_long, int *, int *, int *, int *, double *, int, - cholmod_common *) ; -int cholmod_dump_partition (UF_long, int *, int *, int *, int *, UF_long, - cholmod_common *) ; -int cholmod_dump_work(int, int, UF_long, cholmod_common *) ; - -/* double, UF_long */ -EXTERN int cholmod_l_dump ; -EXTERN int cholmod_l_dump_malloc ; -UF_long cholmod_l_dump_sparse (cholmod_sparse *, const char *, - cholmod_common *) ; -int cholmod_l_dump_factor (cholmod_factor *, const char *, cholmod_common *) ; -int cholmod_l_dump_triplet (cholmod_triplet *, const char *, cholmod_common *); -int cholmod_l_dump_dense (cholmod_dense *, const char *, cholmod_common *) ; -int cholmod_l_dump_subset (UF_long *, size_t, size_t, const char *, - cholmod_common *) ; -int cholmod_l_dump_perm (UF_long *, size_t, size_t, const char *, - cholmod_common *) ; -int cholmod_l_dump_parent (UF_long *, size_t, const char *, cholmod_common *) ; -void cholmod_l_dump_init (const char *, cholmod_common *) ; -int cholmod_l_dump_mem (const char *, UF_long, cholmod_common *) ; -void cholmod_l_dump_real (const char *, Real *, UF_long, UF_long, int, int, - cholmod_common *) ; -void cholmod_l_dump_super (UF_long, UF_long *, UF_long *, UF_long *, UF_long *, - double *, int, cholmod_common *) ; -int cholmod_l_dump_partition (UF_long, UF_long *, UF_long *, UF_long *, - UF_long *, UF_long, cholmod_common *) ; -int cholmod_l_dump_work(int, int, UF_long, cholmod_common *) ; - -#define DEBUG_INIT(s,Common) { CHOLMOD(dump_init)(s, Common) ; } -#define ASSERT(expression) (assert (expression)) - -#define PRK(k,params) \ -{ \ - if (CHOLMOD(dump) >= (k) && Common->print_function != NULL) \ - { \ - (Common->print_function) params ; \ - } \ -} - -#define PRINT0(params) PRK (0, params) -#define PRINT1(params) PRK (1, params) -#define PRINT2(params) PRK (2, params) -#define PRINT3(params) PRK (3, params) - -#define PRINTM(params) \ -{ \ - if (CHOLMOD(dump_malloc) > 0) \ - { \ - printf params ; \ - } \ -} - -#define DEBUG(statement) statement - -#else - -/* Debugging disabled (the normal case) */ -#define PRK(k,params) -#define DEBUG_INIT(s,Common) -#define PRINT0(params) -#define PRINT1(params) -#define PRINT2(params) -#define PRINT3(params) -#define PRINTM(params) -#define ASSERT(expression) -#define DEBUG(statement) -#endif - -#endif diff --git a/spqr_mini/cholmod_memory.c b/spqr_mini/cholmod_memory.c deleted file mode 100644 index 92f9f8ef9..000000000 --- a/spqr_mini/cholmod_memory.c +++ /dev/null @@ -1,563 +0,0 @@ -/* ========================================================================== */ -/* === Core/cholmod_memory ================================================== */ -/* ========================================================================== */ - -/* ----------------------------------------------------------------------------- - * CHOLMOD/Core Module. Copyright (C) 2005-2006, - * Univ. of Florida. Author: Timothy A. Davis - * The CHOLMOD/Core 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 - * -------------------------------------------------------------------------- */ - -/* Core memory management routines: - * - * Primary routines: - * ----------------- - * cholmod_malloc malloc wrapper - * cholmod_free free wrapper - * - * Secondary routines: - * ------------------- - * cholmod_calloc calloc wrapper - * cholmod_realloc realloc wrapper - * cholmod_realloc_multiple realloc wrapper for multiple objects - * - * The user may make use of these, just like malloc and free. You can even - * malloc an object and safely free it with cholmod_free, and visa versa - * (except that the memory usage statistics will be corrupted). These routines - * do differ from malloc and free. If cholmod_free is given a NULL pointer, - * for example, it does nothing (unlike the ANSI free). cholmod_realloc does - * not return NULL if given a non-NULL pointer and a nonzero size, even if it - * fails (it sets an error code in Common->status instead). - * - * CHOLMOD keeps track of the amount of memory it has allocated, and so the - * cholmod_free routine includes as a parameter the size of the object being - * freed. This is only used for memory usage statistics, which are very useful - * in finding memory leaks in your program. If you, the user of CHOLMOD, pass - * the wrong size, the only consequence is that the memory usage statistics - * will be invalid. This will causes assertions to fail if CHOLMOD is - * compiled with debugging enabled, but otherwise it will cause no errors. - * - * The cholmod_free_* routines for each CHOLMOD object keep track of the size - * of the blocks they free, so they do not require you to pass their sizes - * as a parameter. - * - * If a block of size zero is requested, these routines allocate a block of - * size one instead. - */ - -#include "cholmod_internal.h" -#include "cholmod_core.h" - -/* ========================================================================== */ -/* === cholmod_add_size_t =================================================== */ -/* ========================================================================== */ - -/* Safely compute a+b, and check for integer overflow. If overflow occurs, - * return 0 and set OK to FALSE. Also return 0 if OK is FALSE on input. */ - -size_t CHOLMOD(add_size_t) (size_t a, size_t b, int *ok) -{ - size_t s = a + b ; - (*ok) = (*ok) && (s >= a) ; - return ((*ok) ? s : 0) ; -} - -/* ========================================================================== */ -/* === cholmod_mult_size_t ================================================== */ -/* ========================================================================== */ - -/* Safely compute a*k, where k should be small, and check for integer overflow. - * If overflow occurs, return 0 and set OK to FALSE. Also return 0 if OK is - * FALSE on input. */ - -size_t CHOLMOD(mult_size_t) (size_t a, size_t k, int *ok) -{ - size_t p = 0, s ; - while (*ok) - { - if (k % 2) - { - p = p + a ; - (*ok) = (*ok) && (p >= a) ; - } - k = k / 2 ; - if (!k) return (p) ; - s = a + a ; - (*ok) = (*ok) && (s >= a) ; - a = s ; - } - return (0) ; -} - - -/* ========================================================================== */ -/* === cholmod_malloc ======================================================= */ -/* ========================================================================== */ - -/* Wrapper around malloc routine. Allocates space of size MAX(1,n)*size, where - * size is normally a sizeof (...). - * - * This routine, cholmod_calloc, and cholmod_realloc do not set Common->status - * to CHOLMOD_OK on success, so that a sequence of cholmod_malloc's, _calloc's, - * or _realloc's can be used. If any of them fails, the Common->status will - * hold the most recent error status. - * - * Usage, for a pointer to int: - * - * p = cholmod_malloc (n, sizeof (int), Common) - * - * Uses a pointer to the malloc routine (or its equivalent) defined in Common. - */ - -void *CHOLMOD(malloc) /* returns pointer to the newly malloc'd block */ -( - /* ---- input ---- */ - size_t n, /* number of items */ - size_t size, /* size of each item */ - /* --------------- */ - cholmod_common *Common -) -{ - void *p ; - size_t s ; - int ok = TRUE ; - - RETURN_IF_NULL_COMMON (NULL) ; - if (size == 0) - { - ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; - p = NULL ; - } - else if (n >= (Size_max / size) || n >= Int_max) - { - /* object is too big to allocate without causing integer overflow */ - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - p = NULL ; - } - else - { - /* call malloc, or its equivalent */ - s = CHOLMOD(mult_size_t) (MAX (1,n), size, &ok) ; - p = ok ? ((Common->malloc_memory) (s)) : NULL ; - if (p == NULL) - { - /* failure: out of memory */ - ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; - } - else - { - /* success: increment the count of objects allocated */ - Common->malloc_count++ ; - Common->memory_inuse += (n * size) ; - Common->memory_usage = - MAX (Common->memory_usage, Common->memory_inuse) ; - PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n", - p, n*size, Common->malloc_count, Common->memory_inuse)) ; - } - } - return (p) ; -} - - -/* ========================================================================== */ -/* === cholmod_free ========================================================= */ -/* ========================================================================== */ - -/* Wrapper around free routine. Returns NULL, which can be assigned to the - * pointer being freed, as in: - * - * p = cholmod_free (n, sizeof (int), p, Common) ; - * - * In CHOLMOD, the syntax: - * - * cholmod_free (n, sizeof (int), p, Common) ; - * - * is used if p is a local pointer and the routine is returning shortly. - * Uses a pointer to the free routine (or its equivalent) defined in Common. - * Nothing is freed if the pointer is NULL. - */ - -void *CHOLMOD(free) /* always returns NULL */ -( - /* ---- input ---- */ - size_t n, /* number of items */ - size_t size, /* size of each item */ - /* ---- in/out --- */ - void *p, /* block of memory to free */ - /* --------------- */ - cholmod_common *Common -) -{ - RETURN_IF_NULL_COMMON (NULL) ; - if (p != NULL) - { - /* only free the object if the pointer is not NULL */ - /* call free, or its equivalent */ - (Common->free_memory) (p) ; - Common->malloc_count-- ; - Common->memory_inuse -= (n * size) ; - PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n", - p, n*size, Common->malloc_count, Common->memory_inuse)) ; - /* This assertion will fail if the user calls cholmod_malloc and - * cholmod_free with mismatched memory sizes. It shouldn't fail - * otherwise. */ - ASSERT (IMPLIES (Common->malloc_count == 0, Common->memory_inuse == 0)); - } - /* return NULL, and the caller should assign this to p. This avoids - * freeing the same pointer twice. */ - return (NULL) ; -} - - -/* ========================================================================== */ -/* === cholmod_calloc ======================================================= */ -/* ========================================================================== */ - -/* Wrapper around calloc routine. - * - * Uses a pointer to the calloc routine (or its equivalent) defined in Common. - * This routine is identical to malloc, except that it zeros the newly allocated - * block to zero. - */ - -void *CHOLMOD(calloc) /* returns pointer to the newly calloc'd block */ -( - /* ---- input ---- */ - size_t n, /* number of items */ - size_t size, /* size of each item */ - /* --------------- */ - cholmod_common *Common -) -{ - void *p ; - - RETURN_IF_NULL_COMMON (NULL) ; - if (size == 0) - { - ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; - p = NULL ; - } - else if (n >= (Size_max / size) || n >= Int_max) - { - /* object is too big to allocate without causing integer overflow */ - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - p = NULL ; - } - else - { - /* call calloc, or its equivalent */ - p = (Common->calloc_memory) (MAX (1,n), size) ; - if (p == NULL) - { - /* failure: out of memory */ - ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; - } - else - { - /* success: increment the count of objects allocated */ - Common->malloc_count++ ; - Common->memory_inuse += (n * size) ; - Common->memory_usage = - MAX (Common->memory_usage, Common->memory_inuse) ; - PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n", - p, n*size, Common->malloc_count, Common->memory_inuse)) ; - } - } - return (p) ; -} - - -/* ========================================================================== */ -/* === cholmod_realloc ====================================================== */ -/* ========================================================================== */ - -/* Wrapper around realloc routine. Given a pointer p to a block of size - * (*n)*size memory, it changes the size of the block pointed to by p to be - * MAX(1,nnew)*size in size. It may return a pointer different than p. This - * should be used as (for a pointer to int): - * - * p = cholmod_realloc (nnew, sizeof (int), p, *n, Common) ; - * - * If p is NULL, this is the same as p = cholmod_malloc (...). - * A size of nnew=0 is treated as nnew=1. - * - * If the realloc fails, p is returned unchanged and Common->status is set - * to CHOLMOD_OUT_OF_MEMORY. If successful, Common->status is not modified, - * and p is returned (possibly changed) and pointing to a large block of memory. - * - * Uses a pointer to the realloc routine (or its equivalent) defined in Common. - */ - -void *CHOLMOD(realloc) /* returns pointer to reallocated block */ -( - /* ---- input ---- */ - size_t nnew, /* requested # of items in reallocated block */ - size_t size, /* size of each item */ - /* ---- in/out --- */ - void *p, /* block of memory to realloc */ - size_t *n, /* current size on input, nnew on output if successful*/ - /* --------------- */ - cholmod_common *Common -) -{ - size_t nold = (*n) ; - void *pnew ; - size_t s ; - int ok = TRUE ; - - RETURN_IF_NULL_COMMON (NULL) ; - if (size == 0) - { - ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; - p = NULL ; - } - else if (p == NULL) - { - /* A fresh object is being allocated. */ - PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ; - p = CHOLMOD(malloc) (nnew, size, Common) ; - *n = (p == NULL) ? 0 : nnew ; - } - else if (nold == nnew) - { - /* Nothing to do. Do not change p or n. */ - PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ; - } - else if (nnew >= (Size_max / size) || nnew >= Int_max) - { - /* failure: nnew is too big. Do not change p or n. */ - ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; - } - else - { - /* The object exists, and is changing to some other nonzero size. */ - /* call realloc, or its equivalent */ - PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ; - pnew = NULL ; - - s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ; - pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ; - - if (pnew == NULL) - { - /* Do not change p, since it still points to allocated memory */ - if (nnew <= nold) - { - /* The attempt to reduce the size of the block from n to - * nnew has failed. The current block is not modified, so - * pretend to succeed, but do not change p. Do change - * CHOLMOD's notion of the size of the block, however. */ - *n = nnew ; - PRINTM (("nnew <= nold failed, pretend to succeed\n")) ; - PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n" - "cholmod_malloc %p %d cnt: %d inuse %d\n", - p, nold*size, Common->malloc_count-1, - Common->memory_inuse - nold*size, - p, nnew*size, Common->malloc_count, - Common->memory_inuse + (nnew-nold)*size)) ; - Common->memory_inuse += ((nnew-nold) * size) ; - } - else - { - /* Increasing the size of the block has failed. - * Do not change n. */ - ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; - } - } - else - { - /* success: return revised p and change the size of the block */ - PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n" - "cholmod_malloc %p %d cnt: %d inuse %d\n", - p, nold*size, Common->malloc_count-1, - Common->memory_inuse - nold*size, - pnew, nnew*size, Common->malloc_count, - Common->memory_inuse + (nnew-nold)*size)) ; - p = pnew ; - *n = nnew ; - Common->memory_inuse += ((nnew-nold) * size) ; - } - Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse); - } - - return (p) ; -} - - -/* ========================================================================== */ -/* === cholmod_realloc_multiple ============================================= */ -/* ========================================================================== */ - -/* reallocate multiple blocks of memory, all of the same size (up to two integer - * and two real blocks). Either reallocations all succeed, or all are returned - * in the original size (they are freed if the original size is zero). The nnew - * blocks are of size 1 or more. - */ - -int CHOLMOD(realloc_multiple) -( - /* ---- input ---- */ - size_t nnew, /* requested # of items in reallocated blocks */ - int nint, /* number of int/UF_long blocks */ - int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ - /* ---- in/out --- */ - void **I, /* int or UF_long block */ - void **J, /* int or UF_long block */ - void **X, /* complex or double block */ - void **Z, /* zomplex case only: double block */ - size_t *nold_p, /* current size of the I,J,X,Z blocks on input, - * nnew on output if successful */ - /* --------------- */ - cholmod_common *Common -) -{ - double *xx, *zz ; - size_t i, j, x, z, nold ; - - RETURN_IF_NULL_COMMON (FALSE) ; - - if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX) - { - ERROR (CHOLMOD_INVALID, "invalid xtype") ; - return (FALSE) ; - } - - nold = *nold_p ; - - if (nint < 1 && xtype == CHOLMOD_PATTERN) - { - /* nothing to do */ - return (TRUE) ; - } - - i = nold ; - j = nold ; - x = nold ; - z = nold ; - - if (nint > 0) - { - *I = CHOLMOD(realloc) (nnew, sizeof (Int), *I, &i, Common) ; - } - if (nint > 1) - { - *J = CHOLMOD(realloc) (nnew, sizeof (Int), *J, &j, Common) ; - } - - switch (xtype) - { - case CHOLMOD_REAL: - *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ; - break ; - - case CHOLMOD_COMPLEX: - *X = CHOLMOD(realloc) (nnew, 2*sizeof (double), *X, &x, Common) ; - break ; - - case CHOLMOD_ZOMPLEX: - *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ; - *Z = CHOLMOD(realloc) (nnew, sizeof (double), *Z, &z, Common) ; - break ; - } - - if (Common->status < CHOLMOD_OK) - { - /* one or more realloc's failed. Resize all back down to nold. */ - - if (nold == 0) - { - - if (nint > 0) - { - *I = CHOLMOD(free) (i, sizeof (Int), *I, Common) ; - } - if (nint > 1) - { - *J = CHOLMOD(free) (j, sizeof (Int), *J, Common) ; - } - - switch (xtype) - { - case CHOLMOD_REAL: - *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ; - break ; - - case CHOLMOD_COMPLEX: - *X = CHOLMOD(free) (x, 2*sizeof (double), *X, Common) ; - break ; - - case CHOLMOD_ZOMPLEX: - *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ; - *Z = CHOLMOD(free) (x, sizeof (double), *Z, Common) ; - break ; - } - - } - else - { - if (nint > 0) - { - *I = CHOLMOD(realloc) (nold, sizeof (Int), *I, &i, Common) ; - } - if (nint > 1) - { - *J = CHOLMOD(realloc) (nold, sizeof (Int), *J, &j, Common) ; - } - - switch (xtype) - { - case CHOLMOD_REAL: - *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x, - Common) ; - break ; - - case CHOLMOD_COMPLEX: - *X = CHOLMOD(realloc) (nold, 2*sizeof (double), *X, &x, - Common) ; - break ; - - case CHOLMOD_ZOMPLEX: - *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x, - Common) ; - *Z = CHOLMOD(realloc) (nold, sizeof (double), *Z, &z, - Common) ; - break ; - } - - } - - return (FALSE) ; - } - - if (nold == 0) - { - /* New space was allocated. Clear the first entry so that valgrind - * doesn't complain about its access in change_complexity - * (Core/cholmod_complex.c). */ - xx = *X ; - zz = *Z ; - switch (xtype) - { - case CHOLMOD_REAL: - xx [0] = 0 ; - break ; - - case CHOLMOD_COMPLEX: - xx [0] = 0 ; - xx [1] = 0 ; - break ; - - case CHOLMOD_ZOMPLEX: - xx [0] = 0 ; - zz [0] = 0 ; - break ; - } - } - - /* all realloc's succeeded, change size to reflect realloc'ed size. */ - *nold_p = nnew ; - return (TRUE) ; -} diff --git a/spqr_mini/spqr_front.cpp b/spqr_mini/spqr_front.cpp deleted file mode 100644 index 63da97fe0..000000000 --- a/spqr_mini/spqr_front.cpp +++ /dev/null @@ -1,654 +0,0 @@ -// ============================================================================= -// === spqr_front ============================================================== -// ============================================================================= - -/* Given an m-by-n frontal matrix, use Householder reflections to reduce it - to upper trapezoidal form. Columns 0:npiv-1 are checked against tol. - - 0 # x x x x x x - 1 # x x x x x x - 2 # x x x x x x - 3 # x x x x x x - 4 - # x x x x x <- Stair [0] = 4 - 5 # x x x x x - 6 # x x x x x - 7 # x x x x x - 8 - # x x x x <- Stair [1] = 8 - 9 # x x x x - 10 # x x x x - 11 # x x x x - 12 - # x x x <- Stair [2] = 12 - 13 # x x x - 14 - # x x <- Stair [3] = 14 - 15 - # x <- Stair [4] = 15 - 16 - # <- Stair [5] = 16 - - <- Stair [6] = 17 - - Suppose npiv = 3, and no columns fall below tol: - - 0 R r r r r r r - 1 h R r r r r r - 2 h h R r r r r - 3 h h h C c c c - 4 - h h h C c c <- Stair [0] = 4 - 5 h h h h C c - 6 h h h h h C - 7 h h h h h h - 8 - h h h h h <- Stair [1] = 8 - 9 h h h h h - 10 h h h h h - 11 h h h h h - 12 - h h h h <- Stair [2] = 12 - 13 h h h h - 14 - h h h <- Stair [3] = 14 - 15 - h h <- Stair [4] = 15 - 16 - h <- Stair [5] = 16 - - <- Stair [6] = 17 - - where r is an entry in the R block, c is an entry in the C (contribution) - block, and h is an entry in the H block (Householder vectors). Diagonal - entries are capitalized. - - Suppose the 2nd column has a norm <= tol; the result is a "squeezed" R: - - 0 R r r r r r r <- Stair [1] = 0 to denote a dead pivot column - 1 h - R r r r r - 2 h - h C c c c - 3 h - h h C c c - 4 - - h h h C c <- Stair [0] = 4 - 5 - h h h h C - 6 - h h h h h - 7 - h h h h h - 8 - h h h h h - 9 h h h h h - 10 h h h h h - 11 h h h h h - 12 - h h h h <- Stair [2] = 12 - 13 h h h h - 14 - h h h <- Stair [3] = 14 - 15 - h h <- Stair [4] = 15 - 16 - h <- Stair [5] = 16 - - <- Stair [6] = 17 - - where "diagonal" entries are capitalized. The 2nd H vector is missing - (it is H2 = I, identity). The 2nd column of R is not deleted. The - contribution block is always triangular, but the first npiv columns of - the R can become "staggered". Columns npiv to n-1 in the R block are - always the same length. - - If columns are found "dead", the staircase may be updated. Stair[k] is - set to zero if k is dead. Also, Stair[k] is increased, if necessary, to - ensure that R and C reside within the staircase. For example: - - 0 0 0 - 0 0 x - - with npiv = 2 has a Stair = [ 0 1 2 ] on output, to reflect the C block: - - - C c - - - C - - A tol of zero means that any nonzero norm (however small) is accepted; - only exact zero columns are flagged as dead. A negative tol means that - the norms are ignored; a column is never flagged dead. The default tol - is set elsewhere as 20 * (m+1) * eps * max column 2-norm of A. - - LAPACK's dlarf* routines are used to construct and apply the Householder - reflections. The panel size (block size) is provided as an input - parameter, which defines the number of Householder vectors in a panel. - However, when the front is small (or when the remaining part - of a front is small) the block size is increased to include the entire - front. "Small" is defined, below, as fronts with fewer than 5000 entries. - - NOTE: this function does not check its inputs. If the caller runs out of - memory and passes NULL pointers, this function will segfault. -*/ - -#include "spqr_subset.hpp" -#include "iostream" - -#define SMALL 5000 -#define MINCHUNK 4 -#define MINCHUNK_RATIO 4 - -// ============================================================================= -// === spqr_private_house ====================================================== -// ============================================================================= - -// Construct a Householder reflection H = I - tau * v * v' such that H*x is -// reduced to zero except for the first element. Returns X [0] = the first -// entry of H*x, and X [1:n-1] = the Householder vector V [1:n-1], where -// V [0] = 1. If X [1:n-1] is zero, then the H=I (tau = 0) is returned, -// and V [1:n-1] is all zero. In MATLAB (1-based indexing), ignoring the -// rescaling done in dlarfg/zlarfg, this function computes the following: - -/* - function [x, tau] = house (x) - n = length (x) ; - beta = norm (x) ; - if (x (1) > 0) - beta = -beta ; - end - tau = (beta - x (1)) / beta ; - x (2:n) = x (2:n) / (x (1) - beta) ; - x (1) = beta ; -*/ - -// Note that for the complex case, the reflection must be applied as H'*x, -// which requires that tau be conjugated in spqr_private_apply1. -// -// This function performs about 3*n+2 flops - -inline double spqr_private_larfg (Int n, double *X, cholmod_common *cc) -{ - double tau = 0 ; - BLAS_INT N = n, one = 1 ; - if (CHECK_BLAS_INT && !EQ (N,n)) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_DLARFG (&N, X, X + 1, &one, &tau) ; - } - return (tau) ; -} - - -inline Complex spqr_private_larfg (Int n, Complex *X, cholmod_common *cc) -{ - Complex tau = 0 ; - BLAS_INT N = n, one = 1 ; - if (CHECK_BLAS_INT && !EQ (N,n)) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_ZLARFG (&N, X, X + 1, &one, &tau) ; - } - return (tau) ; -} - - -template Entry spqr_private_house // returns tau -( - // inputs, not modified - Int n, - - // input/output - Entry *X, // size n - - cholmod_common *cc -) -{ - return (spqr_private_larfg (n, X, cc)) ; -} - - -// ============================================================================= -// === spqr_private_apply1 ===================================================== -// ============================================================================= - -// Apply a single Householder reflection; C = C - tau * v * v' * C. The -// algorithm used by dlarf is: - -/* - function C = apply1 (C, v, tau) - w = C'*v ; - C = C - tau*v*w' ; -*/ - -// For the complex case, we need to apply H', which requires that tau be -// conjugated. -// -// If applied to a single column, this function performs 2*n-1 flops to -// compute w, and 2*n+1 to apply it to C, for a total of 4*n flops. - -inline void spqr_private_larf (Int m, Int n, double *V, double tau, - double *C, Int ldc, double *W, cholmod_common *cc) -{ - BLAS_INT M = m, N = n, LDC = ldc, one = 1 ; - char left = 'L' ; - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDC,ldc))) - { - cc->blas_ok = FALSE ; - - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_DLARF (&left, &M, &N, V, &one, &tau, C, &LDC, W) ; - } -} - -inline void spqr_private_larf (Int m, Int n, Complex *V, Complex tau, - Complex *C, Int ldc, Complex *W, cholmod_common *cc) -{ - BLAS_INT M = m, N = n, LDC = ldc, one = 1 ; - char left = 'L' ; - Complex conj_tau = spqr_conj (tau) ; - if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDC,ldc))) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_ZLARF (&left, &M, &N, V, &one, &conj_tau, C, &LDC, W) ; - } -} - - -template void spqr_private_apply1 -( - // inputs, not modified - Int m, // C is m-by-n - Int n, - Int ldc, // leading dimension of C - Entry *V, // size m, Householder vector V - Entry tau, // Householder coefficient - - // input/output - Entry *C, // size m-by-n - - // workspace, not defined on input or output - Entry *W, // size n - - cholmod_common *cc -) -{ - Entry vsave ; - if (m <= 0 || n <= 0) - { - return ; // nothing to do - } - vsave = V [0] ; // temporarily restore unit diagonal of V - V [0] = 1 ; - spqr_private_larf (m, n, V, tau, C, ldc, W, cc) ; - V [0] = vsave ; // restore V [0] -} - - -// ============================================================================= -// === spqr_front ============================================================== -// ============================================================================= - -// Factorize a front F into a sequence of Householder vectors H, and an upper -// trapezoidal matrix R. R may be a squeezed upper trapezoidal matrix if any -// of the leading npiv columns are linearly dependent. Returns the row index -// rank that indicates the first entry in C, which is F (rank,npiv), or 0 -// on error. - -template Int spqr_front -( - // input, not modified - Int m, // F is m-by-n with leading dimension m - Int n, - Int npiv, // number of pivot columns - double tol, // a column is flagged as dead if its norm is <= tol - Int ntol, // apply tol only to first ntol pivot columns - Int fchunk, // block size for compact WY Householder reflections, - // treated as 1 if fchunk <= 1 - - // input/output - Entry *F, // frontal matrix F of size m-by-n - Int *Stair, // size n, entries F (Stair[k]:m-1, k) are all zero, - // for each k = 0:n-1, and remain zero on output. - char *Rdead, // size npiv; all zero on input. If k is dead, - // Rdead [k] is set to 1 - - // output, not defined on input - Entry *Tau, // size n, Householder coefficients - - // workspace, undefined on input and output - Entry *W, // size b*n, where b = min (fchunk,n,m) - - // input/output - double *wscale, - double *wssq, - - cholmod_common *cc // for cc->hypotenuse function -) -{ - Entry tau ; - double wk ; - Entry *V ; - Int k, t, g, g1, nv, k1, k2, i, t0, vzeros, mleft, nleft, vsize, minchunk, - rank ; - - // NOTE: inputs are not checked for NULL (except if debugging enabled) - - ASSERT (F != NULL) ; - ASSERT (Stair != NULL) ; - ASSERT (Rdead != NULL) ; - ASSERT (Tau != NULL) ; - ASSERT (W != NULL) ; - ASSERT (m >= 0 && n >= 0) ; - - npiv = MAX (0, npiv) ; // npiv must be between 0 and n - npiv = MIN (n, npiv) ; - - g1 = 0 ; // row index of first queued-up Householder - k1 = 0 ; // pending Householders are in F (g1:t, k1:k2-1) - k2 = 0 ; - V = F ; // Householder vectors start here - g = 0 ; // number of good Householders found - nv = 0 ; // number of Householder reflections queued up - vzeros = 0 ; // number of explicit zeros in queued-up H's - t = 0 ; // staircase of current column - fchunk = MAX (fchunk, 1) ; - minchunk = MAX (MINCHUNK, fchunk/MINCHUNK_RATIO) ; - rank = MIN (m,npiv) ; // F (rank,npiv) is the first entry in C. rank - // is also the number of rows in the R block, - // and the number of good pivot columns found. - - ntol = MIN (ntol, npiv) ; // Note ntol can be negative, which means to - // not use tol at all. - - PR (("Front %ld by %ld with %ld pivots\n", m, n, npiv)) ; - for (k = 0 ; k < n ; k++) - { - - // --------------------------------------------------------------------- - // reduce the kth column of F to eliminate all but "diagonal" F (g,k) - // --------------------------------------------------------------------- - - // get the staircase for the kth column, and operate on the "diagonal" - // F (g,k); eliminate F (g+1:t-1, k) to zero - t0 = t ; // t0 = staircase of column k-1 - t = Stair [k] ; // t = staircase of this column k - - PR (("k %ld g %ld m %ld n %ld npiv %ld\n", k, g, m, n, npiv)) ; - if (g >= m) - { - // F (g,k) is outside the matrix, so we're done. If this happens - // when k < npiv, then there is no contribution block. - PR (("hit the wall, npiv: %ld k %ld rank %ld\n", npiv, k, rank)) ; - for ( ; k < npiv ; k++) - { - Rdead [k] = 1 ; - Stair [k] = 0 ; // remaining pivot columns all dead - Tau [k] = 0 ; - } - for ( ; k < n ; k++) - { - Stair [k] = m ; // non-pivotal columns - Tau [k] = 0 ; - } - ASSERT (nv == 0) ; // there can be no pending updates - return (rank) ; - } - - // if t < g+1, then this column is all zero; fix staircase so that R is - // always inside the staircase. - t = MAX (g+1,t) ; - Stair [k] = t ; - - // --------------------------------------------------------------------- - // If t just grew a lot since the last t, apply H now to all of F - // --------------------------------------------------------------------- - - // vzeros is the number of zero entries in V after including the next - // Householder vector. If it would exceed 50% of the size of V, - // apply the pending Householder reflections now, but only if - // enough vectors have accumulated. - - vzeros += nv * (t - t0) ; - if (nv >= minchunk) - { - vsize = (nv*(nv+1))/2 + nv*(t-g1-nv) ; - if (vzeros > MAX (16, vsize/2)) - { - // apply pending block of Householder reflections - PR (("(1) apply k1 %ld k2 %ld\n", k1, k2)) ; - spqr_larftb ( - 0, // method 0: Left, Transpose - t0-g1, n-k2, nv, m, m, - V, // F (g1:t-1, k1:k1+nv-1) - &Tau [k1], // Tau (k1:k-1) - &F [INDEX (g1,k2,m)], // F (g1:t-1, k2:n-1) - W, cc) ; // size nv*nv + nv*(n-k2) - nv = 0 ; // clear queued-up Householder reflections - vzeros = 0 ; - } - } - - // --------------------------------------------------------------------- - // find a Householder reflection that reduces column k - // --------------------------------------------------------------------- - - tau = spqr_private_house (t-g, &F [INDEX (g,k,m)], cc) ; - - // --------------------------------------------------------------------- - // check to see if the kth column is OK - // --------------------------------------------------------------------- - - if (k < ntol && (wk = spqr_abs (F [INDEX (g,k,m)], cc)) <= tol) - { - // ----------------------------------------------------------------- - // norm (F (g:t-1, k)) is too tiny; the kth pivot column is dead - // ----------------------------------------------------------------- - - // keep track of the 2-norm of w, the dead column 2-norms - if (wk != 0) - { - // see also LAPACK's dnrm2 function - if ((*wscale) == 0) - { - // this is the nonzero first entry in w - (*wssq) = 1 ; - } - if ((*wscale) < wk) - { - double rr = (*wscale) / wk ; - (*wssq) = 1 + (*wssq) * rr * rr ; - (*wscale) = wk ; - } - else - { - double rr = wk / (*wscale) ; - (*wssq) += rr * rr ; - } - } - - // zero out F (g:m-1,k) and flag it as dead - for (i = g ; i < m ; i++) - { - // This is not strictly necessary. On output, entries outside - // the staircase are ignored. - F [INDEX (i,k,m)] = 0 ; - } - Stair [k] = 0 ; - Tau [k] = 0 ; - Rdead [k] = 1 ; - - if (nv > 0) - { - // apply pending block of Householder reflections - PR (("(2) apply k1 %ld k2 %ld\n", k1, k2)) ; - spqr_larftb ( - 0, // method 0: Left, Transpose - t0-g1, n-k2, nv, m, m, - V, // F (g1:t-1, k1:k1+nv-1) - &Tau [k1], // Tau (k1:k-1) - &F [INDEX (g1,k2,m)], // F (g1:t-1, k2:n-1) - W, cc) ; // size nv*nv + nv*(n-k2) - nv = 0 ; // clear queued-up Householder reflections - vzeros = 0 ; - } - - } - else - { - // ----------------------------------------------------------------- - // one more good pivot column found - // ----------------------------------------------------------------- - - Tau [k] = tau ; // save the Householder coefficient - if (nv == 0) - { - // start the queue of pending Householder updates, and define - // the current panel as k1:k2-1 - g1 = g ; // first row of V - k1 = k ; // first column of V - k2 = MIN (n, k+fchunk) ; // k2-1 is last col in panel - V = &F [INDEX (g1,k1,m)] ; // pending V starts here - - // check for switch to unblocked code - mleft = m-g1 ; // number of rows left - nleft = n-k1 ; // number of columns left - if (mleft * (nleft-(fchunk+4)) < SMALL || mleft <= fchunk/2 - || fchunk <= 1) - { - // remaining matrix is small; switch to unblocked code by - // including the rest of the matrix in the panel. Always - // use unblocked code if fchunk <= 1. - k2 = n ; - } - } - nv++ ; // one more pending update; V is F (g1:t-1, k1:k1+nv-1) - - // ----------------------------------------------------------------- - // keep track of "pure" flops, for performance testing only - // ----------------------------------------------------------------- - - // The Householder vector is of length t-g, including the unit - // diagonal, and takes 3*(t-g) flops to compute. It will be - // applied as a block, but compute the "pure" flops by assuming - // that this single Householder vector is computed and then applied - // just by itself to the rest of the frontal matrix (columns - // k+1:n-1, or n-k-1 columns). Applying the Householder reflection - // to just one column takes 4*(t-g) flops. This computation only - // works if TBB is disabled, merely because it uses a global - // variable to keep track of the flop count. If TBB is used, this - // computation may result in a race condition; it is disabled in - // that case. - - FLOP_COUNT ((t-g) * (3 + 4 * (n-k-1))) ; - - // ----------------------------------------------------------------- - // apply the kth Householder reflection to the current panel - // ----------------------------------------------------------------- - - // F (g:t-1, k+1:k2-1) -= v * tau * v' * F (g:t-1, k+1:k2-1), where - // v is stored in F (g:t-1,k). This applies just one reflection - // to the current panel. - PR (("apply 1: k %ld\n", k)) ; - spqr_private_apply1 (t-g, k2-k-1, m, &F [INDEX (g,k,m)], tau, - &F [INDEX (g,k+1,m)], W, cc) ; - - g++ ; // one more pivot found - - // ----------------------------------------------------------------- - // apply the Householder reflections if end of panel reached - // ----------------------------------------------------------------- - - if (k == k2-1 || g == m) // or if last pivot is found - { - // apply pending block of Householder reflections - PR (("(3) apply k1 %ld k2 %ld\n", k1, k2)) ; - spqr_larftb ( - 0, // method 0: Left, Transpose - t-g1, n-k2, nv, m, m, - V, // F (g1:t-1, k1:k1+nv-1) - &Tau [k1], // Tau (k1:k2-1) - &F [INDEX (g1,k2,m)], // F (g1:t-1, k2:n-1) - W, cc) ; // size nv*nv + nv*(n-k2) - nv = 0 ; // clear queued-up Householder reflections - vzeros = 0 ; - } - } - - // --------------------------------------------------------------------- - // determine the rank of the pivot columns - // --------------------------------------------------------------------- - - if (k == npiv-1) - { - // the rank is the number of good columns found in the first - // npiv columns. It is also the number of rows in the R block. - // F (rank,npiv) is first entry in the C block. - rank = g ; - PR (("rank of Front pivcols: %ld\n", rank)) ; - } - } - - if (CHECK_BLAS_INT && !cc->blas_ok) - { - // This cannot occur if the BLAS_INT and the Int are the same integer. - // In that case, CHECK_BLAS_INT is FALSE at compile-time, and the - // compiler will then remove this as dead code. - ERROR (CHOLMOD_INVALID, "problem too large for the BLAS") ; - return (0) ; - } - - return (rank) ; -} - - -// ============================================================================= - -template Int spqr_front -( - // input, not modified - Int m, // F is m-by-n with leading dimension m - Int n, - Int npiv, // number of pivot columns - double tol, // a column is flagged as dead if its norm is <= tol - Int ntol, // apply tol only to first ntol pivot columns - Int fchunk, // block size for compact WY Householder reflections, - // treated as 1 if fchunk <= 1 (in which case the - // unblocked code is used). - - // input/output - double *F, // frontal matrix F of size m-by-n - Int *Stair, // size n, entries F (Stair[k]:m-1, k) are all zero, - // and remain zero on output. - char *Rdead, // size npiv; all zero on input. If k is dead, - // Rdead [k] is set to 1 - - // output, not defined on input - double *Tau, // size n, Householder coefficients - - // workspace, undefined on input and output - double *W, // size b*n, where b = min (fchunk,n,m) - - // input/output - double *wscale, - double *wssq, - - cholmod_common *cc // for cc->hypotenuse function -) ; - -// ============================================================================= - -template Int spqr_front -( - // input, not modified - Int m, // F is m-by-n with leading dimension m - Int n, - Int npiv, // number of pivot columns - double tol, // a column is flagged as dead if its norm is <= tol - Int ntol, // apply tol only to first ntol pivot columns - Int fchunk, // block size for compact WY Householder reflections, - // treated as 1 if fchunk <= 1 (in which case the - // unblocked code is used). - - // input/output - Complex *F, // frontal matrix F of size m-by-n - Int *Stair, // size n, entries F (Stair[k]:m-1, k) are all zero, - // and remain zero on output. - char *Rdead, // size npiv; all zero on input. If k is dead, - // Rdead [k] is set to 1 - - // output, not defined on input - Complex *Tau, // size n, Householder coefficients - - // workspace, undefined on input and output - Complex *W, // size b*n, where b = min (fchunk,n,m) - - // input/output - double *wscale, - double *wssq, - - cholmod_common *cc // for cc->hypotenuse function -) ; diff --git a/spqr_mini/spqr_front.h b/spqr_mini/spqr_front.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/spqr_mini/spqr_larftb.cpp b/spqr_mini/spqr_larftb.cpp deleted file mode 100644 index 3d7d9d713..000000000 --- a/spqr_mini/spqr_larftb.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// ============================================================================= -// === spqr_larftb ============================================================= -// ============================================================================= - -// Apply a set of Householder reflections to a matrix. Given the vectors -// V and coefficients Tau, construct the matrix T and then apply the updates. -// In MATLAB (1-based indexing), this function computes the following: - -/* - function C = larftb (C, V, Tau, method) - [v k] = size (V) ; - [m n] = size (C) ; - % construct T for the compact WY representation - V = tril (V,-1) + eye (v,k) ; - T = zeros (k,k) ; - T (1,1) = Tau (1) ; - for j = 2:k - tau = Tau (j) ; - z = -tau * V (:, 1:j-1)' * V (:,j) ; - T (1:j-1,j) = T (1:j-1,1:j-1) * z ; - T (j,j) = tau ; - end - % apply the updates - if (method == 0) - C = C - V * T' * V' * C ; % method 0: Left, Transpose - elseif (method == 1) - C = C - V * T * V' * C ; % method 1: Left, No Transpose - elseif (method == 2) - C = C - C * V * T' * V' ; % method 2: Right, Transpose - elseif (method == 3) - C = C - C * V * T * V' ; % method 3: Right, No Transpose - end -*/ - -#include "spqr_subset.hpp" - -inline void spqr_private_larft (char direct, char storev, Int n, Int k, - double *V, Int ldv, double *Tau, double *T, Int ldt, cholmod_common *cc) -{ - BLAS_INT N = n, K = k, LDV = ldv, LDT = ldt ; - if (CHECK_BLAS_INT && - !(EQ (N,n) && EQ (K,k) && EQ (LDV,ldv) && EQ (LDT,ldt))) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_DLARFT (&direct, &storev, &N, &K, V, &LDV, Tau, T, &LDT) ; - } -} - -inline void spqr_private_larft (char direct, char storev, Int n, Int k, - Complex *V, Int ldv, Complex *Tau, Complex *T, Int ldt, cholmod_common *cc) -{ - BLAS_INT N = n, K = k, LDV = ldv, LDT = ldt ; - if (CHECK_BLAS_INT && - !(EQ (N,n) && EQ (K,k) && EQ (LDV,ldv) && EQ (LDT,ldt))) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_ZLARFT (&direct, &storev, &N, &K, V, &LDV, Tau, T, &LDT) ; - } -} - - -inline void spqr_private_larfb (char side, char trans, char direct, char storev, - Int m, Int n, Int k, double *V, Int ldv, double *T, Int ldt, double *C, - Int ldc, double *Work, Int ldwork, cholmod_common *cc) -{ - BLAS_INT M = m, N = n, K = k, LDV = ldv, LDT = ldt, LDC = ldc, - LDWORK = ldwork ; - if (CHECK_BLAS_INT && - !(EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDV,ldv) && - EQ (LDT,ldt) && EQ (LDV,ldv) && EQ (LDWORK,ldwork))) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_DLARFB (&side, &trans, &direct, &storev, &M, &N, &K, V, &LDV, - T, &LDT, C, &LDC, Work, &LDWORK) ; - } -} - - -inline void spqr_private_larfb (char side, char trans, char direct, char storev, - Int m, Int n, Int k, Complex *V, Int ldv, Complex *T, Int ldt, Complex *C, - Int ldc, Complex *Work, Int ldwork, cholmod_common *cc) -{ - char tr = (trans == 'T') ? 'C' : 'N' ; // change T to C - BLAS_INT M = m, N = n, K = k, LDV = ldv, LDT = ldt, LDC = ldc, - LDWORK = ldwork ; - if (CHECK_BLAS_INT && - !(EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDV,ldv) && - EQ (LDT,ldt) && EQ (LDV,ldv) && EQ (LDWORK,ldwork))) - { - cc->blas_ok = FALSE ; - } - if (!CHECK_BLAS_INT || cc->blas_ok) - { - LAPACK_ZLARFB (&side, &tr, &direct, &storev, &M, &N, &K, V, &LDV, - T, &LDT, C, &LDC, Work, &LDWORK) ; - } -} - - -// ============================================================================= - -template void spqr_larftb -( - // inputs, not modified (V is modified and then restored on output) - int method, // 0,1,2,3 - Int m, // C is m-by-n - Int n, - Int k, // V is v-by-k - // for methods 0 and 1, v = m, - // for methods 2 and 3, v = n - Int ldc, // leading dimension of C - Int ldv, // leading dimension of V - Entry *V, // V is v-by-k, unit lower triangular (diag not stored) - Entry *Tau, // size k, the k Householder coefficients - - // input/output - Entry *C, // C is m-by-n, with leading dimension ldc - - // workspace, not defined on input or output - Entry *W, // for methods 0,1: size k*k + n*k - // for methods 2,3: size k*k + m*k - cholmod_common *cc -) -{ - Entry *T, *Work ; - - // ------------------------------------------------------------------------- - // check inputs and split up workspace - // ------------------------------------------------------------------------- - - if (m <= 0 || n <= 0 || k <= 0) - { - return ; // nothing to do - } - - T = W ; // triangular k-by-k matrix for block reflector - Work = W + k*k ; // workspace of size n*k or m*k for larfb - - // ------------------------------------------------------------------------- - // construct and apply the k-by-k upper triangular matrix T - // ------------------------------------------------------------------------- - - // larft and larfb are always used "Forward" and "Columnwise" - - if (method == SPQR_QTX) - { - ASSERT (m >= k) ; - spqr_private_larft ('F', 'C', m, k, V, ldv, Tau, T, k, cc) ; - // Left, Transpose, Forward, Columwise: - spqr_private_larfb ('L', 'T', 'F', 'C', m, n, k, V, ldv, T, k, C, ldc, - Work, n, cc) ; - } - else if (method == SPQR_QX) - { - ASSERT (m >= k) ; - spqr_private_larft ('F', 'C', m, k, V, ldv, Tau, T, k, cc) ; - // Left, No Transpose, Forward, Columwise: - spqr_private_larfb ('L', 'N', 'F', 'C', m, n, k, V, ldv, T, k, C, ldc, - Work, n, cc) ; - } - else if (method == SPQR_XQT) - { - ASSERT (n >= k) ; - spqr_private_larft ('F', 'C', n, k, V, ldv, Tau, T, k, cc) ; - // Right, Transpose, Forward, Columwise: - spqr_private_larfb ('R', 'T', 'F', 'C', m, n, k, V, ldv, T, k, C, ldc, - Work, m, cc) ; - } - else if (method == SPQR_XQ) - { - ASSERT (n >= k) ; - spqr_private_larft ('F', 'C', n, k, V, ldv, Tau, T, k, cc) ; - // Right, No Transpose, Forward, Columwise: - spqr_private_larfb ('R', 'N', 'F', 'C', m, n, k, V, ldv, T, k, C, ldc, - Work, m, cc) ; - } -} - -// ============================================================================= - -template void spqr_larftb -( - // inputs, not modified (V is modified and then restored on output) - int method, // 0,1,2,3 - Int m, // C is m-by-n - Int n, - Int k, // V is v-by-k - // for methods 0 and 1, v = m, - // for methods 2 and 3, v = n - Int ldc, // leading dimension of C - Int ldv, // leading dimension of V - double *V, // V is v-by-k, unit lower triangular (diag not stored) - double *Tau, // size k, the k Householder coefficients - - // input/output - double *C, // C is m-by-n, with leading dimension ldc - - // workspace, not defined on input or output - double *W, // for methods 0,1: size k*k + n*k - // for methods 2,3: size k*k + m*k - cholmod_common *cc -) ; - -// ============================================================================= - -template void spqr_larftb -( - // inputs, not modified (V is modified and then restored on output) - int method, // 0,1,2,3 - Int m, // C is m-by-n - Int n, - Int k, // V is v-by-k - // for methods 0 and 1, v = m, - // for methods 2 and 3, v = n - Int ldc, // leading dimension of C - Int ldv, // leading dimension of V - Complex *V, // V is v-by-k, unit lower triangular (diag not stored) - Complex *Tau, // size k, the k Householder coefficients - - // input/output - Complex *C, // C is m-by-n, with leading dimension ldc - - // workspace, not defined on input or output - Complex *W, // for methods 0,1: size k*k + n*k - // for methods 2,3: size k*k + m*k - cholmod_common *cc -) ; diff --git a/spqr_mini/spqr_larftb.h b/spqr_mini/spqr_larftb.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/spqr_mini/spqr_subset.hpp b/spqr_mini/spqr_subset.hpp deleted file mode 100644 index aad6c798a..000000000 --- a/spqr_mini/spqr_subset.hpp +++ /dev/null @@ -1,397 +0,0 @@ -// ============================================================================= -// === spqr.hpp ================================================================ -// ============================================================================= - -// Internal definitions and non-user-callable routines. This should not be -// included in the user's code. - -#ifndef SPQR_INTERNAL_H -#define SPQR_INTERNAL_H - -// ----------------------------------------------------------------------------- -// include files -// ----------------------------------------------------------------------------- - -#include "UFconfig.h" -extern "C" { -#include "cholmod_core.h" -#include "cholmod_blas.h" -} -#include "SuiteSparseQR_definitions.h" -#include -#include -#include -#include -#include - -#include -typedef std::complex Complex ; - -// ----------------------------------------------------------------------------- -// debugging and printing control -// ----------------------------------------------------------------------------- - -// force debugging off -#ifndef NDEBUG -#define NDEBUG -#endif - -// force printing off -#ifndef NPRINT -#define NPRINT -#endif - -// uncomment the following line to turn on debugging (SPQR will be slow!) -/* -#undef NDEBUG -*/ - -// uncomment the following line to turn on printing (LOTS of output!) -/* -#undef NPRINT -*/ - -// uncomment the following line to turn on expensive debugging (very slow!) -/* -#define DEBUG_EXPENSIVE -*/ - -// ----------------------------------------------------------------------------- -// Int is defined at UF_long, from UFconfig.h -// ----------------------------------------------------------------------------- - -#define Int UF_long -#define Int_max UF_long_max - -// ----------------------------------------------------------------------------- -// basic macros -// ----------------------------------------------------------------------------- - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define EMPTY (-1) -#define TRUE 1 -#define FALSE 0 -#define IMPLIES(p,q) (!(p) || (q)) - -// NULL should already be defined, but ensure it is here. -#ifndef NULL -#define NULL ((void *) 0) -#endif - -// column-major indexing; A[i,j] is A (INDEX (i,j,lda)) -#define INDEX(i,j,lda) ((i) + ((j)*(lda))) - -// FLIP is a "negation about -1", and is used to mark an integer i that is -// normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY -// is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i -// for all integers i. UNFLIP (i) is >= EMPTY. -#define EMPTY (-1) -#define FLIP(i) (-(i)-2) -#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i)) - -// ----------------------------------------------------------------------------- -// additional include files -// ----------------------------------------------------------------------------- - -#ifdef MATLAB_MEX_FILE -#include "mex.h" -#endif - -#define ITYPE CHOLMOD_LONG -#define DTYPE CHOLMOD_DOUBLE -#define ID UF_long_id - -// ----------------------------------------------------------------------------- - -#define ERROR(status,msg) \ - printf ("CHOLMOD error: %s\n",msg) // Kai: disable cholmod_l_error to prevent from including tons of files - -// Check a pointer and return if null. Set status to invalid, unless the -// status is already "out of memory" -#define RETURN_IF_NULL(A,result) \ -{ \ - if ((A) == NULL) \ - { \ - if (cc->status != CHOLMOD_OUT_OF_MEMORY) \ - { \ - ERROR (CHOLMOD_INVALID, NULL) ; \ - } \ - return (result) ; \ - } \ -} - -// Return if Common is NULL or invalid -#define RETURN_IF_NULL_COMMON(result) \ -{ \ - if (cc == NULL) \ - { \ - return (result) ; \ - } \ - if (cc->itype != ITYPE || cc->dtype != DTYPE) \ - { \ - cc->status = CHOLMOD_INVALID ; \ - return (result) ; \ - } \ -} - -#define RETURN_IF_XTYPE_INVALID(A,result) \ -{ \ - if (A->xtype != xtype) \ - { \ - ERROR (CHOLMOD_INVALID, "invalid xtype") ; \ - return (result) ; \ - } \ -} - -// ----------------------------------------------------------------------------- -// debugging and printing macros -// ----------------------------------------------------------------------------- - -#ifndef NDEBUG - - #ifdef MATLAB_MEX_FILE - - // #define ASSERT(e) mxAssert (e, "error: ") - - extern char spqr_mx_debug_string [200] ; - char *spqr_mx_id (int line) ; - - #define ASSERT(e) \ - ((e) ? (void) 0 : \ - mexErrMsgIdAndTxt (spqr_mx_id (__LINE__), \ - "assert: (" #e ") file:" __FILE__ )) - - #else - - #include - #define ASSERT(e) assert (e) - - #endif - - #define DEBUG(e) e - #ifdef DEBUG_EXPENSIVE - #define DEBUG2(e) e - #define ASSERT2(e) ASSERT(e) - #else - #define DEBUG2(e) - #define ASSERT2(e) - #endif - -#else - - #define ASSERT(e) - #define ASSERT2(e) - #define DEBUG(e) - #define DEBUG2(e) - -#endif - -#ifndef NPRINT - - #ifdef MATLAB_MEX_FILE - #define PR(e) mexPrintf e - #else - #define PR(e) printf e - #endif - - #define PRVAL(e) spqrDebug_print (e) - -#else - - #define PR(e) - #define PRVAL(e) - -#endif - -// ----------------------------------------------------------------------------- -// For counting flops; disabled if TBB is used or timing not enabled -// ----------------------------------------------------------------------------- - -#if defined(TIMING) -#define FLOP_COUNT(f) { if (cc->SPQR_grain <= 1) cc->other1 [0] += (f) ; } -#else -#define FLOP_COUNT(f) -#endif - -template void spqr_larftb -( - // inputs, not modified (V is modified and then restored on output) - int method, // 0,1,2,3 - Int m, // C is m-by-n - Int n, - Int k, // V is v-by-k - // for methods 0 and 1, v = m, - // for methods 2 and 3, v = n - Int ldc, // leading dimension of C - Int ldv, // leading dimension of V - Entry *V, // V is v-by-k, unit lower triangular (diag not stored) - Entry *Tau, // size k, the k Householder coefficients - - // input/output - Entry *C, // C is m-by-n, with leading dimension ldc - - // workspace, not defined on input or output - Entry *W, // for methods 0,1: size k*k + n*k - // for methods 2,3: size k*k + m*k - cholmod_common *cc -) ; - -// returns rank of F, or 0 on error -template Int spqr_front -( - // input, not modified - Int m, // F is m-by-n with leading dimension m - Int n, - Int npiv, // number of pivot columns - double tol, // a column is flagged as dead if its norm is <= tol - Int ntol, // apply tol only to first ntol pivot columns - Int fchunk, // block size for compact WY Householder reflections, - // treated as 1 if fchunk <= 1 - - // input/output - Entry *F, // frontal matrix F of size m-by-n - Int *Stair, // size n, entries F (Stair[k]:m-1, k) are all zero, - // and remain zero on output. - char *Rdead, // size npiv; all zero on input. If k is dead, - // Rdead [k] is set to 1 - - // output, not defined on input - Entry *Tau, // size n, Householder coefficients - - // workspace, undefined on input and output - Entry *W, // size b*(n+b), where b = min (fchunk,n,m) - - // input/output - double *wscale, - double *wssq, - - cholmod_common *cc // for cc->hypotenuse function -) ; - - -// ============================================================================= -// === spqr_conj =============================================================== -// ============================================================================= - -inline double spqr_conj (double x) -{ - return (x) ; -} - -inline Complex spqr_conj (Complex x) -{ - return (std::conj (x)) ; -} - -// ============================================================================= -// === spqr_abs ================================================================ -// ============================================================================= - -inline double spqr_abs (double x, cholmod_common *cc) // cc is unused -{ - return (fabs (x)) ; -} - -inline double spqr_abs (Complex x, cholmod_common *cc) -{ - return (cc->hypotenuse (x.real ( ), x.imag ( ))) ; -} - -// ============================================================================= -// === BLAS interface ========================================================== -// ============================================================================= - -// To compile SuiteSparseQR with 64-bit BLAS, use -DBLAS64. See also -// CHOLMOD/Include/cholmod_blas.h - -extern "C" { -#include "cholmod_blas.h" -} - -#ifdef SUN64 - -#define BLAS_DNRM2 dnrm2_64_ -#define LAPACK_DLARF dlarf_64_ -#define LAPACK_DLARFG dlarfg_64_ -#define LAPACK_DLARFT dlarft_64_ -#define LAPACK_DLARFB dlarfb_64_ - -#define BLAS_DZNRM2 dznrm2_64_ -#define LAPACK_ZLARF zlarf_64_ -#define LAPACK_ZLARFG zlarfg_64_ -#define LAPACK_ZLARFT zlarft_64_ -#define LAPACK_ZLARFB zlarfb_64_ - -#elif defined (BLAS_NO_UNDERSCORE) - -#define BLAS_DNRM2 dnrm2 -#define LAPACK_DLARF dlarf -#define LAPACK_DLARFG dlarfg -#define LAPACK_DLARFT dlarft -#define LAPACK_DLARFB dlarfb - -#define BLAS_DZNRM2 dznrm2 -#define LAPACK_ZLARF zlarf -#define LAPACK_ZLARFG zlarfg -#define LAPACK_ZLARFT zlarft -#define LAPACK_ZLARFB zlarfb - -#else - -#define BLAS_DNRM2 dnrm2_ -#define LAPACK_DLARF dlarf_ -#define LAPACK_DLARFG dlarfg_ -#define LAPACK_DLARFT dlarft_ -#define LAPACK_DLARFB dlarfb_ - -#define BLAS_DZNRM2 dznrm2_ -#define LAPACK_ZLARF zlarf_ -#define LAPACK_ZLARFG zlarfg_ -#define LAPACK_ZLARFT zlarft_ -#define LAPACK_ZLARFB zlarfb_ - -#endif - -// ============================================================================= -// === BLAS and LAPACK prototypes ============================================== -// ============================================================================= - -extern "C" -{ - -void LAPACK_DLARFT (char *direct, char *storev, BLAS_INT *n, BLAS_INT *k, - double *V, BLAS_INT *ldv, double *Tau, double *T, BLAS_INT *ldt) ; - -void LAPACK_ZLARFT (char *direct, char *storev, BLAS_INT *n, BLAS_INT *k, - Complex *V, BLAS_INT *ldv, Complex *Tau, Complex *T, BLAS_INT *ldt) ; - -void LAPACK_DLARFB (char *side, char *trans, char *direct, char *storev, - BLAS_INT *m, BLAS_INT *n, BLAS_INT *k, double *V, BLAS_INT *ldv, - double *T, BLAS_INT *ldt, double *C, BLAS_INT *ldc, double *Work, - BLAS_INT *ldwork) ; - -void LAPACK_ZLARFB (char *side, char *trans, char *direct, char *storev, - BLAS_INT *m, BLAS_INT *n, BLAS_INT *k, Complex *V, BLAS_INT *ldv, - Complex *T, BLAS_INT *ldt, Complex *C, BLAS_INT *ldc, Complex *Work, - BLAS_INT *ldwork) ; - -double BLAS_DNRM2 (BLAS_INT *n, double *X, BLAS_INT *incx) ; - -double BLAS_DZNRM2 (BLAS_INT *n, Complex *X, BLAS_INT *incx) ; - -void LAPACK_DLARFG (BLAS_INT *n, double *alpha, double *X, BLAS_INT *incx, - double *tau) ; - -void LAPACK_ZLARFG (BLAS_INT *n, Complex *alpha, Complex *X, BLAS_INT *incx, - Complex *tau) ; - -void LAPACK_DLARF (char *side, BLAS_INT *m, BLAS_INT *n, double *V, - BLAS_INT *incv, double *tau, double *C, BLAS_INT *ldc, double *Work) ; - -void LAPACK_ZLARF (char *side, BLAS_INT *m, BLAS_INT *n, Complex *V, - BLAS_INT *incv, Complex *tau, Complex *C, BLAS_INT *ldc, Complex *Work) ; - -} - -#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index c6c26c463..d1228b3e9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -36,7 +36,7 @@ noinst_PROGRAMS = timeGaussianFactorGraph timeLinearOnDataset # rules to build unit tests #---------------------------------------------------------------------------------------------------- TESTS = $(check_PROGRAMS) -AM_CPPFLAGS = -I$(boost) -I$(top_srcdir)/.. +AM_CPPFLAGS = -I$(boost) -I$(SparseInc) -I$(top_srcdir)/.. AM_LDFLAGS = $(BOOST_LDFLAGS) if USE_ACCELERATE_MACOS