Matlab Mex C реализация разложения Холецкого

В настоящее время я исследую время выполнения различных методов обращения матриц и поэтому наткнулся на разложение Холецкого. Чтобы сравнить со встроенной декомпозицией Холецкого в Matlab, я хотел бы преобразовать мою реализацию декомпозиции Холецкого на основе Matlab в C-реализацию с интерфейсом Mex-Matlab.

Я старался изо всех сил с моими ограниченными навыками программирования на C и кучей руководств и примеров, но я не могу скомпилировать свой Mex-интерфейс. Я был бы очень признателен, если бы кто-нибудь мог дать мне руку.

Вот мой код:

#include "mex.h"

/* The computational routine */
void myCholeskyC(double *M, double *L, mwSize n)
{

    mwSize i;
    mwSize j;
    mwSize k;
    mwSize l;

    /* multiply each element y by x */
    for (i=0; i<n; i++) {

        double sum = 0;
        for (k=0; k<n; k++) {
            sum+= L[i][k]*L[i][k];
        } //end of for-loop k
        L[i][i] = sqrt(M[i][i] - sum);

        for (j=i+1; j<n; j++) {
            double sum2 = 0;
            for (l=0; l<n; l++) {
                sum2+= L[i][l]*L[j][l];
            } //end of for-loop l

            L[j][i] = (M[j][i] - sum2)/L[i][i];
        } //end of for-loop j
    } //end of for-loop i
} //end of computational routine

/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
    double multiplier;              /* input scalar */
    double *inMatrix;               /* 1xN input matrix */
    size_t ncols;                   /* size of matrix */
    double *outMatrix;              /* output matrix */

    /* check for proper number of arguments */
    if(nrhs!=1) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","Only one input required.");
    }
    if(nlhs!=1) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required.");
    }
    /* make sure the input argument is type double */
    if( !mxIsDouble(prhs[0]) || 
         mxIsComplex(prhs[0])) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notDouble","Input matrix must be type double.");
    }

    /* create a pointer to the real data in the input matrix  */
    inMatrix = mxGetPr(prhs[0]);

    /* get dimensions of the input matrix */
    ncols = mxGetN(prhs[0]);

    /* create the output matrix */
    plhs[0] = mxCreateDoubleMatrix((mwSize)ncols,(mwSize)ncols,mxREAL);

    /* set output matrix */
    outMatrix = plhs[0];

    /* call the computational routine */
    myCholeskyC(inMatrix,outMatrix,(mwSize)ncols);
}

Реализация Cholesky на основе Matlab, которую я пытаюсь реализовать на C, такова:

function L = cholMatlab2(M)
n = length( M );
L = zeros( n, n );
for i=1:n
   L(i, i) = sqrt(M(i, i) - L(i, :)*L(i, :)');
   for j=(i + 1):n
      L(j, i) = (M(j, i) - L(i,:)*L(j ,:)')/L(i, i);
   end
end

end

Большое спасибо!

Редактировать: вот исправленный код, если кто-то ищет реализацию разложения Холецкого на основе Matlab-mex-C:

#include "mex.h"
#include <math.h>

#define L(x,y) L[(x) + (y)*n]
#define M(x,y) M[(x) + (y)*n]

/* The computational routine */
void myCholeskyC(double *M, double *L, mwSize n)
{

    mwSize i;
    mwSize j;
    mwSize k;
    mwSize l;

    /* multiply each element y by x */
    for (i=0; i<n; i++) {

        double sum = 0;
        for (k=0; k<n; k++) {
            sum+= L(i,k)*L(i,k);
        } //end of for-loop k
        L(i,i) = sqrt(M(i,i) - sum);

        for (j=i+1; j<n; j++) {
            double sum2 = 0;
            for (l=0; l<n; l++) {
                sum2+= L(i,l)*L(j,l);
            } //end of for-loop l

            L(j,i) = (M(j,i) - sum2)/L(i,i);
        } //end of for-loop j
    } //end of for-loop i
} //end of computational routine

/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
    double multiplier;              /* input scalar */
    double *inMatrix;               /* 1xN input matrix */
    size_t ncols;                   /* size of matrix */
    double *outMatrix;              /* output matrix */

    /* check for proper number of arguments */
    if(nrhs!=1) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","Only one input required.");
    }
    if(nlhs!=1) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required.");
    }
    /* make sure the input argument is type double */
    if( !mxIsDouble(prhs[0]) || 
         mxIsComplex(prhs[0])) {
        mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notDouble","Input matrix must be type double.");
    }

    /* create a pointer to the real data in the input matrix  */
    inMatrix = mxGetPr(prhs[0]);

    /* get dimensions of the input matrix */
    ncols = mxGetN(prhs[0]);

    /* create the output matrix */
    plhs[0] = mxCreateDoubleMatrix((mwSize)ncols,(mwSize)ncols,mxREAL);

    /* set output matrix */
    outMatrix = mxGetPr(plhs[0]);

    /* call the computational routine */
    myCholeskyC(inMatrix,outMatrix,(mwSize)ncols);
}

person user3116232    schedule 12.11.2015    source источник
comment
прежде всего L[i][i] = sqrt(M[i][i] - сумма; Здесь не хватает скобки.   -  person terence hill    schedule 12.11.2015
comment
Спасибо! Я исправил это, а также добавил свою реализацию Matlab для лучшего понимания того, что я пытался реализовать.   -  person user3116232    schedule 12.11.2015
comment
Было бы очень полезно, если бы вы опубликовали ошибки компилятора.   -  person JaBe    schedule 12.11.2015
comment
Извините, добавил ошибки компилятора   -  person user3116232    schedule 13.11.2015
comment
Хорошо, я думаю, что проблема действительно сводится к операциям с матрицами, так как почти каждая ошибка связана с этим. Я просто не знаю, как ввести матрицу, передать ее функции, сделать операции над матрицей, отдать ее основной функции и вернуть. Есть идеи?   -  person user3116232    schedule 13.11.2015
comment
Каковы были ваши результаты тестов? Должно ли это быть эквивалентом [V,lam] = eig(C) (ну, без lam)? Не могли бы вы привести один пример вызова вашего метода? Мне нужно сделать матрицы 3x3, и я ищу для этого реализацию Cholesky на C (не QZ).   -  person ggb667    schedule 31.01.2017


Ответы (1)


Прежде всего, невозможно напрямую мультииндексировать mxArray. В C двумерные матрицы представляют собой массивы массивов. Вы можете создать макрос или линейно вычислить индексы, как в этом ответе.

Индексируйте матрицы линейно: L[(i)+(k)*nrows)] вместо L[i][k].

Компилятор прямо говорит вам, что вы должны

#include <math.h>

Вы также должны получить указатель вывода с помощью

outMatrix = mxGetPr(plhs[0]);
person JaBe    schedule 13.11.2015