使用MKL稀疏矩阵向量乘法

时间:2017-05-23 01:14:21

标签: c++ intel-mkl

有没有一个简单的C ++代码示例使用MKL稀疏矩阵向量乘法例程?我需要使用“mkl_zcsrsymv”将复杂的对称矩阵(存储在下三角形中)与复数向量相乘,但我找不到一个示例性示例。无法编译复杂案例的代码。

1 个答案:

答案 0 :(得分:2)

Intel's homepage上阅读mkl_zcsrsymv的文档。这里对称是字面上的! (这并不意味着Hermitian)

使用icpc -mkl test.c进行编译,以获得最大的便利。

#include <stdio.h>
#include "mkl_spblas.h"

int main()
{
  /* Matrix in CRS format
   *
   * { {  0,  0,  i } 
   *   {  0, -1,  2 } 
   *   {  i,  2,  0 } } 
   */
  int m = 3;
  MKL_Complex16 a[] = { {0,1}, {-1,0}, {2,0}, {0,1}, {2,0} };
  int ia[] = { 0, 1, 3, 5 };
  int ja[] = { 2, 1, 2, 0, 1 };

  MKL_Complex16 x[] = { {1,0}, {2,0}, {3,0} };
  MKL_Complex16 y[] = { {0,0}, {0,0}, {0,0} };

  char uplo = 'L';
  // Use MKL to compute
  // y = A*x
  mkl_cspblas_zcsrsymv(&uplo, &m, a, ia, ja, x, y);

  printf("y = { (%g,%g), (%g,%g), (%g,%g) }\n",
         y[0].real, y[0].imag,
         y[1].real, y[1].imag,
         y[2].real, y[2].imag
    );
}

输出为y = { (0,3), (4,0), (4,1) }。在WolframAlpha上查看。

以下是mkl_dcsrmv的示例。

#include <stdio.h>
#include "mkl_spblas.h"

int main()
{
  /* Matrix in CRS format
   *
   * { { 0,  0,  1 } 
   *   { 0, -1,  2 } 
   *   { 1,  0,  0 } } 
   */
  int m = 3;
  int k = 3;
  double val[] = { 1, -1, 2, 1 };
  int indx[]   = { 2, 1, 2, 0 };
  int pntrb[]  = { 0, 1, 3 };
  int pntre[]  = { 1, 3, 4 };

  double x[] = { 1, 2, 3 };
  double y[] = { 0, 0, 0 };

  double alpha = 1;
  double beta  = 0;
  char transa = 'N';
  char matdescra[] = {
    'G', // type of matrix
    ' ', // triangular indicator (ignored in multiplication)
    ' ', // diagonal indicator (ignored in multiplication)
    'C'  // type of indexing
  };

  // Use MKL to compute
  // y = alpha*A*x + beta*y
  mkl_dcsrmv(&transa, &m, &k, &alpha, matdescra, val, indx, pntrb, pntre, x, &beta, y);

  printf("y = { %g, %g, %g }\n", y[0], y[1], y[2]);
}

输出为y = { 3, 4, 1 }。在WolframAlpha上查看。

在玩这个游戏的过程中,我发现这与Armadillo直接兼容。这使得在C ++中使用非常方便。在这里,我首先使用Armadillo生成随机对称矩阵并将其转换为稀疏。这个我乘以随机向量。最后,我将结果与Armadillo的稀疏矩阵向量乘积进行比较。精度差异很大。

#include <iostream>
#include <armadillo>
#define MKL_Complex16 arma::cx_double
#include "mkl_spblas.h"

int main()
{
  /* Matrix in CRS format
   *
   * { {  0,  0,  i } 
   *   {  0, -1,  2 } 
   *   {  i,  2,  0 } } 
   */
  int dim = 1000;
  arma::sp_cx_mat a(arma::randu<arma::cx_mat>(dim,dim));
  a += a.st();
  arma::cx_vec x = arma::randu<arma::cx_vec>(dim);
  arma::cx_vec y(dim);

  char uplo = 'L';
  // Use MKL to compute
  // y = A*x
  mkl_cspblas_zcsrsymv(&uplo, &dim,
                       a.values, (int*)a.col_ptrs, (int*)a.row_indices,
                       x.memptr(), y.memptr());

  std::cout << std::boolalpha
            << arma::approx_equal(y, a*x, "absdiff", 1e-10)
            << '\n';
}