Thread Subject: help regarding 2D matrix using c mex file

Subject: help regarding 2D matrix using c mex file

From: oruganti murthy

Date: 17 Aug, 2009 07:59:02

Message: 1 of 11

Hi
I am beginner and learning mex programming in C.
I am trying to read a 2D matrix and print the pythagoras squares.
Thought compiling is successful, MATALB has thrown exception.
Can someone help me please...

thanking you very much,

with regards,
ramana

*********
#include "mex.h"
#include <math.h>

#define OUT plhs[0]
#define SAMPLE double /* define the type used for data samples */

/****************************************************************************/
/* Function Declarations */
/****************************************************************************/
SAMPLE **get_matrix_pointers(int xDim, int yDim, SAMPLE *output);
void release_matrix_pointers(SAMPLE **a);
void py_dist(SAMPLE **a, int xDim, int yDim);

/****************************************************************************/
/* Gateway function and error checking */
/****************************************************************************/
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
   SAMPLE *output, **a;
   int xDim, yDim;
   
   xDim = (int) mxGetM(prhs[0]);
   yDim = (int) mxGetN(prhs[0]);
   /*do the matlab stuff*/
   mexPrintf("x Dimensions = %d.\n",xDim);
   mexPrintf("y Dimensions = %d.\n",yDim);
   OUT = mxCreateDoubleMatrix(yDim, xDim, mxREAL); // mxArray is transpose of c matrix
   output = mxGetPr(OUT);
   a = mxGetPr(prhs[0]);
   
   py_dist(a, xDim, yDim);
   release_matrix_pointers(a);
}

/****************************************************************************/
/* Free the space when we're done (just the array pointers) */
/****************************************************************************/
void release_matrix_pointers(SAMPLE **a)
{
    mxFree(a+1);
}

/****************************************************************************/
/* Fill with pythagorian distances with the nice offset pointers */
/****************************************************************************/
void py_dist(SAMPLE **a, int xDim, int yDim)
{
    int x,y;
    for(x = 1; x<=xDim; ++x)
        for (y = 1; y<=yDim; ++y)
            a[x][y] = sqrt((x*x)+(y*y));
}
************

Subject: help regarding 2D matrix using c mex file

From: Bruno Luong

Date: 17 Aug, 2009 08:18:02

Message: 2 of 11

"oruganti murthy" <omurthy@yahoo.com> wrote in message <h6b2k6$oh2$1@fred.mathworks.com>...

> a = mxGetPr(prhs[0]);
> ...
> void py_dist(SAMPLE **a, int xDim, int yDim)
> ...
> a[x][y] = sqrt((x*x)+(y*y));

I see at least one error. The "a" returned by mxGetPr is double*. It is a double simple-pointer of linear indexing and *not* 2D C-array.

Bruno

Subject: help regarding 2D matrix using c mex file

From: oruganti murthy

Date: 18 Aug, 2009 09:41:02

Message: 3 of 11

Thank you very much Bruno.
I changed it to
****
void py_dist(SAMPLE **a, int xDim, int yDim, SAMPLE **output)
{
    int x,y;
    for(x = 0; x<=xDim; ++x)
        for (y = 0; y<=yDim; ++y)
            *output++ = *a++ ;
}
********
and now I'm able to read the 2D array.
But how to overcome the Transposed form of reading array from MATLAB...?

with regards,
ramana

Subject: help regarding 2D matrix using c mex file

From: Rune Allnor

Date: 18 Aug, 2009 09:56:35

Message: 4 of 11

On 17 Aug, 09:59, "oruganti murthy" <omur...@yahoo.com> wrote:
> Hi
> I am beginner and learning mex programming in C.

If you mean that you learn C by programming MEX files,
then you might consider dropping the MEX interfaces for
now and use a C IDE to learn C on its own terms first.

There are some free IDEs around, like Visual Studio Express
Edition.

Rune

Subject: help regarding 2D matrix using c mex file

From: Bruno Luong

Date: 18 Aug, 2009 09:57:02

Message: 5 of 11

"oruganti murthy" <omurthy@yahoo.com> wrote in message <h6dsve$37p$1@fred.mathworks.com>...
> But how to overcome the Transposed form of reading array from MATLAB...?

I guess you don't have other choice than transposing the matrix - either in C or in Matlab side. The "issue" is due the way Matlab organizes the data. If your function work with the opposite convention then you have convert back and forth.

Bruno

Subject: help regarding 2D matrix using c mex file

From: James Tursa

Date: 18 Aug, 2009 18:48:02

Message: 6 of 11

"oruganti murthy" <omurthy@yahoo.com> wrote in message <h6dsve$37p$1@fred.mathworks.com>...
> Thank you very much Bruno.
> I changed it to
> ****
> void py_dist(SAMPLE **a, int xDim, int yDim, SAMPLE **output)
> {
> int x,y;
> for(x = 0; x<=xDim; ++x)
> for (y = 0; y<=yDim; ++y)
> *output++ = *a++ ;
> }
> ********
> and now I'm able to read the 2D array.
> But how to overcome the Transposed form of reading array from MATLAB...?
>

This doesn't look correct at all. I suspect you still have bugs in the code if this is what you are currently using. Would you mind posting your current complete routine for us to look at?

James Tursa

Subject: help regarding 2D matrix using c mex file

From: oruganti murthy

Date: 19 Aug, 2009 00:35:04

Message: 7 of 11

"James Tursa" <aclassyguy_with_a_k_not_a_c@hotmail.com> wrote in message <h6et12$284$1@fred.mathworks.com>...
> "oruganti murthy" <omurthy@yahoo.com> wrote in message <h6dsve$37p$1@fred.mathworks.com>...
> > Thank you very much Bruno.
> > I changed it to
> > ****
> > void py_dist(SAMPLE **a, int xDim, int yDim, SAMPLE **output)
> > {
> > int x,y;
> > for(x = 0; x<=xDim; ++x)
> > for (y = 0; y<=yDim; ++y)
> > *output++ = *a++ ;
> > }
> > ********
> > and now I'm able to read the 2D array.
> > But how to overcome the Transposed form of reading array from MATLAB...?
> >
>
> This doesn't look correct at all. I suspect you still have bugs in the code if this is what you are currently using. Would you mind posting your current complete routine for us to look at?
>
> James Tursa

Hi all,
Thank you for your different replies.
Sending the transpose of a matrix from MAtlab seems suitable solution to me. Very simple but didn't struck to me. Thank you bruno.
dear James,
Here is the code and the output I've got.
Please let me know if I can improve it any more

*************
#include "mex.h"
#include <math.h>

#define OUT plhs[0]
#define SAMPLE double /* define the type used for data samples */

/****************************************************************************/
/* Function Declarations */
/****************************************************************************/
SAMPLE **get_matrix_pointers(int xDim, int yDim, SAMPLE *output);
void release_matrix_pointers(SAMPLE **a);
void py_dist(SAMPLE **a, int xDim, int yDim);

/****************************************************************************/
/* Gateway function and error checking */
/****************************************************************************/
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
   SAMPLE **output, **a;
   int xDim, yDim;
   
   xDim = (int) mxGetM(prhs[0]);
   yDim = (int) mxGetN(prhs[0]);
   /*do the matlab stuff*/
   mexPrintf("x Dimensions = %d.\n",xDim);
   mexPrintf("y Dimensions = %d.\n",yDim);
   OUT = mxCreateDoubleMatrix(yDim, xDim, mxREAL); // mxArray is transpose of c matrix
   output = mxGetPr(OUT);
   a = mxGetPr(prhs[0]);
   
   py_dist(a, xDim, yDim, output);
   release_matrix_pointers(a);
}

/****************************************************************************/
/* Free the space when we're done (just the array pointers) */
/****************************************************************************/
void release_matrix_pointers(SAMPLE **a)
{
    mxFree(a+1);
}

/****************************************************************************/
/* Fill with pythagorian distances with the nice offset pointers */
/****************************************************************************/
void py_dist(SAMPLE **a, int xDim, int yDim, SAMPLE **output)
{
    int x,y;
    for(x = 0; x<=xDim; ++x)
        for (y = 0; y<=yDim; ++y)
            *output++ = *a++ ;
}
%%%%%%%%%%%%%%%%%



with regards,
ramana
>> mex Demo3.c
>> a = [1 2 3; 3 4 5];
>> Demo3(a)
x Dimensions = 2.
y Dimensions = 3.

ans =

     1 4
     3 3
     2 5

Subject: help regarding 2D matrix using c mex file

From: James Tursa

Date: 19 Aug, 2009 07:52:01

Message: 8 of 11

"oruganti murthy" <omurthy@yahoo.com> wrote in message <h6fhbo$l34$1@fred.mathworks.com>...
>
> Here is the code and the output I've got.
> Please let me know if I can improve it any more

The code has some very serious errors. I am surprised you got anything reasonable for output. It corrupts memory and crashes my machine. Here are my comments:

>
> *************
> #include "mex.h"
> #include <math.h>
>
> #define OUT plhs[0]
> #define SAMPLE double /* define the type used for data samples */
>
> /****************************************************************************/
> /* Function Declarations */
> /****************************************************************************/
> SAMPLE **get_matrix_pointers(int xDim, int yDim, SAMPLE *output);

Can't comment on this one since you didn't show the code for this function. But I strongly suspect that it is incorrect based on your SAMPLE ** return type. See discussion below.

> void release_matrix_pointers(SAMPLE **a);

Get rid of this ... see comments below.

> void py_dist(SAMPLE **a, int xDim, int yDim);

This prototype doesn't match your function. The prototype has only three arguments, while your function definition has four. You would have seen a compiler warning had you used the -v option with the mex command. Also, based on your intended usage there are too many levels of indirection for "a".

> /****************************************************************************/
> /* Gateway function and error checking */
> /****************************************************************************/
> void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
> {

Note that the prhs points to a const mxArray ... i.e. it is intended to be read-only.

> SAMPLE **output, **a;

No, this is bad. These are being used as pointers to data areas, so there should only be a single level of indirection. i.e., the mxGetPr returns a double *, not a double **. So you should have this instead:

SAMPLE *output, *a;

> int xDim, yDim;
>
> xDim = (int) mxGetM(prhs[0]);
> yDim = (int) mxGetN(prhs[0]);

Moot point for most inputs, but be advised that later versions of MATLAB the return type of mxGetM and mxGetN is not int but mwSize, which may be an unsigned int. So if you happen to get a very large matrix as input that has a size larger than the largest int, the result of these lines will overflow the int and produce implementation dependent results. On 2's complement machines, that usually means modulo result, meaning the overflow will wrap around to negative values and you will end up with xDim and yDim being negative. Better to stick with the return type of these functions. e.g.,

    mwSize xDim, yDim;
    xDim = mxGetM(prhs[0]);
    yDim = mxGetN(prhs[0]);

> /*do the matlab stuff*/
> mexPrintf("x Dimensions = %d.\n",xDim);
> mexPrintf("y Dimensions = %d.\n",yDim);

And if you make the change to mwSize above, then use an unsigned int format here. e.g., %u instead of %d.

> OUT = mxCreateDoubleMatrix(yDim, xDim, mxREAL); // mxArray is transpose of c matrix

I think you missed the point about the transpose stuff. In MATLAB, memory for a 2D array is stored in column order, whereas in C memory for a 2D matrix is stored in row order. So if you take a 2x3 matrix from MATLAB and do a block memory copy into a matrix in C and want to access the elements in C using the [ ][ ] notation, you need to treat the C variable as a 3x2 matrix that is the transpose of the MATLAB matrix. My advice is to not use the [ ][ ] notation. Just use a double * and do your own indexing calculations to match the MATLAB column ordering of the data. It is easier to keep things straight in your code this way, and avoids the extra code needed to set up the [ ][ ] access syntax. So no need to switch xDim and yDim.

> output = mxGetPr(OUT);
> a = mxGetPr(prhs[0]);
> py_dist(a, xDim, yDim, output);

More arguments than prototype as mentioned above.

> release_matrix_pointers(a);

This is very bad. You should *never* free anything associated with an input mxArray such as prhs[0]. In this case, you are passing the result of the a = mxGetPr(prhs[0]) to your routine and then subsequently calling free(a+1). First, a+1 is an invalid address to pass back to free so the result of the free(a+1) call is undefined. Not sure what you intended here. Maybe nothing bad will happen, or maybe corrupt memory and program crash. 2nd, as pointed out above, you shouldn't be doing this anyway since "a" is associated with a const (i.e., intended to be read-only) input. Get rid of this line.

/****************************************************************************/
> /* Free the space when we're done (just the array pointers) */
> /****************************************************************************/
> void release_matrix_pointers(SAMPLE **a)
> {
> mxFree(a+1);
> }

Get rid of this routine.

/****************************************************************************/
> /* Fill with pythagorian distances with the nice offset pointers */
> /****************************************************************************/
> void py_dist(SAMPLE **a, int xDim, int yDim, SAMPLE **output)
> {
> int x,y;
> for(x = 0; x<=xDim; ++x)
> for (y = 0; y<=yDim; ++y)
> *output++ = *a++ ;
> }

This is amazing, at least to me, that it worked as well as it did. You are passing in a (double *), recast as a (double **). Then this line does a single dereference and copy:

> *output++ = *a++ ;

The result of the *output operation is a (double *) type. So you are doing this type assignment:

    (double *) = (double *);

i.e., you are assigning a double * to another double *, even though the underlying data is double, not double *. So it seems to me that an incorrect number of bytes is being copied, and as an incorrect type to boot. Here is what you should be doing (getting rid of one level of indirection on "a" and "output"):

 void py_dist(SAMPLE *a, int xDim, int yDim, SAMPLE *output)
 {
     int x,y;
     for(x = 0; x<=xDim; ++x)
         for (y = 0; y<=yDim; ++y)
             *output++ = *a++ ;
 }

Finally, if you are just doing an element-by-element calculation, it is easier to use mxGetNumberOfElements and use a single for loop to access all the elements linearly.

James Tursa

Subject: help regarding 2D matrix using c mex file

From: oruganti murthy

Date: 20 Aug, 2009 08:41:03

Message: 9 of 11

Dear James,
Thank you very much for your detailed steps.
I have made the changes and here is the output I obtained.
I actually wanted my output (for some later computations in C) the *output to be format output[][]. How can I obtain that?


with regards,
ramana
*********
#include "mex.h"
#include <math.h>

#define OUT plhs[0]
void py_dist(double *a, mwSize xDim, mwSize yDim, double *output) {
    int x, y;
    for(x = 0; x<=xDim; ++x)
        for (y = 0; y<=yDim; ++y)
        { double t = *a++;
          *output++ = t*t;
        }
}

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) {
    double *output, *a;
    mwSize xDim, yDim;
    
    xDim = mxGetM(prhs[0]);
    yDim = mxGetN(prhs[0]);
    /*do the matlab stuff*/
    mexPrintf("x Dimensions = %u.\n", xDim);
    mexPrintf("y Dimensions = %u.\n", yDim);
    OUT = mxCreateDoubleMatrix(xDim, yDim, mxREAL); // mxArray is transpose of c matrix
    output = mxGetPr(OUT);
    a = mxGetPr(prhs[0]);
    py_dist(a, xDim, yDim, output);
}
********
>> mex Demo3.c
>> a = [1 2 3; 3 4 5];
>> Demo3(a)
x Dimensions = 2.
y Dimensions = 3.

ans =

     1 4 9
     9 16 25

Subject: help regarding 2D matrix using c mex file

From: Bruno Luong

Date: 20 Aug, 2009 09:18:18

Message: 10 of 11

"oruganti murthy" <omurthy@yahoo.com> wrote in message <h6j26v$n34$1@fred.mathworks.com>...
> Dear James,
> Thank you very much for your detailed steps.
> I have made the changes and here is the output I obtained.
> I actually wanted my output (for some later computations in C) the *output to be format output[][]. How can I obtain that?

C-2D are pointer array (level1) of pointers (level2); each of the pointer (level2) is 1D array.

So if you want to convert Matlab linear indexing array to C 2D-array you need to do the following.

- Allocate an array of pointers (level1) of the length equal to the number of (Matlab) columns in the data.
- Assign the value of each jth pointer element (level2) as the address of the first element of column #j.

After using it, don't forget to free the array level1.

Remember, C and Matlab arrays are transposed to each other.

Try this:

% On Matlab command line:

mex c2d.c
c2d([1 2 3; 4 5 6]);

/* Mex test program c2d.c */
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
{
    double **Carray;
    double *data;
    mwSize m, n, i, j;
    
    data = mxGetPr(prhs[0]);
    m = mxGetM(prhs[0]);
    n = mxGetN(prhs[0]);
    
    /* Create C 2D array */
    Carray = mxCalloc(n, sizeof(double*));
    for (j=0; j<n; j++)
        Carray[j] = data+m*j;
    
    /* Use it */
    for (i=0; i<m; i++)
        for (j=0; j<n; j++)
            mexPrintf("data(%i,%i) = %f\n", i+1, j+1, Carray[j][i]);
   
    mxFree(Carray);
    
    return;
}

/* Bruno

Subject: help regarding 2D matrix using c mex file

From: oruganti murthy

Date: 20 Aug, 2009 09:37:02

Message: 11 of 11

Hi Bruno,
Excellent code!
I got
********
>> mex c2d.c
>> c2d([1 2 3; 4 5 6]);
data(1,1) = 1.000000
data(1,2) = 2.000000
data(1,3) = 3.000000
data(2,1) = 4.000000
data(2,2) = 5.000000
data(2,3) = 6.000000
*******
Thank you very much. It serves my purpose.


with regards,
ramana

Tags for this Thread

Everyone's Tags:

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Tag Activity for This Thread
Tag Applied By Date/Time
mex code Sprinceana 19 Aug, 2009 04:03:13
source code mex Sprinceana 19 Aug, 2009 04:03:13
c Sprinceana 19 Aug, 2009 04:03:02
mex programming Sprinceana 19 Aug, 2009 04:03:02
rssFeed for this Thread

Contact us at files@mathworks.com