Create mex file

Hi

I am using Octave-6.4.0 with my lapop which runs in Windows 8.1.
I would like to create a mex file from C and C++ files but we are getting the folowwing warning

>> mkoctfile --mex sobolseqDS.c
sobolseqDS.c: In function 'mexFunction':
sobolseqDS.c:41:8: warning: assignment to 'long unsigned int *' from incompatible pointer type 'double *' [-Wincompatible-pointer-types]
   41 |  shift = mxGetPr(prhs[2]);

and when we call the function with Octave, it is crashing. The mex file seems to be working file in Matlab.
Don’t really know if it is an issue with Octave or I do something wrong.
Can you help?

If you need more information, please don’t hesitate to contact me.
Thank you in advance if you can help!

Please see below the mexFunction:

void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
{ 
    double	*vect; 
    int		dim; 
    long		cnt; 
	unsigned long *shift;
        
    if (nrhs != 3) 
        mexErrMsgTxt("Three input arguments required."); 
    cnt = mxGetScalar(prhs[0]); 
    dim = mxGetScalar(prhs[1]);
	shift = mxGetPr(prhs[2]);
	

    plhs[0] = mxCreateDoubleMatrix(1, dim, mxREAL); 
    vect = mxGetPr(plhs[0]);
	
    SobolSeqDS(cnt, dim, shift, vect);
    return;
}

Hi Julien.

I think the issue is because you’re assigning a long int pointer to a double pointer.
double* mxGetPr(mxArray) is taking a mxArray and returning a double pointer, consider
to cast the values or change the type of shift.

void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
{
double *vect;
int dim;
long cnt;
double *shift;

if (nrhs != 3) 
    mexErrMsgTxt("Three input arguments required."); 
cnt = mxGetScalar(prhs[0]); 
dim = mxGetScalar(prhs[1]);
shift = mxGetPr(prhs[2]);


plhs[0] = mxCreateDoubleMatrix(1, dim, mxREAL); 
vect = mxGetPr(plhs[0]);

SobolSeqDS(cnt, dim, shift, vect);
return;

}

Regards

2 Likes

Hi Yassin

Thank you very much for your suggestion! I did a change similar to what you proposed (see below). Indeed the C function SobolSeqDS() is taking
an unsigned long * as its third argument. Now there is no warning. But the call from Octave of the function SobolSeqDS() in a for loop is still crashing. My friend, who uses Matlab, has his code running smoothly.
So we will continue the investigation.

Thank you and will keep you updated.

void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
{ 
    double	*vect; 
    int		dim; 
    long		cnt; 
	unsigned long *shift;
        
    if (nrhs != 3) 
        mexErrMsgTxt("Three input arguments required."); 
    cnt = mxGetScalar(prhs[0]); 
    dim = mxGetScalar(prhs[1]);
    shift = (unsigned long *) mxGetPr(prhs[2]);
	

    plhs[0] = mxCreateDoubleMatrix(1, dim, mxREAL); 
    vect = mxGetPr(plhs[0]);
	
    SobolSeqDS(cnt, dim, shift, vect);
    return;
}

What is the actual type of your third input argument? Afaict, casting a double * to unsigned int* probably doesn’t do what you expect. (Maybe that is compiler dependent.)
See also: Question about assigning prhs to an int * in a mex file. -

1 Like

Agree to @mmuetzel , it might be luck that the code with implicit type cast (double to unsigned long) works under Matlab with whatsoever compiler and might break with another Matlab/compiler version.

If the array prhs[2] a.k.a. shift is not large, a safe option is to copy the data with an appropriate explicit typecast and it will work with every compiler.

@julien: This question is critical. What is the function prototype for sobolseqDS in the file sobolseqDS.c? You can just copy and paste that information into a thread here, but make sure you use three backticks ``` before and after the code so that it isn’t misinterpreted.

Hi everybody

Thank you very much for all your support and ideas!
I did try with

shift = (unsigned long *) mxGetData(prhs[2]);

and it is crashing.
My friend will try to modify the c function itself. I will keep you updated.

To answer @mmuetzel question, please see below the prototype and definition of the SobolSeqDS() C function:

int SobolSeqDS(long cnt, int ndim, unsigned long *shift, double *SobolSeqVector)
{
    const double scale = 4294967296.0;      // 2^32

    if ((unsigned int)cnt > sobolseq_max_number || (unsigned int)cnt < 0 || (unsigned int)ndim > max_dimension || ndim < 1) return -1;

    if (SobolSeq8192(cnt, ndim, SobolSeqVector) != 0) return -1;

    for (int dim = 0; dim <= ndim; ++dim)
    {
        unsigned long val = (unsigned long)(scale * SobolSeqVector[dim]);
        val ^= shift[dim];
        SobolSeqVector[dim] = (double)val / scale;
    }

    return 0;
};

Sorry, I was unclear before. I actually meant to ask for the type of the third input argument in Octave. Is it double or uint32 or something else?

Unfortunately you are running into basic C language behavior. The function mxGetData returns a pointer to type double. The function SobolSeqDS is expecting a pointer to type unsigned long. The line

shift = (unsigned long *) pointer_variable

tells the compiler to pretend that the pointer points to unsigned long. However, the actual values in memory are still double values (taking up 8 bytes and organized according to IEEE-754 standard).

Either you need to convert each value from double to an integer type or you should start with an integer type. For example, mxGetUint64s instead of mxGetPr will return a pointer to a 64-bit unsigned integer.

mmuetzel was interested in how you are calling your MEX function from Octave because you should also be passing integers, not doubles, to this routine for the third argument.

EDIT: I would also add more input validation to your MEX function. One reason to avoid coding outside the Octave interpreter is that your code can very easily crash itself and the entire Octave interpreter causing data loss, lost time by users, etc. One mitigating strategy is to never assume anything about your inputs, but rather check that they are what they need to be for your function to work before executing the function.

In this case, you check that the number of calling arguments is correct which is a step in the right direction.

    if (nrhs != 3) 
        mexErrMsgTxt("Three input arguments required."); 

But you should also check that the type is correct. Functions like mxIsDouble or mxIsUint64 could be helpful here.

1 Like

Hello everybody

Thank you for all your support!
Indeed it was an error from our side. Very sorry.
In the code above,

it was

for (int dim = 0; dim <= ndim ; ++dim)

and it should be

for (int dim = 0; dim < ndim ; ++dim)

Now with the explicit cast

shift = (unsigned long *) mxGetPr(prhs[2]);

we can create the MEX file without warning and the code is running!

To answer @mmuetzel question, please see the code below on how the MEX function is called in our example. From my understanding the shift variable is of type double because it is defined as shift = zeros(dim, 1);

clear all;
clear sobolseqDS;
clc;
% Number of points
j=6;
N=2^j;

% dimension
dim=3;
% Number of replikas
Nrepl=1;

% skip a non-negative integer.
% We skip that many points in the sequence from the start.
skip = 0; 

%imax = 4294967296;
imax = intmax('uint32');

shift = zeros(dim, 1);
x_shift = zeros(N,dim);
for r=1:Nrepl
% currently no handle to fix seed
   for i_d=1:dim
    shift(i_d) = randi(imax,'uint32'); 
   end
   
   for i=1:N
        x_shift(i,:) = sobolseqDS(i-1,dim, shift);
		%r = sobolseqDS(i-1,dim, shift)
		i
   end
end

Sorry, let me re-past the code below properly

clear all;
clear sobolseqDS;
clc;
% Number of points
j=6;
N=2^j;

% dimension
dim=3;
% Number of replikas
Nrepl=1;

% skip a non-negative integer.
% We skip that many points in the sequence from the start.
skip = 0; 

%imax = 4294967296;
imax = intmax('uint32');

shift = zeros(dim, 1);
x_shift = zeros(N,dim);
for r=1:Nrepl
% currently no handle to fix seed
   for i_d=1:dim
    shift(i_d) = randi(imax,'uint32'); 
   end
   
   for i=1:N
        x_shift(i,:) = sobolseqDS(i-1,dim, shift);
   end
end