MatrixExponential.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) 2009, 2010, 2013 Jitse Niesen <jitse@maths.leeds.ac.uk>
5 // Copyright (C) 2011, 2013 Chen-Pang He <jdh8@ms63.hinet.net>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_MATRIX_EXPONENTIAL
12 #define EIGEN_MATRIX_EXPONENTIAL
13 
14 #include "StemFunction.h"
15 
16 // IWYU pragma: private
17 #include "./InternalHeaderCheck.h"
18 
19 namespace Eigen {
20 namespace internal {
21 
26 template <typename RealScalar>
32  MatrixExponentialScalingOp(int squarings) : m_squarings(squarings) {}
33 
38  inline const RealScalar operator()(const RealScalar& x) const {
39  using std::ldexp;
40  return ldexp(x, -m_squarings);
41  }
42 
43  typedef std::complex<RealScalar> ComplexScalar;
44 
49  inline const ComplexScalar operator()(const ComplexScalar& x) const {
50  using std::ldexp;
51  return ComplexScalar(ldexp(x.real(), -m_squarings), ldexp(x.imag(), -m_squarings));
52  }
53 
54  private:
56 };
57 
63 template <typename MatA, typename MatU, typename MatV>
64 void matrix_exp_pade3(const MatA& A, MatU& U, MatV& V) {
65  typedef typename MatA::PlainObject MatrixType;
67  const RealScalar b[] = {120.L, 60.L, 12.L, 1.L};
68  const MatrixType A2 = A * A;
69  const MatrixType tmp = b[3] * A2 + b[1] * MatrixType::Identity(A.rows(), A.cols());
70  U.noalias() = A * tmp;
71  V = b[2] * A2 + b[0] * MatrixType::Identity(A.rows(), A.cols());
72 }
73 
79 template <typename MatA, typename MatU, typename MatV>
80 void matrix_exp_pade5(const MatA& A, MatU& U, MatV& V) {
81  typedef typename MatA::PlainObject MatrixType;
83  const RealScalar b[] = {30240.L, 15120.L, 3360.L, 420.L, 30.L, 1.L};
84  const MatrixType A2 = A * A;
85  const MatrixType A4 = A2 * A2;
86  const MatrixType tmp = b[5] * A4 + b[3] * A2 + b[1] * MatrixType::Identity(A.rows(), A.cols());
87  U.noalias() = A * tmp;
88  V = b[4] * A4 + b[2] * A2 + b[0] * MatrixType::Identity(A.rows(), A.cols());
89 }
90 
96 template <typename MatA, typename MatU, typename MatV>
97 void matrix_exp_pade7(const MatA& A, MatU& U, MatV& V) {
98  typedef typename MatA::PlainObject MatrixType;
100  const RealScalar b[] = {17297280.L, 8648640.L, 1995840.L, 277200.L, 25200.L, 1512.L, 56.L, 1.L};
101  const MatrixType A2 = A * A;
102  const MatrixType A4 = A2 * A2;
103  const MatrixType A6 = A4 * A2;
104  const MatrixType tmp = b[7] * A6 + b[5] * A4 + b[3] * A2 + b[1] * MatrixType::Identity(A.rows(), A.cols());
105  U.noalias() = A * tmp;
106  V = b[6] * A6 + b[4] * A4 + b[2] * A2 + b[0] * MatrixType::Identity(A.rows(), A.cols());
107 }
108 
114 template <typename MatA, typename MatU, typename MatV>
115 void matrix_exp_pade9(const MatA& A, MatU& U, MatV& V) {
116  typedef typename MatA::PlainObject MatrixType;
118  const RealScalar b[] = {17643225600.L, 8821612800.L, 2075673600.L, 302702400.L, 30270240.L,
119  2162160.L, 110880.L, 3960.L, 90.L, 1.L};
120  const MatrixType A2 = A * A;
121  const MatrixType A4 = A2 * A2;
122  const MatrixType A6 = A4 * A2;
123  const MatrixType A8 = A6 * A2;
124  const MatrixType tmp =
125  b[9] * A8 + b[7] * A6 + b[5] * A4 + b[3] * A2 + b[1] * MatrixType::Identity(A.rows(), A.cols());
126  U.noalias() = A * tmp;
127  V = b[8] * A8 + b[6] * A6 + b[4] * A4 + b[2] * A2 + b[0] * MatrixType::Identity(A.rows(), A.cols());
128 }
129 
135 template <typename MatA, typename MatU, typename MatV>
136 void matrix_exp_pade13(const MatA& A, MatU& U, MatV& V) {
137  typedef typename MatA::PlainObject MatrixType;
139  const RealScalar b[] = {64764752532480000.L,
140  32382376266240000.L,
141  7771770303897600.L,
142  1187353796428800.L,
143  129060195264000.L,
144  10559470521600.L,
145  670442572800.L,
146  33522128640.L,
147  1323241920.L,
148  40840800.L,
149  960960.L,
150  16380.L,
151  182.L,
152  1.L};
153  const MatrixType A2 = A * A;
154  const MatrixType A4 = A2 * A2;
155  const MatrixType A6 = A4 * A2;
156  V = b[13] * A6 + b[11] * A4 + b[9] * A2; // used for temporary storage
157  MatrixType tmp = A6 * V;
158  tmp += b[7] * A6 + b[5] * A4 + b[3] * A2 + b[1] * MatrixType::Identity(A.rows(), A.cols());
159  U.noalias() = A * tmp;
160  tmp = b[12] * A6 + b[10] * A4 + b[8] * A2;
161  V.noalias() = A6 * tmp;
162  V += b[6] * A6 + b[4] * A4 + b[2] * A2 + b[0] * MatrixType::Identity(A.rows(), A.cols());
163 }
164 
172 #if LDBL_MANT_DIG > 64
173 template <typename MatA, typename MatU, typename MatV>
174 void matrix_exp_pade17(const MatA& A, MatU& U, MatV& V) {
175  typedef typename MatA::PlainObject MatrixType;
177  const RealScalar b[] = {830034394580628357120000.L,
178  415017197290314178560000.L,
179  100610229646136770560000.L,
180  15720348382208870400000.L,
181  1774878043152614400000.L,
182  153822763739893248000.L,
183  10608466464820224000.L,
184  595373117923584000.L,
185  27563570274240000.L,
186  1060137318240000.L,
187  33924394183680.L,
188  899510451840.L,
189  19554575040.L,
190  341863200.L,
191  4651200.L,
192  46512.L,
193  306.L,
194  1.L};
195  const MatrixType A2 = A * A;
196  const MatrixType A4 = A2 * A2;
197  const MatrixType A6 = A4 * A2;
198  const MatrixType A8 = A4 * A4;
199  V = b[17] * A8 + b[15] * A6 + b[13] * A4 + b[11] * A2; // used for temporary storage
200  MatrixType tmp = A8 * V;
201  tmp += b[9] * A8 + b[7] * A6 + b[5] * A4 + b[3] * A2 + b[1] * MatrixType::Identity(A.rows(), A.cols());
202  U.noalias() = A * tmp;
203  tmp = b[16] * A8 + b[14] * A6 + b[12] * A4 + b[10] * A2;
204  V.noalias() = tmp * A8;
205  V += b[8] * A8 + b[6] * A6 + b[4] * A4 + b[2] * A2 + b[0] * MatrixType::Identity(A.rows(), A.cols());
206 }
207 #endif
208 
218  static void run(const MatrixType& arg, MatrixType& U, MatrixType& V, int& squarings);
219 };
220 
221 template <typename MatrixType>
223  template <typename ArgType>
224  static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings) {
225  using std::frexp;
226  using std::pow;
227  const float l1norm = arg.cwiseAbs().colwise().sum().maxCoeff();
228  squarings = 0;
229  if (l1norm < 4.258730016922831e-001f) {
230  matrix_exp_pade3(arg, U, V);
231  } else if (l1norm < 1.880152677804762e+000f) {
232  matrix_exp_pade5(arg, U, V);
233  } else {
234  const float maxnorm = 3.925724783138660f;
235  frexp(l1norm / maxnorm, &squarings);
236  if (squarings < 0) squarings = 0;
237  MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<float>(squarings));
238  matrix_exp_pade7(A, U, V);
239  }
240  }
241 };
242 
243 template <typename MatrixType>
246  template <typename ArgType>
247  static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings) {
248  using std::frexp;
249  using std::pow;
250  const RealScalar l1norm = arg.cwiseAbs().colwise().sum().maxCoeff();
251  squarings = 0;
252  if (l1norm < 1.495585217958292e-002) {
253  matrix_exp_pade3(arg, U, V);
254  } else if (l1norm < 2.539398330063230e-001) {
255  matrix_exp_pade5(arg, U, V);
256  } else if (l1norm < 9.504178996162932e-001) {
257  matrix_exp_pade7(arg, U, V);
258  } else if (l1norm < 2.097847961257068e+000) {
259  matrix_exp_pade9(arg, U, V);
260  } else {
261  const RealScalar maxnorm = 5.371920351148152;
262  frexp(l1norm / maxnorm, &squarings);
263  if (squarings < 0) squarings = 0;
264  MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<RealScalar>(squarings));
265  matrix_exp_pade13(A, U, V);
266  }
267  }
268 };
269 
270 template <typename MatrixType>
272  template <typename ArgType>
273  static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings) {
274 #if LDBL_MANT_DIG == 53 // double precision
276 
277 #else
278 
279  using std::frexp;
280  using std::pow;
281  const long double l1norm = arg.cwiseAbs().colwise().sum().maxCoeff();
282  squarings = 0;
283 
284 #if LDBL_MANT_DIG <= 64 // extended precision
285 
286  if (l1norm < 4.1968497232266989671e-003L) {
287  matrix_exp_pade3(arg, U, V);
288  } else if (l1norm < 1.1848116734693823091e-001L) {
289  matrix_exp_pade5(arg, U, V);
290  } else if (l1norm < 5.5170388480686700274e-001L) {
291  matrix_exp_pade7(arg, U, V);
292  } else if (l1norm < 1.3759868875587845383e+000L) {
293  matrix_exp_pade9(arg, U, V);
294  } else {
295  const long double maxnorm = 4.0246098906697353063L;
296  frexp(l1norm / maxnorm, &squarings);
297  if (squarings < 0) squarings = 0;
298  MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<long double>(squarings));
299  matrix_exp_pade13(A, U, V);
300  }
301 
302 #elif LDBL_MANT_DIG <= 106 // double-double
303 
304  if (l1norm < 3.2787892205607026992947488108213e-005L) {
305  matrix_exp_pade3(arg, U, V);
306  } else if (l1norm < 6.4467025060072760084130906076332e-003L) {
307  matrix_exp_pade5(arg, U, V);
308  } else if (l1norm < 6.8988028496595374751374122881143e-002L) {
309  matrix_exp_pade7(arg, U, V);
310  } else if (l1norm < 2.7339737518502231741495857201670e-001L) {
311  matrix_exp_pade9(arg, U, V);
312  } else if (l1norm < 1.3203382096514474905666448850278e+000L) {
313  matrix_exp_pade13(arg, U, V);
314  } else {
315  const long double maxnorm = 3.2579440895405400856599663723517L;
316  frexp(l1norm / maxnorm, &squarings);
317  if (squarings < 0) squarings = 0;
318  MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<long double>(squarings));
319  matrix_exp_pade17(A, U, V);
320  }
321 
322 #elif LDBL_MANT_DIG <= 113 // quadruple precision
323 
324  if (l1norm < 1.639394610288918690547467954466970e-005L) {
325  matrix_exp_pade3(arg, U, V);
326  } else if (l1norm < 4.253237712165275566025884344433009e-003L) {
327  matrix_exp_pade5(arg, U, V);
328  } else if (l1norm < 5.125804063165764409885122032933142e-002L) {
329  matrix_exp_pade7(arg, U, V);
330  } else if (l1norm < 2.170000765161155195453205651889853e-001L) {
331  matrix_exp_pade9(arg, U, V);
332  } else if (l1norm < 1.125358383453143065081397882891878e+000L) {
333  matrix_exp_pade13(arg, U, V);
334  } else {
335  const long double maxnorm = 2.884233277829519311757165057717815L;
336  frexp(l1norm / maxnorm, &squarings);
337  if (squarings < 0) squarings = 0;
338  MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<long double>(squarings));
339  matrix_exp_pade17(A, U, V);
340  }
341 
342 #else
343 
344  // this case should be handled in compute()
345  eigen_assert(false && "Bug in MatrixExponential");
346 
347 #endif
348 #endif // LDBL_MANT_DIG
349  }
350 };
351 
352 template <typename T>
354 template <>
355 struct is_exp_known_type<float> : true_type {};
356 template <>
358 #if LDBL_MANT_DIG <= 113
359 template <>
361 #endif
362 
363 template <typename ArgType, typename ResultType>
364 void matrix_exp_compute(const ArgType& arg, ResultType& result, true_type) // natively supported scalar type
365 {
366  typedef typename ArgType::PlainObject MatrixType;
367  MatrixType U, V;
368  int squarings;
369  matrix_exp_computeUV<MatrixType>::run(arg, U, V, squarings); // Pade approximant is (U+V) / (-U+V)
370  MatrixType numer = U + V;
371  MatrixType denom = -U + V;
372  result = denom.partialPivLu().solve(numer);
373  for (int i = 0; i < squarings; i++) result *= result; // undo scaling by repeated squaring
374 }
375 
376 /* Computes the matrix exponential
377  *
378  * \param arg argument of matrix exponential (should be plain object)
379  * \param result variable in which result will be stored
380  */
381 template <typename ArgType, typename ResultType>
382 void matrix_exp_compute(const ArgType& arg, ResultType& result, false_type) // default
383 {
384  typedef typename ArgType::PlainObject MatrixType;
385  typedef typename traits<MatrixType>::Scalar Scalar;
386  typedef typename NumTraits<Scalar>::Real RealScalar;
387  typedef typename std::complex<RealScalar> ComplexScalar;
388  result = arg.matrixFunction(internal::stem_function_exp<ComplexScalar>);
389 }
390 
391 } // namespace internal
392 
403 template <typename Derived>
404 struct MatrixExponentialReturnValue : public ReturnByValue<MatrixExponentialReturnValue<Derived> > {
405  public:
410  MatrixExponentialReturnValue(const Derived& src) : m_src(src) {}
411 
416  template <typename ResultType>
417  inline void evalTo(ResultType& result) const {
420  }
421 
422  Index rows() const { return m_src.rows(); }
423  Index cols() const { return m_src.cols(); }
424 
425  protected:
427 };
428 
429 namespace internal {
430 template <typename Derived>
432  typedef typename Derived::PlainObject ReturnType;
433 };
434 } // namespace internal
435 
436 template <typename Derived>
438  eigen_assert(rows() == cols());
439  return MatrixExponentialReturnValue<Derived>(derived());
440 }
441 
442 } // end namespace Eigen
443 
444 #endif // EIGEN_MATRIX_EXPONENTIAL
int i
Definition: BiCGSTAB_step_by_step.cpp:9
MatrixXcd V
Definition: EigenSolver_EigenSolver_MatrixType.cpp:15
#define eigen_assert(x)
Definition: Macros.h:910
int rows
Definition: Tutorial_commainit_02.cpp:1
int cols
Definition: Tutorial_commainit_02.cpp:1
Scalar * b
Definition: benchVecAdd.cpp:17
SCALAR Scalar
Definition: bench_gemm.cpp:45
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:46
MatrixXf MatrixType
Definition: benchmark-blocking-sizes.cpp:52
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 100 >, boost::multiprecision::et_on > Real
Definition: boostmultiprec.cpp:77
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT
Definition: PlainObjectBase.h:192
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
Definition: PlainObjectBase.h:191
Definition: ReturnByValue.h:50
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 exp(const bfloat16 &a)
Definition: BFloat16.h:615
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
void matrix_exp_pade7(const MatA &A, MatU &U, MatV &V)
Compute the (7,7)-Padé approximant to the exponential.
Definition: MatrixExponential.h:97
void matrix_exp_pade9(const MatA &A, MatU &U, MatV &V)
Compute the (9,9)-Padé approximant to the exponential.
Definition: MatrixExponential.h:115
void matrix_exp_compute(const ArgType &arg, ResultType &result, true_type)
Definition: MatrixExponential.h:364
void matrix_exp_pade3(const MatA &A, MatU &U, MatV &V)
Compute the (3,3)-Padé approximant to the exponential.
Definition: MatrixExponential.h:64
void matrix_exp_pade13(const MatA &A, MatU &U, MatV &V)
Compute the (13,13)-Padé approximant to the exponential.
Definition: MatrixExponential.h:136
void matrix_exp_pade5(const MatA &A, MatU &U, MatV &V)
Compute the (5,5)-Padé approximant to the exponential.
Definition: MatrixExponential.h:80
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:83
double U
Swimming speed.
Definition: two_d_variable_diff_adapt.cc:53
Definition: Eigen_Colamd.h:49
list x
Definition: plotDoE.py:28
Proxy for the matrix exponential of some matrix (expression).
Definition: MatrixExponential.h:404
void evalTo(ResultType &result) const
Compute the matrix exponential.
Definition: MatrixExponential.h:417
MatrixExponentialReturnValue(const Derived &src)
Constructor.
Definition: MatrixExponential.h:410
Index rows() const
Definition: MatrixExponential.h:422
const internal::ref_selector< Derived >::type m_src
Definition: MatrixExponential.h:426
Index cols() const
Definition: MatrixExponential.h:423
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:217
Scaling operator.
Definition: MatrixExponential.h:27
const ComplexScalar operator()(const ComplexScalar &x) const
Scale a matrix coefficient.
Definition: MatrixExponential.h:49
int m_squarings
Definition: MatrixExponential.h:55
std::complex< RealScalar > ComplexScalar
Definition: MatrixExponential.h:43
const RealScalar operator()(const RealScalar &x) const
Scale a matrix coefficient.
Definition: MatrixExponential.h:38
MatrixExponentialScalingOp(int squarings)
Constructor.
Definition: MatrixExponential.h:32
Definition: Meta.h:97
Definition: MatrixExponential.h:353
NumTraits< typename traits< MatrixType >::Scalar >::Real RealScalar
Definition: MatrixExponential.h:245
static void run(const ArgType &arg, MatrixType &U, MatrixType &V, int &squarings)
Definition: MatrixExponential.h:247
static void run(const ArgType &arg, MatrixType &U, MatrixType &V, int &squarings)
Definition: MatrixExponential.h:224
static void run(const ArgType &arg, MatrixType &U, MatrixType &V, int &squarings)
Definition: MatrixExponential.h:273
Compute the (17,17)-Padé approximant to the exponential.
Definition: MatrixExponential.h:210
static void run(const MatrixType &arg, MatrixType &U, MatrixType &V, int &squarings)
Compute Padé approximant to the exponential.
std::conditional_t< Evaluate, PlainObject, typename ref_selector< T >::type > type
Definition: XprHelper.h:549
std::conditional_t< bool(traits< T >::Flags &NestByRefBit), T const &, const T > type
Definition: XprHelper.h:507
Derived::PlainObject ReturnType
Definition: MatrixExponential.h:432
Definition: ForwardDeclarations.h:21
Definition: Meta.h:94