Mex编译函数,用于计算集合交集和差异,保持崩溃

时间:2015-06-11 10:22:42

标签: c matlab mex

[这个问题已经解决]

(这个问题已经发布在Matlab论坛上,在这里:http://www.mathworks.com/matlabcentral/answers/223415-mex-compiled-function-used-to-compute-set-intersection-and-difference-keeps-crashing

嗨,大家好,

我正在尝试构建一个非常简单的函数,它应该计算两组的“交集”和“差异”,返回相应的索引。

例如,如果我们有

in1 = [1 2 4 5 9]
in2 = [2 3 4 8]

它应该返回

common1 = [2 3] % since all(in1(common1) == in2(common2))
common2 = [1 3]
only1 = [1 4 5] % the remaining indices, not in common1
only2 = [2 4]   % the ones not in common2

我可以使用intersect和setdiff来做到这一点,但因为我有小集,因为我将这个函数称为数千次,我认为使用编译的C-mex文件来做这应该是最快的方法。它确实是我算法的瓶颈。

我编写了这个函数

#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],
        int nrhs, const mxArray *prhs[])
{
    mexPrintf("Starting ...\n") ;
    /* Check nbr of inputs and outputs */
    if (nrhs != 2 || nlhs != 4)
        mexErrMsgTxt("intersectFast needs 4 outputs and 2 inputs") ;
    const mxArray* pin1 = prhs[0] ;
    const mxArray* pin2 = prhs[1] ;
    /* Inputs should be column vectors */
    if (mxGetN(pin1) != 1 || mxGetN(pin2) != 1)
        mexErrMsgTxt("inputs arguments should be column vectors") ;
    mwSize dims1 = mxGetM(pin1) ;
    mwSize dims2 = mxGetM(pin2) ;
    double* in1 = mxGetPr(pin1) ;
    double* in2 = mxGetPr(pin2) ;
    mexPrintf("Checks passed\n") ;
    mwIndex* idCommon1 = mxCalloc(dims1, sizeof(mwIndex)) ; // At most dims1 elements
    mwIndex* idCommon2 = mxCalloc(dims2, sizeof(mwIndex)) ; /* AT MOST dims2 and NOT dims1 ... this was the error. Damn I feel so stupid right now. */
    mwIndex* idOnly1   = mxCalloc(dims1, sizeof(mwIndex)) ; /* Same error here */
    mwIndex* idOnly2   = mxCalloc(dims2, sizeof(mwIndex)) ;  
    mwSize sizeCommon1, sizeCommon2, sizeOnly1, sizeOnly2 ;
    mwIndex i, j ;
    mwIndex k, l ;
    int match ;
    /* Intersect fast */
    /* in1 */
    k = 0 ; l = 0 ;
    for(i = 0 ; i < dims1 ; i++) {
        match = 0 ;
        for(j = 0 ; j < dims2 ; j++) {
            if (in1[i] == in2[j]) {
                idCommon1[k++] = (i+1) ; /* Matlab <-> C convention */
                match = 1 ;
                break ;
            }
        }
        if (! match) {
            idOnly1[l++] = (i+1) ;
        }
    }
    sizeCommon1 = k ;
    sizeOnly1 = l ;
    /* in2 */
    k = 0 ; l = 0 ;
    for(i = 0 ; i < dims2 ; i++) {
        match = 0 ;
        for(j = 0 ; j < dims1 ; j++) {
            if (in2[i] == in1[j]) {
                idCommon2[k++] = (i+1) ;
                match = 1 ;
                break ;
            }
        }
        if (! match)
            idOnly2[l++] = (i+1) ;
    }
    sizeCommon2 = k ;
    sizeOnly2 = l ;
    /* Return results */
    mexPrintf("Sizes = %d, %d, %d, %d\n", sizeCommon1, sizeCommon2, sizeOnly1, sizeOnly2) ;
    plhs[0] = mxCreateNumericMatrix(sizeCommon1, 1, mxUINT32_CLASS, mxREAL);
    plhs[1] = mxCreateNumericMatrix(sizeCommon2, 1, mxUINT32_CLASS, mxREAL);
    plhs[2] = mxCreateNumericMatrix(sizeOnly1,   1, mxUINT32_CLASS, mxREAL);
    plhs[3] = mxCreateNumericMatrix(sizeOnly2,   1, mxUINT32_CLASS, mxREAL);
    if (plhs[0] == NULL || plhs[1] == NULL || plhs[2] == NULL || plhs[3] == NULL)
        mexErrMsgTxt("Could not create mxArray.\n");
    mxSetData(plhs[0], idCommon1);
    mxSetData(plhs[1], idCommon2);
    mxSetData(plhs[2], idOnly1);
    mxSetData(plhs[3], idOnly2);
    mexPrintf("Done.\n") ;
}

当我测试它时,它经常有效,但它总是最终崩溃......例如,使用

% Test intersect fast
clc ; close all ; clear all ;
while true    
    clc ;    
    id1 = unique(randi(10, 8, 1)) ;
    id2 = unique(randi(12, 6, 1)) ;       
    [idCommon1, idCommon2, idOnly1, idOnly2] = intersectFast(id1, id2) ;     
    pause(0.1)    
end
完成mex功能后,它总会在某些时候崩溃。我的意思是我得到一个错误,如“Matlab遇到内部问题,需要关闭”。所以我猜mxCreateNumericMatrix或mxSetData都有问题,但我无法弄清楚究竟是什么问题。我尝试更改索引类型(uint32,uint64,int,...)但它并没有真正改变任何东西。

我在OSX 10.10.3上使用R2015a,编译是默认的(Clang)。

非常感谢你的帮助!

=================

编辑:让我更具体地讲述它是如何崩溃的。 有时候,MATLAB才开始冻结(我得到旋转的彩色鼠标指针......),并最终崩溃。在这种情况下,我需要强制MATLAB退出。 在其他一些时候,我从MATLAB收到一条错误消息,说它遇到内部错误并需要退出。在这种情况下,我可以找到一个Matlab崩溃文件。我在此处上传了一份崩溃报告:http://pastebin.com/ry7MN7yw

1 个答案:

答案 0 :(得分:0)

如果您可以从OS X提供错误消息会更好,可以通过单击屏幕右上角的已崩溃通知来获取。对于涉及某些低级(与Matlab本身相比)的问题,例如C,来自操作系统的崩溃报告通常很有用,因为您可以看到崩溃程序的原因。您可以将其全部粘贴到pastebin或其他任何内容。

如果您确实发现它在代码中崩溃,请将-g标记添加到clang,以便在崩溃报告中获取一些行号。

很抱歉没有将此作为评论 - 我还没有50个代表。