【问题标题】:Matrix-vector product with dgemm/dgemv使用 dgemm/dgemv 的矩阵向量积
【发布时间】:2015-04-23 15:14:02
【问题描述】:

在 C++ 中使用 Lapack 让我有点头疼。 我发现为 fortran 定义的函数有点古怪,所以我尝试在 C++ 上创建一些函数,以使我更容易阅读正在发生的事情。

无论如何,我没有让矩阵向量产品按我的意愿工作。 这是该程序的一个小示例。

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;
  }

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

现在函数 matvecprod 是问题所在。 使用示例矩阵 A 和示例向量 v,它应该产生类似的输出

12.4..    26.8..

但它会打印出来

2.00..    0.00..

我尝试使用 dgemm 和 dgemv 生成正确的结果,但未能成功。我有一种预感,我的变量 incx 和 incy 没有正确的值,但很难找到我能理解的解释。

一个较小的问题是,目前我不能像这样使用它们 vecmatprod(v,A,v,SIZE) - 也就是说,我总是必须定义向量 u,它将分别保存结果,并调用 vecmatprod(v,A,u,SIZE)。 任何帮助将不胜感激。

顺便说一句,我也是 C++ 的初学者,因此我很感激您对我的代码提出的任何批评/建议。

【问题讨论】:

  • delete tmp; delete 的格式错误。应该是:delete [] tmp; 但是,当您可以简单地将 u 传递给您的函数时,为什么还要经历这一切呢?
  • 编辑了该部分,但没有解决任何问题。比如说,如果我正在对向量进行转换,我注意到有时只分配 v= Av 会更方便

标签: c++ matrix vector lapack blas


【解决方案1】:

你是对的,问题出在incx的值——应该是1,看看reference

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

因此,当向量x 的值未一一放置时应使用此值(例如,复值向量,当您只想使用实部时)。

您也不能同时使用vecmatprod(v,A,v,SIZE)v 作为xy。这是因为矩阵向量乘法的工作原理(例如,参见wikipedia)。您需要原始 x 的值才能产生正确的结果。小例子:

y = A * x 

在哪里

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

我们这样计算y

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

您可以看到,当我们计算y2 时,我们需要x1x2,但是如果您使用x = A * x(没有临时向量),您会将x1 替换为y1,从而产生错误的答案.

【讨论】:

  • 哦,我明白了。这就是我正在寻找的答案(好吧,我还必须将标志更改为 T),并且您澄清了 incx/incy 的使用。在函数中,我试图通过定义临时变量来解决这个问题,首先将结果存储在那里。出于某种原因,它仍然没有像我想要的那样工作。
  • 忘记了这个,确实需要将变量更改为T。这是因为 LAPACK 函数是用 Fortran 编写的,因此二维数组是按列存储的。
猜你喜欢
  • 2017-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-19
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多