Sparse Matrices with Mex-Files (GNU Octave (version 9.0.90))

#### 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 implementations sparse matrices are required to be two-dimensional. The only difference of importance to the programmer is that the real and imaginary parts of the matrix are stored separately.

The mex-file interface, in addition to using `mxGetM`, `mxGetN`, `mxSetM`, `mxSetN`, `mxGetPr`, `mxGetPi`, `mxSetPr`, and `mxSetPi`, also supplies the following 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 nonzero 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 nonzero 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 nonzero elements stored in the matrix in `nz`. As the arrays returned by `mxGetPr` and `mxGetPi` only contain the nonzero values of the matrix, we also need a pointer to the rows of the nonzero 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` shown below.

    #include "mex.h"

    void
    mexFunction (int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
    {
      mwSize m, n, nz;
      mxArray *v;
      mwIndex i;
      double *pr, *pi;
      double *pr2, *pi2;
      mwIndex *ir, *jc;
      mwIndex *ir2, *jc2;

      if (nrhs != 1 || ! mxIsSparse (prhs[0]))
        mexErrMsgTxt ("ARG1 must be a 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 nonzero 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]))
        {
          mxLogical *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 nonzero 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 nonzero 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;
        }
    }

A sample usage of `mysparse` is

    sm = sparse ([1, 0; 0, pi]);
    mysparse (sm)
    ⇒
    Matrix is 2-by-2 real sparse matrix with 2 elements
    last nonzero element (2, 2) = 3.14159