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 #include "./InternalHeaderCheck.h"
18 
19 namespace Eigen {
20 
21 namespace internal {
22 
23 #ifndef EIGEN_PARSED_BY_DOXYGEN
24 
25 template<int Size>
26 struct decrement_if_fixed_size
27 {
28  enum {
29  ret = (Size == Dynamic) ? Dynamic : Size-1 };
30 };
31 
32 #endif
33 
34 template< typename Scalar_, int Deg_ >
35 class companion
36 {
37  public:
39 
40  enum {
41  Deg = Deg_,
42  Deg_1=decrement_if_fixed_size<Deg>::ret
43  };
44 
45  typedef Scalar_ Scalar;
46  typedef typename NumTraits<Scalar>::Real RealScalar;
47  typedef Matrix<Scalar, Deg, 1> RightColumn;
48  //typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal;
49  typedef Matrix<Scalar, Deg_1, 1> BottomLeftDiagonal;
50 
51  typedef Matrix<Scalar, Deg, Deg> DenseCompanionMatrixType;
52  typedef Matrix< Scalar, Deg_, Deg_1 > LeftBlock;
53  typedef Matrix< Scalar, Deg_1, Deg_1 > BottomLeftBlock;
54  typedef Matrix< Scalar, 1, Deg_1 > LeftBlockFirstRow;
55 
56  typedef DenseIndex Index;
57 
58  public:
59  EIGEN_STRONG_INLINE const Scalar_ operator()(Index row, Index col ) const
60  {
61  if( m_bl_diag.rows() > col )
62  {
63  if( 0 < row ){ return m_bl_diag[col]; }
64  else{ return 0; }
65  }
66  else{ return m_monic[row]; }
67  }
68 
69  public:
70  template<typename VectorType>
71  void setPolynomial( const VectorType& poly )
72  {
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  public:
83  DenseCompanionMatrixType denseMatrix() const
84  {
85  const Index deg = m_monic.size();
86  const Index deg_1 = deg-1;
87  DenseCompanionMatrixType companMat(deg,deg);
88  companMat <<
89  ( LeftBlock(deg,deg_1)
90  << LeftBlockFirstRow::Zero(1,deg_1),
91  BottomLeftBlock::Identity(deg-1,deg-1)*m_bl_diag.asDiagonal() ).finished()
92  , m_monic;
93  return companMat;
94  }
95 
96 
97 
98  protected:
105  bool balanced( RealScalar colNorm, RealScalar rowNorm,
106  bool& isBalanced, RealScalar& colB, RealScalar& rowB );
107 
114  bool balancedR( RealScalar colNorm, RealScalar rowNorm,
115  bool& isBalanced, RealScalar& colB, RealScalar& rowB );
116 
117  public:
126  void balance();
127 
128  protected:
129  RightColumn m_monic;
130  BottomLeftDiagonal m_bl_diag;
131 };
132 
133 
134 
135 template< typename Scalar_, int Deg_ >
136 inline
137 bool companion<Scalar_,Deg_>::balanced( RealScalar colNorm, RealScalar rowNorm,
138  bool& isBalanced, RealScalar& colB, RealScalar& rowB )
139 {
140  if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm
141  || !(numext::isfinite)(colNorm) || !(numext::isfinite)(rowNorm)){
142  return true;
143  }
144  else
145  {
146  //To find the balancing coefficients, if the radix is 2,
147  //one finds \f$ \sigma \f$ such that
148  // \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
149  // then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
150  // and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
151  const RealScalar radix = RealScalar(2);
152  const RealScalar radix2 = RealScalar(4);
153 
154  rowB = rowNorm / radix;
155  colB = RealScalar(1);
156  const RealScalar s = colNorm + rowNorm;
157 
158  // Find sigma s.t. rowNorm / 2 <= 2^(2*sigma) * colNorm
159  RealScalar scout = colNorm;
160  while (scout < rowB)
161  {
162  colB *= radix;
163  scout *= radix2;
164  }
165 
166  // We now have an upper-bound for sigma, try to lower it.
167  // Find sigma s.t. 2^(2*sigma) * colNorm / 2 < rowNorm
168  scout = colNorm * (colB / radix) * colB; // Avoid overflow.
169  while (scout >= rowNorm)
170  {
171  colB /= radix;
172  scout /= radix2;
173  }
174 
175  // This line is used to avoid insubstantial balancing.
176  if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB)
177  {
178  isBalanced = false;
179  rowB = RealScalar(1) / colB;
180  return false;
181  }
182  else
183  {
184  return true;
185  }
186  }
187 }
188 
189 template< typename Scalar_, int Deg_ >
190 inline
191 bool companion<Scalar_,Deg_>::balancedR( RealScalar colNorm, RealScalar rowNorm,
192  bool& isBalanced, RealScalar& colB, RealScalar& rowB )
193 {
194  if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm ){ return true; }
195  else
196  {
201  const RealScalar q = colNorm/rowNorm;
202  if( !isApprox( q, Scalar_(1) ) )
203  {
204  rowB = sqrt( colNorm/rowNorm );
205  colB = RealScalar(1)/rowB;
206 
207  isBalanced = false;
208  return false;
209  }
210  else{
211  return true; }
212  }
213 }
214 
215 
216 template< typename Scalar_, int Deg_ >
217 void companion<Scalar_,Deg_>::balance()
218 {
219  using std::abs;
220  EIGEN_STATIC_ASSERT( Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE );
221  const Index deg = m_monic.size();
222  const Index deg_1 = deg-1;
223 
224  bool hasConverged=false;
225  while( !hasConverged )
226  {
227  hasConverged = true;
228  RealScalar colNorm,rowNorm;
229  RealScalar colB,rowB;
230 
231  //First row, first column excluding the diagonal
232  //==============================================
233  colNorm = abs(m_bl_diag[0]);
234  rowNorm = abs(m_monic[0]);
235 
236  //Compute balancing of the row and the column
237  if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
238  {
239  m_bl_diag[0] *= colB;
240  m_monic[0] *= rowB;
241  }
242 
243  //Middle rows and columns excluding the diagonal
244  //==============================================
245  for( Index i=1; i<deg_1; ++i )
246  {
247  // column norm, excluding the diagonal
248  colNorm = abs(m_bl_diag[i]);
249 
250  // row norm, excluding the diagonal
251  rowNorm = abs(m_bl_diag[i-1]) + abs(m_monic[i]);
252 
253  //Compute balancing of the row and the column
254  if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
255  {
256  m_bl_diag[i] *= colB;
257  m_bl_diag[i-1] *= rowB;
258  m_monic[i] *= rowB;
259  }
260  }
261 
262  //Last row, last column excluding the diagonal
263  //============================================
264  const Index ebl = m_bl_diag.size()-1;
265  VectorBlock<RightColumn,Deg_1> headMonic( m_monic, 0, deg_1 );
266  colNorm = headMonic.array().abs().sum();
267  rowNorm = abs( m_bl_diag[ebl] );
268 
269  //Compute balancing of the row and the column
270  if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
271  {
272  headMonic *= colB;
273  m_bl_diag[ebl] *= rowB;
274  }
275  }
276 }
277 
278 } // end namespace internal
279 
280 } // end namespace Eigen
281 
282 #endif // EIGEN_COMPANION_H
int i
RowXpr row(Index i) const
ColXpr col(Index i) const
IndexedView_or_VectorBlock operator()(const Indices &indices)
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar, Size)
#define EIGEN_STATIC_ASSERT(X, MSG)
static const ConstantReturnType Zero()
static const IdentityReturnType Identity()
bool isApprox(const Scalar &x, const Scalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
EIGEN_ALWAYS_INLINE bool() isfinite(const Eigen::bfloat16 &h)
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex
const int Dynamic
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
adouble abs(const adouble &x)
Definition: AdolcForward:74