1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2012, 2013 Chen-Pang He <jdh8@ms63.hinet.net> 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_MATRIX_POWER 11 #define EIGEN_MATRIX_POWER 12 13 namespace Eigen { 14 15 template<typename MatrixType> class MatrixPower; 16 17 /** 18 * \ingroup MatrixFunctions_Module 19 * 20 * \brief Proxy for the matrix power of some matrix. 21 * 22 * \tparam MatrixType type of the base, a matrix. 23 * 24 * This class holds the arguments to the matrix power until it is 25 * assigned or evaluated for some other reason (so the argument 26 * should not be changed in the meantime). It is the return type of 27 * MatrixPower::operator() and related functions and most of the 28 * time this is the only way it is used. 29 */ 30 /* TODO This class is only used by MatrixPower, so it should be nested 31 * into MatrixPower, like MatrixPower::ReturnValue. However, my 32 * compiler complained about unused template parameter in the 33 * following declaration in namespace internal. 34 * 35 * template<typename MatrixType> 36 * struct traits<MatrixPower<MatrixType>::ReturnValue>; 37 */ 38 template<typename MatrixType> 39 class MatrixPowerParenthesesReturnValue : public ReturnByValue< MatrixPowerParenthesesReturnValue<MatrixType> > 40 { 41 public: 42 typedef typename MatrixType::RealScalar RealScalar; 43 typedef typename MatrixType::Index Index; 44 45 /** 46 * \brief Constructor. 47 * 48 * \param[in] pow %MatrixPower storing the base. 49 * \param[in] p scalar, the exponent of the matrix power. 50 */ 51 MatrixPowerParenthesesReturnValue(MatrixPower<MatrixType>& pow, RealScalar p) : m_pow(pow), m_p(p) 52 { } 53 54 /** 55 * \brief Compute the matrix power. 56 * 57 * \param[out] result 58 */ 59 template<typename ResultType> 60 inline void evalTo(ResultType& res) const 61 { m_pow.compute(res, m_p); } 62 63 Index rows() const { return m_pow.rows(); } 64 Index cols() const { return m_pow.cols(); } 65 66 private: 67 MatrixPower<MatrixType>& m_pow; 68 const RealScalar m_p; 69 }; 70 71 /** 72 * \ingroup MatrixFunctions_Module 73 * 74 * \brief Class for computing matrix powers. 75 * 76 * \tparam MatrixType type of the base, expected to be an instantiation 77 * of the Matrix class template. 78 * 79 * This class is capable of computing triangular real/complex matrices 80 * raised to a power in the interval \f$ (-1, 1) \f$. 81 * 82 * \note Currently this class is only used by MatrixPower. One may 83 * insist that this be nested into MatrixPower. This class is here to 84 * faciliate future development of triangular matrix functions. 85 */ 86 template<typename MatrixType> 87 class MatrixPowerAtomic : internal::noncopyable 88 { 89 private: 90 enum { 91 RowsAtCompileTime = MatrixType::RowsAtCompileTime, 92 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime 93 }; 94 typedef typename MatrixType::Scalar Scalar; 95 typedef typename MatrixType::RealScalar RealScalar; 96 typedef std::complex<RealScalar> ComplexScalar; 97 typedef typename MatrixType::Index Index; 98 typedef Block<MatrixType,Dynamic,Dynamic> ResultType; 99 100 const MatrixType& m_A; 101 RealScalar m_p; 102 103 void computePade(int degree, const MatrixType& IminusT, ResultType& res) const; 104 void compute2x2(ResultType& res, RealScalar p) const; 105 void computeBig(ResultType& res) const; 106 static int getPadeDegree(float normIminusT); 107 static int getPadeDegree(double normIminusT); 108 static int getPadeDegree(long double normIminusT); 109 static ComplexScalar computeSuperDiag(const ComplexScalar&, const ComplexScalar&, RealScalar p); 110 static RealScalar computeSuperDiag(RealScalar, RealScalar, RealScalar p); 111 112 public: 113 /** 114 * \brief Constructor. 115 * 116 * \param[in] T the base of the matrix power. 117 * \param[in] p the exponent of the matrix power, should be in 118 * \f$ (-1, 1) \f$. 119 * 120 * The class stores a reference to T, so it should not be changed 121 * (or destroyed) before evaluation. Only the upper triangular 122 * part of T is read. 123 */ 124 MatrixPowerAtomic(const MatrixType& T, RealScalar p); 125 126 /** 127 * \brief Compute the matrix power. 128 * 129 * \param[out] res \f$ A^p \f$ where A and p are specified in the 130 * constructor. 131 */ 132 void compute(ResultType& res) const; 133 }; 134 135 template<typename MatrixType> 136 MatrixPowerAtomic<MatrixType>::MatrixPowerAtomic(const MatrixType& T, RealScalar p) : 137 m_A(T), m_p(p) 138 { 139 eigen_assert(T.rows() == T.cols()); 140 eigen_assert(p > -1 && p < 1); 141 } 142 143 template<typename MatrixType> 144 void MatrixPowerAtomic<MatrixType>::compute(ResultType& res) const 145 { 146 using std::pow; 147 switch (m_A.rows()) { 148 case 0: 149 break; 150 case 1: 151 res(0,0) = pow(m_A(0,0), m_p); 152 break; 153 case 2: 154 compute2x2(res, m_p); 155 break; 156 default: 157 computeBig(res); 158 } 159 } 160 161 template<typename MatrixType> 162 void MatrixPowerAtomic<MatrixType>::computePade(int degree, const MatrixType& IminusT, ResultType& res) const 163 { 164 int i = 2*degree; 165 res = (m_p-degree) / (2*i-2) * IminusT; 166 167 for (--i; i; --i) { 168 res = (MatrixType::Identity(IminusT.rows(), IminusT.cols()) + res).template triangularView<Upper>() 169 .solve((i==1 ? -m_p : i&1 ? (-m_p-i/2)/(2*i) : (m_p-i/2)/(2*i-2)) * IminusT).eval(); 170 } 171 res += MatrixType::Identity(IminusT.rows(), IminusT.cols()); 172 } 173 174 // This function assumes that res has the correct size (see bug 614) 175 template<typename MatrixType> 176 void MatrixPowerAtomic<MatrixType>::compute2x2(ResultType& res, RealScalar p) const 177 { 178 using std::abs; 179 using std::pow; 180 res.coeffRef(0,0) = pow(m_A.coeff(0,0), p); 181 182 for (Index i=1; i < m_A.cols(); ++i) { 183 res.coeffRef(i,i) = pow(m_A.coeff(i,i), p); 184 if (m_A.coeff(i-1,i-1) == m_A.coeff(i,i)) 185 res.coeffRef(i-1,i) = p * pow(m_A.coeff(i,i), p-1); 186 else if (2*abs(m_A.coeff(i-1,i-1)) < abs(m_A.coeff(i,i)) || 2*abs(m_A.coeff(i,i)) < abs(m_A.coeff(i-1,i-1))) 187 res.coeffRef(i-1,i) = (res.coeff(i,i)-res.coeff(i-1,i-1)) / (m_A.coeff(i,i)-m_A.coeff(i-1,i-1)); 188 else 189 res.coeffRef(i-1,i) = computeSuperDiag(m_A.coeff(i,i), m_A.coeff(i-1,i-1), p); 190 res.coeffRef(i-1,i) *= m_A.coeff(i-1,i); 191 } 192 } 193 194 template<typename MatrixType> 195 void MatrixPowerAtomic<MatrixType>::computeBig(ResultType& res) const 196 { 197 using std::ldexp; 198 const int digits = std::numeric_limits<RealScalar>::digits; 199 const RealScalar maxNormForPade = digits <= 24? 4.3386528e-1L // single precision 200 : digits <= 53? 2.789358995219730e-1L // double precision 201 : digits <= 64? 2.4471944416607995472e-1L // extended precision 202 : digits <= 106? 1.1016843812851143391275867258512e-1L // double-double 203 : 9.134603732914548552537150753385375e-2L; // quadruple precision 204 MatrixType IminusT, sqrtT, T = m_A.template triangularView<Upper>(); 205 RealScalar normIminusT; 206 int degree, degree2, numberOfSquareRoots = 0; 207 bool hasExtraSquareRoot = false; 208 209 for (Index i=0; i < m_A.cols(); ++i) 210 eigen_assert(m_A(i,i) != RealScalar(0)); 211 212 while (true) { 213 IminusT = MatrixType::Identity(m_A.rows(), m_A.cols()) - T; 214 normIminusT = IminusT.cwiseAbs().colwise().sum().maxCoeff(); 215 if (normIminusT < maxNormForPade) { 216 degree = getPadeDegree(normIminusT); 217 degree2 = getPadeDegree(normIminusT/2); 218 if (degree - degree2 <= 1 || hasExtraSquareRoot) 219 break; 220 hasExtraSquareRoot = true; 221 } 222 matrix_sqrt_triangular(T, sqrtT); 223 T = sqrtT.template triangularView<Upper>(); 224 ++numberOfSquareRoots; 225 } 226 computePade(degree, IminusT, res); 227 228 for (; numberOfSquareRoots; --numberOfSquareRoots) { 229 compute2x2(res, ldexp(m_p, -numberOfSquareRoots)); 230 res = res.template triangularView<Upper>() * res; 231 } 232 compute2x2(res, m_p); 233 } 234 235 template<typename MatrixType> 236 inline int MatrixPowerAtomic<MatrixType>::getPadeDegree(float normIminusT) 237 { 238 const float maxNormForPade[] = { 2.8064004e-1f /* degree = 3 */ , 4.3386528e-1f }; 239 int degree = 3; 240 for (; degree <= 4; ++degree) 241 if (normIminusT <= maxNormForPade[degree - 3]) 242 break; 243 return degree; 244 } 245 246 template<typename MatrixType> 247 inline int MatrixPowerAtomic<MatrixType>::getPadeDegree(double normIminusT) 248 { 249 const double maxNormForPade[] = { 1.884160592658218e-2 /* degree = 3 */ , 6.038881904059573e-2, 1.239917516308172e-1, 250 1.999045567181744e-1, 2.789358995219730e-1 }; 251 int degree = 3; 252 for (; degree <= 7; ++degree) 253 if (normIminusT <= maxNormForPade[degree - 3]) 254 break; 255 return degree; 256 } 257 258 template<typename MatrixType> 259 inline int MatrixPowerAtomic<MatrixType>::getPadeDegree(long double normIminusT) 260 { 261 #if LDBL_MANT_DIG == 53 262 const int maxPadeDegree = 7; 263 const double maxNormForPade[] = { 1.884160592658218e-2L /* degree = 3 */ , 6.038881904059573e-2L, 1.239917516308172e-1L, 264 1.999045567181744e-1L, 2.789358995219730e-1L }; 265 #elif LDBL_MANT_DIG <= 64 266 const int maxPadeDegree = 8; 267 const long double maxNormForPade[] = { 6.3854693117491799460e-3L /* degree = 3 */ , 2.6394893435456973676e-2L, 268 6.4216043030404063729e-2L, 1.1701165502926694307e-1L, 1.7904284231268670284e-1L, 2.4471944416607995472e-1L }; 269 #elif LDBL_MANT_DIG <= 106 270 const int maxPadeDegree = 10; 271 const double maxNormForPade[] = { 1.0007161601787493236741409687186e-4L /* degree = 3 */ , 272 1.0007161601787493236741409687186e-3L, 4.7069769360887572939882574746264e-3L, 1.3220386624169159689406653101695e-2L, 273 2.8063482381631737920612944054906e-2L, 4.9625993951953473052385361085058e-2L, 7.7367040706027886224557538328171e-2L, 274 1.1016843812851143391275867258512e-1L }; 275 #else 276 const int maxPadeDegree = 10; 277 const double maxNormForPade[] = { 5.524506147036624377378713555116378e-5L /* degree = 3 */ , 278 6.640600568157479679823602193345995e-4L, 3.227716520106894279249709728084626e-3L, 279 9.619593944683432960546978734646284e-3L, 2.134595382433742403911124458161147e-2L, 280 3.908166513900489428442993794761185e-2L, 6.266780814639442865832535460550138e-2L, 281 9.134603732914548552537150753385375e-2L }; 282 #endif 283 int degree = 3; 284 for (; degree <= maxPadeDegree; ++degree) 285 if (normIminusT <= maxNormForPade[degree - 3]) 286 break; 287 return degree; 288 } 289 290 template<typename MatrixType> 291 inline typename MatrixPowerAtomic<MatrixType>::ComplexScalar 292 MatrixPowerAtomic<MatrixType>::computeSuperDiag(const ComplexScalar& curr, const ComplexScalar& prev, RealScalar p) 293 { 294 using std::ceil; 295 using std::exp; 296 using std::log; 297 using std::sinh; 298 299 ComplexScalar logCurr = log(curr); 300 ComplexScalar logPrev = log(prev); 301 int unwindingNumber = ceil((numext::imag(logCurr - logPrev) - RealScalar(EIGEN_PI)) / RealScalar(2*EIGEN_PI)); 302 ComplexScalar w = numext::log1p((curr-prev)/prev)/RealScalar(2) + ComplexScalar(0, EIGEN_PI*unwindingNumber); 303 return RealScalar(2) * exp(RealScalar(0.5) * p * (logCurr + logPrev)) * sinh(p * w) / (curr - prev); 304 } 305 306 template<typename MatrixType> 307 inline typename MatrixPowerAtomic<MatrixType>::RealScalar 308 MatrixPowerAtomic<MatrixType>::computeSuperDiag(RealScalar curr, RealScalar prev, RealScalar p) 309 { 310 using std::exp; 311 using std::log; 312 using std::sinh; 313 314 RealScalar w = numext::log1p((curr-prev)/prev)/RealScalar(2); 315 return 2 * exp(p * (log(curr) + log(prev)) / 2) * sinh(p * w) / (curr - prev); 316 } 317 318 /** 319 * \ingroup MatrixFunctions_Module 320 * 321 * \brief Class for computing matrix powers. 322 * 323 * \tparam MatrixType type of the base, expected to be an instantiation 324 * of the Matrix class template. 325 * 326 * This class is capable of computing real/complex matrices raised to 327 * an arbitrary real power. Meanwhile, it saves the result of Schur 328 * decomposition if an non-integral power has even been calculated. 329 * Therefore, if you want to compute multiple (>= 2) matrix powers 330 * for the same matrix, using the class directly is more efficient than 331 * calling MatrixBase::pow(). 332 * 333 * Example: 334 * \include MatrixPower_optimal.cpp 335 * Output: \verbinclude MatrixPower_optimal.out 336 */ 337 template<typename MatrixType> 338 class MatrixPower : internal::noncopyable 339 { 340 private: 341 typedef typename MatrixType::Scalar Scalar; 342 typedef typename MatrixType::RealScalar RealScalar; 343 typedef typename MatrixType::Index Index; 344 345 public: 346 /** 347 * \brief Constructor. 348 * 349 * \param[in] A the base of the matrix power. 350 * 351 * The class stores a reference to A, so it should not be changed 352 * (or destroyed) before evaluation. 353 */ 354 explicit MatrixPower(const MatrixType& A) : 355 m_A(A), 356 m_conditionNumber(0), 357 m_rank(A.cols()), 358 m_nulls(0) 359 { eigen_assert(A.rows() == A.cols()); } 360 361 /** 362 * \brief Returns the matrix power. 363 * 364 * \param[in] p exponent, a real scalar. 365 * \return The expression \f$ A^p \f$, where A is specified in the 366 * constructor. 367 */ 368 const MatrixPowerParenthesesReturnValue<MatrixType> operator()(RealScalar p) 369 { return MatrixPowerParenthesesReturnValue<MatrixType>(*this, p); } 370 371 /** 372 * \brief Compute the matrix power. 373 * 374 * \param[in] p exponent, a real scalar. 375 * \param[out] res \f$ A^p \f$ where A is specified in the 376 * constructor. 377 */ 378 template<typename ResultType> 379 void compute(ResultType& res, RealScalar p); 380 381 Index rows() const { return m_A.rows(); } 382 Index cols() const { return m_A.cols(); } 383 384 private: 385 typedef std::complex<RealScalar> ComplexScalar; 386 typedef Matrix<ComplexScalar, Dynamic, Dynamic, 0, 387 MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> ComplexMatrix; 388 389 /** \brief Reference to the base of matrix power. */ 390 typename MatrixType::Nested m_A; 391 392 /** \brief Temporary storage. */ 393 MatrixType m_tmp; 394 395 /** \brief Store the result of Schur decomposition. */ 396 ComplexMatrix m_T, m_U; 397 398 /** \brief Store fractional power of m_T. */ 399 ComplexMatrix m_fT; 400 401 /** 402 * \brief Condition number of m_A. 403 * 404 * It is initialized as 0 to avoid performing unnecessary Schur 405 * decomposition, which is the bottleneck. 406 */ 407 RealScalar m_conditionNumber; 408 409 /** \brief Rank of m_A. */ 410 Index m_rank; 411 412 /** \brief Rank deficiency of m_A. */ 413 Index m_nulls; 414 415 /** 416 * \brief Split p into integral part and fractional part. 417 * 418 * \param[in] p The exponent. 419 * \param[out] p The fractional part ranging in \f$ (-1, 1) \f$. 420 * \param[out] intpart The integral part. 421 * 422 * Only if the fractional part is nonzero, it calls initialize(). 423 */ 424 void split(RealScalar& p, RealScalar& intpart); 425 426 /** \brief Perform Schur decomposition for fractional power. */ 427 void initialize(); 428 429 template<typename ResultType> 430 void computeIntPower(ResultType& res, RealScalar p); 431 432 template<typename ResultType> 433 void computeFracPower(ResultType& res, RealScalar p); 434 435 template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> 436 static void revertSchur( 437 Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, 438 const ComplexMatrix& T, 439 const ComplexMatrix& U); 440 441 template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> 442 static void revertSchur( 443 Matrix<RealScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, 444 const ComplexMatrix& T, 445 const ComplexMatrix& U); 446 }; 447 448 template<typename MatrixType> 449 template<typename ResultType> 450 void MatrixPower<MatrixType>::compute(ResultType& res, RealScalar p) 451 { 452 using std::pow; 453 switch (cols()) { 454 case 0: 455 break; 456 case 1: 457 res(0,0) = pow(m_A.coeff(0,0), p); 458 break; 459 default: 460 RealScalar intpart; 461 split(p, intpart); 462 463 res = MatrixType::Identity(rows(), cols()); 464 computeIntPower(res, intpart); 465 if (p) computeFracPower(res, p); 466 } 467 } 468 469 template<typename MatrixType> 470 void MatrixPower<MatrixType>::split(RealScalar& p, RealScalar& intpart) 471 { 472 using std::floor; 473 using std::pow; 474 475 intpart = floor(p); 476 p -= intpart; 477 478 // Perform Schur decomposition if it is not yet performed and the power is 479 // not an integer. 480 if (!m_conditionNumber && p) 481 initialize(); 482 483 // Choose the more stable of intpart = floor(p) and intpart = ceil(p). 484 if (p > RealScalar(0.5) && p > (1-p) * pow(m_conditionNumber, p)) { 485 --p; 486 ++intpart; 487 } 488 } 489 490 template<typename MatrixType> 491 void MatrixPower<MatrixType>::initialize() 492 { 493 const ComplexSchur<MatrixType> schurOfA(m_A); 494 JacobiRotation<ComplexScalar> rot; 495 ComplexScalar eigenvalue; 496 497 m_fT.resizeLike(m_A); 498 m_T = schurOfA.matrixT(); 499 m_U = schurOfA.matrixU(); 500 m_conditionNumber = m_T.diagonal().array().abs().maxCoeff() / m_T.diagonal().array().abs().minCoeff(); 501 502 // Move zero eigenvalues to the bottom right corner. 503 for (Index i = cols()-1; i>=0; --i) { 504 if (m_rank <= 2) 505 return; 506 if (m_T.coeff(i,i) == RealScalar(0)) { 507 for (Index j=i+1; j < m_rank; ++j) { 508 eigenvalue = m_T.coeff(j,j); 509 rot.makeGivens(m_T.coeff(j-1,j), eigenvalue); 510 m_T.applyOnTheRight(j-1, j, rot); 511 m_T.applyOnTheLeft(j-1, j, rot.adjoint()); 512 m_T.coeffRef(j-1,j-1) = eigenvalue; 513 m_T.coeffRef(j,j) = RealScalar(0); 514 m_U.applyOnTheRight(j-1, j, rot); 515 } 516 --m_rank; 517 } 518 } 519 520 m_nulls = rows() - m_rank; 521 if (m_nulls) { 522 eigen_assert(m_T.bottomRightCorner(m_nulls, m_nulls).isZero() 523 && "Base of matrix power should be invertible or with a semisimple zero eigenvalue."); 524 m_fT.bottomRows(m_nulls).fill(RealScalar(0)); 525 } 526 } 527 528 template<typename MatrixType> 529 template<typename ResultType> 530 void MatrixPower<MatrixType>::computeIntPower(ResultType& res, RealScalar p) 531 { 532 using std::abs; 533 using std::fmod; 534 RealScalar pp = abs(p); 535 536 if (p<0) 537 m_tmp = m_A.inverse(); 538 else 539 m_tmp = m_A; 540 541 while (true) { 542 if (fmod(pp, 2) >= 1) 543 res = m_tmp * res; 544 pp /= 2; 545 if (pp < 1) 546 break; 547 m_tmp *= m_tmp; 548 } 549 } 550 551 template<typename MatrixType> 552 template<typename ResultType> 553 void MatrixPower<MatrixType>::computeFracPower(ResultType& res, RealScalar p) 554 { 555 Block<ComplexMatrix,Dynamic,Dynamic> blockTp(m_fT, 0, 0, m_rank, m_rank); 556 eigen_assert(m_conditionNumber); 557 eigen_assert(m_rank + m_nulls == rows()); 558 559 MatrixPowerAtomic<ComplexMatrix>(m_T.topLeftCorner(m_rank, m_rank), p).compute(blockTp); 560 if (m_nulls) { 561 m_fT.topRightCorner(m_rank, m_nulls) = m_T.topLeftCorner(m_rank, m_rank).template triangularView<Upper>() 562 .solve(blockTp * m_T.topRightCorner(m_rank, m_nulls)); 563 } 564 revertSchur(m_tmp, m_fT, m_U); 565 res = m_tmp * res; 566 } 567 568 template<typename MatrixType> 569 template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> 570 inline void MatrixPower<MatrixType>::revertSchur( 571 Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, 572 const ComplexMatrix& T, 573 const ComplexMatrix& U) 574 { res.noalias() = U * (T.template triangularView<Upper>() * U.adjoint()); } 575 576 template<typename MatrixType> 577 template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> 578 inline void MatrixPower<MatrixType>::revertSchur( 579 Matrix<RealScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, 580 const ComplexMatrix& T, 581 const ComplexMatrix& U) 582 { res.noalias() = (U * (T.template triangularView<Upper>() * U.adjoint())).real(); } 583 584 /** 585 * \ingroup MatrixFunctions_Module 586 * 587 * \brief Proxy for the matrix power of some matrix (expression). 588 * 589 * \tparam Derived type of the base, a matrix (expression). 590 * 591 * This class holds the arguments to the matrix power until it is 592 * assigned or evaluated for some other reason (so the argument 593 * should not be changed in the meantime). It is the return type of 594 * MatrixBase::pow() and related functions and most of the 595 * time this is the only way it is used. 596 */ 597 template<typename Derived> 598 class MatrixPowerReturnValue : public ReturnByValue< MatrixPowerReturnValue<Derived> > 599 { 600 public: 601 typedef typename Derived::PlainObject PlainObject; 602 typedef typename Derived::RealScalar RealScalar; 603 typedef typename Derived::Index Index; 604 605 /** 606 * \brief Constructor. 607 * 608 * \param[in] A %Matrix (expression), the base of the matrix power. 609 * \param[in] p real scalar, the exponent of the matrix power. 610 */ 611 MatrixPowerReturnValue(const Derived& A, RealScalar p) : m_A(A), m_p(p) 612 { } 613 614 /** 615 * \brief Compute the matrix power. 616 * 617 * \param[out] result \f$ A^p \f$ where \p A and \p p are as in the 618 * constructor. 619 */ 620 template<typename ResultType> 621 inline void evalTo(ResultType& res) const 622 { MatrixPower<PlainObject>(m_A.eval()).compute(res, m_p); } 623 624 Index rows() const { return m_A.rows(); } 625 Index cols() const { return m_A.cols(); } 626 627 private: 628 const Derived& m_A; 629 const RealScalar m_p; 630 }; 631 632 /** 633 * \ingroup MatrixFunctions_Module 634 * 635 * \brief Proxy for the matrix power of some matrix (expression). 636 * 637 * \tparam Derived type of the base, a matrix (expression). 638 * 639 * This class holds the arguments to the matrix power until it is 640 * assigned or evaluated for some other reason (so the argument 641 * should not be changed in the meantime). It is the return type of 642 * MatrixBase::pow() and related functions and most of the 643 * time this is the only way it is used. 644 */ 645 template<typename Derived> 646 class MatrixComplexPowerReturnValue : public ReturnByValue< MatrixComplexPowerReturnValue<Derived> > 647 { 648 public: 649 typedef typename Derived::PlainObject PlainObject; 650 typedef typename std::complex<typename Derived::RealScalar> ComplexScalar; 651 typedef typename Derived::Index Index; 652 653 /** 654 * \brief Constructor. 655 * 656 * \param[in] A %Matrix (expression), the base of the matrix power. 657 * \param[in] p complex scalar, the exponent of the matrix power. 658 */ 659 MatrixComplexPowerReturnValue(const Derived& A, const ComplexScalar& p) : m_A(A), m_p(p) 660 { } 661 662 /** 663 * \brief Compute the matrix power. 664 * 665 * Because \p p is complex, \f$ A^p \f$ is simply evaluated as \f$ 666 * \exp(p \log(A)) \f$. 667 * 668 * \param[out] result \f$ A^p \f$ where \p A and \p p are as in the 669 * constructor. 670 */ 671 template<typename ResultType> 672 inline void evalTo(ResultType& res) const 673 { res = (m_p * m_A.log()).exp(); } 674 675 Index rows() const { return m_A.rows(); } 676 Index cols() const { return m_A.cols(); } 677 678 private: 679 const Derived& m_A; 680 const ComplexScalar m_p; 681 }; 682 683 namespace internal { 684 685 template<typename MatrixPowerType> 686 struct traits< MatrixPowerParenthesesReturnValue<MatrixPowerType> > 687 { typedef typename MatrixPowerType::PlainObject ReturnType; }; 688 689 template<typename Derived> 690 struct traits< MatrixPowerReturnValue<Derived> > 691 { typedef typename Derived::PlainObject ReturnType; }; 692 693 template<typename Derived> 694 struct traits< MatrixComplexPowerReturnValue<Derived> > 695 { typedef typename Derived::PlainObject ReturnType; }; 696 697 } 698 699 template<typename Derived> 700 const MatrixPowerReturnValue<Derived> MatrixBase<Derived>::pow(const RealScalar& p) const 701 { return MatrixPowerReturnValue<Derived>(derived(), p); } 702 703 template<typename Derived> 704 const MatrixComplexPowerReturnValue<Derived> MatrixBase<Derived>::pow(const std::complex<RealScalar>& p) const 705 { return MatrixComplexPowerReturnValue<Derived>(derived(), p); } 706 707 } // namespace Eigen 708 709 #endif // EIGEN_MATRIX_POWER 710