How to input and output variable in mex function

42 vues (au cours des 30 derniers jours)
Christopher Grose
Christopher Grose le 29 Nov 2018
Modifié(e) : James Tursa le 3 Fév 2021
I want to input an array into a mex function, modify the array, and then output the array without changing the variable name. My attempts to do this have failed. The code runs if I remove the lines:
b = mxGetPr(plhs[1]);
d = mxGetPr(plhs[2]);
but I want to return the values of b and d... I have also tried
plhs[1] = b;
plhs[2] = d;
Also, it is not acceptable to copy the array into another variable which can then be output.
Here is my failing mex function:
#include "mex.h" /*The mex library*/
#include <math.h>
#include <stdlib.h>
void runfunc(double *a, double *b, double *c, double *d, double *x, long ynum)
{
long i;
double w;
for (i = 1; i<ynum; i++)
{
w = a[i]/b[i-1];
b[i] = b[i]-w*c[i-1];
d[i] = d[i]-w*d[i-1];
}
x[ynum-1] = d[ynum-1]/b[ynum-1];
for (i = ynum-2; i!=-1; i--)
{
x[i] = (d[i]-c[i]*x[i+1])/b[i];
}
}
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
/* DECLARATIONS*/
double *a, *b, *c, *d, *x;
long ynum;
/* INPUTS */
a = mxGetPr(prhs[0]);
b = mxGetPr(prhs[1]);
c = mxGetPr(prhs[2]);
d = mxGetPr(prhs[3]);
ynum = mxGetScalar(prhs[4]);
/* OUTPUTS */
plhs[0] = mxCreateDoubleMatrix(ynum,1,mxREAL);
x = mxGetPr(plhs[0]);
b = mxGetPr(plhs[1]);
d = mxGetPr(plhs[2]);
/* CALL ROUTINE */
runfunc(a,b,c,d,x,ynum);
}

Réponse acceptée

James Tursa
James Tursa le 30 Nov 2018
Modifié(e) : James Tursa le 30 Nov 2018
Some issues:
b = mxGetPr(plhs[1]);
d = mxGetPr(plhs[2]);
The above lines crash MATLAB when you try to use b and d downstream because plhs[1] and plhs[2] haven't been created. The plhs variables are output variables that you the programmer need to create before you access them. So, create them first. E.g.,
if( nlhs < 3 ) {
mexErrMsgTxt("Need to specify three output variables");
}
plhs[0] = mxCreateDoubleMatrix(ynum,1,mxREAL);
plhs[1] = mxDuplicateArray(prhs[1]);
plhs[2] = mxDuplicateArray(prhs[3]);
x = mxGetPr(plhs[0]);
b = mxGetPr(plhs[1]);
d = mxGetPr(plhs[2]);
Then of course you don't need these earlier lines at all:
b = mxGetPr(prhs[1]);
:
d = mxGetPr(prhs[3]);
And, to make your mex routine more robust, you should be checking the number and class and size of all of your inputs before using them downstream in your code.
  2 commentaires
Kinan Bezem
Kinan Bezem le 2 Fév 2021
I have a similar question, but my setup is a bit different, I'm trying to input and output fail and dualfail.
It doesn't like the mx duplicate array lines
#include "fintrf.h"
C Gateway routine
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C Declarations
implicit none
C mexFunction arguments:
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
C Function declarations:
mwPointer mxCreateDoubleMatrix
mwPointer mxDuplicateArray
mwPointer mxGetPr
mwPointer mxGetM, mxGetN
integer mxIsNumeric
C Pointers to input/output mxArrays:
mwPointer coord_pr,dualnumfam_pr,dualfail_pr,dualpointfam_pr
mwPointer dualnodefam_pr,totnode_pr,width_pr,scr0_pr,vol_pr,bc_pr
mwPointer disp_pr,numfam_pr,nodefam_pr,pointfam_pr,fail_pr
mwPointer dmgpar1_pr,dmgpar2_pr, pforce_pr, dualpforce_pr
C Array information:
mwPointer m, n, x, y, u, l
integer mm, nn
mwSize size, row, sizes
C Arguments for computational routine:
real*8 coord(600000), dualnumfam(190000)
real*8 dualfail(40000000), dualpointfam(190000)
real*8 dualnodefam(40000000),totnode(1) ,width(1)
real*8 scr0(190000), vol(190000), bc(190000)
real*8 disp(600000), numfam(190000),nodefam(40000000)
real*8 pointfam(190000),fail(40000000)
real*8 dmgpar1(190000),dmgpar2(190000)
real*8 pforce(600000),dualpforce(600000)
character*200 msg
character*20 fmt
character*10 sm, sn, sx, sy
C-----------------------------------------------------------------------
C Check for proper number of arguments.
if (nrhs .ne. 15) then
call mexErrMsgIdAndTxt ('MATLAB:test:nInput',
+ 'One inputs required.')
endif
C Validate inputs
C Check to see both inputs are numeric.
if (mxIsNumeric(prhs(1)) .ne. 1) then
call mexErrMsgIdAndTxt ('MATLAB:test:NonNumeric1',
+ 'Input # 1 is not a numeric.')
endif
C Check that input #1 is a scalar.
m = mxGetM(prhs(1))
n = mxGetN(prhs(1))
size = m*n
x = mxGetM(prhs(3))
y = mxGetN(prhs(3))
sizes=x*y
u = mxGetM(prhs(5))
fmt = '(I8)'
write (sm,fmt) m
write (sn,fmt) n
write (sx,fmt) x
write (sy,fmt) y
msg = 'm=' // trim(sm) // ',\t n=' // trim(sn) // '\n'
call mexPrintf(trim(msg))
msg = 'x=' // trim(sx) // ',\t y=' // trim(sy) // '\n'
call mexPrintf(trim(msg))
C Create matrix for the return argument.
coord_pr = mxGetPr(prhs(1))
dualnumfam_pr = mxGetPr(prhs(2))
dualfail_pr = mxGetPr(prhs(3))
dualpointfam_pr = mxGetPr(prhs(4))
dualnodefam_pr = mxGetPr(prhs(5))
totnode_pr = mxGetPr(prhs(6))
width_pr = mxGetPr(prhs(7))
scr0_pr = mxGetPr(prhs(8))
vol_pr = mxGetPr(prhs(9))
bc_pr = mxGetPr(prhs(10))
disp_pr = mxGetPr(prhs(11))
numfam_pr = mxGetPr(prhs(12))
nodefam_pr = mxGetPr(prhs(13))
pointfam_pr = mxGetPr(prhs(14))
fail_pr = mxGetPr(prhs(15))
dmgpar1_pr = mxGetPr(plhs(1))
dmgpar2_pr = mxGetPr(plhs(2))
pforce_pr = mxGetPr(plhs(3))
dualpforce_pr = mxGetPr(plhs(4))
fail_pr = mxGetPr(plhs(5))
dualfail_pr = mxGetPr(plhs(6))
plhs(1) = mxCreateDoubleMatrix(m,1,0)
plhs(2) = mxCreateDoubleMatrix(m,1,0)
plhs(3) = mxCreateDoubleMatrix(m,3,0)
plhs(4) = mxCreateDoubleMatrix(m,3,0)
plhs(4) = mxCreateDoubleMatrix(m,200,0)
plhs(5) = mxCreateDoubleMatrix(m,200,0)
plhs(5) = mxDuplicateArray(fail_pr)
plhs(6) = mxDuplicateArray(dualfail_pr)
C Load the data into Fortran arrays.
call mxCopyPtrToReal8(coord_pr,coord,size)
call mxCopyPtrToReal8(dualnumfam_pr,dualnumfam,m)
call mxCopyPtrToReal8(dualfail_pr,dualfail,sizes)
call mxCopyPtrToReal8(dualpointfam_pr,dualpointfam,m)
call mxCopyPtrToReal8(dualnodefam_pr,dualnodefam,u)
call mxCopyPtrToReal8(totnode_pr,totnode,1)
call mxCopyPtrToReal8(width_pr,width,1)
call mxCopyPtrToReal8(scr0_pr,scr0,m)
call mxCopyPtrToReal8(vol_pr,vol,m)
call mxCopyPtrToReal8(bc_pr,bc,m)
call mxCopyPtrToReal8(disp_pr,disp,size)
call mxCopyPtrToReal8(numfam_pr,numfam,m)
call mxCopyPtrToReal8(nodefam_pr,nodefam,u)
call mxCopyPtrToReal8(pointfam_pr,pointfam,m)
call mxCopyPtrToReal8(fail_pr,fail,sizes)
call mxCopyPtrToReal8(dmgpar1_pr,dmgpar1,m)
call mxCopyPtrToReal8(dmgpar2_pr,dmgpar2,m)
call mxCopyPtrToReal8(pforce_pr,pforce,size)
call mxCopyPtrToReal8(dualpforce_pr,dualpforce,size)
C Call the computational subroutine.
call body(coord,dualnumfam,dualfail,dualpointfam,dualnodefam,
+ totnode,width,scr0,vol,bc,disp,numfam,nodefam,pointfam,fail
+ ,m,n,dmgpar1,dmgpar2,pforce,dualpforce,u)
C Load the output into a MATLAB array.
call mxCopyReal8ToPtr(dmgpar1,dmgpar1_pr,m)
call mxCopyReal8ToPtr(dmgpar2,dmgpar2_pr,m)
call mxCopyReal8ToPtr(pforce,pforce_pr,size)
call mxCopyReal8ToPtr(dualpforce,dualpforce_pr,size)
call mxCopyReal8ToPtr(fail,fail_pr,sizes)
call mxCopyReal8ToPtr(dualfail,dualfail_pr,sizes)
James Tursa
James Tursa le 2 Fév 2021
Modifié(e) : James Tursa le 3 Fév 2021
@Kinan: Please delete this comment and instead open up a new Question, since the issues may be totally different than this original post, and since yours is a Fortran question. Thanks.
The issue with your mxDuplicateArray( ) calls is that you are passing in data pointers when you should be passing in mxArray pointers. Also, you access the plhs( ) variables before you create them. Both of these problems will cause a MATLAB crash.

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Write C Functions Callable from MATLAB (MEX Files) dans Help Center et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by