Using Eigen in MATLAB MEX - matlab

I have encountered an issue when using Eigen in MATLAB MEX files.
Consider this excerpt of code, in which I call a mex function to create an object of the class vars. The class has an integer N, an integer S, and two Eigen arrays.
//constructMat.cpp
class vars {
public:
int N
int S
Eigen::ArrayXd upperLims
Eigen::ArrayXd lowerLims
stateVars (double *, double *, double *)
};
stateVars::stateVars (double *upperInput, double *lowerInput, double *gridInput)
Eigen::ArrayXd upper; upper = Eigen::Map<Eigen::VectorXd>(upperInput, sizeof(*upperInput),1);
Eigen::ArrayXd lower; lower = Eigen::Map<Eigen::VectorXd>(lowerInput, sizeof(*lowerInput),1);
Eigen::ArrayXd gridSizes; gridSizes = Eigen::Map<Eigen::VectorXd>(gridInput, sizeof(*gridInput),1);
upperLims = upper;
lowerLims = lower;
N = upperLims.size();
S = gridSizes.prod();
}
//MEX CODE
void
mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
//....checks to make sure the inputs are okay...
double* upper = mxGetPr(prhs[0]);
double* lower = mxGetPr(prhs[1]);
double* grids = mxGetPr(prhs[2]);
stateVars stateSpace(upper, lower, grids);
mexPrintf("N =%f \n\n", stateSpace.N );
mexPrintf("S =%f \n\n", stateSpace.S );
}
However, when I execute the function, I call constructMat([7.0, 8.0, 9.0], [4.0, 2.0, 3.0], [10, 10, 10]), and I expect mexPrintf("N =%f \n\n", stateSpace.N ) to yield 3 since the array upperLims only has three elements. However, it yields 7. Similarly, I expect mexPrintf("S =%f \n\n", stateSpace.S ) to yield 10^3 = 1000, but it yields 7 as well. I'm not sure what I did wrong. The mex file was compiled successfully.
Also, if I call mexPrintf("upperlims =%f \n\n",stateSpace.upperLims(0) ), i.e. printing out the first element of the Eigen array upperLims, it gives me the right number. Does it have something to do with the method .size() and .prod()?

Related

Extracting data from a matlab struct in mex

I'm following this example but I'm not sure what I missed. Specifically, I have this struct in MATLAB:
a = struct; a.one = 1.0; a.two = 2.0; a.three = 3.0; a.four = 4.0;
And this is my test code in MEX ---
First, I wanted to make sure that I'm passing in the right thing, so I did this check:
int nfields = mxGetNumberOfFields(prhs[0]);
mexPrintf("nfields =%i \n\n", nfields);
And it does yield 4, since I have four fields.
However, when I tried to extract the value in field three:
tmp = mxGetField(prhs[0], 0, "three");
mexPrintf("data =%f \n\n", (double *)mxGetData(tmp) );
It returns data =1.000000. I'm not sure what I did wrong. My logic is that I want to get the first element (hence index is 0) of the field three, so I expected data =3.00000.
Can I get a pointer or a hint?
EDITED
Ok, since you didn't provide your full code but you are working on a test, let's try to make a new one from scratch.
On Matlab side, use the following code:
a.one = 1;
a.two = 2;
a.three = 3;
a.four = 4;
read_struct(a);
Now, create and compile the MEX read_struct function as follows:
#include "mex.h"
void read_struct(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 1)
mexErrMsgTxt("One input argument required.");
/* Let's check if the input is a struct... */
if (!mxIsStruct(prhs[0]))
mexErrMsgTxt("The input must be a structure.");
int ne = mxGetNumberOfElements(prhs[0]);
int nf = mxGetNumberOfFields(prhs[0]);
mexPrintf("The structure contains %i elements and %i fields.\n", ne, nf);
mwIndex i;
mwIndex j;
mxArray *mxValue;
double *value;
for (i = 0; i < nf; ++i)
{
for (j = 0; j < ne; ++j)
{
mxValue = mxGetFieldByNumber(prhs[0], j, i);
value = mxGetPr(mxValue);
mexPrintf("Field %s(%d) = %.1f\n", mxGetFieldNameByNumber(prhs[0],i), j, value[0]);
}
}
return;
}
Does this correctly prints your structure?

QR factorization from lapack subroutine dgeqrf not working in C

I want to find diagonal elements of R matrix obtained from QR-decomposition of A matrix as A=QR using lapack. I tried lapack dgeqrf subroutine but it is giving back the same matrix A i.e. input and output matrices are same. How to find R matrix and its diagonals ? I can't figure out what is going wrong with this code. I am programming in C.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void dgeqrf_(int *rows, int *cols, double *matA, int *LDA, double *TAU, double *WORK, int *LWORK, int *INFO);
int main()
{
int rows=3;
int cols=3;
double *matA=malloc(sizeof(double)*rows*cols);
matA[0]=10;
matA[1]=20;
matA[2]=10;
matA[3]=40;
matA[4]=20;
matA[5]=50;
matA[6]=70;
matA[7]=30;
matA[8]=20;
for(int i=0; i<rows*cols; i++)
{
printf("%f ",matA[i]);
}
printf("\n");
int LDA=rows;
int INFO;
double *WORK=malloc(sizeof(double)*2);
int LWORK=-1;
int rowcolmin=rows;
if(rowcolmin>cols)
{
rowcolmin=cols;
}
double *TAU=malloc(sizeof(double)*rowcolmin);
dgeqrf_(&rows, &cols, matA, &LDA, TAU, WORK, &LWORK, &INFO);
for(int i=0; i<rows*cols; i++)
{
printf("%f ",matA[i]);
}
printf("\n");
free(WORK);
free(TAU);
free(matA);
return 0;
}
The matrix matA is not modified because LAPACK's dgeqrf() is called using a value of -1 for the argument LWORK. This correspond to a workspace query:
If LWORK = -1, then a workspace query is assumed; the routine
only calculates the optimal size of the WORK array, returns
this value as the first entry of the WORK array, and no error
message related to LWORK is issued by XERBLA.
Indeed, the usual way to use dgeqrf() and many other routines from LAPACK is to call them twice: once for the workspace query and once for the actual computation of the result. For instance, the C interface to LAPACK wraps dgeqrf() in lapacke__dgeqrf(), which calls lapacke__dgeqrf_work() twice for this very reason.
Here is how your code could be modified:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void dgeqrf_(int *rows, int *cols, double *matA, int *LDA, double *TAU, double *WORK, int *LWORK, int *INFO);
int main()
{
int i;
int rows=3;
int cols=3;
double *matA=malloc(sizeof(double)*rows*cols);
matA[0]=1;
matA[1]=2;
matA[2]=4;
matA[3]=1;
matA[4]=3;
matA[5]=9;
matA[6]=1;
matA[7]=4;
matA[8]=16;
for(i=0; i<rows*cols; i++)
{
printf("%f ",matA[i]);
}
printf("\n");
int LDA=rows;
int INFO;
int rowcolmin=rows;
if(rowcolmin>cols)
{
rowcolmin=cols;
}
double *TAU=malloc(sizeof(double)*rowcolmin);
int LWORK=-1;
// since the value of LWORK is -1, this is a workspace query.
// it only return the optimum size of work in work[0].
double lwork2;
dgeqrf_(&rows, &cols, matA, &LDA, TAU, &lwork2, &LWORK, &INFO);
// allocate work using the optimal size
int lwork3=(int)lwork2;
double *WORK=malloc(sizeof(double)*lwork3);
// perform the QR factorization
dgeqrf_(&rows, &cols, matA, &LDA, TAU, WORK, &lwork3, &INFO);
if(INFO !=0){fprintf(stderr,"QR factorization failed, error code %d\n",INFO);exit(1);}
for(i=0; i<rows*cols; i++)
{
printf("%f ",matA[i]);
}
printf("\n");
// for instance, the determinant is...
if(cols==rows){
// det of R
double det=1;
for (i=0;i<cols;i++){
det*=matA[i*cols+i];
}
// det of Q, Householder algorithm
if(cols%2==0){
det*=-1;
}
printf("det is %g\n",det);
}
free(WORK);
free(TAU);
free(matA);
return 0;
}
It is compiled by gcc main.c -o main -llapack -lblas -lm.
Given the question you asked, entitled compute determinant from LU decomposition in lapack , the computation of the determinant is added at the end of the code. The matrix matA is now a Vandermonde matrix, so as to easily check the correctness of the result.

In mex file, I can't overwrite scalar through the pointer in matlab2016a, although I can overwrite the scalar in 2013a and also the array in 2016a

[environment]
OS: OSX10.11 and maxOS Sierra(10.12)
MATLAB: matlab2013a and matlab2016a
Xcode: xcode7 and xcode8
In my work, I must use the following mex file in the old package.
//destructiveMatrixWriteAtIndices.c
//------------------------------------------------------
#include <matrix.h> /* Matlab matrices */
#include <mex.h>
#include <stddef.h> /* NULL */
#define notDblMtx(it) (!mxIsNumeric(it) || !mxIsDouble(it) || mxIsSparse(it) || mxIsComplex(it))
void mexFunction(int nlhs, /* Num return vals on lhs */
mxArray *plhs[], /* Matrices on lhs */
int nrhs, /* Num args on rhs */
const mxArray *prhs[] /* Matrices on rhs */
)
{
double *mtx;
double *newValues;
double *doubleStartIndex;
int i, startIndex, size;
mxArray *arg;
if (nrhs != 3) mexErrMsgTxt("requires 3 arguments.");
/* ARG 1: MATRIX */
arg = prhs[0];
if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
mtx = mxGetPr(arg);
arg = prhs[1];
if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
newValues = mxGetPr(arg);
size = (int) mxGetM(arg) * mxGetN(arg);
arg = prhs[2];
if notDblMtx(arg) mexErrMsgTxt("MTX arg must be a real non-sparse matrix.");
doubleStartIndex = mxGetPr(arg);
startIndex = (int) doubleStartIndex[0];
for (i=0; i<size; i++){
mtx[i+startIndex] = newValues[i];
}
return;
}
//------------------------------------------------------
This mex file is the function to overwrite the scalar and the part of matrix through the pointer.
e.g. in matlab2013a command window (scalar in matlab2013a)
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
and the variable "a" becomes "3".
e.g. in matlab2013a and matlab2016a command window (matrix in matlab2013a and matlab2016a)
a = [1, 2];
destructiveMatrixWriteAtIndices(a, 3, 0);
and the variable "a" becomes "[3, 2]".
e.g. in matlab2016a command window (scalar in matlab2016a)
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
and the variable "a" becomes "1"! Why?
I also used the lldb, and revealed the strange behavior of this code.
In matlab2013a and matlab2016a, when I run the following snippet.
a = 1;
destructiveMatrixWriteAtIndices(a, 3, 0);
The lldb revealed "*mtx = 3" at the end of the mex function in both matlab, but the mex function couldn't pass the result(*mtx = 3, or prhs[0] = 3) through the pointer in the only matlab2016a.
It's very strange behavior!
※I have understood that this mex function is very danger, but this mex function was used at some points in the package that I must use. Therefore, I must fix this mex file and make the package run in matlab2016a.
Please help me.
I'm pretty sure you're not meant to modify the input array in a mex function. More details here Does Matlab ever copy data passed to a mex function?. The "matlab" solution is probably to return the modified array as an output of the mex rather modifying in place.

Passing mxArray to mexCallMatlab fails

I am writing a mex file in which conv2 function is called. This mex file will get an image of size (M, N) and apply convolution several time using conv2.
#include "mex.h"
void myconv( mxArray *Ain, mxArray *Kernel, mxArray *&Aout )
{
mxArray *rhs[3];
rhs[0] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
rhs[1] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
rhs[2] = mxCreateString ( "same" );
double *ainPtr = mxGetPr( Ain );
mxSetPr( rhs[0], ainPtr );
mxSetM ( rhs[0], mxGetM(Ain) );
mxSetN ( rhs[0], mxGetM(Ain) );
double *kernelPtr = mxGetPr( Kernel );
mxSetPr( rhs[1], kernelPtr );
mxSetM ( rhs[1], mxGetM(Kernel) );
mxSetN ( rhs[1], mxGetN(Kernel) );
mexCallMATLAB(1, &Aout, 3, rhs, "conv2");
mxSetPr( rhs[0], NULL );
mxSetPr( rhs[1], NULL );
}
void myconv_combine( mxArray *Ain, mxArray *&Aout )
{
mxArray *mask = mxCreateDoubleMatrix( 1, 5, mxREAL );
double *maskPtr = mxGetPr( mask );
maskPtr[0] = 0.05;
maskPtr[1] = 0.25;
maskPtr[2] = 0.4;
maskPtr[3] = 0.25;
maskPtr[4] = 0.05;
mxArray *maskTranspose = mxCreateDoubleMatrix( 0, 0, mxREAL );
mxSetPr( maskTranspose, maskPtr );
mxSetM ( maskTranspose, mxGetN(mask) );
mxSetN ( maskTranspose, mxGetM(mask) );
mxArray *AinConvolved = mxCreateDoubleMatrix( (mwSize)mxGetM(Ain), (mwSize)mxGetN(Ain), mxREAL );
double *AinConvolvedPtr = mxGetPr( AinConvolved );
myconv( Ain, mask, AinConvolved );
// Some modifications.
mxArray *Temp = mxCreateDoubleMatrix( (mwSize)mxGetM(Ain), (mwSize)mxGetN(Ain), mxREAL );
double *TempPtr = mxGetPr( Temp );
for( int i = 0; i < (mwSize)mxGetM(Ain)*(mwSize)mxGetN(Ain); i++ )
TempPtr[ i ] = 2.0*AinConvolvedPtr[ i ];
// Some other convolution.
mxArray *TempConvolved = mxCreateDoubleMatrix( (mwSize)mxGetM(Ain), (mwSize)mxGetN(Ain), mxREAL );
double *TempConvolvedPtr = mxGetPr( TempConvolved );
myconv( Temp, maskTranspose, TempConvolved );
// Some other modifications.
double *AoutPtr = mxGetPr( Aout );
for( int i = 0; i < (mwSize)mxGetM(Ain)*(mwSize)mxGetN(Ain); i++ )
AoutPtr[ i ] = 2.0*TempConvolvedPtr[ i ];
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mxArray *Ain = mxCreateDoubleMatrix( 100, 100, mxREAL );
mxArray *Aout = mxCreateDoubleMatrix( 100, 100, mxREAL );
myconv_combine( Ain, Aout );
}
In my actual code, when it reaches the line:
myconv( Temp, maskTranspose, TempConvolved );
MATLAB crashes which I have no clue why this happens and unfortunately I could not duplicate the same error in the example code I provided above. In my actual code, the image is convolved successfully by line:
myconv( Ain, mask, AinConvolved );
However, as soon as it wants to apply a second convolution:
myconv( Temp, maskTranspose, TempConvolved );
It crashes and when I debug it, it occurs when mexCallMATLAB is called on myconv function. What can be the difference between Temp/TempConvolved and Ain/AinConvolved that makes the former crash at the time of mexCallMATLAB?
Could someone kindly help me fix this issue?
Reusing data buffers
Reusing the data pointer from mxArray *mask for mxArray *maskTransposed is asking for trouble, as MATLAB has rigorous mechanisms for reference counting as shared-data arrays are an important part of MATLAB's memory optimizations. Instead, duplicate the whole thing with mxDuplicateArray:
mxArray *maskTranspose = mxDuplicateArray(mask);
There is an undocumented mxCreateSharedDataCopy that emulates MATLAB's lazy-copy mechanism, but that's really overkill for a 5-element array.
Superfluous-to-problematic mxArray initialization prior to mexCallMATLAB
Also, do not bother initializing mxArray *AinConvolved before calling mexCallMATLAB. Just pass a NULL pointer and it will create it for you. If you don't it will just wipe the old one (send it to garbage collection) and create a fresh one for the output of conv2. Which reminds me this demonstrates how this is a problem in your code:
mxArray *AinConvolved = mxCreateDoubleMatrix(mxGetM(Ain), mxGetN(Ain), mxREAL);
double *AinConvolvedPtr0 = mxGetPr(AinConvolved);
myconv(Ain, mask, AinConvolved);
double *AinConvolvedPtr = mxGetPr(AinConvolved);
mexPrintf("%p\n%p\n", AinConvolvedPtr0, AinConvolvedPtr);
Output in MATLAB:
00000000B852FA20
0000000026B8EB00
As you can see, if you try to use the pointer you got with mxGetPr before using mexCallMATLAB, you're probably using the wrong data, possibly already deallocated memory..
Automatic separable filtering with imfilter
Also, note that if you have imfilter, you don't need to implement separable convolution because it has that functionality built in. Just have a look at imfilter.m and note the isSeparable function. See here for more information.
Try that, I'll post a test.

FFTW with MEX and MATLAB argument issues

I wrote the following C/MEX code using the FFTW library to control the number of threads used for a FFT computation from MATLAB. The code works great (complex FFT forward and backward) with the FFTW_ESTIMATE argument in the planner although it is slower than MATLAB. But, when I switch to the FFTW_MEASURE argument to tune up the FFTW planner, it turns out that applying one FFT forward and then one FFT backward does not return the initial image. Instead, the image is scaled by a factor. Using FFTW_PATIENT gives me an even worse result with null matrices.
My code is as follows:
Matlab functions:
FFT forward:
function Y = fftNmx(X,NumCPU)
if nargin < 2
NumCPU = maxNumCompThreads;
disp('Warning: Use the max maxNumCompThreads');
end
Y = FFTN_mx(X,NumCPU)./numel(X);
FFT backward:
function Y = ifftNmx(X,NumCPU)
if nargin < 2
NumCPU = maxNumCompThreads;
disp('Warning: Use the max maxNumCompThreads');
end
Y = iFFTN_mx(X,NumCPU);
Mex functions:
FFT forward:
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <mex.h>
# include <matrix.h>
# include <math.h>
# include </home/nicolas/Code/C/lib/include/fftw3.h>
char *Wisfile = NULL;
char *Wistemplate = "%s/.fftwis";
#define WISLEN 8
void set_wisfile(void)
{
char *home;
if (Wisfile) return;
home = getenv("HOME");
Wisfile = (char *)malloc(strlen(home) + WISLEN + 1);
sprintf(Wisfile, Wistemplate, home);
}
fftw_plan CreatePlan(int NumDims, int N[], double *XReal, double *XImag, double *YReal, double *YImag)
{
fftw_plan Plan;
fftw_iodim Dim[NumDims];
int k, NumEl;
FILE *wisdom;
for(k = 0, NumEl = 1; k < NumDims; k++)
{
Dim[NumDims - k - 1].n = N[k];
Dim[NumDims - k - 1].is = Dim[NumDims - k - 1].os = (k == 0) ? 1 : (N[k-1] * Dim[NumDims-k].is);
NumEl *= N[k];
}
/* Import the wisdom. */
set_wisfile();
wisdom = fopen(Wisfile, "r");
if (wisdom) {
fftw_import_wisdom_from_file(wisdom);
fclose(wisdom);
}
if(!(Plan = fftw_plan_guru_split_dft(NumDims, Dim, 0, NULL, XReal, XImag, YReal, YImag, FFTW_MEASURE *(or FFTW_ESTIMATE respectively)* )))
mexErrMsgTxt("FFTW3 failed to create plan.");
/* Save the wisdom. */
wisdom = fopen(Wisfile, "w");
if (wisdom) {
fftw_export_wisdom_to_file(wisdom);
fclose(wisdom);
}
return Plan;
}
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
#define B_OUT plhs[0]
int k, numCPU, NumDims;
const mwSize *N;
double *pr, *pi, *pr2, *pi2;
static long MatLeng = 0;
fftw_iodim Dim[NumDims];
fftw_plan PlanForward;
int NumEl = 1;
int *N2;
if (nrhs != 2) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"Two input argument required.");
}
if (!mxIsDouble(prhs[0])) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"Array must be double");
}
numCPU = (int) mxGetScalar(prhs[1]);
if (numCPU > 8) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"NumOfThreads < 8 requested");
}
if (!mxIsComplex(prhs[0])) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"Array must be complex");
}
NumDims = mxGetNumberOfDimensions(prhs[0]);
N = mxGetDimensions(prhs[0]);
N2 = (int*) mxMalloc( sizeof(int) * NumDims);
for(k=0;k<NumDims;k++) {
NumEl *= NumEl * N[k];
N2[k] = N[k];
}
pr = (double *) mxGetPr(prhs[0]);
pi = (double *) mxGetPi(prhs[0]);
//B_OUT = mxCreateNumericArray(NumDims, N, mxDOUBLE_CLASS, mxCOMPLEX);
B_OUT = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxCOMPLEX);
mxSetDimensions(B_OUT , N, NumDims);
mxSetData(B_OUT , (double* ) mxMalloc( sizeof(double) * mxGetNumberOfElements(prhs[0]) ));
mxSetImagData(B_OUT , (double* ) mxMalloc( sizeof(double) * mxGetNumberOfElements(prhs[0]) ));
pr2 = (double* ) mxGetPr(B_OUT);
pi2 = (double* ) mxGetPi(B_OUT);
fftw_init_threads();
fftw_plan_with_nthreads(numCPU);
PlanForward = CreatePlan(NumDims, N2, pr, pi, pr2, pi2);
fftw_execute_split_dft(PlanForward, pr, pi, pr2, pi2);
fftw_destroy_plan(PlanForward);
fftw_cleanup_threads();
}
FFT backward:
This MEX function differs from the above only in switching pointers pr <-> pi, and pr2 <-> pi2 in the CreatePlan function and in the execution of the plan, as suggested in the FFTW documentation.
If I run
A = imread('cameraman.tif');
>> A = double(A) + i*double(A);
>> B = fftNmx(A,8);
>> C = ifftNmx(B,8);
>> figure,imagesc(real(C))
with the FFTW_MEASURE and FFTW_ESTIMATE arguments respectively I get this result.
I wonder if this is due to an error in my code or in the library. I tried different thing around the wisdom, saving not saving. Using the wisdom produce by the FFTW standalone tool to produce wisdom. I haven't seen any improvement. Can anyone suggest why this is happening?
Additional information:
I compile the MEX code using static libraries:
mex FFTN_Meas_mx.cpp /home/nicolas/Code/C/lib/lib/libfftw3.a /home/nicolas/Code/C/lib/lib/libfftw3_threads.a -lm
The FFTW library hasn't been compiled with:
./configure CFLAGS="-fPIC" --prefix=/home/nicolas/Code/C/lib --enable-sse2 --enable-threads --&& make && make install
I tried different flags without success. I am using MATLAB 2011b on a Linux 64-bit station (AMD opteron quad core).
FFTW computes not normalized transform, see here:
http://www.fftw.org/doc/What-FFTW-Really-Computes.html
Roughly speaking, when you perform direct transform followed by inverse one, you get
back the input (plus round-off errors) multiplied by the length of your data.
When you create a plan using flags other than FFTW_ESTIMATE, your input is overwritten:
http://www.fftw.org/doc/Planner-Flags.html