4 #include <Eigen/IterativeLinearSolvers>
5 #include <unsupported/Eigen/IterativeSolvers>
7 class MatrixReplacement
;
8 using Eigen::SparseMatrix
;
12 // MatrixReplacement looks-like a SparseMatrix, so let's inherits its traits:
14 struct traits
<MatrixReplacement
> : public Eigen::internal::traits
<Eigen::SparseMatrix
<double> >
19 // Example of a matrix-free wrapper from a user type to Eigen's compatible type
20 // For the sake of simplicity, this example simply wrap a Eigen::SparseMatrix.
21 class MatrixReplacement
: public Eigen::EigenBase
<MatrixReplacement
> {
23 // Required typedefs, constants, and method:
24 typedef double Scalar
;
25 typedef double RealScalar
;
26 typedef int StorageIndex
;
28 ColsAtCompileTime
= Eigen::Dynamic
,
29 MaxColsAtCompileTime
= Eigen::Dynamic
,
33 Index
rows() const { return mp_mat
->rows(); }
34 Index
cols() const { return mp_mat
->cols(); }
36 template<typename Rhs
>
37 Eigen::Product
<MatrixReplacement
,Rhs
,Eigen::AliasFreeProduct
> operator*(const Eigen::MatrixBase
<Rhs
>& x
) const {
38 return Eigen::Product
<MatrixReplacement
,Rhs
,Eigen::AliasFreeProduct
>(*this, x
.derived());
42 MatrixReplacement() : mp_mat(0) {}
44 void attachMyMatrix(const SparseMatrix
<double> &mat
) {
47 const SparseMatrix
<double> my_matrix() const { return *mp_mat
; }
50 const SparseMatrix
<double> *mp_mat
;
54 // Implementation of MatrixReplacement * Eigen::DenseVector though a specialization of internal::generic_product_impl:
58 template<typename Rhs
>
59 struct generic_product_impl
<MatrixReplacement
, Rhs
, SparseShape
, DenseShape
, GemvProduct
> // GEMV stands for matrix-vector
60 : generic_product_impl_base
<MatrixReplacement
,Rhs
,generic_product_impl
<MatrixReplacement
,Rhs
> >
62 typedef typename Product
<MatrixReplacement
,Rhs
>::Scalar Scalar
;
64 template<typename Dest
>
65 static void scaleAndAddTo(Dest
& dst
, const MatrixReplacement
& lhs
, const Rhs
& rhs
, const Scalar
& alpha
)
67 // This method should implement "dst += alpha * lhs * rhs" inplace,
68 // however, for iterative solvers, alpha is always equal to 1, so let's not bother about it.
69 assert(alpha
==Scalar(1) && "scaling is not implemented");
71 // Here we could simply call dst.noalias() += lhs.my_matrix() * rhs,
72 // but let's do something fancier (and less efficient):
73 for(Index i
=0; i
<lhs
.cols(); ++i
)
74 dst
+= rhs(i
) * lhs
.my_matrix().col(i
);
84 Eigen::SparseMatrix
<double> S
= Eigen::MatrixXd::Random(n
,n
).sparseView(0.5,1);
90 Eigen::VectorXd
b(n
), x
;
93 // Solve Ax = b using various iterative solver with matrix-free version:
95 Eigen::ConjugateGradient
<MatrixReplacement
, Eigen::Lower
|Eigen::Upper
, Eigen::IdentityPreconditioner
> cg
;
98 std::cout
<< "CG: #iterations: " << cg
.iterations() << ", estimated error: " << cg
.error() << std::endl
;
102 Eigen::BiCGSTAB
<MatrixReplacement
, Eigen::IdentityPreconditioner
> bicg
;
105 std::cout
<< "BiCGSTAB: #iterations: " << bicg
.iterations() << ", estimated error: " << bicg
.error() << std::endl
;
109 Eigen::GMRES
<MatrixReplacement
, Eigen::IdentityPreconditioner
> gmres
;
112 std::cout
<< "GMRES: #iterations: " << gmres
.iterations() << ", estimated error: " << gmres
.error() << std::endl
;
116 Eigen::DGMRES
<MatrixReplacement
, Eigen::IdentityPreconditioner
> gmres
;
119 std::cout
<< "DGMRES: #iterations: " << gmres
.iterations() << ", estimated error: " << gmres
.error() << std::endl
;
123 Eigen::MINRES
<MatrixReplacement
, Eigen::Lower
|Eigen::Upper
, Eigen::IdentityPreconditioner
> minres
;
126 std::cout
<< "MINRES: #iterations: " << minres
.iterations() << ", estimated error: " << minres
.error() << std::endl
;