| #include <iostream> |
| #include <Eigen/Core> |
| #include <Eigen/Dense> |
| #include <Eigen/IterativeLinearSolvers> |
| #include <unsupported/Eigen/IterativeSolvers> |
| |
| class MatrixReplacement; |
| using Eigen::SparseMatrix; |
| |
| namespace Eigen { |
| namespace internal { |
| // MatrixReplacement looks-like a SparseMatrix, so let's inherits its traits: |
| template<> |
| struct traits<MatrixReplacement> : public Eigen::internal::traits<Eigen::SparseMatrix<double> > |
| {}; |
| } |
| } |
| |
| // Example of a matrix-free wrapper from a user type to Eigen's compatible type |
| // For the sake of simplicity, this example simply wrap a Eigen::SparseMatrix. |
| class MatrixReplacement : public Eigen::EigenBase<MatrixReplacement> { |
| public: |
| // Required typedefs, constants, and method: |
| typedef double Scalar; |
| typedef double RealScalar; |
| typedef int StorageIndex; |
| enum { |
| ColsAtCompileTime = Eigen::Dynamic, |
| MaxColsAtCompileTime = Eigen::Dynamic, |
| IsRowMajor = false |
| }; |
| |
| Index rows() const { return mp_mat->rows(); } |
| Index cols() const { return mp_mat->cols(); } |
| |
| template<typename Rhs> |
| Eigen::Product<MatrixReplacement,Rhs,Eigen::AliasFreeProduct> operator*(const Eigen::MatrixBase<Rhs>& x) const { |
| return Eigen::Product<MatrixReplacement,Rhs,Eigen::AliasFreeProduct>(*this, x.derived()); |
| } |
| |
| // Custom API: |
| MatrixReplacement() : mp_mat(0) {} |
| |
| void attachMyMatrix(const SparseMatrix<double> &mat) { |
| mp_mat = &mat; |
| } |
| const SparseMatrix<double> my_matrix() const { return *mp_mat; } |
| |
| private: |
| const SparseMatrix<double> *mp_mat; |
| }; |
| |
| |
| // Implementation of MatrixReplacement * Eigen::DenseVector though a specialization of internal::generic_product_impl: |
| namespace Eigen { |
| namespace internal { |
| |
| template<typename Rhs> |
| struct generic_product_impl<MatrixReplacement, Rhs, SparseShape, DenseShape, GemvProduct> // GEMV stands for matrix-vector |
| : generic_product_impl_base<MatrixReplacement,Rhs,generic_product_impl<MatrixReplacement,Rhs> > |
| { |
| typedef typename Product<MatrixReplacement,Rhs>::Scalar Scalar; |
| |
| template<typename Dest> |
| static void scaleAndAddTo(Dest& dst, const MatrixReplacement& lhs, const Rhs& rhs, const Scalar& alpha) |
| { |
| // This method should implement "dst += alpha * lhs * rhs" inplace, |
| // however, for iterative solvers, alpha is always equal to 1, so let's not bother about it. |
| assert(alpha==Scalar(1) && "scaling is not implemented"); |
| EIGEN_ONLY_USED_FOR_DEBUG(alpha); |
| |
| // Here we could simply call dst.noalias() += lhs.my_matrix() * rhs, |
| // but let's do something fancier (and less efficient): |
| for(Index i=0; i<lhs.cols(); ++i) |
| dst += rhs(i) * lhs.my_matrix().col(i); |
| } |
| }; |
| |
| } |
| } |
| |
| int main() |
| { |
| int n = 10; |
| Eigen::SparseMatrix<double> S = Eigen::MatrixXd::Random(n,n).sparseView(0.5,1); |
| S = S.transpose()*S; |
| |
| MatrixReplacement A; |
| A.attachMyMatrix(S); |
| |
| Eigen::VectorXd b(n), x; |
| b.setRandom(); |
| |
| // Solve Ax = b using various iterative solver with matrix-free version: |
| { |
| Eigen::ConjugateGradient<MatrixReplacement, Eigen::Lower|Eigen::Upper, Eigen::IdentityPreconditioner> cg; |
| cg.compute(A); |
| x = cg.solve(b); |
| std::cout << "CG: #iterations: " << cg.iterations() << ", estimated error: " << cg.error() << std::endl; |
| } |
| |
| { |
| Eigen::BiCGSTAB<MatrixReplacement, Eigen::IdentityPreconditioner> bicg; |
| bicg.compute(A); |
| x = bicg.solve(b); |
| std::cout << "BiCGSTAB: #iterations: " << bicg.iterations() << ", estimated error: " << bicg.error() << std::endl; |
| } |
| |
| { |
| Eigen::GMRES<MatrixReplacement, Eigen::IdentityPreconditioner> gmres; |
| gmres.compute(A); |
| x = gmres.solve(b); |
| std::cout << "GMRES: #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl; |
| } |
| |
| { |
| Eigen::DGMRES<MatrixReplacement, Eigen::IdentityPreconditioner> gmres; |
| gmres.compute(A); |
| x = gmres.solve(b); |
| std::cout << "DGMRES: #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl; |
| } |
| |
| { |
| Eigen::MINRES<MatrixReplacement, Eigen::Lower|Eigen::Upper, Eigen::IdentityPreconditioner> minres; |
| minres.compute(A); |
| x = minres.solve(b); |
| std::cout << "MINRES: #iterations: " << minres.iterations() << ", estimated error: " << minres.error() << std::endl; |
| } |
| } |