Vivek Subramanian
Vivek Subramanian

Reputation: 1234

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?

Upvotes: 2

Views: 1143

Answers (1)

rahnema1
rahnema1

Reputation: 15837

-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;
} 

Upvotes: 3

Related Questions