//------------------------------------------------------------------------------ // CAMD/Include/camd.h: constrained approximate minimum degree ordering //------------------------------------------------------------------------------ // CAMD, Copyright (c) 1996-2024, Timothy A. Davis, Yanqing Chen, // Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause //------------------------------------------------------------------------------ /* CAMD finds a symmetric ordering P of a matrix A so that the Cholesky * factorization of P*A*P' has fewer nonzeros and takes less work than the * Cholesky factorization of A. If A is not symmetric, then it performs its * ordering on the matrix A+A'. Two sets of user-callable routines are * provided, one for int32_t integers and the other for int64_t integers. * * The method is based on the approximate minimum degree algorithm, discussed * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. * 886-905, 1996. */ #ifndef CAMD_H #define CAMD_H #include "SuiteSparse_config.h" /* make it easy for C++ programs to include CAMD */ #ifdef __cplusplus extern "C" { #endif int camd_order /* returns CAMD_OK, CAMD_OK_BUT_JUMBLED, * CAMD_INVALID, or CAMD_OUT_OF_MEMORY */ ( int32_t n, /* A is n-by-n. n must be >= 0. */ const int32_t Ap [ ], /* column pointers for A, of size n+1 */ const int32_t Ai [ ], /* row indices of A, of size nz = Ap [n] */ int32_t P [ ], /* output permutation, of size n */ double Control [ ], /* input Control settings, of size CAMD_CONTROL */ double Info [ ], /* output Info statistics, of size CAMD_INFO */ const int32_t C [ ] /* Constraint set of A, of size n; can be NULL */ ) ; int camd_l_order /* see above for description */ ( int64_t n, const int64_t Ap [ ], const int64_t Ai [ ], int64_t P [ ], double Control [ ], double Info [ ], const int64_t C [ ] ) ; /* Input arguments (not modified): * * n: the matrix A is n-by-n. * Ap: an int32_t/int64_t array of size n+1, containing column * pointers of A. * Ai: an int32_t/int64_t array of size nz, containing the row * indices of A, where nz = Ap [n]. * Control: a double array of size CAMD_CONTROL, containing control * parameters. Defaults are used if Control is NULL. * * Output arguments (not defined on input): * * P: an int32_t/int64_t array of size n, containing the output * permutation. If row i is the kth pivot row, then P [k] = i. In * MATLAB notation, the reordered matrix is A (P,P). * Info: a double array of size CAMD_INFO, containing statistical * information. Ignored if Info is NULL. * * On input, the matrix A is stored in column-oriented form. The row indices * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. * * If the row indices appear in ascending order in each column, and there * are no duplicate entries, then camd_order is slightly more efficient in * terms of time and memory usage. If this condition does not hold, a copy * of the matrix is created (where these conditions do hold), and the copy is * ordered. * * Row indices must be in the range 0 to * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. * The matrix does not need to be symmetric, and the diagonal does not need to * be present (if diagonal entries are present, they are ignored except for * the output statistic Info [CAMD_NZDIAG]). The arrays Ai and Ap are not * modified. This form of the Ap and Ai arrays to represent the nonzero * pattern of the matrix A is the same as that used internally by MATLAB. * If you wish to use a more flexible input structure, please see the * umfpack_*_triplet_to_col routines in the UMFPACK package, at * http://www.suitesparse.com. * * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these * restrictions are not met, CAMD returns CAMD_INVALID. * * CAMD returns: * * CAMD_OK if the matrix is valid and sufficient memory can be allocated to * perform the ordering. * * CAMD_OUT_OF_MEMORY if not enough memory can be allocated. * * CAMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is * NULL. * * CAMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate * entries, but was otherwise valid. * * The CAMD routine first forms the pattern of the matrix A+A', and then * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of * the original is the kth pivotal row. In MATLAB notation, the permuted * matrix is A (P,P), except that 0-based indexing is used instead of the * 1-based indexing in MATLAB. * * The Control array is used to set various parameters for CAMD. If a NULL * pointer is passed, default values are used. The Control array is not * modified. * * Control [CAMD_DENSE]: controls the threshold for "dense" rows/columns. * A dense row/column in A+A' can cause CAMD to spend a lot of time in * ordering the matrix. If Control [CAMD_DENSE] >= 0, rows/columns * with more than Control [CAMD_DENSE] * sqrt (n) entries are ignored * during the ordering, and placed last in the output order. The * default value of Control [CAMD_DENSE] is 10. If negative, no * rows/columns are treated as "dense". Rows/columns with 16 or * fewer off-diagonal entries are never considered "dense". * * Control [CAMD_AGGRESSIVE]: controls whether or not to use aggressive * absorption, in which a prior element is absorbed into the current * element if is a subset of the current element, even if it is not * adjacent to the current pivot element (refer to Amestoy, Davis, * & Duff, 1996, for more details). The default value is nonzero, * which means to perform aggressive absorption. This nearly always * leads to a better ordering (because the approximate degrees are * more accurate) and a lower execution time. There are cases where * it can lead to a slightly worse ordering, however. To turn it off, * set Control [CAMD_AGGRESSIVE] to 0. * * Control [2..4] are not used in the current version, but may be used in * future versions. * * The Info array provides statistics about the ordering on output. If it is * not present, the statistics are not returned. This is not an error * condition. * * Info [CAMD_STATUS]: the return value of CAMD, either CAMD_OK, * CAMD_OK_BUT_JUMBLED, CAMD_OUT_OF_MEMORY, or CAMD_INVALID. * * Info [CAMD_N]: n, the size of the input matrix * * Info [CAMD_NZ]: the number of nonzeros in A, nz = Ap [n] * * Info [CAMD_SYMMETRY]: the symmetry of the matrix A. It is the number * of "matched" off-diagonal entries divided by the total number of * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also * an entry, for any pair (i,j) for which i != j. In MATLAB notation, * S = spones (A) ; * B = tril (S, -1) + triu (S, 1) ; * symmetry = nnz (B & B') / nnz (B) ; * * Info [CAMD_NZDIAG]: the number of entries on the diagonal of A. * * Info [CAMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the * diagonal. If A is perfectly symmetric (Info [CAMD_SYMMETRY] = 1) * with a fully nonzero diagonal, then Info [CAMD_NZ_A_PLUS_AT] = nz-n * (the smallest possible value). If A is perfectly unsymmetric * (Info [CAMD_SYMMETRY] = 0, for an upper triangular matrix, for * example) with no diagonal, then Info [CAMD_NZ_A_PLUS_AT] = 2*nz * (the largest possible value). * * Info [CAMD_NDENSE]: the number of "dense" rows/columns of A+A' that were * removed from A prior to ordering. These are placed last in the * output order P. * * Info [CAMD_MEMORY]: the amount of memory used by CAMD, in bytes. In the * current version, this is 1.2 * Info [CAMD_NZ_A_PLUS_AT] + 9*n * times the size of an integer. This is at most 2.4nz + 9n. This * excludes the size of the input arguments Ai, Ap, and P, which have * a total size of nz + 2*n + 1 integers. * * Info [CAMD_NCMPA]: the number of garbage collections performed. * * Info [CAMD_LNZ]: the number of nonzeros in L (excluding the diagonal). * This is a slight upper bound because mass elimination is combined * with the approximate degree update. It is a rough upper bound if * there are many "dense" rows/columns. The rest of the statistics, * below, are also slight or rough upper bounds, for the same reasons. * The post-ordering of the assembly tree might also not exactly * correspond to a true elimination tree postordering. * * Info [CAMD_NDIV]: the number of divide operations for a subsequent LDL' * or LU factorization of the permuted matrix A (P,P). * * Info [CAMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a * subsequent LDL' factorization of A (P,P). * * Info [CAMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a * subsequent LU factorization of A (P,P), assuming that no numerical * pivoting is required. * * Info [CAMD_DMAX]: the maximum number of nonzeros in any column of L, * including the diagonal. * * Info [14..19] are not used in the current version, but may be used in * future versions. */ /* ------------------------------------------------------------------------- */ /* direct interface to CAMD */ /* ------------------------------------------------------------------------- */ /* camd_2 is the primary CAMD ordering routine. It is not meant to be * user-callable because of its restrictive inputs and because it destroys * the user's input matrix. It does not check its inputs for errors, either. * However, if you can work with these restrictions it can be faster than * camd_order and use less memory (assuming that you can create your own copy * of the matrix for CAMD to destroy). Refer to CAMD/Source/camd_2.c for a * description of each parameter. */ void camd_2 ( int32_t n, int32_t Pe [ ], int32_t Iw [ ], int32_t Len [ ], int32_t iwlen, int32_t pfree, int32_t Nv [ ], int32_t Next [ ], int32_t Last [ ], int32_t Head [ ], int32_t Elen [ ], int32_t Degree [ ], int32_t W [ ], double Control [ ], double Info [ ], const int32_t C [ ], int32_t BucketSet [ ] ) ; void camd_l2 ( int64_t n, int64_t Pe [ ], int64_t Iw [ ], int64_t Len [ ], int64_t iwlen, int64_t pfree, int64_t Nv [ ], int64_t Next [ ], int64_t Last [ ], int64_t Head [ ], int64_t Elen [ ], int64_t Degree [ ], int64_t W [ ], double Control [ ], double Info [ ], const int64_t C [ ], int64_t BucketSet [ ] ) ; /* ------------------------------------------------------------------------- */ /* camd_valid */ /* ------------------------------------------------------------------------- */ /* Returns CAMD_OK or CAMD_OK_BUT_JUMBLED if the matrix is valid as input to * camd_order; the latter is returned if the matrix has unsorted and/or * duplicate row indices in one or more columns. Returns CAMD_INVALID if the * matrix cannot be passed to camd_order. For camd_order, the matrix must also * be square. The first two arguments are the number of rows and the number * of columns of the matrix. For its use in CAMD, these must both equal n. */ int camd_valid ( int32_t n_row, /* # of rows */ int32_t n_col, /* # of columns */ const int32_t Ap [ ], /* column pointers, of size n_col+1 */ const int32_t Ai [ ] /* row indices, of size Ap [n_col] */ ) ; int camd_l_valid ( int64_t n_row, int64_t n_col, const int64_t Ap [ ], const int64_t Ai [ ] ) ; /* ------------------------------------------------------------------------- */ /* camd_cvalid */ /* ------------------------------------------------------------------------- */ /* Returns TRUE if the constraint set is valid as input to camd_order, * FALSE otherwise. */ int camd_cvalid ( int32_t n, const int32_t C [ ] ) ; int camd_l_cvalid ( int64_t n, const int64_t C [ ] ) ; /* ------------------------------------------------------------------------- */ /* CAMD Control and Info arrays */ /* ------------------------------------------------------------------------- */ /* camd_defaults: sets the default control settings */ void camd_defaults (double Control [ ]) ; void camd_l_defaults (double Control [ ]) ; /* camd_control: prints the control settings */ void camd_control (double Control [ ]) ; void camd_l_control (double Control [ ]) ; /* camd_info: prints the statistics */ void camd_info (double Info [ ]) ; void camd_l_info (double Info [ ]) ; // camd_version: return CAMD version. The version array is returned with // version [0..2] = {CAMD_MAIN_VERSION, CAMD_SUB_VERSION, CAMD_SUBSUB_VERSION} void camd_version (int version [3]) ; #ifdef __cplusplus } #endif #define CAMD_CONTROL 5 /* size of Control array */ #define CAMD_INFO 20 /* size of Info array */ /* contents of Control */ #define CAMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ #define CAMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ /* default Control settings */ #define CAMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ #define CAMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ /* contents of Info */ #define CAMD_STATUS 0 /* return value of camd_order and camd_l_order */ #define CAMD_N 1 /* A is n-by-n */ #define CAMD_NZ 2 /* number of nonzeros in A */ #define CAMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ #define CAMD_NZDIAG 4 /* # of entries on diagonal */ #define CAMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ #define CAMD_NDENSE 6 /* number of "dense" rows/columns in A */ #define CAMD_MEMORY 7 /* amount of memory used by CAMD */ #define CAMD_NCMPA 8 /* number of garbage collections in CAMD */ #define CAMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ #define CAMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ #define CAMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ #define CAMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ #define CAMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ /* ------------------------------------------------------------------------- */ /* return values of CAMD */ /* ------------------------------------------------------------------------- */ #define CAMD_OK 0 /* success */ #define CAMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ #define CAMD_INVALID -2 /* input arguments are not valid */ #define CAMD_OK_BUT_JUMBLED 1 /* input matrix is OK for camd_order, but * columns were not sorted, and/or duplicate entries were present. CAMD had * to do extra work before ordering the matrix. This is a warning, not an * error. */ /* ========================================================================== */ /* === CAMD version ========================================================= */ /* ========================================================================== */ /* * As an example, to test if the version you are using is 1.2 or later: * * if (CAMD_VERSION >= CAMD_VERSION_CODE (1,2)) ... * * This also works during compile-time: * * #if (CAMD_VERSION >= CAMD_VERSION_CODE (1,2)) * printf ("This is version 1.2 or later\n") ; * #else * printf ("This is an early version\n") ; * #endif */ #define CAMD_DATE "@CAMD_DATE@" #define CAMD_MAIN_VERSION @CAMD_VERSION_MAJOR@ #define CAMD_SUB_VERSION @CAMD_VERSION_MINOR@ #define CAMD_SUBSUB_VERSION @CAMD_VERSION_SUB@ #define CAMD_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) #define CAMD_VERSION CAMD_VERSION_CODE(@CAMD_VERSION_MAJOR@,@CAMD_VERSION_MINOR@) #define CAMD__VERSION SUITESPARSE__VERCODE(@CAMD_VERSION_MAJOR@,@CAMD_VERSION_MINOR@,@CAMD_VERSION_SUB@) #if !defined (SUITESPARSE__VERSION) || \ (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,7,0)) #error "CAMD @CAMD_VERSION_MAJOR@.@CAMD_VERSION_MINOR@.@CAMD_VERSION_SUB@ requires SuiteSparse_config 7.7.0 or later" #endif #endif