Search code examples
c++arraysmatlabindexingmex

Indexing and accessing elements of cell arrays and matrices in mex functions


I'm trying to write a C++ mex function to iterate through a cell array of matrices, each matrix of which is a different size. In Matlab, I could do this using the following code:

function Z = myFunction(X, Z, B)

for i = 1:size(X, 1)
    for j = 1:size(X, 2)
        for k = 1:size(X, 3)
            temp = X{i, j, k};
            for m = 1:size(temp, 1)
                Z{temp(m, 1)}(temp(m, 2)) = Z{temp(m, 1)}(temp(m, 2)) + B(i, j, k);
            end
        end
    end
end

Here X is a 3-dimensional cell array, where each cell contains a matrix with a variable number of rows and 2 columns. These two columns allow me to index another cell array of vectors Z, where each vector is of different length. Elements of vectors in Z that are indexed are incremented by elements from a 3-dimensional matrix B.

So far, I have the following code in C++ (I have never coded in C++ before):

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    const mxArray* X = prhs[0];
    const mxArray* Z = prhs[1];
    const mxArray* B = prhs[2];

    const int* pDims = mxGetDimensions(X);

    mwSize nsubs = mxGetNumberOfDimensions(X);

    for (size_t i = 0; i < pDims[0]; i++) {
        for (size_t j = 0; j < pDims[1]; j++) {
            for (size_t k = 0; k < pDims[2]; k++) {
                int subs [] = {i, j, k};
                mxArray* temp = mxGetCell(X, mxCalcSingleSubscript(X, nsubs, subs));

                const int* matDims = mxGetDimensions(temp);
                for (size_t m = 0; m < matDims[0]; m++) {

                }
            }
        }
    }
}

Questions:

  1. To access elements of the matrix B, can I use the same mxCalcSingleSubscript function as I did to access elements of the cell array X? If not, how do I do this?
  2. How do I access elements of temp and perform the indexing as I have done in the Matlab code?

Solution

  • -Since all input arrays are const you should make a copy of Z.

    -mxCalcSingleSubscript can be used for any type of array including cell arrays. Here I renamed it to sub2ind.

    -mxGetPr is used to access elements of an array .

    Here is an implementation (hasn't been tested on real data):

    #include "mex.h"
    #define sub2ind mxCalcSingleSubscript
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
    {
        const mxArray* X = prhs[0];
        const mxArray* Z = prhs[1];
        const mxArray* B = prhs[2];
        mxArray * out = mxDuplicateArray (Z);
        const int* pDims = mxGetDimensions(X);
    
        mwSize nsubs = mxGetNumberOfDimensions(X);
        double* B_arr = mxGetPr(B);
        for (size_t i = 0; i < pDims[0]; i++) {
            for (size_t j = 0; j < pDims[1]; j++) {
                for (size_t k = 0; k < pDims[2]; k++) {
                    int subs [] = {i, j, k};
                    mwIndex  idx = sub2ind(X, nsubs, subs);
                    mxArray* temp = mxGetCell(X, idx);
                    double* temp_arr = mxGetPr(temp);
    
                    const int* matDims = mxGetDimensions(temp);
                    mwSize nsubs_temp = mxGetNumberOfDimensions(temp);
                    for (size_t m = 0; m < matDims[0]; m++) {
                        int subs_out_1 [] = {m,0};
                        int subs_out_2 [] = {m,1};
                        mwIndex temp_m_1 = temp_arr[sub2ind(temp, nsubs_temp, subs_out_1)]-1;
                        mwIndex temp_m_2 = temp_arr[sub2ind(temp, nsubs_temp, subs_out_2)]-1;
                        double* Z_out = mxGetPr (mxGetCell(out,temp_m_1));
                        Z_out[temp_m_2] += B_arr[idx];
                    }
                }
            }
        }
        plhs[0] = out;
    }
    

    However both MATLAB and c implementations can be changed to use linear indexing:

    function Z = myFunction(X, Z, B)
        for k = 1:numel(X)
            for m = 1:size(X{k}, 1)
                Z{X{k}(m, 1)}(X{k}(m, 2)) = Z{X{k}(m, 1)}(X{k}(m, 2)) + B(k);
            end
        end
    end
    
    
    #include "mex.h"
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
    {
        const mxArray* X = prhs[0];
        const mxArray* Z = prhs[1];
        const mxArray* B = prhs[2];
        mxArray * out = mxDuplicateArray (Z);
    
        mwSize n_X = mxGetNumberOfElements(X);
        double* B_arr = mxGetPr(B);
        for (size_t k = 0; k < n_X; k++) {
            mxArray* temp = mxGetCell(X, k);
            double* temp_arr = mxGetPr(temp);
    
            const int* matDims = mxGetDimensions(temp);
            size_t rows = matDims[0];
            for (size_t m = 0; m < rows; m++) {
                mwIndex temp_m_1 = temp_arr[m]-1;
                mwIndex temp_m_2 = temp_arr[m+rows]-1;
                double* Z_out = mxGetPr (mxGetCell(out,temp_m_1));
                Z_out[temp_m_2] += B_arr[k];
            }
        }
        plhs[0] = out;
    }