How to input and output variable in mex function

14 Ansichten (letzte 30 Tage)
Christopher Grose
Christopher Grose am 29 Nov. 2018
Bearbeitet: James Tursa am 3 Feb. 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);
}

Akzeptierte Antwort

James Tursa
James Tursa am 30 Nov. 2018
Bearbeitet: James Tursa am 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 Kommentare
Kinan Bezem
Kinan Bezem am 2 Feb. 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 am 2 Feb. 2021
Bearbeitet: James Tursa am 3 Feb. 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.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Kategorien

Mehr zu Startup and Shutdown finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by