未能在MATLAB mex代码中使用LAPACK函数(cgeev函数)

时间:2017-11-06 05:33:25

标签: c matlab mex

我一直试图在我的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;
}

如果这可以帮助别人,我感到很高兴。

感谢。

0 个答案:

没有答案