在MATLAB中使用glmnet-mex时的分割错误
从我的MATLAB代码中调用glmnet(从此处下载:)时,由于分段错误,我的工作一直受到影响。我调用glmnet例程数千次。我注意到问题发生的以下特点:在MATLAB中使用glmnet-mex时的分割错误,matlab,segmentation-fault,mex,Matlab,Segmentation Fault,Mex,从我的MATLAB代码中调用glmnet(从此处下载:)时,由于分段错误,我的工作一直受到影响。我调用glmnet例程数千次。我注意到问题发生的以下特点: 当我的输入矩阵的大小更大时,问题就更频繁了 我在单独的作业中使用高斯分布和泊松分布,并且我注意到在拟合泊松分布时问题更频繁(这通常需要更长的时间才能收敛,因此可能会在内部涉及更多的循环?) 由于没有关于这两个发行版的R版本出现分段错误的报告,我怀疑问题(可能是内存泄漏)可能在于mex接口,而不是核心glmnet Fortran代码,我将在下面
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
我要做的第一件事是清理MatlabAPI接口的东西。请记住,在Fortran中,不会像在C/C++中那样在函数/子例程参数列表中获得自动类型提升。因此,获得准确的签名非常重要。永远不要将文字整数传递给MatlabAPI函数。您应该完全按照API指定的类型传递变量,以确保不存在不匹配。例如,以以下代码为例:
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
API中mxCopyPtrToReal8的签名为:
subroutine mxCopyPtrToReal8(px, y, n)
mwPointer px
real*8 y(n)
mwSize n
因此,可能存在不匹配,因为默认Fortran整数可能与mwSize不匹配。此外,size是Fortran instrinsic函数的名称,因此变量的不同名称可能更合适。我会将该子程序更改为:
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
现在可以确保sizex是合适的类型。您还需要更改调用例程中变量的类型
(旁注:实际上,我不会做您正在做的任何事情……我只会编写一个循环,将值直接从mxArray复制到实际数组中,而无需额外的拷贝和内存分配/释放)
另一个例子是:
integer ...,nx,...
:
integer lmu,...
:
plhs(3) = mxCreateDoubleMatrix(nx,lmu,0)
应替换为:
mwSize nx, lmu
integer*4 :: ComplexFlag = 0
:
plhs(3) = mxCreateDoubleMatrix(nx,lmu,ComplexFlag)
x = temp
坦率地说,您有很多赋值循环,可以用简单的语句代替。例如:
call real8toreal(temp,x,sizex)
可替换为:
mwSize nx, lmu
integer*4 :: ComplexFlag = 0
:
plhs(3) = mxCreateDoubleMatrix(nx,lmu,ComplexFlag)
x = temp
这是:
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)
可替换为以下内容:
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
等等。谢谢!这真的很有见地。这不是我自己的代码,我是通过glmnet包页面获得的。我不太确定如何在代码处于的状态下调试代码,但您的建议为我提供了一个很好的方向,可以开始清理代码并进行调试。