运行MEX文件时

时间:2018-08-02 13:42:10

标签: c++ matlab mex

我正在尝试编写一个mex文件,在评估mex时,每次运行MATLAB都会崩溃。这是我编写的C ++代码的一部分:

void mexFunction(mwSize nlhs, mxArray *plhs[],
             mwSize nrhs, const mxArray *prhs[]){   

vector<int> *NNLt;
double *NNLtout;
Vector *V;
Vector *Fb;
mwSize *sn;
mwSize nsn; 
mwSize nf; 
double hs;
double bw;
double mw; 
mwSize ncols; 
mwSize i;
double *NNLtoutt;

/* check for proper number of arguments */
if(nrhs!=9) {
    mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","Nine inputs required.");
}
if(nlhs!=1) {
    mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required.");
}

/* get the value of the scalar input  */
nsn = mxGetScalar(prhs[4]);
nf = mxGetScalar(prhs[5]);
hs = mxGetScalar(prhs[6]);  
bw = mxGetScalar(prhs[7]);
mw = mxGetScalar(prhs[8]);
/* create a pointer to the real data in the input matrix  */
NNLt = (vector<int> *)mxGetData(prhs[0]);
V = (Vector *)mxGetData(prhs[1]);
Fb =(Vector *)mxGetData(prhs[2]);
sn = (mwSize *)mxGetData(prhs[3]); 

/* call the computational routine */    
createNNLtriangle(NNLt, V, Fb, sn, nsn, nf, hs, bw, mw);    

/* create the output matrix */
plhs[0] = mxCreateCellMatrix(nsn,50);

for(i=0;i<nsn;i++){
     mxArray* tmp = mxCreateDoubleMatrix(1, NNLt[i].size(), mxREAL);
     copy(NNLt[i].begin(), NNLt[i].end(), mxGetPr(tmp));     
     mxSetCell(plhs[0], i, tmp);
     mxFree(tmp);  
}}

所以,我遇到以下错误:

------------------------------------------------------------------------
       Segmentation violation detected at Thu Aug  2 14:41:25 2018
------------------------------------------------------------------------
...
    Stack Trace (from fault):
[  0] 0x00007f0b0c635426 /home/user/dir/createNNLtriangle.mexa64+00005158
[  1] 0x00007f0b0c635893 /home/user/dir/createNNLtriangle.mexa64+00006291 mexFunction+00000240
[  2] 0x00007f0c562cac4a /home/user/bin/glnxa64/libmex.so+00142410 mexRunMexFile+00000090
...

对于我们造成的混乱,同事们的澄清和其他问题,我们深表歉意。

您可以找到我们如何定义“ NNLt”。而这里的“ tmp”是什么意思?

std::copy(mxGetPr(tmp), mxGetPr(tmp)+N, NNLt.begin());

下面是Mexfile中的cpp函数,它在MexFunction之前:

#include "mex.h"
#include "matrix.h"
#include <omp.h>
#include "vema.h"s
#include "eig3.h"
#include <stdlib.h>
#include <iostream>
#include <cmath>
#include <vector>
#include <fstream>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>

using namespace std;

Vector closestPointTriangle(Vector&, Vector&, Vector&, Vector&, double&, double&, double&);

// Generates pomwSize-triangle proximity lists using the linked cell algorithm
void createNNLtriangle(vector<int>* NNLt, Vector* Ut, Vector* faces, int* SN, mwSize nsn, mwSize nf, double hs, double bw, double mw) {

int mx = max(1, (int)(bw/mw)); // ** = 40 cells bw=3.2, mw=0.08
vector<int> head(mx*mx*mx, -1);
vector<int> list(nf);
//  std::vector<int> head(mx*mx*mx, -1); //****** mx*mx*mx cells nomber, size mx*mx*mx vector with all values are -1, 40*40*40 = 64000
//  std::vector<int> list(nf); // **** nf = 101882
int xa, ya, za, xi, yi, zi;
double ub, vb, wb;
int pt, tri;
Vector cog;
for (int i = 0; i < nf; i++) { // Divide triangle faces mwSizeo cells, i index of face
    //Vector cog = (Ut[faces[i].n1] + Ut[faces[i].n2] + Ut[faces[i].n3])/3.0;
    cog = (Ut[(int)faces[i].x] + Ut[(int)faces[i].y] + Ut[(int)faces[i].z])/3.0;
    int xa = (int)((cog.x + 0.5*bw)/bw*mx);
    int ya = (int)((cog.y + 0.5*bw)/bw*mx);
    int za = (int)((cog.z + 0.5*bw)/bw*mx);
    int tmp =  mx*mx*za + mx*ya + xa; // *** 1641838 > 64000

    list[i]=head[mx*mx*za + mx*ya + xa];
    head[mx*mx*za + mx*ya + xa] = i;
}
#pragma omp parallel for
for (int i = 0; i < nsn; i++) { // Search cells around each pomwSize and build proximity list
    int pt = SN[i];
    NNLt[i].clear();
    int xa = (int)((Ut[pt].x + 0.5*bw)/bw*mx);
    int ya = (int)((Ut[pt].y + 0.5*bw)/bw*mx);
    int za = (int)((Ut[pt].z + 0.5*bw)/bw*mx);

    for (int xi = max(0, xa-1); xi <= min(mx-1, xa+1); xi++)// *** Browse head list
    for (int yi = max(0, ya-1); yi <= min(mx-1, ya+1); yi++)
    for (int zi = max(0, za-1); zi <= min(mx-1, za+1); zi++) {
        int tri = head[mx*mx*zi + mx*yi + xi];
        while (tri != -1) {
            if ( pt != (int)faces[tri].x && pt != (int)faces[tri].y && pt != (int)faces[tri].z ) {              
                if ( (closestPointTriangle(Ut[pt], Ut[(int)faces[tri].x], Ut[(int)faces[tri].y], Ut[(int)faces[tri].z], ub, vb, wb) - Ut[pt]).length() < hs) {
                    NNLt[i].push_back(tri);
                }
            }
            tri = list[tri];
        }
    }
    }
}


   // Returns the closest pomwSize of triangle abc to pomwSize p ***** a or b or c, if not, pt projection through the barycenter inside the triangle 
   Vector closestPointTriangle(Vector& p, Vector& a, Vector& b, Vector& c, double& u, double& v, double& w) {

Vector ab = b - a;
Vector ac = c - a;
Vector ap = p - a;
double d1 = ab.dot(ap);
double d2 = ac.dot(ap);
if (d1 <= 0.0 && d2 <= 0.0) {
    u = 1.0;
    v = 0.0;
    w = 0.0;
    return a;
}
Vector bp = p - b;
double d3 = ab.dot(bp);
double d4 = ac.dot(bp);
if (d3 >= 0.0 && d4 <= d3) {
    u = 0.0;
    v = 1.0;
    w = 0.0;
    return b;
}
double vc = d1*d4 - d3*d2;
if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) {
    v = d1 / (d1 - d3);
    u = 1.0 - v;
    w = 0.0;
    return a + ab * v;
}
Vector cp = p - c;
double d5 = ab.dot(cp);
double d6 = ac.dot(cp);
if (d6 >= 0.0 && d5 <= d6) {
    u = 0.0;
    v = 0.0;
    w = 1.0;
    return c;
}
double vb = d5*d2 - d1*d6;
if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) {
    w = d2 / (d2 - d6);
    u = 1.0 - w;
    v = 0.0;    
    return a + ac * w;
}
double va = d3*d6 - d5*d4;
if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0) {
    w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
    u = 0.0;
    v = 1.0 - w;
    return b + (c - b) * w;
}
double denom = 1.0 / (va + vb + vc);
v = vb * denom;
w = vc * denom;
u = 1.0 - v - w;
return a + ab * v + ac * w;
 }

下面是在Matlab中调用Mexfile的部分:

NNLt = cell(1,nsn);
V = A(1:n,1:3); //A: Matrix
Fb = A(n:2*n,1:3);
nf = size(Fb,1);
sn = B(1,:); //B: Matrix

parfor i = 1:nsn
     maxDist = max(maxDist, length(V(sn(i),:) - Vtold(i,:)));
end

if maxDist > 0.5*(hs-hc)
    [NNLt] = createNNLtriangle(NNLt, V, Fb, sn, nsn, nf, hs, bw, mw);
    for i = 1:nsn
        Vtold(i,:) = V(sn(i),:);
    end
 end

最后,这是我们的V和Fb定义的“ Vector *”类:

class Vector{
public:
double x, y, z;
Vector(): x(0.0), y(0.0), z(0.0) {};
Vector(double ax, double ay, double az): x(ax), y(ay), z(az) {};

double length(){
    return sqrt(x*x + y*y + z*z);
}
double dot(const Vector& b){
    return x*b.x + y*b.y + z*b.z;
}
Vector cross(const Vector& b){
    return Vector(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
}
void normalize(){
    double temp = 1.0/length();
    x *= temp;
    y *= temp;
    z *= temp;
}
void clear(){
    x = y = z = 0.0;
}
Vector& operator+= (const Vector& b){
    x += b.x;
    y += b.y;
    z += b.z;
    return *this;
}
Vector& operator-= (const Vector& b){
    x -= b.x;
    y -= b.y;
    z -= b.z;
    return *this;
}
Vector& operator*= (const double& c){
    x *= c;
    y *= c;
    z *= c;
    return *this;
}
Vector& operator/= (const double& c){
    x /= c;
    y /= c;
    z /= c;
    return *this;
}
Vector operator+ (const Vector& b){
    Vector r = *this;
    return r += b;
}
Vector operator- (const Vector& b){
    Vector r = *this;
    return r -= b;
}
Vector operator* (const double& c){
    Vector r = *this;
    return r *= c;
}
Vector operator/ (const double& c){
    Vector r = *this;
    return r /= c;
}
};
再次

很抱歉! 谢谢, 干杯

1 个答案:

答案 0 :(得分:2)

rahnema1 said in a comment一样,您无法将mxGetData的输出强制转换为所需的任何指针类型。此输出指向mxArray的数据,您需要这样读取它。

例如,

NNLt = (vector<int> *)mxGetData(prhs[0]);

vector<int>是特定的C ++数据结构,您正在将MATLAB数组中的数据重新解释为C ++数据结构。该数据结构的元素之一是指向数据的指针,因此您正在将(大概)双浮点值重新解释为指针,然后访问该指针,显然会导致崩溃。

您对Vector*的强制转换也是如此,尽管我不知道此类是什么。

相反,首先请确保输入的类型正确,然后将数据复制到以下位置:

if(!mxIsDouble(prhs[0])) {
   mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","First input must be a double array.");
}
std::size_t N = mxGetNumberOfElements(prhs[0]);
std::vector<int> NNLt(N);
std::copy(mxGetPr(prhs[0]), mxGetPr(prhs[0])+N, NNLt.begin());

但是,在您的其余代码中,NNLt似乎是向量的向量,而不是单个向量。 createNNLtriangle函数是否取自here?看起来像是对C和C ++的可怕破坏。

也许您然后需要在此处执行以下操作:

if(!mxIsDouble(prhs[0])) {
   mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","First input must be a double array.");
}
std::size_t M = mxGetM(prhs[0]); // number of rows
std::size_t N = mxGetN(prhs[0]); // number of columns
std::vector<std::vector<int>> NNLt(N, std::vector<int>(M));
double* ptr = mxGetPr(prhs[0]);
for(std::size_t ii = 0; ii < N; ++ii) {
   std::copy(ptr, ptr+M, NNLt[ii].begin());
   ptr += M;
}

// mwSize nsn = static_cast<mwSize>(mxGetScalar(prhs[4])); // Ignore this value!

// ... read the other values here in the same way

createNNLtriangle(NNLt.data(), V, Fb, sn, N, nf, hs, bw, mw);
//                ^^^^^^^^^^^             ^--- NOTE!

还要注意,第三个参数Fbvector<Face>,而不是Vector*。您将必须弄清楚如何转换Vector*vector<Face>,它将涉及如上所述的大量代码,而不仅仅是转换指针!

第四个参数是int*,而不是mwSize*

sn = (mwSize *)mxGetData(prhs[3]); 

您需要确保prhs[3]实际上包含一个int32矩阵,然后才能将其指针强制转换为int*。否则,您将必须像上面一样复制数据。

还要仔细检查所有其他参数,以确保传递正确的类型。设置编译器以警告所有隐式强制转换,然后注意所有这些警告。这些警告中的每一个都是导致您的程序在运行时崩溃的潜在原因。全部解决!