|  | // 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 |