4

Using Lapack with C++ is giving me a small headache. I found the functions defined for fortran a bit eccentric, so I tried to make a few functions on C++ to make it easier for me to read what's going on.

Anyway, I'm not getting th matrix-vector product working as I wish. Here is a small sample of the program.

smallmatlib.cpp:

#include <cstdio>
#include <stdlib.h>


extern "C"{
    // product C= alphaA.B + betaC                                               
   void dgemm_(char* TRANSA, char* TRANSB, const int* M,
               const int* N, const int* K, double* alpha, double* A,
               const int* LDA, double* B, const int* LDB, double* beta,
               double* C, const int* LDC);
    // product Y= alphaA.X + betaY                                               
   void dgemv_(char* TRANS, const int* M, const int* N,
               double* alpha, double* A, const int* LDA, double* X,
               const int* INCX, double* beta, double* C, const int* INCY);
   } 

void initvec(double* v, int N){
    for(int i= 0; i<N; ++i){
        v[i]= 0.0;
        }
   }

void matvecprod(double* A, double* v, double* u, int N){ 
    double alpha= 1.0, beta= 0.0;
    char no= 'N', tr= 'T';
    int m= N, n= N, lda= N, incx= N, incy= N;
    double* tmp= new double[N];
    initvec(tmp, N);
    dgemv_(&no,&m,&n,&alpha,A,&lda,v,&incx,&beta,tmp,&incy);
    for(int i= 0; i<N; ++i){
        u[i]= tmp[i];
        }
    delete [] tmp;
    }

void vecmatprod(double* v, double* A, double* u, int N){
    double alpha= 1.0, beta= 0.0;
    char no= 'N', tr= 'T';
    int m= N, n= 1, k= N, lda= N, ldb= N, ldc= N;
    double* tmp= new double[N];
    initvec(tmp, N);
    dgemm_(&no,&no,&m,&n,&k,&alpha,A,&lda,v,&ldb,&beta,tmp,&ldc);
    for(int i= 0; i<N; ++i){ 
        u[i]= tmp[i];
        }
    delete [] tmp;
    }

smallmatlib.h:

#ifndef SMALLMATLIB_H
#define SMALLMATLIB_H

void initvec(double* v, int N);

void matvecprod(double* A, double* v, double* u, int N);

void vecmatprod(double* v, double* A, double* u, int N);

#endif

smallmatlab.cpp:

#include "smallmatlib.h"
#include <cstdio>
#include <stdlib.h>
#define SIZE 2

int main(){
  double A[SIZE*SIZE]=
    { 1,2,
      3,4 };
  double v[SIZE]= {2,5.2};
  double u[SIZE]= {0,0};
  matvecprod(A,v,u,SIZE);
  printf("%f %f\n",u[0],u[1]);
  vecmatprod(v,A,u,SIZE);
  printf("%f %f\n",u[0],u[1]);
  return 0;
  }

Compiling:
g++ -c smallmatlib.cpp
g++ smallmatlab.cpp smallmatlib.o -L/usr/local/lib -lclapack -lcblas

Now the function matvecprod is the problem. With the example matrix A and example vector v, it should produce an output like

12.4..    26.8..

but instead it prints out

2.00..    0.00..

I tried to produce the correct result with both dgemm and dgemv, but wasn't able to. I have a hunch that my variables incx and incy do not have correct values, but it's difficult to find an explanation for them that I'd understand.

A smaller problem is that at the moment I can't use them like vecmatprod(v,A,v,SIZE) - that is, I always have to define the vector u, that will hold the result, separately, and call vecmatprod(v,A,u,SIZE). Any help would be appreciated.

As a side note, I'm also a beginner at C++, so I appreciate any criticism/suggestion you might have about my code.

jww
  • 97,681
  • 90
  • 411
  • 885
swirld
  • 89
  • 1
  • 7
  • `delete tmp;` Wrong form of `delete`. It should be: `delete [] tmp;` But why go through all this when you could have simply passed `u` to your function? – PaulMcKenzie Feb 22 '15 at 04:57
  • Edited that part, didn't help with any of the problems though. Say, if I'm making a transformation for a vector, I noticed that sometimes it would be more convinient to be able just assign v= Av – swirld Feb 22 '15 at 05:02

1 Answers1

2

You are right, the problem is in incx value - it should be 1, take a look at reference.

INCX is INTEGER
  On entry, INCX specifies the increment for the elements of
  X. INCX must not be zero.

So this value should be used when values of vector x is not placed one by one (vector of complex values for example, when you want to use only real part).

Also you can not use vecmatprod(v,A,v,SIZE) with v as both x and y. This is because how matrix-vector multiplication works (see wikipedia for example). You need values of original x the whole time to produce correct result. Small example:

y = A * x 

where

y = [ y1 y2 ]
A = [ [a11 a12] [a21 a22] ]
x = [ x1 x2 ]

And we calculate y like this

y1 = a11 * x1 + a12 * x2
y2 = a21 * x1 + a22 * x2

You can see, that when we calculate y2 we need x1 and x2, but if you use x = A * x(without temporary vector) you will replace x1 with y1 thus produce wrong answer.

Nikolay K
  • 3,770
  • 3
  • 25
  • 37
  • Oh, I see. This is the answer I'm looking for (well, I also had to change the flag to T), and you clarified the use of incx/incy. In the function, I tried to go around that problem by defining the temporary variable, storing result there first. For some reason, it still didn't work like I wanted. – swirld Feb 22 '15 at 08:47
  • Fogot about this, indeed you need to changevariable to ``T``. This is because LAPACK functions written in Fortran and thus 2-dimensional arrays are stored by column. – Nikolay K Feb 22 '15 at 08:54