我一直试图在我的MATLAB mex代码中使用cgeev函数来计算(偏斜对称)复杂矩阵的特征值和特征向量,但到目前为止最终失败了。
这是我写的代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/* Macro to define the correct function prototype */
#if defined (_WIN32) || defined(__APPLE__)
#define FORTRAN_COMPLEX_FUNCTIONS_RETURN_VOID 1
#endif
#include "mex.h"
#include "blas.h"
#include "lapack.h"
#include "fort.h" /* defines complex data handling functions */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if(nrhs != 1)
mexErrMsgTxt("Only one input argument is allowed.");
else if(nlhs > 3)
mexErrMsgTxt("Too many output arguments.");
const mxArray *X = prhs[0];
size_t n = mxGetM(X);
size_t two_n = 2 * n;
size_t one = 1;
mxArray *D = mxCreateDoubleMatrix(n, one, mxCOMPLEX);
mxArray *VL = mxCreateDoubleMatrix(n, n, mxCOMPLEX);
mxArray *VR = mxCreateDoubleMatrix(n, n, mxCOMPLEX);
double *Dfort = mat2fort(D, n, one);
double *VLfort = mat2fort(VL, n, n);
double *VRfort = mat2fort(VR, n, n);
double *Xfort = mat2fort(X, n, n);
char *jobvlr = 'V';
mxArray *LWORK = mxCreateDoubleMatrix(one, two_n, mxCOMPLEX);
double *LWORKfort = mat2fort(LWORK, two_n, two_n);
mxArray *RWORK = mxCreateDoubleMatrix(one, two_n, mxREAL);
double* RWORKfort = mat2fort(RWORK, one, two_n);
int INFO = 0;
/* call BLAS function */
cgeev_(jobvlr, jobvlr, &n, Xfort, &n, Dfort, VLfort, &n, VRfort, &n,
LWORKfort, &two_n, RWORKfort, &INFO);
plhs[0] = fort2mat(VLfort, n, n, n);
plhs[1] = fort2mat(Dfort, n, n, one);
plhs[2] = fort2mat(VRfort, n, n, n);
mxDestroyArray(D);
mxDestroyArray(VL);
mxDestroyArray(VR);
mxDestroyArray(LWORK);
mxFree(LWORKfort);
mxDestroyArray(RWORK);
mxFree(RWORKfort);
mxFree(Xfort);
return;
}
这个代码可以在我的环境中编译(Macbook pro with High Sierra和MATLAB 2017a),但是一旦执行编译后的函数,它就会崩溃而没有任何错误消息(当我们执行具有分段错误的mex代码时,这是MATLAB的典型行为一种错误)。当我注释掉cgeev_函数调用行时,它也是可编译的,现在可以执行而没有任何错误。所以我认为在我的代码中使用LAPACK函数时会出现一些错误。
我还尝试用LAPACK编译矩阵乘法代码,由Mathworks提供,如下所示。我成功编译并执行它。
copyfile(fullfile(matlabroot,'extern','examples','refbook','matrixMultiply.c'),'.')
是否有人有建议或帮助识别我的代码中的实际错误?
后记
我最终自己解决了这个问题。我的第一个代码的问题是我对clapack函数规范的误解。 cgeev_和zgeev_函数接收&#34;复杂&#34;或&#34; doublecomplex&#34;类型变量,在&#34; f2c.h&#34;中定义。从c代码中特定使用lapack函数。 &#34; fort.h&#34; Mathworks提供的标题并不包含此类数据类型的实用程序函数(它们可能提供一些我对clapack使用不了解的其他函数)。所以我需要将自己的转换函数从MATLAB矩阵编写到复杂的数组中。 这是我重写的代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/* Macro to define the correct function prototype */
#if defined (_WIN32) || defined(__APPLE__)
#define FORTRAN_COMPLEX_FUNCTIONS_RETURN_VOID 1
#endif
#include "mex.h"
#include "blas.h"
#include "lapack.h"
#include "fort.h" /* defines complex data handling functions */
doublecomplex* mat2clapack(const mxArray *X)
{
int m = (int)mxGetM(X);
int n = (int)mxGetN(X);
doublecomplex *Z = (doublecomplex *)mxCalloc(m * n, sizeof(doublecomplex));
double *xr = mxGetPr(X);
doublecomplex *zp = Z;
if(mxIsComplex(X)){
double *xi = mxGetPi(X);
for (int j = 0; j < n; j++) {
for (int i = 0; i < m; i++) {
zp->r = *xr++;
zp->i = *xi++;
zp++;
}
}
}else{
for (int j = 0; j < n; j++) {
for (int i = 0; i < m; i++) {
zp->r = *xr++;
zp->i = 0.0;
zp++;
}
}
}
return(Z);
}
mxArray* clapack2mat(doublecomplex *Z, mwSignedIndex m, mwSignedIndex n)
{
mxArray *X = mxCreateDoubleMatrix(m, n, mxCOMPLEX);
double *xr = mxGetPr(X);
double *xi = mxGetPi(X);
doublecomplex *zp = Z;
for (int j = 0; j < n; j++) {
for (int i = 0; i < m; i++) {
*xr++ = zp->r;
*xi++ = zp->i;
zp++;
}
}
return(X);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if(nrhs != 1)
mexErrMsgTxt("Only one input argument is allowed.");
else if(nlhs > 3)
mexErrMsgTxt("Too many output arguments.");
const mxArray *X = prhs[0];
mwSignedIndex n = mxGetM(X);
mwSignedIndex two_n = 2 * n;
mwSignedIndex one = 1;
mxArray *D = mxCreateDoubleMatrix(n, one, mxCOMPLEX);
mxArray *VL = mxCreateDoubleMatrix(n, n, mxCOMPLEX);
mxArray *VR = mxCreateDoubleMatrix(n, n, mxCOMPLEX);
doublecomplex *Dfort = mat2clapack(D);
doublecomplex *VLfort = mat2clapack(VL);
doublecomplex *VRfort = mat2clapack(VR);
doublecomplex *Xfort = mat2clapack(X);
char *jobvlr = "V";
mxArray *LWORK = mxCreateDoubleMatrix(one, two_n, mxCOMPLEX);
doublecomplex *LWORKfort = mat2clapack(LWORK);
mxArray *RWORK = mxCreateDoubleMatrix(one, two_n, mxREAL);
double* RWORKfort = mat2fort(RWORK, one, two_n);
ptrdiff_t INFO = 0;
/* call BLAS function */
zgeev_(jobvlr, jobvlr, &n, Xfort, &n, Dfort, VLfort, &n, VRfort, &n,
LWORKfort, &two_n, RWORKfort, &INFO);
plhs[0] = clapack2mat(VLfort, n, n);
plhs[1] = clapack2mat(Dfort, n, one);
plhs[2] = clapack2mat(VRfort, n, n);
mxDestroyArray(D);
mxDestroyArray(VL);
mxDestroyArray(VR);
mxDestroyArray(LWORK);
mxDestroyArray(RWORK);
return;
}
如果这可以帮助别人,我感到很高兴。
感谢。