| // This file is part of Eigen, a lightweight C++ template library | 
 | // for linear algebra. | 
 | // | 
 | // Copyright (C) 2010 Manuel Yguel <manuel.yguel@gmail.com> | 
 | // | 
 | // 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_COMPANION_H | 
 | #define EIGEN_COMPANION_H | 
 |  | 
 | // This file requires the user to include | 
 | // * Eigen/Core | 
 | // * Eigen/src/PolynomialSolver.h | 
 |  | 
 | // IWYU pragma: private | 
 | #include "./InternalHeaderCheck.h" | 
 |  | 
 | namespace Eigen { | 
 |  | 
 | namespace internal { | 
 |  | 
 | #ifndef EIGEN_PARSED_BY_DOXYGEN | 
 |  | 
 | template <int Size> | 
 | struct decrement_if_fixed_size { | 
 |   enum { ret = (Size == Dynamic) ? Dynamic : Size - 1 }; | 
 | }; | 
 |  | 
 | #endif | 
 |  | 
 | template <typename Scalar_, int Deg_> | 
 | class companion { | 
 |  public: | 
 |   EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_) | 
 |  | 
 |   enum { Deg = Deg_, Deg_1 = decrement_if_fixed_size<Deg>::ret }; | 
 |  | 
 |   typedef Scalar_ Scalar; | 
 |   typedef typename NumTraits<Scalar>::Real RealScalar; | 
 |   typedef Matrix<Scalar, Deg, 1> RightColumn; | 
 |   // typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal; | 
 |   typedef Matrix<Scalar, Deg_1, 1> BottomLeftDiagonal; | 
 |  | 
 |   typedef Matrix<Scalar, Deg, Deg> DenseCompanionMatrixType; | 
 |   typedef Matrix<Scalar, Deg_, Deg_1> LeftBlock; | 
 |   typedef Matrix<Scalar, Deg_1, Deg_1> BottomLeftBlock; | 
 |   typedef Matrix<Scalar, 1, Deg_1> LeftBlockFirstRow; | 
 |  | 
 |   typedef DenseIndex Index; | 
 |  | 
 |  public: | 
 |   EIGEN_STRONG_INLINE const Scalar_ operator()(Index row, Index col) const { | 
 |     if (m_bl_diag.rows() > col) { | 
 |       if (0 < row) { | 
 |         return m_bl_diag[col]; | 
 |       } else { | 
 |         return 0; | 
 |       } | 
 |     } else { | 
 |       return m_monic[row]; | 
 |     } | 
 |   } | 
 |  | 
 |  public: | 
 |   template <typename VectorType> | 
 |   void setPolynomial(const VectorType& poly) { | 
 |     const Index deg = poly.size() - 1; | 
 |     m_monic = -poly.head(deg) / poly[deg]; | 
 |     m_bl_diag.setOnes(deg - 1); | 
 |   } | 
 |  | 
 |   template <typename VectorType> | 
 |   companion(const VectorType& poly) { | 
 |     setPolynomial(poly); | 
 |   } | 
 |  | 
 |  public: | 
 |   DenseCompanionMatrixType denseMatrix() const { | 
 |     const Index deg = m_monic.size(); | 
 |     const Index deg_1 = deg - 1; | 
 |     DenseCompanionMatrixType companMat(deg, deg); | 
 |     companMat << (LeftBlock(deg, deg_1) << LeftBlockFirstRow::Zero(1, deg_1), | 
 |                   BottomLeftBlock::Identity(deg - 1, deg - 1) * m_bl_diag.asDiagonal()) | 
 |                      .finished(), | 
 |         m_monic; | 
 |     return companMat; | 
 |   } | 
 |  | 
 |  protected: | 
 |   /** Helper function for the balancing algorithm. | 
 |    * \returns true if the row and the column, having colNorm and rowNorm | 
 |    * as norms, are balanced, false otherwise. | 
 |    * colB and rowB are respectively the multipliers for | 
 |    * the column and the row in order to balance them. | 
 |    * */ | 
 |   bool balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB); | 
 |  | 
 |   /** Helper function for the balancing algorithm. | 
 |    * \returns true if the row and the column, having colNorm and rowNorm | 
 |    * as norms, are balanced, false otherwise. | 
 |    * colB and rowB are respectively the multipliers for | 
 |    * the column and the row in order to balance them. | 
 |    * */ | 
 |   bool balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB); | 
 |  | 
 |  public: | 
 |   /** | 
 |    * Balancing algorithm from B. N. PARLETT and C. REINSCH (1969) | 
 |    * "Balancing a matrix for calculation of eigenvalues and eigenvectors" | 
 |    * adapted to the case of companion matrices. | 
 |    * A matrix with non zero row and non zero column is balanced | 
 |    * for a certain norm if the i-th row and the i-th column | 
 |    * have same norm for all i. | 
 |    */ | 
 |   void balance(); | 
 |  | 
 |  protected: | 
 |   RightColumn m_monic; | 
 |   BottomLeftDiagonal m_bl_diag; | 
 | }; | 
 |  | 
 | template <typename Scalar_, int Deg_> | 
 | inline bool companion<Scalar_, Deg_>::balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, | 
 |                                                RealScalar& colB, RealScalar& rowB) { | 
 |   if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm || !(numext::isfinite)(colNorm) || | 
 |       !(numext::isfinite)(rowNorm)) { | 
 |     return true; | 
 |   } else { | 
 |     // To find the balancing coefficients, if the radix is 2, | 
 |     // one finds \f$ \sigma \f$ such that | 
 |     //  \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$ | 
 |     //  then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$ | 
 |     //  and the balancing coefficient for the column is \f$ 2^{\sigma} \f$ | 
 |     const RealScalar radix = RealScalar(2); | 
 |     const RealScalar radix2 = RealScalar(4); | 
 |  | 
 |     rowB = rowNorm / radix; | 
 |     colB = RealScalar(1); | 
 |     const RealScalar s = colNorm + rowNorm; | 
 |  | 
 |     // Find sigma s.t. rowNorm / 2 <= 2^(2*sigma) * colNorm | 
 |     RealScalar scout = colNorm; | 
 |     while (scout < rowB) { | 
 |       colB *= radix; | 
 |       scout *= radix2; | 
 |     } | 
 |  | 
 |     // We now have an upper-bound for sigma, try to lower it. | 
 |     // Find sigma s.t. 2^(2*sigma) * colNorm / 2 < rowNorm | 
 |     scout = colNorm * (colB / radix) * colB;  // Avoid overflow. | 
 |     while (scout >= rowNorm) { | 
 |       colB /= radix; | 
 |       scout /= radix2; | 
 |     } | 
 |  | 
 |     // This line is used to avoid insubstantial balancing. | 
 |     if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB) { | 
 |       isBalanced = false; | 
 |       rowB = RealScalar(1) / colB; | 
 |       return false; | 
 |     } else { | 
 |       return true; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | template <typename Scalar_, int Deg_> | 
 | inline bool companion<Scalar_, Deg_>::balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, | 
 |                                                 RealScalar& colB, RealScalar& rowB) { | 
 |   if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm) { | 
 |     return true; | 
 |   } else { | 
 |     /** | 
 |      * Set the norm of the column and the row to the geometric mean | 
 |      * of the row and column norm | 
 |      */ | 
 |     const RealScalar q = colNorm / rowNorm; | 
 |     if (!isApprox(q, Scalar_(1))) { | 
 |       rowB = sqrt(colNorm / rowNorm); | 
 |       colB = RealScalar(1) / rowB; | 
 |  | 
 |       isBalanced = false; | 
 |       return false; | 
 |     } else { | 
 |       return true; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | template <typename Scalar_, int Deg_> | 
 | void companion<Scalar_, Deg_>::balance() { | 
 |   using std::abs; | 
 |   EIGEN_STATIC_ASSERT(Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE); | 
 |   const Index deg = m_monic.size(); | 
 |   const Index deg_1 = deg - 1; | 
 |  | 
 |   bool hasConverged = false; | 
 |   while (!hasConverged) { | 
 |     hasConverged = true; | 
 |     RealScalar colNorm, rowNorm; | 
 |     RealScalar colB, rowB; | 
 |  | 
 |     // First row, first column excluding the diagonal | 
 |     //============================================== | 
 |     colNorm = abs(m_bl_diag[0]); | 
 |     rowNorm = abs(m_monic[0]); | 
 |  | 
 |     // Compute balancing of the row and the column | 
 |     if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) { | 
 |       m_bl_diag[0] *= colB; | 
 |       m_monic[0] *= rowB; | 
 |     } | 
 |  | 
 |     // Middle rows and columns excluding the diagonal | 
 |     //============================================== | 
 |     for (Index i = 1; i < deg_1; ++i) { | 
 |       // column norm, excluding the diagonal | 
 |       colNorm = abs(m_bl_diag[i]); | 
 |  | 
 |       // row norm, excluding the diagonal | 
 |       rowNorm = abs(m_bl_diag[i - 1]) + abs(m_monic[i]); | 
 |  | 
 |       // Compute balancing of the row and the column | 
 |       if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) { | 
 |         m_bl_diag[i] *= colB; | 
 |         m_bl_diag[i - 1] *= rowB; | 
 |         m_monic[i] *= rowB; | 
 |       } | 
 |     } | 
 |  | 
 |     // Last row, last column excluding the diagonal | 
 |     //============================================ | 
 |     const Index ebl = m_bl_diag.size() - 1; | 
 |     VectorBlock<RightColumn, Deg_1> headMonic(m_monic, 0, deg_1); | 
 |     colNorm = headMonic.array().abs().sum(); | 
 |     rowNorm = abs(m_bl_diag[ebl]); | 
 |  | 
 |     // Compute balancing of the row and the column | 
 |     if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) { | 
 |       headMonic *= colB; | 
 |       m_bl_diag[ebl] *= rowB; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | }  // end namespace internal | 
 |  | 
 | }  // end namespace Eigen | 
 |  | 
 | #endif  // EIGEN_COMPANION_H |