Sparse Matrices with Mex-Files - Untitled
Description: Untitled

Next: Calling Other Functions in Mex-Files, 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;
             }
         }