Eigen-unsupported  5.0.1-dev+7c7d8473
 
Loading...
Searching...
No Matches
Companion.h
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
20namespace Eigen {
21
22namespace internal {
23
24#ifndef EIGEN_PARSED_BY_DOXYGEN
25
26template <int Size>
27struct decrement_if_fixed_size {
28 enum { ret = (Size == Dynamic) ? Dynamic : Size - 1 };
29};
30
31#endif
32
33template <typename Scalar_, int Deg_>
34class companion {
35 public:
36 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
37
38 enum { Deg = Deg_, Deg_1 = decrement_if_fixed_size<Deg>::ret };
39
40 typedef Scalar_ Scalar;
41 typedef typename NumTraits<Scalar>::Real RealScalar;
42 typedef Matrix<Scalar, Deg, 1> RightColumn;
43 // typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal;
44 typedef Matrix<Scalar, Deg_1, 1> BottomLeftDiagonal;
45
46 typedef Matrix<Scalar, Deg, Deg> DenseCompanionMatrixType;
47 typedef Matrix<Scalar, Deg_, Deg_1> LeftBlock;
48 typedef Matrix<Scalar, Deg_1, Deg_1> BottomLeftBlock;
49 typedef Matrix<Scalar, 1, Deg_1> LeftBlockFirstRow;
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#ifdef EIGEN_MULTIDIMENSIONAL_SUBSCRIPT
67 EIGEN_STRONG_INLINE const Scalar_ operator[](Index row, Index col) const { return operator()(row, col); }
68#endif
69
70 public:
71 template <typename VectorType>
72 void setPolynomial(const VectorType& poly) {
73 const Index deg = poly.size() - 1;
74 m_monic = -poly.head(deg) / poly[deg];
75 m_bl_diag.setOnes(deg - 1);
76 }
77
78 template <typename VectorType>
79 companion(const VectorType& poly) {
80 setPolynomial(poly);
81 }
82
83 public:
84 DenseCompanionMatrixType denseMatrix() const {
85 const Index deg = m_monic.size();
86 const Index deg_1 = deg - 1;
87 DenseCompanionMatrixType companMat(deg, deg);
88 companMat << (LeftBlock(deg, deg_1) << LeftBlockFirstRow::Zero(1, deg_1),
89 BottomLeftBlock::Identity(deg - 1, deg - 1) * m_bl_diag.asDiagonal())
90 .finished(),
91 m_monic;
92 return companMat;
93 }
94
95 protected:
102 bool balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB);
103
110 bool balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB);
111
112 public:
121 void balance();
122
123 protected:
124 RightColumn m_monic;
125 BottomLeftDiagonal m_bl_diag;
126};
127
128template <typename Scalar_, int Deg_>
129inline bool companion<Scalar_, Deg_>::balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced,
130 RealScalar& colB, RealScalar& rowB) {
131 if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm || !(numext::isfinite)(colNorm) ||
132 !(numext::isfinite)(rowNorm)) {
133 return true;
134 } else {
135 // To find the balancing coefficients, if the radix is 2,
136 // one finds \f$ \sigma \f$ such that
137 // \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
138 // then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
139 // and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
140 const RealScalar radix = RealScalar(2);
141 const RealScalar radix2 = RealScalar(4);
142
143 rowB = rowNorm / radix;
144 colB = RealScalar(1);
145 const RealScalar s = colNorm + rowNorm;
146
147 // Find sigma s.t. rowNorm / 2 <= 2^(2*sigma) * colNorm
148 RealScalar scout = colNorm;
149 while (scout < rowB) {
150 colB *= radix;
151 scout *= radix2;
152 }
153
154 // We now have an upper-bound for sigma, try to lower it.
155 // Find sigma s.t. 2^(2*sigma) * colNorm / 2 < rowNorm
156 scout = colNorm * (colB / radix) * colB; // Avoid overflow.
157 while (scout >= rowNorm) {
158 colB /= radix;
159 scout /= radix2;
160 }
161
162 // This line is used to avoid insubstantial balancing.
163 if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB) {
164 isBalanced = false;
165 rowB = RealScalar(1) / colB;
166 return false;
167 } else {
168 return true;
169 }
170 }
171}
172
173template <typename Scalar_, int Deg_>
174inline bool companion<Scalar_, Deg_>::balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced,
175 RealScalar& colB, RealScalar& rowB) {
176 if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm) {
177 return true;
178 } else {
183 const RealScalar q = colNorm / rowNorm;
184 if (!isApprox(q, Scalar_(1))) {
185 rowB = sqrt(colNorm / rowNorm);
186 colB = RealScalar(1) / rowB;
187
188 isBalanced = false;
189 return false;
190 } else {
191 return true;
192 }
193 }
194}
195
196template <typename Scalar_, int Deg_>
197void companion<Scalar_, Deg_>::balance() {
198 using std::abs;
199 EIGEN_STATIC_ASSERT(Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE);
200 const Index deg = m_monic.size();
201 const Index deg_1 = deg - 1;
202
203 bool hasConverged = false;
204 while (!hasConverged) {
205 hasConverged = true;
206 RealScalar colNorm, rowNorm;
207 RealScalar colB, rowB;
208
209 // First row, first column excluding the diagonal
210 //==============================================
211 colNorm = abs(m_bl_diag[0]);
212 rowNorm = abs(m_monic[0]);
213
214 // Compute balancing of the row and the column
215 if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
216 m_bl_diag[0] *= colB;
217 m_monic[0] *= rowB;
218 }
219
220 // Middle rows and columns excluding the diagonal
221 //==============================================
222 for (Index i = 1; i < deg_1; ++i) {
223 // column norm, excluding the diagonal
224 colNorm = abs(m_bl_diag[i]);
225
226 // row norm, excluding the diagonal
227 rowNorm = abs(m_bl_diag[i - 1]) + abs(m_monic[i]);
228
229 // Compute balancing of the row and the column
230 if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
231 m_bl_diag[i] *= colB;
232 m_bl_diag[i - 1] *= rowB;
233 m_monic[i] *= rowB;
234 }
235 }
236
237 // Last row, last column excluding the diagonal
238 //============================================
239 const Index ebl = m_bl_diag.size() - 1;
240 VectorBlock<RightColumn, Deg_1> headMonic(m_monic, 0, deg_1);
241 colNorm = headMonic.array().abs().sum();
242 rowNorm = abs(m_bl_diag[ebl]);
243
244 // Compute balancing of the row and the column
245 if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
246 headMonic *= colB;
247 m_bl_diag[ebl] *= rowB;
248 }
249 }
250}
251
252} // end namespace internal
253
254} // end namespace Eigen
255
256#endif // EIGEN_COMPANION_H
Namespace containing all symbols from the Eigen library.
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
const int Dynamic