Reputation: 21
I need create a Matlab mex function that will take an input matrix and return the matrix diagonal.
Input:
1 2 3
4 5 6
Expected output:
1 2 3 0 0 0
0 0 0 4 5 6
My problem is that since Matlab reads matrices column-wise instead of row-wise, my mex function gives the wrong output.
Current output:
1 4 0 0 0 0
0 0 2 5 0 0
0 0 0 0 3 6
How would you go about changing my code to read the input matrix row-wise so I can have the proper output?
My code is as follows:
#include <matrix.h>
#include <mex.h>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
mxArray *a_in, *b_out;
const mwSize *dims;
double *a, *b;
int rows, cols;
// Input array:
a_in = mxDuplicateArray(prhs[0]);
// Get dimensions of input array:
dims = mxGetDimensions(prhs[0]);
rows = (int) dims[0];
cols = (int) dims[1];
// Output array:
if(rows == cols){
b_out = plhs[0] = mxCreateDoubleMatrix(rows, rows*cols, mxREAL);
}
else{
b_out = plhs[0] = mxCreateDoubleMatrix(cols, rows*cols, mxREAL);
}
// Access the contents of the input and output arrays:
a = mxGetPr(a_in);
b = mxGetPr(b_out);
// Compute exdiag function of the input array
int count = 0;
for (int i = 0; i < rows; i++) {
for(int j = 0; j<cols;j++){
if(rows == cols){
b[rows*count+count/rows] = a[j + rows * i];
count++;
}
else if(rows < cols){
b[cols*count+count/rows] = a[j + cols * i];
count++;
}
else if(rows>cols){
b[cols*count+count/rows] = a[j + cols * i];
count++;
}
}
}
}
Upvotes: 1
Views: 556
Reputation: 60615
Inside your loops, i
is the row index and j
is the column index. You do a[j + rows * i]
, mixing up the two indices. MATLAB stores data column-wise, so you need to do a[i + rows * j]
to read the input matrix correctly.
For indexing the output, you want the row to remain i
, and you want the column to be i * cols + j
:
b[i + rows * (i * cols + j)] = a[i + rows * j];
Note that you don't need to do a_in = mxDuplicateArray(prhs[0])
, since you are not writing into a_in
. You can directly access the prhs[0]
matrix, or do a_in = prhs[0]
if you want an alias.
Also, casting array sizes to int
will cause trouble if the array is very large. It is best to use mwSize
and mwIndex
for array sizes and indices.
Finally, you should always check the type of the input array, if you are given an array that is not doubles, you will likely cause a read out of bounds error.
This is my code:
#include <matrix.h>
#include <mex.h>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
mwSize const* dims;
double *a, *b;
mwSize rows, cols;
if (!mxIsDouble(prhs[0])) {
mexErrMsgTxt("Input must be doubles");
}
// Get dimensions of input array:
dims = mxGetDimensions(prhs[0]);
rows = dims[0];
cols = dims[1];
// Output array:
plhs[0] = mxCreateDoubleMatrix(rows, rows*cols, mxREAL);
// Access the contents of the input and output arrays:
a = mxGetPr(prhs[0]);
b = mxGetPr(plhs[0]);
// Compute exdiag function of the input array
for (mwIndex i = 0; i < rows; i++) {
for (mwIndex j = 0; j < cols; j++) {
b[i + rows * (i * cols + j)] = a[i + rows * j];
}
}
}
Upvotes: 1