Next: , Previous: Structures with Mex-Files, Up: Mex-Files


A.2.6 Sparse Matrices with Mex-Files

The Octave format for sparse matrices is identical to the mex format in that it is a compressed column sparse format. Also in both, sparse matrices are required to be two dimensional. The only difference is that the real and imaginary parts of the matrix are stored separately.

The mex-file interface, as well as using mxGetM, mxGetN, mxSetM, mxSetN, mxGetPr, mxGetPi, mxSetPr and mxSetPi, the mex-file interface supplies the functions

     mwIndex *mxGetIr (const mxArray *ptr);
     mwIndex *mxGetJc (const mxArray *ptr);
     mwSize mxGetNzmax (const mxArray *ptr);
     
     void mxSetIr (mxArray *ptr, mwIndex *ir);
     void mxSetJc (mxArray *ptr, mwIndex *jc);
     void mxSetNzmax (mxArray *ptr, mwSize nzmax);

mxGetNzmax gets the maximum number of elements that can be stored in the sparse matrix. This is not necessarily the number of non-zero elements in the sparse matrix. mxGetJc returns an array with one additional value than the number of columns in the sparse matrix. The difference between consecutive values of the array returned by mxGetJc define the number of non-zero elements in each column of the sparse matrix. Therefore

     mwSize nz, n;
     mwIndex *Jc;
     mxArray *m;
     ...
     n = mxGetN (m);
     Jc = mxGetJc (m);
     nz = Jc[n];

returns the actual number of non-zero elements stored in the matrix in nz. As the arrays returned by mxGetPr and mxGetPi only contain the non-zero values of the matrix, we also need a pointer to the rows of the non-zero elements, and this is given by mxGetIr. A complete example of the use of sparse matrices in mex-files is given by the file mysparse.c as seen below

     /*
     
     Copyright (C) 2006, 2007 David Bateman
     
     This file is part of Octave.
     
     Octave is free software; you can redistribute it and/or modify it
     under the terms of the GNU General Public License as published by the
     Free Software Foundation; either version 3 of the License, or (at your
     option) any later version.
     
     Octave is distributed in the hope that it will be useful, but WITHOUT
     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
     
     You should have received a copy of the GNU General Public License
     along with Octave; see the file COPYING.  If not, see
     <http://www.gnu.org/licenses/>.
     
     */
     
     #include "mex.h"
     
     void
     mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
     {
       mwSize n, m, nz;
       mxArray *v;
       mwIndex i;
       double *pr, *pi;
       double *pr2, *pi2;
       mwIndex *ir, *jc;
       mwIndex *ir2, *jc2;
       
       if (nrhs != 1 || ! mxIsSparse (prhs[0]))
         mexErrMsgTxt ("expects sparse matrix");
     
       m = mxGetM (prhs [0]);
       n = mxGetN (prhs [0]);
       nz = mxGetNzmax (prhs [0]);
       
       if (mxIsComplex (prhs[0]))
         {
           mexPrintf ("Matrix is %d-by-%d complex sparse matrix", m, n);
           mexPrintf (" with %d elements\n", nz);
     
           pr = mxGetPr (prhs[0]);
           pi = mxGetPi (prhs[0]);
           ir = mxGetIr (prhs[0]);
           jc = mxGetJc (prhs[0]);
     
           i = n;
           while (jc[i] == jc[i-1] && i != 0) i--;
           mexPrintf ("last non-zero element (%d, %d) = (%g, %g)\n", 
                     ir[nz-1]+ 1, i, pr[nz-1], pi[nz-1]);
     
           v = mxCreateSparse (m, n, nz, mxCOMPLEX);
           pr2 = mxGetPr (v);
           pi2 = mxGetPi (v);
           ir2 = mxGetIr (v);
           jc2 = mxGetJc (v);
           
           for (i = 0; i < nz; i++)
             {
               pr2[i] = 2 * pr[i];
               pi2[i] = 2 * pi[i];
               ir2[i] = ir[i];
             }
           for (i = 0; i < n + 1; i++)
             jc2[i] = jc[i];
     
           if (nlhs > 0)
             plhs[0] = v;
         }
       else if (mxIsLogical (prhs[0]))
         {
           bool *pbr, *pbr2;
           mexPrintf ("Matrix is %d-by-%d logical sparse matrix", m, n);
           mexPrintf (" with %d elements\n", nz);
     
           pbr = mxGetLogicals (prhs[0]);
           ir = mxGetIr (prhs[0]);
           jc = mxGetJc (prhs[0]);
     
           i = n;
           while (jc[i] == jc[i-1] && i != 0) i--;
           mexPrintf ("last non-zero element (%d, %d) = %d\n", ir[nz-1]+ 1, 
                     i, pbr[nz-1]);
     
           v = mxCreateSparseLogicalMatrix (m, n, nz);
           pbr2 = mxGetLogicals (v);
           ir2 = mxGetIr (v);
           jc2 = mxGetJc (v);
           
           for (i = 0; i < nz; i++)
             {
               pbr2[i] = pbr[i];
               ir2[i] = ir[i];
             }
           for (i = 0; i < n + 1; i++)
             jc2[i] = jc[i];
     
           if (nlhs > 0)
             plhs[0] = v;
         }
       else
         {
           mexPrintf ("Matrix is %d-by-%d real sparse matrix", m, n);
           mexPrintf (" with %d elements\n", nz);
     
           pr = mxGetPr (prhs[0]);
           ir = mxGetIr (prhs[0]);
           jc = mxGetJc (prhs[0]);
     
           i = n;
           while (jc[i] == jc[i-1] && i != 0) i--;
           mexPrintf ("last non-zero element (%d, %d) = %g\n", ir[nz-1]+ 1, 
                     i, pr[nz-1]);
     
           v = mxCreateSparse (m, n, nz, mxREAL);
           pr2 = mxGetPr (v);
           ir2 = mxGetIr (v);
           jc2 = mxGetJc (v);
           
           for (i = 0; i < nz; i++)
             {
               pr2[i] = 2 * pr[i];
               ir2[i] = ir[i];
             }
           for (i = 0; i < n + 1; i++)
             jc2[i] = jc[i];
     
           if (nlhs > 0)
             plhs[0] = v;
         }
     }