| 1 | #include <iostream>
|
|---|
| 2 | #include <Eigen/Core>
|
|---|
| 3 | #include <Eigen/Dense>
|
|---|
| 4 | #include <Eigen/IterativeLinearSolvers>
|
|---|
| 5 |
|
|---|
| 6 | class MatrixReplacement;
|
|---|
| 7 | template<typename Rhs> class MatrixReplacement_ProductReturnType;
|
|---|
| 8 |
|
|---|
| 9 | namespace Eigen {
|
|---|
| 10 | namespace internal {
|
|---|
| 11 | template<>
|
|---|
| 12 | struct traits<MatrixReplacement> : Eigen::internal::traits<Eigen::SparseMatrix<double> >
|
|---|
| 13 | {};
|
|---|
| 14 |
|
|---|
| 15 | template <typename Rhs>
|
|---|
| 16 | struct traits<MatrixReplacement_ProductReturnType<Rhs> > {
|
|---|
| 17 | // The equivalent plain objet type of the product. This type is used if the product needs to be evaluated into a temporary.
|
|---|
| 18 | typedef Eigen::Matrix<typename Rhs::Scalar, Eigen::Dynamic, Rhs::ColsAtCompileTime> ReturnType;
|
|---|
| 19 | };
|
|---|
| 20 | }
|
|---|
| 21 | }
|
|---|
| 22 |
|
|---|
| 23 | // Inheriting EigenBase should not be needed in the future.
|
|---|
| 24 | class MatrixReplacement : public Eigen::EigenBase<MatrixReplacement> {
|
|---|
| 25 | public:
|
|---|
| 26 | // Expose some compile-time information to Eigen:
|
|---|
| 27 | typedef double Scalar;
|
|---|
| 28 | typedef double RealScalar;
|
|---|
| 29 | enum {
|
|---|
| 30 | ColsAtCompileTime = Eigen::Dynamic,
|
|---|
| 31 | RowsAtCompileTime = Eigen::Dynamic,
|
|---|
| 32 | MaxColsAtCompileTime = Eigen::Dynamic,
|
|---|
| 33 | MaxRowsAtCompileTime = Eigen::Dynamic
|
|---|
| 34 | };
|
|---|
| 35 |
|
|---|
| 36 | Index rows() const { return 4; }
|
|---|
| 37 | Index cols() const { return 4; }
|
|---|
| 38 |
|
|---|
| 39 | void resize(Index a_rows, Index a_cols)
|
|---|
| 40 | {
|
|---|
| 41 | // This method should not be needed in the future.
|
|---|
| 42 | assert(a_rows==0 && a_cols==0 || a_rows==rows() && a_cols==cols());
|
|---|
| 43 | }
|
|---|
| 44 |
|
|---|
| 45 | // In the future, the return type should be Eigen::Product<MatrixReplacement,Rhs>
|
|---|
| 46 | template<typename Rhs>
|
|---|
| 47 | MatrixReplacement_ProductReturnType<Rhs> operator*(const Eigen::MatrixBase<Rhs>& x) const {
|
|---|
| 48 | return MatrixReplacement_ProductReturnType<Rhs>(*this, x.derived());
|
|---|
| 49 | }
|
|---|
| 50 |
|
|---|
| 51 | };
|
|---|
| 52 |
|
|---|
| 53 | // The proxy class representing the product of a MatrixReplacement with a MatrixBase<>
|
|---|
| 54 | template<typename Rhs>
|
|---|
| 55 | class MatrixReplacement_ProductReturnType : public Eigen::ReturnByValue<MatrixReplacement_ProductReturnType<Rhs> > {
|
|---|
| 56 | public:
|
|---|
| 57 | typedef MatrixReplacement::Index Index;
|
|---|
| 58 |
|
|---|
| 59 | // The ctor store references to the matrix and right-hand-side object (usually a vector).
|
|---|
| 60 | MatrixReplacement_ProductReturnType(const MatrixReplacement& matrix, const Rhs& rhs)
|
|---|
| 61 | : m_matrix(matrix), m_rhs(rhs)
|
|---|
| 62 | {}
|
|---|
| 63 |
|
|---|
| 64 | Index rows() const { return m_matrix.rows(); }
|
|---|
| 65 | Index cols() const { return m_rhs.cols(); }
|
|---|
| 66 |
|
|---|
| 67 | // This function is automatically called by Eigen. It must evaluate the product of matrix * rhs into y.
|
|---|
| 68 | template<typename Dest>
|
|---|
| 69 | void evalTo(Dest& y) const
|
|---|
| 70 | {
|
|---|
| 71 | y.setZero(4);
|
|---|
| 72 |
|
|---|
| 73 | y(0) += 2 * m_rhs(0); y(1) += 1 * m_rhs(0);
|
|---|
| 74 | y(0) += 1 * m_rhs(1); y(1) += 2 * m_rhs(1); y(2) += 1 * m_rhs(1);
|
|---|
| 75 | y(1) += 1 * m_rhs(2); y(2) += 2 * m_rhs(2); y(3) += 1 * m_rhs(2);
|
|---|
| 76 | y(2) += 1 * m_rhs(3); y(3) += 2 * m_rhs(3);
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | protected:
|
|---|
| 80 | const MatrixReplacement& m_matrix;
|
|---|
| 81 | typename Rhs::Nested m_rhs;
|
|---|
| 82 | };
|
|---|
| 83 |
|
|---|
| 84 |
|
|---|
| 85 | /*****/
|
|---|
| 86 |
|
|---|
| 87 | // This class simply warp a diagonal matrix as a Jacobi preconditioner.
|
|---|
| 88 | // In the future such simple and generic wrapper should be shipped within Eigen itsel.
|
|---|
| 89 | template <typename _Scalar>
|
|---|
| 90 | class MyJacobiPreconditioner
|
|---|
| 91 | {
|
|---|
| 92 | typedef _Scalar Scalar;
|
|---|
| 93 | typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> Vector;
|
|---|
| 94 | typedef typename Vector::Index Index;
|
|---|
| 95 |
|
|---|
| 96 | public:
|
|---|
| 97 | // this typedef is only to export the scalar type and compile-time dimensions to solve_retval
|
|---|
| 98 | typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
|
|---|
| 99 |
|
|---|
| 100 | MyJacobiPreconditioner() : m_isInitialized(false) {}
|
|---|
| 101 |
|
|---|
| 102 | void setInvDiag(const Eigen::VectorXd &invdiag) {
|
|---|
| 103 | m_invdiag=invdiag;
|
|---|
| 104 | m_isInitialized=true;
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | Index rows() const { return m_invdiag.size(); }
|
|---|
| 108 | Index cols() const { return m_invdiag.size(); }
|
|---|
| 109 |
|
|---|
| 110 | template<typename MatType>
|
|---|
| 111 | MyJacobiPreconditioner& analyzePattern(const MatType& ) { return *this; }
|
|---|
| 112 |
|
|---|
| 113 | template<typename MatType>
|
|---|
| 114 | MyJacobiPreconditioner& factorize(const MatType& mat) { return *this; }
|
|---|
| 115 |
|
|---|
| 116 | template<typename MatType>
|
|---|
| 117 | MyJacobiPreconditioner& compute(const MatType& mat) { return *this; }
|
|---|
| 118 |
|
|---|
| 119 | template<typename Rhs, typename Dest>
|
|---|
| 120 | void _solve(const Rhs& b, Dest& x) const
|
|---|
| 121 | {
|
|---|
| 122 | x = m_invdiag.array() * b.array() ;
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 | template<typename Rhs> inline const Eigen::internal::solve_retval<MyJacobiPreconditioner, Rhs>
|
|---|
| 126 | solve(const Eigen::MatrixBase<Rhs>& b) const
|
|---|
| 127 | {
|
|---|
| 128 | eigen_assert(m_isInitialized && "MyJacobiPreconditioner is not initialized.");
|
|---|
| 129 | eigen_assert(m_invdiag.size()==b.rows()
|
|---|
| 130 | && "MyJacobiPreconditioner::solve(): invalid number of rows of the right hand side matrix b");
|
|---|
| 131 | return Eigen::internal::solve_retval<MyJacobiPreconditioner, Rhs>(*this, b.derived());
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | protected:
|
|---|
| 135 | Vector m_invdiag;
|
|---|
| 136 | bool m_isInitialized;
|
|---|
| 137 | };
|
|---|
| 138 |
|
|---|
| 139 | namespace Eigen {
|
|---|
| 140 | namespace internal {
|
|---|
| 141 |
|
|---|
| 142 | template<typename _MatrixType, typename Rhs>
|
|---|
| 143 | struct solve_retval<MyJacobiPreconditioner<_MatrixType>, Rhs>
|
|---|
| 144 | : solve_retval_base<MyJacobiPreconditioner<_MatrixType>, Rhs>
|
|---|
| 145 | {
|
|---|
| 146 | typedef MyJacobiPreconditioner<_MatrixType> Dec;
|
|---|
| 147 | EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
|
|---|
| 148 |
|
|---|
| 149 | template<typename Dest> void evalTo(Dest& dst) const
|
|---|
| 150 | {
|
|---|
| 151 | dec()._solve(rhs(),dst);
|
|---|
| 152 | }
|
|---|
| 153 | };
|
|---|
| 154 |
|
|---|
| 155 | }
|
|---|
| 156 | }
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 | /*****/
|
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 | int main()
|
|---|
| 163 | {
|
|---|
| 164 | MatrixReplacement A;
|
|---|
| 165 | Eigen::VectorXd b(4), x;
|
|---|
| 166 | b << 1, 1, 1, 1;
|
|---|
| 167 |
|
|---|
| 168 | // solve Ax = b using CG with matrix-free version:
|
|---|
| 169 | Eigen::ConjugateGradient < MatrixReplacement, Eigen::Lower|Eigen::Upper, MyJacobiPreconditioner<double> > cg;
|
|---|
| 170 |
|
|---|
| 171 | Eigen::VectorXd invdiag(4);
|
|---|
| 172 | invdiag << 1./3., 1./4., 1./4., 1./3.;
|
|---|
| 173 |
|
|---|
| 174 | cg.preconditioner().setInvDiag(invdiag);
|
|---|
| 175 | cg.compute(A);
|
|---|
| 176 | x = cg.solve(b);
|
|---|
| 177 |
|
|---|
| 178 | std::cout << "#iterations: " << cg.iterations() << std::endl;
|
|---|
| 179 | std::cout << "estimated error: " << cg.error() << std::endl;
|
|---|
| 180 | }
|
|---|