This tutorial shows how data can be directly transferred from the Eigen Library to ViennaCL objects using the built-in convenience wrappers.
The first step is to include the necessary headers and activate the Eigen convenience functions in ViennaCL:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Sparse>
#define VIENNACL_WITH_EIGEN 1
The following is a set of auxiliary dispatchers for obtaining the right Eigen types for a given floating point type. This is merely an implementation detail, so feel free to skip over it.
template<typename T>
struct Eigen_dense_matrix
{
typedef typename T::ERROR_NO_EIGEN_TYPE_AVAILABLE error_type;
};
template<>
struct Eigen_dense_matrix<float>
{
typedef Eigen::MatrixXf type;
};
template<>
struct Eigen_dense_matrix<double>
{
typedef Eigen::MatrixXd type;
};
template<typename T>
struct Eigen_vector
{
typedef typename T::ERROR_NO_EIGEN_TYPE_AVAILABLE error_type;
};
template<>
struct Eigen_vector<float>
{
typedef Eigen::VectorXf type;
};
template<>
struct Eigen_vector<double>
{
typedef Eigen::VectorXd type;
};
The following function contains the main code for this tutorial. It consists of the following steps:
- Creates Eigen matrices and vectors
- Initializes them with data
- Create ViennaCL objects
- Copy them over to the respective ViennaCL objects
- Compute matrix-vector products in both Eigen and ViennaCL and compare results.
template<typename ScalarType>
void run_tutorial()
{
Get Eigen matrix and vector types for the provided ScalarType. Involves a little bit of template-metaprogramming.
typedef typename Eigen_dense_matrix<ScalarType>::type EigenMatrix;
typedef typename Eigen_vector<ScalarType>::type EigenVector;
Create and fill dense matrices from the Eigen library:
EigenMatrix eigen_densemat(6, 5);
EigenMatrix eigen_densemat2(6, 5);
eigen_densemat(0,0) = 2.0; eigen_densemat(0,1) = -1.0;
eigen_densemat(1,0) = -1.0; eigen_densemat(1,1) = 2.0; eigen_densemat(1,2) = -1.0;
eigen_densemat(2,1) = -1.0; eigen_densemat(2,2) = -1.0; eigen_densemat(2,3) = -1.0;
eigen_densemat(3,2) = -1.0; eigen_densemat(3,3) = 2.0; eigen_densemat(3,4) = -1.0;
eigen_densemat(5,4) = -1.0; eigen_densemat(4,4) = -1.0;
Eigen::Map<EigenMatrix> eigen_densemat_map(eigen_densemat.data(), 6, 5);
Create and fill sparse matrices from the Eigen library:
Eigen::SparseMatrix<ScalarType, Eigen::RowMajor> eigen_sparsemat(6, 5);
Eigen::SparseMatrix<ScalarType, Eigen::RowMajor> eigen_sparsemat2(6, 5);
eigen_sparsemat.reserve(5*2);
eigen_sparsemat.insert(0,0) = 2.0; eigen_sparsemat.insert(0,1) = -1.0;
eigen_sparsemat.insert(1,1) = 2.0; eigen_sparsemat.insert(1,2) = -1.0;
eigen_sparsemat.insert(2,2) = -1.0; eigen_sparsemat.insert(2,3) = -1.0;
eigen_sparsemat.insert(3,3) = 2.0; eigen_sparsemat.insert(3,4) = -1.0;
eigen_sparsemat.insert(5,4) = -1.0;
Create and fill a few vectors from the Eigen library:
EigenVector eigen_rhs(5);
Eigen::Map<EigenVector> eigen_rhs_map(eigen_rhs.data(), 5);
EigenVector eigen_result(6);
EigenVector eigen_temp(6);
eigen_rhs(0) = 10.0;
eigen_rhs(1) = 11.0;
eigen_rhs(2) = 12.0;
eigen_rhs(3) = 13.0;
eigen_rhs(4) = 14.0;
Create the corresponding ViennaCL objects:
Directly copy the Eigen objects to ViennaCL objects
viennacl::copy(&(eigen_rhs[0]), &(eigen_rhs[0]) + 5, vcl_rhs.begin());
std::cout << "VCL sparsematrix dimensions: " << vcl_sparsemat.size1() << ", " << vcl_sparsemat.size2() << std::endl;
Run dense matrix-vector products and compare results:
eigen_result = eigen_densemat * eigen_rhs;
std::cout << "Difference for dense matrix-vector product: " << (eigen_result - eigen_temp).norm() << std::endl;
std::cout << "Difference for dense matrix-vector product (Eigen->ViennaCL->Eigen): "
<< (eigen_densemat2 * eigen_rhs - eigen_temp).norm() << std::endl;
Run sparse matrix-vector products and compare results:
eigen_result = eigen_sparsemat * eigen_rhs;
std::cout << "Difference for sparse matrix-vector product: " << (eigen_result - eigen_temp).norm() << std::endl;
std::cout << "Difference for sparse matrix-vector product (Eigen->ViennaCL->Eigen): "
<< (eigen_sparsemat2 * eigen_rhs - eigen_temp).norm() << std::endl;
}
In the main() routine we only call the worker function defined above with both single and double precision arithmetic.
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "## Single precision" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
run_tutorial<float>();
#ifdef VIENNACL_HAVE_OPENCL
#endif
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "## Double precision" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
run_tutorial<double>();
}
That's it. Print a success message and exit.
std::cout << std::endl;
std::cout << "!!!! TUTORIAL COMPLETED SUCCESSFULLY !!!!" << std::endl;
std::cout << std::endl;
}
Full Example Code
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Sparse>
#define VIENNACL_WITH_EIGEN 1
template<typename T>
struct Eigen_dense_matrix
{
typedef typename T::ERROR_NO_EIGEN_TYPE_AVAILABLE error_type;
};
template<>
struct Eigen_dense_matrix<float>
{
typedef Eigen::MatrixXf type;
};
template<>
struct Eigen_dense_matrix<double>
{
typedef Eigen::MatrixXd type;
};
template<typename T>
struct Eigen_vector
{
typedef typename T::ERROR_NO_EIGEN_TYPE_AVAILABLE error_type;
};
template<>
struct Eigen_vector<float>
{
typedef Eigen::VectorXf type;
};
template<>
struct Eigen_vector<double>
{
typedef Eigen::VectorXd type;
};
template<typename ScalarType>
void run_tutorial()
{
typedef typename Eigen_dense_matrix<ScalarType>::type EigenMatrix;
typedef typename Eigen_vector<ScalarType>::type EigenVector;
EigenMatrix eigen_densemat(6, 5);
EigenMatrix eigen_densemat2(6, 5);
eigen_densemat(0,0) = 2.0; eigen_densemat(0,1) = -1.0;
eigen_densemat(1,0) = -1.0; eigen_densemat(1,1) = 2.0; eigen_densemat(1,2) = -1.0;
eigen_densemat(2,1) = -1.0; eigen_densemat(2,2) = -1.0; eigen_densemat(2,3) = -1.0;
eigen_densemat(3,2) = -1.0; eigen_densemat(3,3) = 2.0; eigen_densemat(3,4) = -1.0;
eigen_densemat(5,4) = -1.0; eigen_densemat(4,4) = -1.0;
Eigen::Map<EigenMatrix> eigen_densemat_map(eigen_densemat.data(), 6, 5);
Eigen::SparseMatrix<ScalarType, Eigen::RowMajor> eigen_sparsemat(6, 5);
Eigen::SparseMatrix<ScalarType, Eigen::RowMajor> eigen_sparsemat2(6, 5);
eigen_sparsemat.reserve(5*2);
eigen_sparsemat.insert(0,0) = 2.0; eigen_sparsemat.insert(0,1) = -1.0;
eigen_sparsemat.insert(1,1) = 2.0; eigen_sparsemat.insert(1,2) = -1.0;
eigen_sparsemat.insert(2,2) = -1.0; eigen_sparsemat.insert(2,3) = -1.0;
eigen_sparsemat.insert(3,3) = 2.0; eigen_sparsemat.insert(3,4) = -1.0;
eigen_sparsemat.insert(5,4) = -1.0;
EigenVector eigen_rhs(5);
Eigen::Map<EigenVector> eigen_rhs_map(eigen_rhs.data(), 5);
EigenVector eigen_result(6);
EigenVector eigen_temp(6);
eigen_rhs(0) = 10.0;
eigen_rhs(1) = 11.0;
eigen_rhs(2) = 12.0;
eigen_rhs(3) = 13.0;
eigen_rhs(4) = 14.0;
viennacl::copy(&(eigen_rhs[0]), &(eigen_rhs[0]) + 5, vcl_rhs.begin());
std::cout << "VCL sparsematrix dimensions: " << vcl_sparsemat.size1() << ", " << vcl_sparsemat.size2() << std::endl;
eigen_result = eigen_densemat * eigen_rhs;
std::cout << "Difference for dense matrix-vector product: " << (eigen_result - eigen_temp).norm() << std::endl;
std::cout << "Difference for dense matrix-vector product (Eigen->ViennaCL->Eigen): "
<< (eigen_densemat2 * eigen_rhs - eigen_temp).norm() << std::endl;
eigen_result = eigen_sparsemat * eigen_rhs;
std::cout << "Difference for sparse matrix-vector product: " << (eigen_result - eigen_temp).norm() << std::endl;
std::cout << "Difference for sparse matrix-vector product (Eigen->ViennaCL->Eigen): "
<< (eigen_sparsemat2 * eigen_rhs - eigen_temp).norm() << std::endl;
}
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "## Single precision" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
run_tutorial<float>();
#ifdef VIENNACL_HAVE_OPENCL
#endif
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "## Double precision" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
run_tutorial<double>();
}
std::cout << std::endl;
std::cout << "!!!! TUTORIAL COMPLETED SUCCESSFULLY !!!!" << std::endl;
std::cout << std::endl;
}