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