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