Armadillo + Matlab Mex segfault

强颜欢笑 提交于 2019-12-06 11:50:21

The segfault seems to be caused by the fact that Matlab uses 64bits integers (long long or int64_t) in its bundled LAPACK and BLAS libraries. Armadillo on the other hand, uses 32bits integers (regular int on a 64bits platform, or int32_t) by default.

There are two solutions; the first one involves forcing Matlab to link to the system's libraries instead (which use ints), the second involves changing Armadillo's config file to enable long longs with BLAS. I tend to think that the first is more reliable, because there is no black-box effect, but it's also more troublesome, because you need to manually install and remember the path of your BLAS and LAPACK libs.

Both solutions required that I stopped using Armadillo's shared libraries and linked/included manually the sources. To do this, you must simply install LAPACK and BLAS on your system (if they are not already there, in Ubuntu that's libblas-dev and liblapack-dev), and copy the entire includes directory somewhere sensible like in $HOME/.local/arma for example.


Solution 1: linking to system's libraries

From the matlab console, set the environment variables BLAS_VERSION and LAPACK_VERSION to point to your system's libraries. In my case (Ubuntu 14.04, Matlab R2014b):

setenv('BLAS_VERSION','/usr/lib/libblas.so');
setenv('LAPACK_VERSION','/usr/lib/liblapack.so');

You can then compile normally:

mex -compatibleArrayDims -outdir +mx -L/home/john/.local/arma -llapack -lblas -I/home/john/.local/arma test_arma.cpp

or if you define the flag ARMA_64BIT_WORD in includes/armadillo_bits/config.hpp, you can drop the option -compatibleArrayDims.


Solution 2: changing Armadillo's config

The second solution involves uncommenting the flag ARMA_BLAS_LONG_LONG in Armadillo's config file includes/armadillo_bits/config.hpp. Matlab will link to its bundled LAPACK and BLAS libraries, but this time Armadillo won't segfault because it's using the right word-size. Same than before, you can also uncomment ARMA_64BIT_WORD if you want to drop the -compatibleArrayDims.

Compiled with

mex -larmadillo -DARMA_BLAS_LONG_LONG armaMex_demo2.cpp

(In Matlab)

armaMex_demo2(rand(1))

works without segfault.

However, compiled with

mex -larmadillo  armaMex_demo2.cpp

(In Matlab)

armaMex_demo2(rand(1))

causes a segfault.

Here, armaMex_demo2.cpp is

/* ******************************************************************* */
// armaMex_demo2.cpp: Modified from armaMex_demo.cpp copyright Conrad Sanderson and George Yammine.
/* ******************************************************************* */
// Demonstration of how to connect Armadillo with Matlab mex functions.
// Version 0.2
// 
// Copyright (C) 2014 George Yammine
// Copyright (C) 2014 Conrad Sanderson
// 
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/////////////////////////////
#include "armaMex.hpp"


void
mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  /* 
     Input:   X (real matrix)
     Output:  Eigenvalues of X X.T
  */


  if (nrhs != 1)
    mexErrMsgTxt("Incorrect number of input arguments.");


  // Check matrix is real
  if( (mxGetClassID(prhs[0]) != mxDOUBLE_CLASS) || mxIsComplex(prhs[0]))
    mexErrMsgTxt("Input must be double and not complex.");


  // Create matrix X from the first argument.
  arma::mat X = armaGetPr(prhs[0],true);


  // Run an arma function  (eig_sym)
  arma::vec eigvals(X.n_rows);
  if(not arma::eig_sym(eigvals, X*X.t()))
    mexErrMsgTxt("arma::eig_sym failed.");    


  // return result to matlab
  plhs[0] = armaCreateMxMatrix(eigvals.n_elem, 1);
  armaSetPr(plhs[0], eigvals);

  return;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!