Trying to return array from Fortran to Matlab with mex, getting empty array instead - matlab

So, I'm trying to return a an array of numbers from 1-n.
#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
mwPointer mxGetPr
mwPointer mxCreateDoubleMatrix
mwPointer mxGetM, mxGetN
mwPointer mrows, ncols
mwSize size
mwPointer x_ptr, y_ptr
integer x_input,i
real*8, allocatable :: vec(:)
x_ptr = mxGetPr(prhs(1))
mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1))
size = mrows*ncols
x_ptr=mxGetPr(prhs(1))
call mxCopyPtrToReal8(x_ptr,x_input,size)
allocate (vec(x_input))
do i=1,x_input
vec(i)=i
end do
plhs(1) = mxCreateDoubleMatrix(1, x_input, 0)
y_ptr = mxGetPr(plhs(1))
call mxCopyReal8ToPtr(vec,y_ptr,x_input)
deallocate ( vec )
return
end
I then call the mex file in fortran here
mex testingvec.F
Building with 'gfortran'.
MEX completed successfully.
a=testingvec(10);
and then find
a=[]
Can someone give me some help on this? If someone can give me some example code how to return a matrix as well, that would be sweet.
Thanks guys.
edit: new installment of the code. Still trying to get some help.
#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
mwPointer mxGetPr
mwPointer mxCreateDoubleMatrix
mwPointer mxGetM, mxGetN
mwPointer mrows, ncols
mwSize size
mwPointer x_ptr, y_ptr
integer i
mwSize sizeone, x_input
integer*4 izero
real*8, allocatable :: vec(:)
x_ptr = mxGetPr(prhs(1))
mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1))
size = mrows*ncols
sizeone=1
izero=0
x_ptr=mxGetPr(prhs(1))
call mxCopyPtrToReal8(x_ptr,x_input,size)
allocate (vec(x_input))
do i=1,x_input
vec(i)=i
end do
plhs(1) = mxCreateDoubleMatrix(sizeone,x_input,izero)
call mxCopyReal8ToPtr(vec,mxGetPr(plhs(1)),x_input)
deallocate ( vec )
return
end

There were both declaration problems and issues with calls to mex functions. Here's a solution, which assumes that the input is an integer-valued double giving you the length of the output vector (assuming that this is what you wanted).
#include "fintrf.h"
C Gateway routine
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C Declarations
implicit none
C mexFunction arguments:
mwPointer plhs(*), prhs(*)
integer*4 nlhs, nrhs
mwPointer mxGetPr
mwPointer mxCreateDoubleMatrix
mwSize mxGetM, mxGetN
mwSignedIndex mrows, ncols
mwSize size, x_input, sizeone
mwPointer x_ptr, y_ptr
integer*4 i, izero, x_int
real*8, allocatable :: vec(:)
real*8 :: x_dbl
sizeone = 1
izero = 0
!check input/output syntax
if (nrhs /= 1) then
call mexErrMsgIdAndTxt("MATLAB:testingvec:rhs",
> "Exactly 1 input variable required.")
end if
if (nlhs /= 1) then
call mexErrMsgIdAndTxt("MATLAB:testingvec:lhs",
> "Exactly 1 output matrix required.")
end if
x_ptr = mxGetPr(prhs(1))
mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1))
size = mrows*ncols
call mxCopyPtrToReal8(x_ptr,x_dbl,sizeone)
x_input = int(x_dbl)
allocate (vec(x_input))
do i=1,x_input
vec(i)=i
end do
plhs(1) = mxCreateDoubleMatrix(sizeone, x_input, izero)
y_ptr = mxGetPr(plhs(1))
call mxCopyReal8ToPtr(vec,y_ptr,x_input)
deallocate ( vec )
return
end
I introduced a check for the number of input/output variables (to be updated in the actual program). And I introduced an auxiliary x_dbl which might or might not be necessary. This version reads the double input given to your function, and truncates it to get x_input.

Related

Segmentation Fault when using glmnet mex with MATLAB

My jobs have been suffering due to segmentation faults when calling glmnet (downloaded from here:http://web.stanford.edu/~hastie/glmnet_matlab/download.html) from my MATLAB code. I call the glmnet routine thousands of times. I have noticed the following peculiarities about the problem occurence:
The problem is more frequent when the size of my input matrices are larger.
I use both gaussian and poisson distribution in separate jobs, and I notice that the problem is more frequent when fitting the Poisson distribution (which also takes usually longer to converge, so might involve more loops internally?)
Since there haven't been reports of segmentation faults for the R version for these two distributions, my suspicion is that the problem, likely a memory leak, might lie in the mex interface rather than the core glmnet Fortran code, which I am pasting below. Any insights into where a memory leak might be happening is greatly appreciated! Apologies for the lengthy code dump.
Thanks!
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C-----------------------------------------------------------------------
mwpointer plhs(*), prhs(*)
mwpointer mxCreateDoubleMatrix, mxGetPr, mxCreateNumericArray
integer nlhs, nrhs
mwsize mxGetM, mxGetN, mxGetNzmax
integer mxIsNumeric
integer mxIsSparse
C-----------------------------------------------------------------------
C Input
real parm,flmin,thr, intr
integer ka,no,ni,nr,nc,ne,nx,nlam,isd,maxit,kopt,isparse,nnz,jsd
real, dimension (:), allocatable :: x,y,w,vp,ulam,cl,sr,xs,o,d,
$ flog,a
integer, dimension (:), allocatable :: ix,jx,jd,irs,jcs
mwpointer pr
C Output
integer lmu,nlp,jerr
real dev0
real, dimension (:), allocatable :: a0,ca,alm,dev,rsq
integer, dimension (:), allocatable :: ia,nin
C Temporary
mwpointer temp_pr
mwsize temp_m, temp_n, temp_nzmax, dims(3)
integer task,i
C For internal parameters
real fdev, devmax, eps, big, pmin, prec, exmx
integer mnlam, mxit
C Check for proper number of arguments.
if (nrhs .eq. 0) then
task = -1;
else
temp_pr = mxGetPr(prhs(1))
call getinteger(temp_pr,task,1)
endif
C Get input
if (task .eq. -1) then
call get_int_parms(fdev,eps,big,mnlam,devmax,pmin,exmx)
call get_bnorm(prec,mxit)
plhs(1) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(1))
call putreal(fdev,temp_pr,1)
plhs(2) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(2))
call putreal(devmax,temp_pr,1)
plhs(3) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(3))
call putreal(eps,temp_pr,1)
plhs(4) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(4))
call putreal(big,temp_pr,1)
plhs(5) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(5))
call putinteger(mnlam,temp_pr,1)
plhs(6) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(6))
call putreal(pmin,temp_pr,1)
plhs(7) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(7))
call putreal(exmx,temp_pr,1)
plhs(8) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(8))
call putreal(prec,temp_pr,1)
plhs(9) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(9))
call putinteger(mxit,temp_pr,1)
return
endif
if (task .eq. 0) then
temp_pr = mxGetPr(prhs(2))
call getreal(temp_pr,fdev,1)
temp_pr = mxGetPr(prhs(3))
call getreal(temp_pr,devmax,1)
temp_pr = mxGetPr(prhs(4))
call getreal(temp_pr,eps,1)
temp_pr = mxGetPr(prhs(5))
call getreal(temp_pr,big,1)
temp_pr = mxGetPr(prhs(6))
call getinteger(temp_pr,mnlam,1)
temp_pr = mxGetPr(prhs(7))
call getreal(temp_pr,pmin,1)
temp_pr = mxGetPr(prhs(8))
call getreal(temp_pr,exmx,1)
temp_pr = mxGetPr(prhs(9))
call getreal(temp_pr,prec,1)
temp_pr = mxGetPr(prhs(10))
call getinteger(temp_pr,mxit,1)
call chg_fract_dev(fdev)
call chg_dev_max(devmax)
call chg_min_flmin(eps)
call chg_big(big)
call chg_min_lambdas(mnlam)
call chg_min_null_prob(pmin)
call chg_max_exp(exmx)
call chg_bnorm(prec, mxit)
return
endif
c$$$ -----------------Gaussian--------------------
c$$$ ---input---
if (task .eq. 10 .or. task .eq. 11) then
if (task .eq. 11) then
temp_pr = mxGetPr(prhs(3))
temp_m = mxGetM(prhs(3))
no = temp_m
temp_n = mxGetN(prhs(3))
ni = temp_n
allocate(x(1:no*ni))
call getreal(temp_pr,x,no*ni)
else
temp_m = mxGetM(prhs(4))
no = temp_m
temp_pr = mxGetPr(prhs(3))
temp_m = mxGetM(prhs(3))
nnz = temp_m
allocate(xs(1:nnz))
call getreal(temp_pr,xs,nnz)
temp_pr = mxGetPr(prhs(19))
allocate(irs(1:nnz))
call getinteger(temp_pr,irs,nnz)
temp_pr = mxGetPr(prhs(20))
temp_n = mxGetM(prhs(20))
ni = temp_n - 1
allocate(jcs(1:(ni+1)))
call getinteger(temp_pr,jcs,(ni+1))
endif
temp_pr = mxGetPr(prhs(2))
call getreal(temp_pr,parm,1)
temp_pr = mxGetPr(prhs(4))
allocate(y(1:no))
call getreal(temp_pr,y,no)
temp_pr = mxGetPr(prhs(5))
temp_m = mxGetM(prhs(5))
temp_n = mxGetN(prhs(5))
allocate(jd(temp_m*temp_n))
call getinteger(temp_pr,jd,temp_m*temp_n)
temp_pr = mxGetPr(prhs(6))
allocate(vp(1:ni))
call getreal(temp_pr,vp,ni)
temp_pr = mxGetPr(prhs(7))
call getinteger(temp_pr,ne,1)
temp_pr = mxGetPr(prhs(8))
call getinteger(temp_pr,nx,1)
temp_pr = mxGetPr(prhs(9))
call getinteger(temp_pr,nlam,1)
temp_pr = mxGetPr(prhs(10))
call getreal(temp_pr,flmin,1)
temp_pr = mxGetPr(prhs(11))
temp_m = mxGetM(prhs(11))
temp_n = mxGetN(prhs(11))
allocate(ulam(1:temp_m * temp_n))
call getreal(temp_pr,ulam,temp_m * temp_n)
temp_pr = mxGetPr(prhs(12))
call getreal(temp_pr,thr,1)
temp_pr = mxGetPr(prhs(13))
call getinteger(temp_pr,isd,1)
temp_pr = mxGetPr(prhs(14))
allocate(w(1:no))
call getreal(temp_pr,w,no)
temp_pr = mxGetPr(prhs(15))
call getinteger(temp_pr,ka,1)
temp_pr = mxGetPr(prhs(16))
allocate(cl(1:2*ni))
call getreal(temp_pr,cl,2*ni)
temp_pr = mxGetPr(prhs(17))
call getinteger(temp_pr,intr,1)
temp_pr = mxGetPr(prhs(18))
call getinteger(temp_pr,maxit,1)
c$$$ ---prepare output---
allocate(ia(1:nx))
call zerointeger(ia,nx)
allocate(nin(1:nlam))
call zerointeger(nin,nlam)
allocate(alm(1:nlam))
call zeroreal(alm,nlam)
allocate(a0(1:nlam))
call zeroreal(a0,nlam)
allocate(ca(1:nx*nlam))
call zeroreal(ca,nx*nlam)
allocate(rsq(1:nlam))
call zeroreal(rsq,nlam)
c$$$ ---computation----
if (task .eq. 11) then
call elnet(ka,parm,no,ni,x,y,w,jd,vp,cl,ne,nx,nlam,flmin,
$ ulam,thr,isd,intr,maxit,lmu,a0,ca,ia,nin,rsq,alm,
$ nlp,jerr)
else
call spelnet(ka,parm,no,ni,xs,jcs,irs,y,w,jd,vp,cl,ne,nx,
$ nlam,flmin,ulam,thr,isd,intr,maxit,lmu,a0,ca,ia,nin,
$ rsq,alm,nlp,jerr)
endif
c$$$ ----output-----
plhs(1) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(1))
call putinteger(lmu,temp_pr,1)
plhs(4) = mxCreateDoubleMatrix(nx,1,0)
temp_pr = mxGetPr(plhs(4))
call putinteger(ia,temp_pr,nx)
plhs(5) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(5))
call putinteger(nin,temp_pr,lmu)
plhs(7) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(7))
call putreal(alm,temp_pr,lmu)
plhs(8) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(8))
call putinteger(nlp,temp_pr,1)
plhs(9) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(9))
call putinteger(jerr,temp_pr,1)
plhs(2) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(2))
call putreal(a0,temp_pr,lmu)
plhs(3) = mxCreateDoubleMatrix(nx,lmu,0)
temp_pr = mxGetPr(plhs(3))
call putreal(ca,temp_pr,nx*lmu)
plhs(6) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(6))
call putreal(rsq,temp_pr,lmu)
deallocate(y)
deallocate(jd)
deallocate(vp)
deallocate(ulam)
deallocate(a0)
deallocate(ca)
deallocate(ia)
deallocate(nin)
deallocate(alm)
deallocate(w)
deallocate(rsq)
deallocate(cl)
if (task .eq. 11) then
deallocate(x)
else
deallocate(xs)
deallocate(irs)
deallocate(jcs)
endif
return
endif
c$$$ --------------end of Gaussian---------------------------
c$$$ ---------------Poisson--------------------------
c$$$ ---input---
if (task .eq. 50 .or. task .eq. 51) then
if (task .eq. 51) then
temp_pr = mxGetPr(prhs(3))
temp_m = mxGetM(prhs(3))
no = temp_m
temp_n = mxGetN(prhs(3))
ni = temp_n
allocate(x(1:no*ni))
call getreal(temp_pr,x,no*ni)
else
temp_m = mxGetM(prhs(4))
no = temp_m
temp_pr = mxGetPr(prhs(3))
temp_m = mxGetM(prhs(3))
nnz = temp_m
allocate(xs(1:nnz))
call getreal(temp_pr,xs,nnz)
temp_pr = mxGetPr(prhs(19))
allocate(irs(1:nnz))
call getinteger(temp_pr,irs,nnz)
temp_pr = mxGetPr(prhs(20))
temp_n = mxGetM(prhs(20))
ni = temp_n - 1
allocate(jcs(1:(ni+1)))
call getinteger(temp_pr,jcs,(ni+1))
endif
temp_pr = mxGetPr(prhs(2))
call getreal(temp_pr,parm,1)
temp_pr = mxGetPr(prhs(4))
allocate(y(1:no))
call getreal(temp_pr,y,no)
temp_pr = mxGetPr(prhs(5))
temp_m = mxGetM(prhs(5))
temp_n = mxGetN(prhs(5))
allocate(jd(temp_m*temp_n))
call getinteger(temp_pr,jd,temp_m*temp_n)
temp_pr = mxGetPr(prhs(6))
allocate(vp(1:ni))
call getreal(temp_pr,vp,ni)
temp_pr = mxGetPr(prhs(7))
call getinteger(temp_pr,ne,1)
temp_pr = mxGetPr(prhs(8))
call getinteger(temp_pr,nx,1)
temp_pr = mxGetPr(prhs(9))
call getinteger(temp_pr,nlam,1)
temp_pr = mxGetPr(prhs(10))
call getreal(temp_pr,flmin,1)
temp_pr = mxGetPr(prhs(11))
temp_m = mxGetM(prhs(11))
temp_n = mxGetN(prhs(11))
allocate(ulam(1:temp_m * temp_n))
call getreal(temp_pr,ulam,temp_m * temp_n)
temp_pr = mxGetPr(prhs(12))
call getreal(temp_pr,thr,1)
temp_pr = mxGetPr(prhs(13))
call getinteger(temp_pr,isd,1)
temp_pr = mxGetPr(prhs(14))
allocate(w(1:no))
call getreal(temp_pr,w,no)
temp_pr = mxGetPr(prhs(15))
allocate(cl(1:2*ni))
call getreal(temp_pr,cl,2*ni)
temp_pr = mxGetPr(prhs(16))
call getinteger(temp_pr,intr,1)
temp_pr = mxGetPr(prhs(17))
call getinteger(temp_pr,maxit,1)
temp_pr = mxGetPr(prhs(18))
allocate(o(1:no))
call getreal(temp_pr,o,no)
c$$$ ---prepare output---
allocate(ia(1:nx))
call zerointeger(ia,nx)
allocate(nin(1:nlam))
call zerointeger(nin,nlam)
allocate(alm(1:nlam))
call zeroreal(alm,nlam)
allocate(a0(1:nlam))
call zeroreal(a0,nlam)
allocate(ca(1:nx*nlam))
call zeroreal(ca,nx*nlam)
allocate(dev(1:nlam))
call zeroreal(dev,nlam)
c$$$ ---computation----
if (task .eq. 51) then
call fishnet(parm,no,ni,x,y,o,w,jd,vp,cl,ne,nx,nlam,flmin,
$ ulam,thr,isd,intr,maxit,lmu,a0,ca,ia,nin,dev0,dev,alm,
$ nlp,jerr)
else
call spfishnet(parm,no,ni,xs,jcs,irs,y,o,w,jd,vp,cl,ne,nx,
$ nlam,flmin,ulam,thr,isd,intr,maxit,lmu,a0,ca,ia,
$ nin,dev0,dev,alm,nlp,jerr)
endif
c$$$ ----output-----
plhs(1) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(1))
call putinteger(lmu,temp_pr,1)
plhs(4) = mxCreateDoubleMatrix(nx,1,0)
temp_pr = mxGetPr(plhs(4))
call putinteger(ia,temp_pr,nx)
plhs(5) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(5))
call putinteger(nin,temp_pr,lmu)
plhs(7) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(7))
call putreal(alm,temp_pr,lmu)
plhs(8) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(8))
call putinteger(nlp,temp_pr,1)
plhs(9) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(9))
call putinteger(jerr,temp_pr,1)
plhs(2) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(2))
call putreal(a0,temp_pr,lmu)
plhs(3) = mxCreateDoubleMatrix(nx,lmu,0)
temp_pr = mxGetPr(plhs(3))
call putreal(ca,temp_pr,nx*lmu)
plhs(6) = mxCreateDoubleMatrix(lmu,1,0)
temp_pr = mxGetPr(plhs(6))
call putreal(dev,temp_pr,lmu)
plhs(10) = mxCreateDoubleMatrix(1,1,0)
temp_pr = mxGetPr(plhs(10))
call putreal(dev0,temp_pr,1)
plhs(11) = mxCreateDoubleMatrix(no,1,0)
temp_pr = mxGetPr(plhs(11))
call putreal(o,temp_pr,no)
deallocate(y)
deallocate(jd)
deallocate(vp)
deallocate(ulam)
deallocate(a0)
deallocate(ca)
deallocate(ia)
deallocate(nin)
deallocate(alm)
deallocate(cl)
deallocate(o)
deallocate(dev)
if (task .eq. 51) then
deallocate(x)
else
deallocate(xs)
deallocate(irs)
deallocate(jcs)
endif
return
endif
c$$$ --------------------end of Poisson------------------
return
end
C End of subroutine mexFunction
subroutine real8toreal(x, y, size)
integer size
real*8 x(size)
real y(size)
do 10 i=1,size
y(i)= x(i)
10 continue
return
end
subroutine realtoreal8(x, y, size)
integer size
real x(size)
real*8 y(size)
do 20 i=1,size
y(i)= x(i)
20 continue
return
end
subroutine real8tointeger(x, y, size)
integer size
real*8 x(size)
integer y(size)
do 30 i=1,size
y(i)= x(i)
30 continue
return
end
subroutine integertoreal8(x, y, size)
integer size
integer x(size)
real*8 y(size)
do 40 i=1,size
y(i)= x(i)
40 continue
return
end
subroutine getreal(pr,x,size)
mwpointer pr
integer size
real x(size)
real*8, dimension (:), allocatable :: temp
allocate(temp(1:size))
call mxCopyPtrToReal8(pr,temp,size)
call real8toreal(temp,x,size)
deallocate(temp)
return
end
subroutine getinteger(pr,x,size)
mwpointer pr
integer size
integer x(size)
real*8, dimension (:), allocatable :: temp
allocate(temp(1:size))
call mxCopyPtrToReal8(pr,temp,size)
call real8tointeger(temp,x,size)
deallocate(temp)
return
end
subroutine putreal(x,pr,size)
mwpointer pr
integer size
real x(size)
real*8, dimension (:), allocatable :: temp
allocate(temp(1:size))
call realtoreal8(x,temp,size)
call mxCopyReal8ToPtr(temp,pr,size)
deallocate(temp)
return
end
subroutine putinteger(x,pr,size)
mwpointer pr
integer size
integer x(size)
real*8, dimension (:), allocatable :: temp
allocate(temp(1:size))
call integertoreal8(x,temp,size)
call mxCopyReal8ToPtr(temp,pr,size)
deallocate(temp)
return
end
subroutine zeroreal(x,size)
integer size
real x(size)
do 90 i=1,size
x(i) = 0
90 continue
return
end
subroutine zerointeger(x,size)
integer size
integer x(size)
do 100 i=1,size
x(i) = 0
100 continue
return
end
First thing I would do is clean up the MATLAB API interface stuff. Remember that in Fortran you do not get automatic type promotion in function/subroutine argument lists like you do in C/C++. So it is important to get the signatures exact. You should NEVER be passing literal integers to MATLAB API functions. You should be passing variables that are typed exactly as the API specifies to ensure that there is not a mismatch. E.g., take this code:
subroutine getreal(pr,x,size)
mwpointer pr
integer size
real x(size)
real*8, dimension (:), allocatable :: temp
allocate(temp(1:size))
call mxCopyPtrToReal8(pr,temp,size)
call real8toreal(temp,x,size)
deallocate(temp)
return
end
The signature for mxCopyPtrToReal8 in the API is:
subroutine mxCopyPtrToReal8(px, y, n)
mwPointer px
real*8 y(n)
mwSize n
So you have a potential mismatch because the default Fortran integer might not match mwSize. Also, size is the name of a Fortran instrinsic function, so a different name for your variable would probably be more appropriate.
I would change that subroutine to:
subroutine getreal(pr,x,sizex)
mwpointer pr
mwSize sizex
real x(sizex)
real*8, dimension (:), allocatable :: temp
allocate(temp(1:sizex))
call mxCopyPtrToReal8(pr,temp,sizex)
call real8toreal(temp,x,sizex)
deallocate(temp)
return
end
Now you are ensured that sizex is the appropriate type. You would also need to change the types of the variables in the calling routine.
(SIDE NOTE: Actually, I wouldn't do any of what you are doing ... I would simply write a loop to copy the values directly from the mxArray into your real array without extra copies and memory allocation/deallocation)
Another example is this:
integer ...,nx,...
:
integer lmu,...
:
plhs(3) = mxCreateDoubleMatrix(nx,lmu,0)
Should be replaced with:
mwSize nx, lmu
integer*4 :: ComplexFlag = 0
:
plhs(3) = mxCreateDoubleMatrix(nx,lmu,ComplexFlag)
And, frankly, you have lots of assignment loops that can be replace by simple statements. E.g.,
call real8toreal(temp,x,sizex)
can be replaced with:
x = temp
And this:
allocate(ia(1:nx))
call zerointeger(ia,nx)
allocate(nin(1:nlam))
call zerointeger(nin,nlam)
allocate(alm(1:nlam))
call zeroreal(alm,nlam)
allocate(a0(1:nlam))
call zeroreal(a0,nlam)
allocate(ca(1:nx*nlam))
call zeroreal(ca,nx*nlam)
allocate(dev(1:nlam))
call zeroreal(dev,nlam)
can be replaced with this:
allocate(ia(1:nx))
ia = 0
allocate(nin(1:nlam))
nin = 0
allocate(alm(1:nlam))
alm = 0.0
allocate(a0(1:nlam))
a0 = 0.0
allocate(ca(1:nx*nlam))
ca = 0.0
allocate(dev(1:nlam))
dev = 0.0
etc.

How to fix illegal character error in mex files

I'm getting some error message when I try to compile the fortran code on matlab.
>> mex points.f
Warning: MATLAB FORTRAN MEX Files are now defaulting to -largeArrayDims and 8 byte integers.
If you are building a FORTRAN S-Function, please recompile using the -compatibleArrayDims flag.
You can find more about adapting code to use 64-bit array dimensions at:
https://www.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html.
Building with 'Intel Parallel Studio XE 2019 for Fortran with Microsoft Visual Studio 2017'.
Error using mex
C:\Users\Kinan\Desktop\Strathshare\Personal Folders\PhD\MATLABPERIDYNAMICS\points.f(44): error #5149: Illegal character in statement
label field [r]
re*8 dx, ral
----^
C:\Users\Kinan\Desktop\Strathshare\Personal Folders\PhD\MATLABPERIDYNAMICS\points.f(45): error #5149: Illegal character in statement
label field [r]
re*8 coordx, coordy, coordz
----^
>C:\Users\Kinan\Desktop\Strathshare\Personal Folders\PhD\MATLABPERIDYNAMICS\points.f(46): error #5149: Illegal character in statement
label field [r]
real*8 coord(totnode,3)
----^
The actual code is
#include "fintrf.h"
C======================================================================
C points.f
C Computational function that creates a cube of equdistant points
C This is a MEX file for MATLAB.
C======================================================================
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 mxGetDoubles
mwPointer mxCreateDoubleMatrix
integer mxIsNumeric
mwPointer mxGetM, mxGetN
C Pointers to input/output mxArrays:
mwPointer x_ptr, y_ptr
C Array information:
mwPointer mrows, ncols
mwSize size
C Arguments for computational routine:
real*8 dx, r
real*8 coordx, coordy, coordz
real*8 coord(totnode,3)
real*8 ndivx, ndivy, ndivz
integer i, j, k
C Get the size of the input array.
mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1))
size = mrows*ncols
MX_HAS_INTERLEAVED_COMPLEX
x_ptr = mxGetDoubles(prhs(1))
C Create matrix for the return argument.
plhs(1) = mxCreateDoubleMatrix(29791,3,0)
y_ptr = mxGetDoubles(plhs(1))
call points(coord,r,dx,ndivx,ndivy,ndivz)
C Load the data into y_ptr, which is the output to MATLAB.
call mxCopyReal8ToPtr(y_output,y_ptr,size)
return
end
C-----------------------------------------------------------------------
C Computational routine
subroutine points(coord,r,dx,ndivx,ndivy,ndivz)
C Arguments for computational routine:
real*8 dx, r, coordx, coordy, coordz
real*8 coord(totnode,3), ndivx, ndivy, ndivz
integer i, j, k
do i = 1,ndivx
do j = 1,ndivy
do k = 1,ndivz
coordx = -1.0d0 / 2.0d0 * r + (dx / 2.0d0) + (i - 1) * dx
coordy = -1.0d0 / 2.0d0 * r + (dx / 2.0d0) + (j - 1) * dx
coordz = -1.0d0 / 2.0d0 * r + (dx / 2.0d0) + (k - 1) * dx
nnum = nnum + 1
coord(nnum,1) = coordx
coord(nnum,2) = coordy
coord(nnum,3) = coordz
enddo
enddo
enddo
return
end
I have a few for loops I need to do this for so if I can get a working template it would help a lot.
Sorry I tried to add more of the error message but it said I had too much code
I managed to MEX the code, but there are too many errors...
For suppressing the warning about largeArrayDims you can execute:
warning('Off', 'MATLAB:mex:FortranLargeArrayDimsWarn_link');
Note: Your Fortran code applies MX_HAS_INTERLEAVED_COMPLEX, so you need to add -2018a flag to the mex command.
I could not find a way to avoid the warning when using -2018a flag.
MEX command line uses -2018a flag:
mex -R2018a points.F
I had to make too many modifications to your code, in order to pass compilation:
I added spaces to the beginning of the lines.
I removed MX_HAS_INTERLEAVED_COMPLEX.
I didn't know what to do with totnode, so I replaced it with the value 100.
I didn't know what to do with y_output, so I replaced it with coord.
Here is your modified code that passes compilation:
#include "fintrf.h"
C======================================================================
C points.f
C Computational function that creates a cube of equdistant points
C This is a MEX file for MATLAB.
C======================================================================
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 mxGetDoubles
mwPointer mxCreateDoubleMatrix
integer mxIsNumeric
mwPointer mxGetM, mxGetN
C Pointers to input/output mxArrays:
mwPointer x_ptr, y_ptr
C Array information:
mwPointer mrows, ncols
mwSize size
C Arguments for computational routine:
real*8 dx, r
real*8 coordx, coordy, coordz
C What is totnode???
C real*8 coord(totnode,3)
real*8 coord(100,3)
real*8 ndivx, ndivy, ndivz
integer i, j, k
C Get the size of the input array.
mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1))
size = mrows*ncols
C MX_HAS_INTERLEAVED_COMPLEX
x_ptr = mxGetDoubles(prhs(1))
C Create matrix for the return argument.
plhs(1) = mxCreateDoubleMatrix(29791,3,0)
y_ptr = mxGetDoubles(plhs(1))
call points(coord,r,dx,ndivx,ndivy,ndivz)
C Load the data into y_ptr, which is the output to MATLAB.
C call mxCopyReal8ToPtr(y_output,y_ptr,size) What is y_output???
call mxCopyReal8ToPtr(coord,y_ptr,size)
return
end
C-----------------------------------------------------------------------
C Computational routine
subroutine points(coord,r,dx,ndivx,ndivy,ndivz)
C Arguments for computational routine:
real*8 dx, r, coordx, coordy, coordz
C What is totnode???
C real*8 coord(totnode,3), ndivx, ndivy, ndivz
real*8 coord(100,3), ndivx, ndivy, ndivz
integer i, j, k
do i = 1,ndivx
do j = 1,ndivy
do k = 1,ndivz
coordx = -1.0d0 / 2.0d0 * r + (dx / 2.0d0) + (i - 1) * dx
coordy = -1.0d0 / 2.0d0 * r + (dx / 2.0d0) + (j - 1) * dx
coordz = -1.0d0 / 2.0d0 * r + (dx / 2.0d0) + (k - 1) * dx
nnum = nnum + 1
coord(nnum,1) = coordx
coord(nnum,2) = coordy
coord(nnum,3) = coordz
enddo
enddo
enddo
return
end
I hope it helps you continue your development.

Can a MATLAB Mex function accept both single and doubles?

I have a mex function that accepts double matrices as the input, but I just realized that the code this function is used for, can have single precision matrices as well. Is it possible to allow the function to accept either?
Or if not, what is an alternative way to fix this issue?
The simple solution would be to convert the inputs in MATLAB to a consistent type (presumably double), but if you would like to have your MEX function handle multiple types, here is one way.
Check the input type with mxIsSingle and mxIsDouble (or mxIsClass) and handle it accordingly. You might have an ifstatement in mexFunction that sets up the inputs and outputs and then calls a template function. See the example below, which thresholds all the values in an array using the C++ standard library function template std::min<T> without requiring any data conversion.
flexibleFunction.cpp
#include "mex.h"
#include <algorithm> // std::min
template <typename T>
void threshArrayLT(T *out, const T *arr, mwSize n, T c)
{ // you allocate out
for (mwSize i = 0; i < n; ++i)
out[i] = std::min<T>(arr[i], c);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nlhs > 1 || nrhs != 2)
mexErrMsgTxt("Syntax:\n\tH = flexibleFunction(arr,c)");
if (!mxIsDouble(prhs[0]) && !mxIsSingle(prhs[0]))
mexErrMsgTxt("Array must be double or single.");
if ((mxIsDouble(prhs[0]) && !mxIsDouble(prhs[1])) ||
(mxIsSingle(prhs[0]) && !mxIsSingle(prhs[1])))
mexErrMsgTxt("Arguments must have same type.");
const mwSize* dims = mxGetDimensions(prhs[0]);
int ndims = static_cast<int>(mxGetNumberOfDimensions(prhs[0]));
size_t numel = mxGetNumberOfElements(prhs[0]);
if (mxIsDouble(prhs[0])) {
double *arr = mxGetPr(prhs[0]);
double c = mxGetScalar(prhs[1]);
plhs[0] = mxCreateNumericArray(ndims,dims,mxDOUBLE_CLASS,mxREAL);
threshArrayLT(mxGetPr(plhs[0]),arr,numel,c);
// In reality, if it's this simple, use std::transform with lambda or bind:
//std::transform(arr, arr+numel, mxGetPr(plhs[0]),
// [&](double s){ return std::min(s,c); });
} else if (mxIsSingle(prhs[0])) {
float *arr = (float*)mxGetData(prhs[0]);
float c = static_cast<float>(mxGetScalar(prhs[1]));
plhs[0] = mxCreateNumericArray(ndims,dims,mxSINGLE_CLASS,mxREAL);
threshArrayLT((float*)mxGetData(plhs[0]),arr,numel,c);
}
}
You can also use function overloading in C++ (same name, different argument types).
Example
>> v = rand(1,8); c = 0.5;
>> whos v c
Name Size Bytes Class Attributes
c 1x1 8 double
v 1x8 64 double
>> flexibleFunction(v,c)
ans =
0.2760 0.5000 0.5000 0.1626 0.1190 0.4984 0.5000 0.3404
>> flexibleFunction(single(v),single(c))
ans =
0.2760 0.5000 0.5000 0.1626 0.1190 0.4984 0.5000 0.3404

Best way of handling NaN in MATLAB/MEX

I am using solvers of LAPACK libraries in a MATLAB MEX file for solving linear system of equations. For some of the cases, the system that I solve is singular. For example, the system is as follows for one of my cases:
A =
0.00000000 0.00000000 0.00000000
0.00000000 0.00000000 0.00000000
0.00000000 0.00000000 77.31867171
b:
-0.00000000 -0.00000000 -0.00000000
What would be the best approach to label the solution of Ax=b of the above system as NaN similar to MATLAB?
Here is an example to create a numeric vector filled with NaNs from a MEX-function:
test_nan.cpp
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
plhs[0] = mxCreateDoubleMatrix(3, 1, mxREAL);
double *x = mxGetPr(plhs[0]);
double nanVal = mxGetNaN();
for (int i=0; i<3; ++i) {
x[i] = nanVal;
}
}
MATLAB
>> mex -largeArrayDims test_nan.cpp
>> x = test_nan()
x =
NaN
NaN
NaN

how to create a single float sparse matrix in mex files

This Creating sparse matrix in MEX has a good example on mxCreateSparse. But this function return a double sparse matrix instead of single. If I want to return a single sparse matrix, what should I do ? Thanks !
As #horchler suggested, you could use the undocumented function mxCreateSparseNumericMatrix. Example:
singlesparse.c
#include "mex.h"
#include <string.h> /* memcpy */
/* undocumented function prototype */
EXTERN_C mxArray *mxCreateSparseNumericMatrix(mwSize m, mwSize n,
mwSize nzmax, mxClassID classid, mxComplexity ComplexFlag);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
const float pr[] = {1.0, 7.0, 5.0, 3.0, 4.0, 2.0, 6.0};
const mwIndex ir[] = {0, 2, 4, 2, 3, 0, 4};
const mwIndex jc[] = {0, 3, 5, 5, 7};
const mwSize nzmax = 10;
const mwSize m = 5;
const mwSize n = 4;
plhs[0] = mxCreateSparseNumericMatrix(m, n, nzmax, mxSINGLE_CLASS, mxREAL);
memcpy((void*)mxGetPr(plhs[0]), (const void*)pr, sizeof(pr));
memcpy((void*)mxGetIr(plhs[0]), (const void*)ir, sizeof(ir));
memcpy((void*)mxGetJc(plhs[0]), (const void*)jc, sizeof(jc));
}
Usage:
>> mex -largeArrayDims singlesparse.c
>> s = singlesparse()
s =
(1,1) 1
(3,1) 7
(5,1) 5
(3,2) 3
(4,2) 4
(1,4) 2
(5,4) 6
>> ss = double(s);
>> whos s ss
Name Size Bytes Class Attributes
s 5x4 160 single sparse
ss 5x4 152 double sparse
>> f = full(s)
One or more output arguments not assigned during call to "full".
>> f = full(ss)
f =
1 0 0 2
0 0 0 0
7 3 0 0
0 4 0 0
5 0 0 6
>> s + s;
Undefined function 'plus' for input arguments of type 'single' and attributes 'sparse 2d real'.
>> ss + ss;
>> 2 * s;
Error using *
Undefined function 'times' for input arguments of type 'single' and attributes 'sparse 2d real'.
>> 2 * ss;
>> s * s';
Error using *
MTIMES is not supported for one sparse input and one single input.
>> ss * ss';
>> nnz(s)
ans =
7
>> nzmax(s)
ans =
10
>> dmperm(s)
Undefined function 'dmperm' for input arguments of type 'single'.
>> dmperm(ss)
ans =
1 3 0 5
>> svds(s)
Error using horzcat
The following error occurred converting from double to single:
Error using single
Attempt to convert to unimplemented sparse type
Error in svds (line 64)
B = [sparse(m,m) A; A' sparse(n,n)];
>> svds(ss)
ans =
9.9249
5.5807
3.2176
0.0000
>> % abs(s), cos(s), sin(s), s.^2, s.*s, etc.. all give errors
As you can see, the sparse single array was created successfully, however many functions expect the array to be of type double, so there is a lot of missing functionality...
Another restriction is that you cannot create multi-dimensional sparse arrays in MATLAB, they have to be 2D matrices..
Bottom line is: stick with double sparse 2D matrices in MATLAB!