| // This file is part of Eigen, a lightweight C++ template library | 
 | // for linear algebra. | 
 | // | 
 | // Copyright (C) 2012 Desire NUENTSA WAKAM <desire.nuentsa_wakam@inria.fr | 
 | // | 
 | // This Source Code Form is subject to the terms of the Mozilla | 
 | // Public License v. 2.0. If a copy of the MPL was not distributed | 
 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
 |  | 
 | #ifndef EIGEN_ITERSCALING_H | 
 | #define EIGEN_ITERSCALING_H | 
 |  | 
 | // IWYU pragma: private | 
 | #include "./InternalHeaderCheck.h" | 
 |  | 
 | namespace Eigen { | 
 |  | 
 | /** | 
 |  * \ingroup IterativeSolvers_Module | 
 |  * \brief iterative scaling algorithm to equilibrate rows and column norms in matrices | 
 |  * | 
 |  * This class can be used as a preprocessing tool to accelerate the convergence of iterative methods | 
 |  * | 
 |  * This feature is  useful to limit the pivoting amount during LU/ILU factorization | 
 |  * The  scaling strategy as presented here preserves the symmetry of the problem | 
 |  * NOTE It is assumed that the matrix does not have empty row or column, | 
 |  * | 
 |  * Example with key steps | 
 |  * \code | 
 |  * VectorXd x(n), b(n); | 
 |  * SparseMatrix<double> A; | 
 |  * // fill A and b; | 
 |  * IterScaling<SparseMatrix<double> > scal; | 
 |  * // Compute the left and right scaling vectors. The matrix is equilibrated at output | 
 |  * scal.computeRef(A); | 
 |  * // Scale the right hand side | 
 |  * b = scal.LeftScaling().cwiseProduct(b); | 
 |  * // Now, solve the equilibrated linear system with any available solver | 
 |  * | 
 |  * // Scale back the computed solution | 
 |  * x = scal.RightScaling().cwiseProduct(x); | 
 |  * \endcode | 
 |  * | 
 |  * \tparam MatrixType_ the type of the matrix. It should be a real square sparsematrix | 
 |  * | 
 |  * References : D. Ruiz and B. Ucar, A Symmetry Preserving Algorithm for Matrix Scaling, INRIA Research report RR-7552 | 
 |  * | 
 |  * \sa \ref IncompleteLUT | 
 |  */ | 
 | template <typename MatrixType_> | 
 | class IterScaling { | 
 |  public: | 
 |   typedef MatrixType_ MatrixType; | 
 |   typedef typename MatrixType::Scalar Scalar; | 
 |   typedef typename MatrixType::Index Index; | 
 |  | 
 |  public: | 
 |   IterScaling() { init(); } | 
 |  | 
 |   IterScaling(const MatrixType& matrix) { | 
 |     init(); | 
 |     compute(matrix); | 
 |   } | 
 |  | 
 |   ~IterScaling() {} | 
 |  | 
 |   /** | 
 |    * Compute the left and right diagonal matrices to scale the input matrix @p mat | 
 |    * | 
 |    * FIXME This algorithm will be modified such that the diagonal elements are permuted on the diagonal. | 
 |    * | 
 |    * \sa LeftScaling() RightScaling() | 
 |    */ | 
 |   void compute(const MatrixType& mat) { | 
 |     using std::abs; | 
 |     int m = mat.rows(); | 
 |     int n = mat.cols(); | 
 |     eigen_assert((m > 0 && m == n) && "Please give a non - empty matrix"); | 
 |     m_left.resize(m); | 
 |     m_right.resize(n); | 
 |     m_left.setOnes(); | 
 |     m_right.setOnes(); | 
 |     m_matrix = mat; | 
 |     VectorXd Dr, Dc, DrRes, DcRes;  // Temporary Left and right scaling vectors | 
 |     Dr.resize(m); | 
 |     Dc.resize(n); | 
 |     DrRes.resize(m); | 
 |     DcRes.resize(n); | 
 |     double EpsRow = 1.0, EpsCol = 1.0; | 
 |     int its = 0; | 
 |     do {  // Iterate until the infinite norm of each row and column is approximately 1 | 
 |       // Get the maximum value in each row and column | 
 |       Dr.setZero(); | 
 |       Dc.setZero(); | 
 |       for (int k = 0; k < m_matrix.outerSize(); ++k) { | 
 |         for (typename MatrixType::InnerIterator it(m_matrix, k); it; ++it) { | 
 |           if (Dr(it.row()) < abs(it.value())) Dr(it.row()) = abs(it.value()); | 
 |  | 
 |           if (Dc(it.col()) < abs(it.value())) Dc(it.col()) = abs(it.value()); | 
 |         } | 
 |       } | 
 |       for (int i = 0; i < m; ++i) { | 
 |         Dr(i) = std::sqrt(Dr(i)); | 
 |       } | 
 |       for (int i = 0; i < n; ++i) { | 
 |         Dc(i) = std::sqrt(Dc(i)); | 
 |       } | 
 |       // Save the scaling factors | 
 |       for (int i = 0; i < m; ++i) { | 
 |         m_left(i) /= Dr(i); | 
 |       } | 
 |       for (int i = 0; i < n; ++i) { | 
 |         m_right(i) /= Dc(i); | 
 |       } | 
 |       // Scale the rows and the columns of the matrix | 
 |       DrRes.setZero(); | 
 |       DcRes.setZero(); | 
 |       for (int k = 0; k < m_matrix.outerSize(); ++k) { | 
 |         for (typename MatrixType::InnerIterator it(m_matrix, k); it; ++it) { | 
 |           it.valueRef() = it.value() / (Dr(it.row()) * Dc(it.col())); | 
 |           // Accumulate the norms of the row and column vectors | 
 |           if (DrRes(it.row()) < abs(it.value())) DrRes(it.row()) = abs(it.value()); | 
 |  | 
 |           if (DcRes(it.col()) < abs(it.value())) DcRes(it.col()) = abs(it.value()); | 
 |         } | 
 |       } | 
 |       DrRes.array() = (1 - DrRes.array()).abs(); | 
 |       EpsRow = DrRes.maxCoeff(); | 
 |       DcRes.array() = (1 - DcRes.array()).abs(); | 
 |       EpsCol = DcRes.maxCoeff(); | 
 |       its++; | 
 |     } while ((EpsRow > m_tol || EpsCol > m_tol) && (its < m_maxits)); | 
 |     m_isInitialized = true; | 
 |   } | 
 |   /** Compute the left and right vectors to scale the vectors | 
 |    * the input matrix is scaled with the computed vectors at output | 
 |    * | 
 |    * \sa compute() | 
 |    */ | 
 |   void computeRef(MatrixType& mat) { | 
 |     compute(mat); | 
 |     mat = m_matrix; | 
 |   } | 
 |   /** Get the vector to scale the rows of the matrix | 
 |    */ | 
 |   VectorXd& LeftScaling() { return m_left; } | 
 |  | 
 |   /** Get the vector to scale the columns of the matrix | 
 |    */ | 
 |   VectorXd& RightScaling() { return m_right; } | 
 |  | 
 |   /** Set the tolerance for the convergence of the iterative scaling algorithm | 
 |    */ | 
 |   void setTolerance(double tol) { m_tol = tol; } | 
 |  | 
 |  protected: | 
 |   void init() { | 
 |     m_tol = 1e-10; | 
 |     m_maxits = 5; | 
 |     m_isInitialized = false; | 
 |   } | 
 |  | 
 |   MatrixType m_matrix; | 
 |   mutable ComputationInfo m_info; | 
 |   bool m_isInitialized; | 
 |   VectorXd m_left;   // Left scaling vector | 
 |   VectorXd m_right;  // m_right scaling vector | 
 |   double m_tol; | 
 |   int m_maxits;  // Maximum number of iterations allowed | 
 | }; | 
 | }  // namespace Eigen | 
 | #endif |