Calling MATLAB's built-in LAPACK/BLAS routines
Asked Answered
J

2

9

I want to learn how to call the built-in LAPACK/BLAS routines in MATLAB. I have experience in MATLAB and mex files but I've actually no idea how to call LAPACK or BLAS libraries. I've found the gateway routines in file exchange that simplifies the calls since I don't have to write a mex file for any function such as this one. I need any toy example to learn the basic messaging between MATLAB and these built-in libraries. Any toy example such as matrix multiplication or LU decomposition is welcome.

Julesjuley answered 22/6, 2011 at 10:44 Comment(3)
Why FORTRAN? I am not sure but I always thought that LAPACK/BLAS have been ported to C/C++ 30 years ago and MATLAB uses this implementation!Tinworks
Well, you see that I'm so new to it :( I see FORTRAN codes when I check for their documentation. Let me update the question accordingly.Julesjuley
@Mikhail, @Ismail: They libraries themselves are written in Fortran, and the calling conventions are those of Fortran. You are right that there are wrappers for C/C++, CBLAS/ CLAPACK being the most straightforward ones, and then a bunch of templated/generic/whatever things for C++.Instrumentation
V
10

If you look inside the lapack.m file from the FEX submission mentioned, you will see a couple of examples on how to use the function:

Example: SVD decomposition using DGESVD:

X = rand(4,3);
[m,n] = size(X);
C = lapack('dgesvd', ...
     'A', 'A', ...           % compute ALL left/right singular vectors
      m, n, X, m, ...        % input MxN matrix
      zeros(n,1), ...        % output S array
      zeros(m), m, ...       % output U matrix
      zeros(n), n, ....      % output VT matrix
      zeros(5*m,1), 5*m, ... % workspace array
      0 ...                  % return value
);
[s,U,VT] = C{[7,8,10]};      % extract outputs
V = VT';

(Note: the reason we used those dummy variables for output variables is because Fortran functions expect all arguments to be passed by reference, but MEX-functions in MATLAB do not allow modifying their input, thus it's written to return copies of all inputs in a cell array with any modifications)

We get:

U =
     -0.44459      -0.6264     -0.54243       0.3402
     -0.61505     0.035348      0.69537      0.37004
     -0.41561     -0.26532      0.10543     -0.86357
     -0.50132      0.73211     -0.45948    -0.039753
s =
       2.1354
      0.88509
      0.27922
V =
     -0.58777      0.20822     -0.78178
      -0.6026     -0.75743      0.25133
     -0.53981      0.61882      0.57067

Which is equivalent to MATLAB's own SVD function:

[U,S,V] = svd(X);
s = diag(S);

that gives:

U =
     -0.44459      -0.6264     -0.54243       0.3402
     -0.61505     0.035348      0.69537      0.37004
     -0.41561     -0.26532      0.10543     -0.86357
     -0.50132      0.73211     -0.45948    -0.039753
s =
       2.1354
      0.88509
      0.27922
V =
     -0.58777      0.20822     -0.78178
      -0.6026     -0.75743      0.25133
     -0.53981      0.61882      0.57067

EDIT:

For completeness, I show below an example of a MEX-function directly calling the Fortran interface of the DGESVD routine.

The good news is that MATLAB provides libmwlapack and libmwblas libraries and two corresponding header files blas.h and lapack.h we can use. In fact, there is a page in the documentation explaining the process of calling BLAS/LAPACK functions from MEX-files.

In our case, lapack.h defines the following prototype:

extern void dgesvd(char *jobu, char *jobvt, 
  ptrdiff_t *m, ptrdiff_t *n, double *a, ptrdiff_t *lda,
  double *s, double *u, ptrdiff_t *ldu, double *vt, ptrdiff_t *ldvt,
  double *work, ptrdiff_t *lwork, ptrdiff_t *info);

svd_lapack.c

#include "mex.h"
#include "lapack.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    mwSignedIndex m, n, lwork, info=0;
    double *A, *U, *S, *VT, *work;
    double workopt = 0;
    mxArray *in;

    /* verify input/output arguments */
    if (nrhs != 1) {
        mexErrMsgTxt("One input argument required.");
    }
    if (nlhs > 3) {
        mexErrMsgTxt("Too many output arguments.");
    }
    if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])) {
        mexErrMsgTxt("Input matrix must be real double matrix.");
    }

    /* duplicate input matrix (since its contents will be overwritten) */
    in = mxDuplicateArray(prhs[0]);

    /* dimensions of input matrix */
    m = mxGetM(in);
    n = mxGetN(in);

    /* create output matrices */
    plhs[0] = mxCreateDoubleMatrix(m, m, mxREAL);
    plhs[1] = mxCreateDoubleMatrix((m<n)?m:n, 1, mxREAL);
    plhs[2] = mxCreateDoubleMatrix(n, n, mxREAL);

    /* get pointers to data */
    A = mxGetPr(in);
    U = mxGetPr(plhs[0]);
    S = mxGetPr(plhs[1]);
    VT = mxGetPr(plhs[2]);

    /* query and allocate the optimal workspace size */
    lwork = -1;
    dgesvd("A", "A", &m, &n, A, &m, S, U, &m, VT, &n, &workopt, &lwork, &info);
    lwork = (mwSignedIndex) workopt;
    work = (double *) mxMalloc(lwork * sizeof(double));

    /* perform SVD decomposition */
    dgesvd("A", "A", &m, &n, A, &m, S, U, &m, VT, &n, work, &lwork, &info);

    /* cleanup */
    mxFree(work);
    mxDestroyArray(in);

    /* check if call was successful */
    if (info < 0) {
        mexErrMsgTxt("Illegal values in arguments.");
    } else if (info > 0) {
        mexErrMsgTxt("Failed to converge.");
    }
}

On my 64-bit Windows, I compile the MEX-file as: mex -largeArrayDims svd_lapack.c "C:\Program Files\MATLAB\R2013a\extern\lib\win64\microsoft\libmwlapack.lib"

Here is a test:

>> X = rand(4,3);
>> [U,S,VT] = svd_lapack(X)
U =
   -0.5964    0.4049    0.6870   -0.0916
   -0.3635    0.3157   -0.3975    0.7811
   -0.3514    0.3645   -0.6022   -0.6173
   -0.6234   -0.7769   -0.0861   -0.0199
S =
    1.0337
    0.5136
    0.0811
VT =
   -0.6065   -0.5151   -0.6057
    0.0192    0.7521   -0.6588
   -0.7949    0.4112    0.4462

vs.

>> [U,S,V] = svd(X);
>> U, diag(S), V'
U =
   -0.5964    0.4049    0.6870    0.0916
   -0.3635    0.3157   -0.3975   -0.7811
   -0.3514    0.3645   -0.6022    0.6173
   -0.6234   -0.7769   -0.0861    0.0199
ans =
    1.0337
    0.5136
    0.0811
ans =
   -0.6065   -0.5151   -0.6057
    0.0192    0.7521   -0.6588
   -0.7949    0.4112    0.4462

(remember that the sign of the eigenvectors in U and V is arbitrary, so you might get flipped signs comparing the two)

Veilleux answered 22/6, 2011 at 13:42 Comment(1)
@Acorbe: I added an implementation of a MEX-file that directly calls the Fortran functions, so you can try it yourself and compare the speed... I did a quick test, and MATLAB's own svd is about twice as fast. I think this in part due to the overhead of calling MEX-functions as opposed to a builtin function. The advantage of the mentioned FEX submission is that you don't have to write a MEX-file for each LAPACK routine, their solution takes care of all the boilerplate code for you, into a single function!Veilleux
H
-2

A good/pratical example of how to use SVD in matlab is explained here: Transforming captured co-ordinates into screen co-ordinates

More on how to calculate svd in objective-c with lapack is written here calculate the V from A = USVt in objective-C with SVD from LAPACK in xcode

Hertha answered 9/8, 2012 at 21:23 Comment(1)
fellowworldcitizen, welcome to SO. The question asks how to call built-in LAPACK routines from MATLAB. Your answer has good references but it is not a real answer to the question.Julesjuley

© 2022 - 2024 — McMap. All rights reserved.