//------------------------------------------------------------------------------ // COLAMD/MATLAB/colamdmex: MATLAB interface for COLAMD //------------------------------------------------------------------------------ // COLAMD, Copyright (c) 1998-2022, Timothy A. Davis and Stefan Larimore, // All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause //------------------------------------------------------------------------------ /* Usage: P = colamd2 (A) ; [ P, stats ] = colamd2 (A, knobs) ; see colamd.m for a description. Authors: The authors of the code itself are Stefan I. Larimore and Timothy A. Davis (DrTimothyAldenDavis@gmail.com). 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. Availability: The colamd/symamd library is available at http://www.suitesparse.com */ /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ #include "colamd.h" #include "mex.h" #include "matrix.h" #include #include /* ========================================================================== */ /* === colamd mexFunction =================================================== */ /* ========================================================================== */ void mexFunction ( /* === Parameters ======================================================= */ int nlhs, /* number of left-hand sides */ mxArray *plhs [], /* left-hand side matrices */ int nrhs, /* number of right--hand sides */ const mxArray *prhs [] /* right-hand side matrices */ ) { /* === Local variables ================================================== */ int64_t *A ; /* colamd's copy of the matrix, and workspace */ int64_t *p ; /* colamd's copy of the column pointers */ int64_t Alen ; /* size of A */ int64_t n_col ; /* number of columns of A */ int64_t n_row ; /* number of rows of A */ int64_t nnz ; /* number of entries in A */ int full ; /* TRUE if input matrix full, FALSE if sparse */ double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */ double *out_perm ; /* output permutation vector */ double *out_stats ; /* output stats vector */ double *in_knobs ; /* input knobs vector */ int64_t i ; /* loop counter */ mxArray *Ainput ; /* input matrix handle */ int spumoni ; /* verbosity variable */ int64_t stats [COLAMD_STATS] ; /* stats for colamd */ /* === Check inputs ===================================================== */ if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) { mexErrMsgTxt ( "colamd: incorrect number of input and/or output arguments") ; } /* === Get knobs ======================================================== */ colamd_l_set_defaults (knobs) ; spumoni = 0 ; /* check for user-passed knobs */ if (nrhs == 2) { in_knobs = mxGetPr (prhs [1]) ; i = mxGetNumberOfElements (prhs [1]) ; if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ; if (i > 1) knobs [COLAMD_DENSE_COL] = in_knobs [1] ; if (i > 2) spumoni = (int) (in_knobs [2] != 0) ; } /* print knob settings if spumoni is set */ if (spumoni) { mexPrintf ("\ncolamd version %d.%d, %s:\n", COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ; if (knobs [COLAMD_DENSE_ROW] >= 0) { mexPrintf ("knobs(1): %g, rows with > max(16,%g*sqrt(size(A,2)))" " entries removed\n", in_knobs [0], knobs [COLAMD_DENSE_ROW]) ; } else { mexPrintf ("knobs(1): %g, only completely dense rows removed\n", in_knobs [0]) ; } if (knobs [COLAMD_DENSE_COL] >= 0) { mexPrintf ("knobs(2): %g, cols with > max(16,%g*sqrt(min(size(A)))" " entries removed\n", in_knobs [1], knobs [COLAMD_DENSE_COL]) ; } else { mexPrintf ("knobs(2): %g, only completely dense columns removed\n", in_knobs [1]) ; } mexPrintf ("knobs(3): %g, statistics and knobs printed\n", in_knobs [2]) ; } /* === If A is full, convert to a sparse matrix ========================= */ Ainput = (mxArray *) prhs [0] ; if (mxGetNumberOfDimensions (Ainput) != 2) { mexErrMsgTxt ("colamd: input matrix must be 2-dimensional") ; } full = !mxIsSparse (Ainput) ; if (full) { mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; } /* === Allocate workspace for colamd ==================================== */ /* get size of matrix */ n_row = mxGetM (Ainput) ; n_col = mxGetN (Ainput) ; /* get column pointer vector so we can find nnz */ p = (int64_t *) mxCalloc (n_col+1, sizeof (int64_t)) ; (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (int64_t)) ; nnz = p [n_col] ; Alen = (int64_t) colamd_l_recommended (nnz, n_row, n_col) ; if (Alen == 0) { mexErrMsgTxt ("colamd: problem too large") ; } /* === Copy input matrix into workspace ================================= */ A = (int64_t *) mxCalloc (Alen, sizeof (int64_t)) ; (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (int64_t)) ; if (full) { mxDestroyArray (Ainput) ; } /* === Order the columns (destroys A) =================================== */ if (!colamd_l (n_row, n_col, Alen, A, p, knobs, stats)) { colamd_l_report (stats) ; mexErrMsgTxt ("colamd error!") ; } mxFree (A) ; /* === Return the permutation vector ==================================== */ plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; out_perm = mxGetPr (plhs [0]) ; for (i = 0 ; i < n_col ; i++) { /* colamd is 0-based, but MATLAB expects this to be 1-based */ out_perm [i] = p [i] + 1 ; } mxFree (p) ; /* === Return the stats vector ========================================== */ /* print stats if spumoni is set */ if (spumoni) { colamd_l_report (stats) ; } if (nlhs == 2) { plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ; out_stats = mxGetPr (plhs [1]) ; for (i = 0 ; i < COLAMD_STATS ; i++) { out_stats [i] = stats [i] ; } /* fix stats (5) and (6), for 1-based information on jumbled matrix. */ /* note that this correction doesn't occur if symamd returns FALSE */ out_stats [COLAMD_INFO1] ++ ; out_stats [COLAMD_INFO2] ++ ; } }