Mercurial > octave-nkf
diff liboctave/COLAMD/symamdtestmex.c @ 5164:57077d0ddc8e
[project @ 2005-02-25 19:55:24 by jwe]
author | jwe |
---|---|
date | Fri, 25 Feb 2005 19:55:28 +0000 |
parents | |
children | 49ff3dd744ee |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/COLAMD/symamdtestmex.c Fri Feb 25 19:55:28 2005 +0000 @@ -0,0 +1,575 @@ +/* ========================================================================== */ +/* === symamdtest mexFunction =============================================== */ +/* ========================================================================== */ + +/* + This MATLAB mexFunction is for testing only. It is not meant for + production use. See symamdmex.c instead. + + Usage: + + [ P, stats ] = symamdtest (A, knobs) ; + + Returns a permutation vector P such that the Cholesky factorization of + A (P,P) tends to be sparser than that of A. This routine provides the same + functionality as SYMMMD, but tends to be much faster and tends to return a + better permutation vector. Note that the SYMMMD m-file in + MATLAB 5.2 also performs a symmetric elimination tree post-ordering. This + mexFunction does not do this post-ordering. This mexFunction is a + replacement for the p = sparsfun ('symmmd', A) operation. + + A must be square, and is assummed to have a symmetric nonzero pattern. + Only the nonzero pattern of the lower triangular portion of A is accessed. + This routine constructs a matrix M such that the nonzero pattern of M'M is + equal to A (assuming A has symmetric pattern), and then performs a column + ordering of M using colamd. + + The knobs and stats vectors are optional: + + knobs (1) rows and columns with more than (knobs(1))*n entries + are removed prior to ordering, and placed last in + the output ordering. If knobs is not present, then the + default of 0.5 is used. + + knobs (2) print level, similar to spparms ('spumoni') + + knobs (3) for testing only. Controls how the input matrix is + jumbled prior to calling symamd, to test its error + handling capability. + + stats (1) the number of dense (or empty) rows and columms. These + are ordered last, in their natural order. + + stats (2) (same as stats (1)) + + stats (3) the number of garbage collections performed. + + stats (4) return status: + + 0: matrix is a valid MATLAB matrix. + + 1: matrix has duplicate entries or unsorted columns. + This should not occur in a valid MATLAB matrix, + but the ordering proceeded anyway by ignoring the + duplicate row indices in each column. See + stats (5:7) for more information. + + stats (5) highest numbered column that is unsorted or has + duplicate entries (zero if none) + + stats (6) last seen duplicate or unsorted row index + (zero if none) + + stats (7) number of duplicate or unsorted row indices + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (davis@cise.ufl.edu), University of Florida. The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Date: + + September 8, 2003. Version 2.3. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2003 by the University of Florida. + All Rights Reserved. + + See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c + file) for the License. + + 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/symamdtestmex.c + file. It requires the colamd.c and colamd.h files. + +*/ + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include "colamd.h" +#include "mex.h" +#include "matrix.h" +#include <stdlib.h> +#include <string.h> + +static void dump_matrix +( + int A [ ], + int p [ ], + int n_row, + int n_col, + int Alen, + int limit +) ; + +/* ========================================================================== */ +/* === symamd 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 ================================================== */ + + int *perm ; /* column ordering of M and ordering of A */ + int *A ; /* row indices of input matrix A */ + int *p ; /* column pointers of input matrix A */ + int n_col ; /* number of columns of A */ + int n_row ; /* number of rows of 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 */ + int i ; /* loop counter */ + mxArray *Ainput ; /* input matrix handle */ + int spumoni ; /* verbosity variable */ + int stats2 [COLAMD_STATS] ; /* stats for symamd */ + + int *cp, *cp_end, result, nnz, col, length ; + int *stats ; + stats = stats2 ; + + /* === Check inputs ===================================================== */ + + if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) + { + mexErrMsgTxt ( + "symamd: incorrect number of input and/or output arguments.") ; + } + + if (nrhs != 2) + { + mexErrMsgTxt ("symamdtest: knobs are required") ; + } + /* for testing we require all 3 knobs */ + if (mxGetNumberOfElements (prhs [1]) < 3) + { + mexErrMsgTxt ("symamdtest: must have all 3 knobs for testing") ; + } + + /* === Get knobs ======================================================== */ + + colamd_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 [COLAMD_DENSE_ROW] ; + if (i > 1) spumoni = (int) in_knobs [1] ; + } + + /* print knob settings if spumoni > 0 */ + if (spumoni > 0) + { + mexPrintf ("symamd: dense row/col fraction: %f\n", + knobs [COLAMD_DENSE_ROW]) ; + } + + /* === If A is full, convert to a sparse matrix ========================= */ + + Ainput = (mxArray *) prhs [0] ; + if (mxGetNumberOfDimensions (Ainput) != 2) + { + mexErrMsgTxt ("symamd: input matrix must be 2-dimensional.") ; + } + full = !mxIsSparse (Ainput) ; + if (full) + { + mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; + } + + /* === Allocate workspace for symamd ==================================== */ + + /* get size of matrix */ + n_row = mxGetM (Ainput) ; + n_col = mxGetN (Ainput) ; + if (n_col != n_row) + { + mexErrMsgTxt ("symamd: matrix must be square.") ; + } + + /* p = mxGetJc (Ainput) ; */ + p = (int *) mxCalloc (n_col+1, sizeof (int)) ; + (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (int)) ; + + nnz = p [n_col] ; + if (spumoni > 0) + { + mexPrintf ("symamdtest: nnz %d\n", nnz) ; + } + + /* A = mxGetIr (Ainput) ; */ + A = (int *) mxCalloc (nnz+1, sizeof (int)) ; + (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (int)) ; + + perm = (int *) mxCalloc (n_col+1, sizeof (int)) ; + +/* === Jumble matrix ======================================================== */ + + +/* + knobs [2] FOR TESTING ONLY: Specifies how to jumble matrix + 0 : No jumbling + 1 : (no errors) + 2 : Make first pointer non-zero + 3 : Make column pointers not non-decreasing + 4 : (no errors) + 5 : Make row indices not strictly increasing + 6 : Make a row index greater or equal to n_row + 7 : Set A = NULL + 8 : Set p = NULL + 9 : Repeat row index + 10: make row indices not sorted + 11: jumble columns massively (note this changes + the pattern of the matrix A.) + 12: Set stats = NULL + 13: Make n_col less than zero +*/ + + /* jumble appropriately */ + switch ((int) in_knobs [2]) + { + + case 0 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: no errors expected\n") ; + } + result = 1 ; /* no errors */ + break ; + + case 1 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: no errors expected (1)\n") ; + } + result = 1 ; + break ; + + case 2 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: p [0] nonzero\n") ; + } + result = 0 ; /* p [0] must be zero */ + p [0] = 1 ; + break ; + + case 3 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: negative length last column\n") ; + } + result = (n_col == 0) ; /* p must be monotonically inc. */ + p [n_col] = p [0] ; + break ; + + case 4 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: no errors expected (4)\n") ; + } + result = 1 ; + break ; + + case 5 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: row index out of range (-1)\n") ; + } + if (nnz > 0) /* row index out of range */ + { + result = 0 ; + A [nnz-1] = -1 ; + } + else + { + if (spumoni > 0) + { + mexPrintf ("Note: no row indices to put out of range\n") ; + } + result = 1 ; + } + break ; + + case 6 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: row index out of range (ncol)\n") ; + } + if (nnz > 0) /* row index out of range */ + { + result = 0 ; + A [nnz-1] = n_col ; + } + else + { + if (spumoni > 0) + { + mexPrintf ("Note: no row indices to put out of range\n") ; + } + result = 1 ; + } + break ; + + case 7 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: A not present\n") ; + } + result = 0 ; /* A not present */ + A = (int *) NULL ; + break ; + + case 8 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: p not present\n") ; + } + result = 0 ; /* p not present */ + p = (int *) NULL ; + break ; + + case 9 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: duplicate row index\n") ; + } + result = 1 ; /* duplicate row index */ + + for (col = 0 ; col < n_col ; col++) + { + length = p [col+1] - p [col] ; + if (length > 1) + { + A [p [col+1]-2] = A [p [col+1] - 1] ; + if (spumoni > 0) + { + mexPrintf ("Made duplicate row %d in col %d\n", + A [p [col+1] - 1], col) ; + } + break ; + } + } + + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, nnz, col+2) ; + } + break ; + + case 10 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: unsorted column\n") ; + } + result = 1 ; /* jumbled columns */ + + for (col = 0 ; col < n_col ; col++) + { + length = p [col+1] - p [col] ; + if (length > 1) + { + i = A[p [col]] ; + A [p [col]] = A[p [col] + 1] ; + A [p [col] + 1] = i ; + if (spumoni > 0) + { + mexPrintf ("Unsorted column %d \n", col) ; + } + break ; + } + } + + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, nnz, col+2) ; + } + break ; + + case 11 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: massive jumbling\n") ; + } + result = 1 ; /* massive jumbling, but no errors */ + srand (1) ; + for (i = 0 ; i < n_col ; i++) + { + cp = &A [p [i]] ; + cp_end = &A [p [i+1]] ; + while (cp < cp_end) + { + *cp++ = rand() % n_row ; + } + } + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, nnz, n_col) ; + } + break ; + + case 12 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: stats not present\n") ; + } + result = 0 ; /* stats not present */ + stats = (int *) NULL ; + break ; + + case 13 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: ncol out of range\n") ; + } + result = 0 ; /* ncol out of range */ + n_col = -1 ; + break ; + + } + + /* === Order the rows and columns of A (does not destroy A) ============= */ + + if (!symamd (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree)) + { + + /* return p = -1 if colamd failed */ + plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + out_perm [0] = -1 ; + mxFree (p) ; + mxFree (A) ; + + if (spumoni > 0 || result) + { + symamd_report (stats) ; + } + + if (result) + { + mexErrMsgTxt ("symamd should have returned TRUE\n") ; + } + + return ; + /* mexErrMsgTxt ("symamd error!") ; */ + } + + if (!result) + { + symamd_report (stats) ; + mexErrMsgTxt ("symamd should have returned FALSE\n") ; + } + + if (full) + { + mxDestroyArray (Ainput) ; + } + + /* === Return the permutation vector ==================================== */ + + plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + for (i = 0 ; i < n_col ; i++) + { + /* symamd is 0-based, but MATLAB expects this to be 1-based */ + out_perm [i] = perm [i] + 1 ; + } + mxFree (perm) ; + + /* === Return the stats vector ========================================== */ + + /* print stats if spumoni > 0 */ + if (spumoni > 0) + { + symamd_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] ++ ; + } +} + + +#ifdef MIN +#undef MIN +#endif +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + + +static void dump_matrix +( + int A [ ], + int p [ ], + int n_row, + int n_col, + int Alen, + int limit +) +{ + int col, k, row ; + + mexPrintf ("dump matrix: nrow %d ncol %d Alen %d\n", n_row, n_col, Alen) ; + + if (!A) + { + mexPrintf ("A not present\n") ; + return ; + } + + if (!p) + { + mexPrintf ("p not present\n") ; + return ; + } + + for (col = 0 ; col < MIN (n_col, limit) ; col++) + { + mexPrintf ("column %d, p[col] %d, p [col+1] %d, length %d\n", + col, p [col], p [col+1], p [col+1] - p [col]) ; + for (k = p [col] ; k < p [col+1] ; k++) + { + row = A [k] ; + mexPrintf (" %d", row) ; + } + mexPrintf ("\n") ; + } +}