MATLAB: A sparse matrix vector multiplication in C mex programming

cmexsparse matrix

Hi everyone,
I'm new in C mex programming and I'm really stuck. I would like to write a code that computes a sparse matrix vector multiplication (sparse_matrix*vector=result_vector). Given how sparse matrices are managed in C mex, I have difficulties getting the non zero elements of each row (to do the multiplication with the vector), because the pointers Ir=mxGetIr(sparse_matrix) and Jc=mxGetJc(sparse_matrix) give the information about the columns only and not the rows.
I would be really grateful if somebody helps me out because I can't move on without solving this problem.
Thanks in advance.
Sincerely,
J

Best Answer

Here is the bare bones C code for this. Most of the code consists of argument checking etc. The actual computation part of the code is only a few lines and is fairly trivial. It simply accumulates the individual element multiplies into the appropriate resulting element. The j for-loop loops over the columns of M, and the while loop does the individual element multiplies within each column.
/* Bare bones sparse matrix * full vector */
/* Produces a full vector result */
/* Assumes all input elements are finite */
/* E.g., does not account for NaN or 0*inf etc. */
/* Programmer: James Tursa */
/* Includes ----------------------------------------------------------- */
#include "mex.h"
/* Gateway ------------------------------------------------------------ */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mwSize m, n, j, nrow;
double *Mpr, *Vpr, *Cpr;
mwIndex *Mir, *Mjc;
/* Argument checks */
if( nlhs > 1 ) {
mexErrMsgTxt("Too many outputs");
}
if( nrhs != 2 ) {
mexErrMsgTxt("Need exactly two inputs");
}
if( !mxIsDouble(prhs[0]) || !mxIsSparse(prhs[0]) || mxIsComplex(prhs[0]) ) {
mexErrMsgTxt("1st argument must be real double sparse matrix");
}
if( !mxIsDouble(prhs[1]) || mxIsSparse(prhs[1]) || mxIsComplex(prhs[1]) ||
mxGetNumberOfDimensions(prhs[1])!=2 || mxGetN(prhs[1])!=1 ) {
mexErrMsgTxt("2nd argument must be real double full column vector");
}
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
if( mxGetM(prhs[1])!=n ) {
mexErrMsgTxt("Inner matrix dimensions must agree.");
}
/* Create output */
plhs[0] = mxCreateDoubleMatrix( m, 1, mxREAL );
/* Get data pointers */
Mpr = mxGetPr(prhs[0]);
Vpr = mxGetPr(prhs[1]);
Cpr = mxGetPr(plhs[0]);
Mir = mxGetIr(prhs[0]);
Mjc = mxGetJc(prhs[0]);
/* Calculate result */
for( j=0; j<n; j++ ) {
nrow = Mjc[j+1] - Mjc[j]; /* Number of row elements for this column */
while( nrow-- ) {
Cpr[*Mir++] += *Mpr++ * Vpr[j]; /* Accumulate contribution of Vpr[j] */
}
}
}
Related Question