1 /* ========================================================================== */
2 /* === csymamd mexFunction ================================================== */
3 /* ========================================================================== */
4 
5 /* ----------------------------------------------------------------------------
6  * CCOLAMD, Copyright (C), Univ. of Florida.  Authors: Timothy A. Davis,
7  * Sivasankaran Rajamanickam, and Stefan Larimore
8  * -------------------------------------------------------------------------- */
9 
10 /*
11  * Usage:
12  *	p = csymamd (A) ;
13  *	[p stats] = csymamd (A, knobs, cmember) ;
14  *
15  * See csymamd.m for a description.
16  */
17 
18 /* ========================================================================== */
19 /* === Include files ======================================================== */
20 /* ========================================================================== */
21 
22 #include "ccolamd.h"
23 #include "mex.h"
24 #include "matrix.h"
25 #include <stdlib.h>
26 #define Long SuiteSparse_long
27 
28 /* ========================================================================== */
29 /* === csymamd mexFunction ================================================== */
30 /* ========================================================================== */
31 
mexFunction(int nargout,mxArray * pargout[],int nargin,const mxArray * pargin[])32 void mexFunction
33 (
34     /* === Parameters ======================================================= */
35 
36     int nargout,
37     mxArray *pargout [ ],
38     int nargin,
39     const mxArray *pargin [ ]
40 )
41 {
42     /* === Local variables ================================================== */
43 
44     Long *A ;                   /* row indices of input matrix A */
45     Long *perm ;                /* column ordering of M and ordering of A */
46     Long *cmember ;             /* csymamd's copy of the constraint set */
47     double *in_cmember ;        /* input constraint set */
48     Long *p ;                   /* column pointers of input matrix A */
49     Long cslen ;                /* size of constraint set */
50     Long n_col ;                /* number of columns of A */
51     Long n_row ;                /* number of rows of A */
52     Long full ;                 /* TRUE if input matrix full, FALSE if sparse */
53     double knobs [CCOLAMD_KNOBS] ; /* csymamd user-controllable parameters */
54     double *out_perm ;          /* output permutation vector */
55     double *out_stats ;         /* output stats vector */
56     double *in_knobs ;          /* input knobs vector */
57     Long i ;                    /* loop counter */
58     mxArray *Ainput ;           /* input matrix handle */
59     Long spumoni ;              /* verbosity variable */
60     Long stats [CCOLAMD_STATS] ;/* stats for symamd */
61 
62     /* === Check inputs ===================================================== */
63 
64     if (nargin < 1 || nargin > 3 || nargout < 0 || nargout > 2)
65     {
66 	mexErrMsgTxt ("Usage: [p stats] = csymamd (S, knobs, cmember)") ;
67     }
68 
69     /* === Get cmember ====================================================== */
70 
71     cmember = NULL ;
72     cslen = 0 ;
73     if (nargin > 2)
74     {
75 	in_cmember = mxGetPr (pargin [2]) ;
76 	cslen = mxGetNumberOfElements (pargin [2]) ;
77 	if (cslen != 0)
78 	{
79 	    cmember = (Long *) mxCalloc (cslen, sizeof (Long)) ;
80 	    for (i = 0 ; i < cslen ; i++)
81 	    {
82 		/* convert cmember from 1-based to 0-based */
83 		cmember[i] = ((Long) in_cmember [i] - 1) ;
84 	    }
85 	}
86     }
87 
88     /* === Get knobs ======================================================== */
89 
90     ccolamd_l_set_defaults (knobs) ;
91     spumoni = 0 ;
92 
93     /* check for user-passed knobs */
94     i = 0 ;
95     if (nargin > 1)
96     {
97 	in_knobs = mxGetPr (pargin [1]) ;
98 	i = mxGetNumberOfElements (pargin [1]) ;
99 	if (i > 0) knobs [CCOLAMD_DENSE_ROW] = in_knobs [0] ;
100 	if (i > 1) knobs [CCOLAMD_AGGRESSIVE] = in_knobs [1] ;
101 	if (i > 2) spumoni = (in_knobs [2] != 0) ;
102     }
103 
104     /* print knob settings if spumoni is set */
105     if (spumoni)
106     {
107 	mexPrintf ("\ncsymamd version %d.%d, %s:\n",
108 	    CCOLAMD_MAIN_VERSION, CCOLAMD_SUB_VERSION, CCOLAMD_DATE) ;
109 	if (knobs [CCOLAMD_DENSE_ROW] >= 0)
110 	{
111 	    mexPrintf ("knobs(1): %g, rows/cols with > "
112 		"max(16,%g*sqrt(size(A,2))) entries removed\n",
113 		in_knobs [0], knobs [CCOLAMD_DENSE_ROW]) ;
114 	}
115 	else
116 	{
117 	    mexPrintf ("knobs(1): %g, no dense rows removed\n",
118 		in_knobs [0]) ;
119 	}
120 	mexPrintf ("knobs(2): %g, aggressive absorption: %s\n",
121 	    in_knobs [1], (knobs [CCOLAMD_AGGRESSIVE] != 0) ? "yes" : "no") ;
122 	mexPrintf ("knobs(3): %g, statistics and knobs printed\n",
123 		in_knobs [2]) ;
124     }
125 
126     /* === If A is full, convert to a sparse matrix ========================= */
127 
128     Ainput = (mxArray *) pargin [0] ;
129     if (mxGetNumberOfDimensions (Ainput) != 2)
130     {
131 	mexErrMsgTxt ("csymamd: input matrix must be 2-dimensional.") ;
132     }
133     full = !mxIsSparse (Ainput) ;
134     if (full)
135     {
136 	mexCallMATLAB (1, &Ainput, 1, (mxArray **) pargin, "sparse") ;
137     }
138 
139     /* === Allocate workspace for csymamd =================================== */
140 
141     /* get size of matrix */
142     n_row = mxGetM (Ainput) ;
143     n_col = mxGetN (Ainput) ;
144     if (n_col != n_row)
145     {
146 	mexErrMsgTxt ("csymamd: matrix must be square.") ;
147     }
148 
149     if (cmember != NULL && cslen != n_col)
150     {
151     	mexErrMsgTxt ("csymamd: cmember must be of length equal to #cols of A");
152     }
153 
154     A = (Long *) mxGetIr (Ainput) ;
155     p = (Long *) mxGetJc (Ainput) ;
156     perm = (Long *) mxCalloc (n_col+1, sizeof (Long)) ;
157 
158     /* === Order the rows and columns of A (does not destroy A) ============= */
159 
160     if (!csymamd_l (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree,
161 	    cmember, -1))
162     {
163 	csymamd_l_report (stats) ;
164 	mexErrMsgTxt ("csymamd error!") ;
165     }
166 
167     if (full)
168     {
169 	mxDestroyArray (Ainput) ;
170     }
171 
172     /* === Return the permutation vector ==================================== */
173 
174     pargout [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ;
175     out_perm = mxGetPr (pargout [0]) ;
176     for (i = 0 ; i < n_col ; i++)
177     {
178 	/* symamd is 0-based, but MATLAB expects this to be 1-based */
179 	out_perm [i] = perm [i] + 1 ;
180     }
181     mxFree (perm) ;
182     mxFree (cmember) ;
183 
184     /* === Return the stats vector ========================================== */
185 
186     /* print stats if spumoni is set */
187     if (spumoni)
188     {
189 	csymamd_l_report (stats) ;
190     }
191 
192     if (nargout == 2)
193     {
194 	pargout [1] = mxCreateDoubleMatrix (1, CCOLAMD_STATS, mxREAL) ;
195 	out_stats = mxGetPr (pargout [1]) ;
196 	for (i = 0 ; i < CCOLAMD_STATS ; i++)
197 	{
198 	    out_stats [i] = stats [i] ;
199 	}
200 
201 	/* fix stats (5) and (6), for 1-based information on jumbled matrix. */
202 	/* note that this correction doesn't occur if symamd returns FALSE */
203 	out_stats [CCOLAMD_INFO1] ++ ;
204 	out_stats [CCOLAMD_INFO2] ++ ;
205     }
206 }
207