Companion.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2010 Manuel Yguel <manuel.yguel@gmail.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_COMPANION_H
11 #define EIGEN_COMPANION_H
12 
13 // This file requires the user to include
14 // * Eigen/Core
15 // * Eigen/src/PolynomialSolver.h
16 
17 // IWYU pragma: private
18 #include "./InternalHeaderCheck.h"
19 
20 namespace Eigen {
21 
22 namespace internal {
23 
24 #ifndef EIGEN_PARSED_BY_DOXYGEN
25 
26 template <int Size>
28  enum { ret = (Size == Dynamic) ? Dynamic : Size - 1 };
29 };
30 
31 #endif
32 
33 template <typename Scalar_, int Deg_>
34 class companion {
35  public:
37 
39 
40  typedef Scalar_ Scalar;
43  // typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal;
45 
50 
51  typedef DenseIndex Index;
52 
53  public:
54  EIGEN_STRONG_INLINE const Scalar_ operator()(Index row, Index col) const {
55  if (m_bl_diag.rows() > col) {
56  if (0 < row) {
57  return m_bl_diag[col];
58  } else {
59  return 0;
60  }
61  } else {
62  return m_monic[row];
63  }
64  }
65 
66  public:
67  template <typename VectorType>
68  void setPolynomial(const VectorType& poly) {
69  const Index deg = poly.size() - 1;
70  m_monic = -poly.head(deg) / poly[deg];
71  m_bl_diag.setOnes(deg - 1);
72  }
73 
74  template <typename VectorType>
75  companion(const VectorType& poly) {
76  setPolynomial(poly);
77  }
78 
79  public:
81  const Index deg = m_monic.size();
82  const Index deg_1 = deg - 1;
83  DenseCompanionMatrixType companMat(deg, deg);
84  companMat << (LeftBlock(deg, deg_1) << LeftBlockFirstRow::Zero(1, deg_1),
85  BottomLeftBlock::Identity(deg - 1, deg - 1) * m_bl_diag.asDiagonal())
86  .finished(),
87  m_monic;
88  return companMat;
89  }
90 
91  protected:
98  bool balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB);
99 
106  bool balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB);
107 
108  public:
117  void balance();
118 
119  protected:
122 };
123 
124 template <typename Scalar_, int Deg_>
125 inline bool companion<Scalar_, Deg_>::balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced,
126  RealScalar& colB, RealScalar& rowB) {
127  if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm || !(numext::isfinite)(colNorm) ||
128  !(numext::isfinite)(rowNorm)) {
129  return true;
130  } else {
131  // To find the balancing coefficients, if the radix is 2,
132  // one finds \f$ \sigma \f$ such that
133  // \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
134  // then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
135  // and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
136  const RealScalar radix = RealScalar(2);
137  const RealScalar radix2 = RealScalar(4);
138 
139  rowB = rowNorm / radix;
140  colB = RealScalar(1);
141  const RealScalar s = colNorm + rowNorm;
142 
143  // Find sigma s.t. rowNorm / 2 <= 2^(2*sigma) * colNorm
144  RealScalar scout = colNorm;
145  while (scout < rowB) {
146  colB *= radix;
147  scout *= radix2;
148  }
149 
150  // We now have an upper-bound for sigma, try to lower it.
151  // Find sigma s.t. 2^(2*sigma) * colNorm / 2 < rowNorm
152  scout = colNorm * (colB / radix) * colB; // Avoid overflow.
153  while (scout >= rowNorm) {
154  colB /= radix;
155  scout /= radix2;
156  }
157 
158  // This line is used to avoid insubstantial balancing.
159  if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB) {
160  isBalanced = false;
161  rowB = RealScalar(1) / colB;
162  return false;
163  } else {
164  return true;
165  }
166  }
167 }
168 
169 template <typename Scalar_, int Deg_>
170 inline bool companion<Scalar_, Deg_>::balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced,
171  RealScalar& colB, RealScalar& rowB) {
172  if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm) {
173  return true;
174  } else {
179  const RealScalar q = colNorm / rowNorm;
180  if (!isApprox(q, Scalar_(1))) {
181  rowB = sqrt(colNorm / rowNorm);
182  colB = RealScalar(1) / rowB;
183 
184  isBalanced = false;
185  return false;
186  } else {
187  return true;
188  }
189  }
190 }
191 
192 template <typename Scalar_, int Deg_>
194  using std::abs;
195  EIGEN_STATIC_ASSERT(Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE);
196  const Index deg = m_monic.size();
197  const Index deg_1 = deg - 1;
198 
199  bool hasConverged = false;
200  while (!hasConverged) {
201  hasConverged = true;
202  RealScalar colNorm, rowNorm;
203  RealScalar colB, rowB;
204 
205  // First row, first column excluding the diagonal
206  //==============================================
207  colNorm = abs(m_bl_diag[0]);
208  rowNorm = abs(m_monic[0]);
209 
210  // Compute balancing of the row and the column
211  if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
212  m_bl_diag[0] *= colB;
213  m_monic[0] *= rowB;
214  }
215 
216  // Middle rows and columns excluding the diagonal
217  //==============================================
218  for (Index i = 1; i < deg_1; ++i) {
219  // column norm, excluding the diagonal
220  colNorm = abs(m_bl_diag[i]);
221 
222  // row norm, excluding the diagonal
223  rowNorm = abs(m_bl_diag[i - 1]) + abs(m_monic[i]);
224 
225  // Compute balancing of the row and the column
226  if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
227  m_bl_diag[i] *= colB;
228  m_bl_diag[i - 1] *= rowB;
229  m_monic[i] *= rowB;
230  }
231  }
232 
233  // Last row, last column excluding the diagonal
234  //============================================
235  const Index ebl = m_bl_diag.size() - 1;
236  VectorBlock<RightColumn, Deg_1> headMonic(m_monic, 0, deg_1);
237  colNorm = headMonic.array().abs().sum();
238  rowNorm = abs(m_bl_diag[ebl]);
239 
240  // Compute balancing of the row and the column
241  if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
242  headMonic *= colB;
243  m_bl_diag[ebl] *= rowB;
244  }
245  }
246 }
247 
248 } // end namespace internal
249 
250 } // end namespace Eigen
251 
252 #endif // EIGEN_COMPANION_H
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
int i
Definition: BiCGSTAB_step_by_step.cpp:9
#define EIGEN_STRONG_INLINE
Definition: Macros.h:834
m col(1)
m row(1)
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar, Size)
Definition: Memory.h:880
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:46
EIGEN_DEVICE_FUNC Derived & setOnes(Index size)
Definition: CwiseNullaryOp.h:708
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
Definition: PlainObjectBase.h:191
Expression of a fixed-size or dynamic-size sub-vector.
Definition: VectorBlock.h:58
Definition: Companion.h:34
NumTraits< Scalar >::Real RealScalar
Definition: Companion.h:41
companion(const VectorType &poly)
Definition: Companion.h:75
Matrix< Scalar, 1, Deg_1 > LeftBlockFirstRow
Definition: Companion.h:49
Matrix< Scalar, Deg_, Deg_1 > LeftBlock
Definition: Companion.h:47
DenseIndex Index
Definition: Companion.h:51
Matrix< Scalar, Deg, 1 > RightColumn
Definition: Companion.h:42
bool balanced(RealScalar colNorm, RealScalar rowNorm, bool &isBalanced, RealScalar &colB, RealScalar &rowB)
Definition: Companion.h:125
EIGEN_STRONG_INLINE const Scalar_ operator()(Index row, Index col) const
Definition: Companion.h:54
DenseCompanionMatrixType denseMatrix() const
Definition: Companion.h:80
@ Deg_1
Definition: Companion.h:38
@ Deg
Definition: Companion.h:38
Matrix< Scalar, Deg_1, 1 > BottomLeftDiagonal
Definition: Companion.h:44
Matrix< Scalar, Deg, Deg > DenseCompanionMatrixType
Definition: Companion.h:46
bool balancedR(RealScalar colNorm, RealScalar rowNorm, bool &isBalanced, RealScalar &colB, RealScalar &rowB)
Definition: Companion.h:170
void balance()
Definition: Companion.h:193
void setPolynomial(const VectorType &poly)
Definition: Companion.h:68
Matrix< Scalar, Deg_1, Deg_1 > BottomLeftBlock
Definition: Companion.h:48
RightColumn m_monic
Definition: Companion.h:120
BottomLeftDiagonal m_bl_diag
Definition: Companion.h:121
Scalar_ Scalar
Definition: Companion.h:40
RealScalar s
Definition: level1_cplx_impl.h:130
EIGEN_DEVICE_FUNC bool isApprox(const Scalar &x, const Scalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
Definition: MathFunctions.h:1923
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool() isfinite(const Eigen::bfloat16 &h)
Definition: BFloat16.h:752
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:2019
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex
Definition: Meta.h:75
const int Dynamic
Definition: Constants.h:25
bool finished
Definition: MergeRestartFiles.py:79
Definition: Eigen_Colamd.h:49
double Zero
Definition: pseudosolid_node_update_elements.cc:35
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:217
@ ret
Definition: Companion.h:28
Definition: fft_test_shared.h:66