| // This file is part of Eigen, a lightweight C++ template library | 
 | // for linear algebra. | 
 | // | 
 | // Copyright (C) 2009-2011, 2013 Jitse Niesen <jitse@maths.leeds.ac.uk> | 
 | // | 
 | // This Source Code Form is subject to the terms of the Mozilla | 
 | // Public License v. 2.0. If a copy of the MPL was not distributed | 
 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
 |  | 
 | #ifndef EIGEN_MATRIX_FUNCTION_H | 
 | #define EIGEN_MATRIX_FUNCTION_H | 
 |  | 
 | #include "StemFunction.h" | 
 |  | 
 | // IWYU pragma: private | 
 | #include "./InternalHeaderCheck.h" | 
 |  | 
 | namespace Eigen { | 
 |  | 
 | namespace internal { | 
 |  | 
 | /** \brief Maximum distance allowed between eigenvalues to be considered "close". */ | 
 | static const float matrix_function_separation = 0.1f; | 
 |  | 
 | /** \ingroup MatrixFunctions_Module | 
 |  * \class MatrixFunctionAtomic | 
 |  * \brief Helper class for computing matrix functions of atomic matrices. | 
 |  * | 
 |  * Here, an atomic matrix is a triangular matrix whose diagonal entries are close to each other. | 
 |  */ | 
 | template <typename MatrixType> | 
 | class MatrixFunctionAtomic { | 
 |  public: | 
 |   typedef typename MatrixType::Scalar Scalar; | 
 |   typedef typename stem_function<Scalar>::type StemFunction; | 
 |  | 
 |   /** \brief Constructor | 
 |    * \param[in]  f  matrix function to compute. | 
 |    */ | 
 |   MatrixFunctionAtomic(StemFunction f) : m_f(f) {} | 
 |  | 
 |   /** \brief Compute matrix function of atomic matrix | 
 |    * \param[in]  A  argument of matrix function, should be upper triangular and atomic | 
 |    * \returns  f(A), the matrix function evaluated at the given matrix | 
 |    */ | 
 |   MatrixType compute(const MatrixType& A); | 
 |  | 
 |  private: | 
 |   StemFunction* m_f; | 
 | }; | 
 |  | 
 | template <typename MatrixType> | 
 | typename NumTraits<typename MatrixType::Scalar>::Real matrix_function_compute_mu(const MatrixType& A) { | 
 |   typedef typename plain_col_type<MatrixType>::type VectorType; | 
 |   Index rows = A.rows(); | 
 |   const MatrixType N = MatrixType::Identity(rows, rows) - A; | 
 |   VectorType e = VectorType::Ones(rows); | 
 |   N.template triangularView<Upper>().solveInPlace(e); | 
 |   return e.cwiseAbs().maxCoeff(); | 
 | } | 
 |  | 
 | template <typename MatrixType> | 
 | MatrixType MatrixFunctionAtomic<MatrixType>::compute(const MatrixType& A) { | 
 |   // TODO: Use that A is upper triangular | 
 |   typedef typename NumTraits<Scalar>::Real RealScalar; | 
 |   Index rows = A.rows(); | 
 |   Scalar avgEival = A.trace() / Scalar(RealScalar(rows)); | 
 |   MatrixType Ashifted = A - avgEival * MatrixType::Identity(rows, rows); | 
 |   RealScalar mu = matrix_function_compute_mu(Ashifted); | 
 |   MatrixType F = m_f(avgEival, 0) * MatrixType::Identity(rows, rows); | 
 |   MatrixType P = Ashifted; | 
 |   MatrixType Fincr; | 
 |   for (Index s = 1; double(s) < 1.1 * double(rows) + 10.0; s++) {  // upper limit is fairly arbitrary | 
 |     Fincr = m_f(avgEival, static_cast<int>(s)) * P; | 
 |     F += Fincr; | 
 |     P = Scalar(RealScalar(1) / RealScalar(s + 1)) * P * Ashifted; | 
 |  | 
 |     // test whether Taylor series converged | 
 |     const RealScalar F_norm = F.cwiseAbs().rowwise().sum().maxCoeff(); | 
 |     const RealScalar Fincr_norm = Fincr.cwiseAbs().rowwise().sum().maxCoeff(); | 
 |     if (Fincr_norm < NumTraits<Scalar>::epsilon() * F_norm) { | 
 |       RealScalar delta = 0; | 
 |       RealScalar rfactorial = 1; | 
 |       for (Index r = 0; r < rows; r++) { | 
 |         RealScalar mx = 0; | 
 |         for (Index i = 0; i < rows; i++) | 
 |           mx = (std::max)(mx, std::abs(m_f(Ashifted(i, i) + avgEival, static_cast<int>(s + r)))); | 
 |         if (r != 0) rfactorial *= RealScalar(r); | 
 |         delta = (std::max)(delta, mx / rfactorial); | 
 |       } | 
 |       const RealScalar P_norm = P.cwiseAbs().rowwise().sum().maxCoeff(); | 
 |       if (mu * delta * P_norm < NumTraits<Scalar>::epsilon() * F_norm)  // series converged | 
 |         break; | 
 |     } | 
 |   } | 
 |   return F; | 
 | } | 
 |  | 
 | /** \brief Find cluster in \p clusters containing some value | 
 |  * \param[in] key Value to find | 
 |  * \returns Iterator to cluster containing \p key, or \c clusters.end() if no cluster in \p m_clusters | 
 |  * contains \p key. | 
 |  */ | 
 | template <typename Index, typename ListOfClusters> | 
 | typename ListOfClusters::iterator matrix_function_find_cluster(Index key, ListOfClusters& clusters) { | 
 |   typename std::list<Index>::iterator j; | 
 |   for (typename ListOfClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) { | 
 |     j = std::find(i->begin(), i->end(), key); | 
 |     if (j != i->end()) return i; | 
 |   } | 
 |   return clusters.end(); | 
 | } | 
 |  | 
 | /** \brief Partition eigenvalues in clusters of ei'vals close to each other | 
 |  * | 
 |  * \param[in]  eivals    Eigenvalues | 
 |  * \param[out] clusters  Resulting partition of eigenvalues | 
 |  * | 
 |  * The partition satisfies the following two properties: | 
 |  * # Any eigenvalue in a certain cluster is at most matrix_function_separation() away from another eigenvalue | 
 |  *   in the same cluster. | 
 |  * # The distance between two eigenvalues in different clusters is more than matrix_function_separation(). | 
 |  * The implementation follows Algorithm 4.1 in the paper of Davies and Higham. | 
 |  */ | 
 | template <typename EivalsType, typename Cluster> | 
 | void matrix_function_partition_eigenvalues(const EivalsType& eivals, std::list<Cluster>& clusters) { | 
 |   typedef typename EivalsType::RealScalar RealScalar; | 
 |   for (Index i = 0; i < eivals.rows(); ++i) { | 
 |     // Find cluster containing i-th ei'val, adding a new cluster if necessary | 
 |     typename std::list<Cluster>::iterator qi = matrix_function_find_cluster(i, clusters); | 
 |     if (qi == clusters.end()) { | 
 |       Cluster l; | 
 |       l.push_back(i); | 
 |       clusters.push_back(l); | 
 |       qi = clusters.end(); | 
 |       --qi; | 
 |     } | 
 |  | 
 |     // Look for other element to add to the set | 
 |     for (Index j = i + 1; j < eivals.rows(); ++j) { | 
 |       if (abs(eivals(j) - eivals(i)) <= RealScalar(matrix_function_separation) && | 
 |           std::find(qi->begin(), qi->end(), j) == qi->end()) { | 
 |         typename std::list<Cluster>::iterator qj = matrix_function_find_cluster(j, clusters); | 
 |         if (qj == clusters.end()) { | 
 |           qi->push_back(j); | 
 |         } else { | 
 |           qi->insert(qi->end(), qj->begin(), qj->end()); | 
 |           clusters.erase(qj); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Compute size of each cluster given a partitioning */ | 
 | template <typename ListOfClusters, typename Index> | 
 | void matrix_function_compute_cluster_size(const ListOfClusters& clusters, Matrix<Index, Dynamic, 1>& clusterSize) { | 
 |   const Index numClusters = static_cast<Index>(clusters.size()); | 
 |   clusterSize.setZero(numClusters); | 
 |   Index clusterIndex = 0; | 
 |   for (typename ListOfClusters::const_iterator cluster = clusters.begin(); cluster != clusters.end(); ++cluster) { | 
 |     clusterSize[clusterIndex] = cluster->size(); | 
 |     ++clusterIndex; | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Compute start of each block using clusterSize */ | 
 | template <typename VectorType> | 
 | void matrix_function_compute_block_start(const VectorType& clusterSize, VectorType& blockStart) { | 
 |   blockStart.resize(clusterSize.rows()); | 
 |   blockStart(0) = 0; | 
 |   for (Index i = 1; i < clusterSize.rows(); i++) { | 
 |     blockStart(i) = blockStart(i - 1) + clusterSize(i - 1); | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Compute mapping of eigenvalue indices to cluster indices */ | 
 | template <typename EivalsType, typename ListOfClusters, typename VectorType> | 
 | void matrix_function_compute_map(const EivalsType& eivals, const ListOfClusters& clusters, VectorType& eivalToCluster) { | 
 |   eivalToCluster.resize(eivals.rows()); | 
 |   Index clusterIndex = 0; | 
 |   for (typename ListOfClusters::const_iterator cluster = clusters.begin(); cluster != clusters.end(); ++cluster) { | 
 |     for (Index i = 0; i < eivals.rows(); ++i) { | 
 |       if (std::find(cluster->begin(), cluster->end(), i) != cluster->end()) { | 
 |         eivalToCluster[i] = clusterIndex; | 
 |       } | 
 |     } | 
 |     ++clusterIndex; | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Compute permutation which groups ei'vals in same cluster together */ | 
 | template <typename DynVectorType, typename VectorType> | 
 | void matrix_function_compute_permutation(const DynVectorType& blockStart, const DynVectorType& eivalToCluster, | 
 |                                          VectorType& permutation) { | 
 |   DynVectorType indexNextEntry = blockStart; | 
 |   permutation.resize(eivalToCluster.rows()); | 
 |   for (Index i = 0; i < eivalToCluster.rows(); i++) { | 
 |     Index cluster = eivalToCluster[i]; | 
 |     permutation[i] = indexNextEntry[cluster]; | 
 |     ++indexNextEntry[cluster]; | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Permute Schur decomposition in U and T according to permutation */ | 
 | template <typename VectorType, typename MatrixType> | 
 | void matrix_function_permute_schur(VectorType& permutation, MatrixType& U, MatrixType& T) { | 
 |   for (Index i = 0; i < permutation.rows() - 1; i++) { | 
 |     Index j; | 
 |     for (j = i; j < permutation.rows(); j++) { | 
 |       if (permutation(j) == i) break; | 
 |     } | 
 |     eigen_assert(permutation(j) == i); | 
 |     for (Index k = j - 1; k >= i; k--) { | 
 |       JacobiRotation<typename MatrixType::Scalar> rotation; | 
 |       rotation.makeGivens(T(k, k + 1), T(k + 1, k + 1) - T(k, k)); | 
 |       T.applyOnTheLeft(k, k + 1, rotation.adjoint()); | 
 |       T.applyOnTheRight(k, k + 1, rotation); | 
 |       U.applyOnTheRight(k, k + 1, rotation); | 
 |       std::swap(permutation.coeffRef(k), permutation.coeffRef(k + 1)); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Compute block diagonal part of matrix function. | 
 |  * | 
 |  * This routine computes the matrix function applied to the block diagonal part of \p T (which should be | 
 |  * upper triangular), with the blocking given by \p blockStart and \p clusterSize. The matrix function of | 
 |  * each diagonal block is computed by \p atomic. The off-diagonal parts of \p fT are set to zero. | 
 |  */ | 
 | template <typename MatrixType, typename AtomicType, typename VectorType> | 
 | void matrix_function_compute_block_atomic(const MatrixType& T, AtomicType& atomic, const VectorType& blockStart, | 
 |                                           const VectorType& clusterSize, MatrixType& fT) { | 
 |   fT.setZero(T.rows(), T.cols()); | 
 |   for (Index i = 0; i < clusterSize.rows(); ++i) { | 
 |     fT.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i)) = | 
 |         atomic.compute(T.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i))); | 
 |   } | 
 | } | 
 |  | 
 | /** \brief Solve a triangular Sylvester equation AX + XB = C | 
 |  * | 
 |  * \param[in]  A  the matrix A; should be square and upper triangular | 
 |  * \param[in]  B  the matrix B; should be square and upper triangular | 
 |  * \param[in]  C  the matrix C; should have correct size. | 
 |  * | 
 |  * \returns the solution X. | 
 |  * | 
 |  * If A is m-by-m and B is n-by-n, then both C and X are m-by-n.  The (i,j)-th component of the Sylvester | 
 |  * equation is | 
 |  * \f[ | 
 |  *     \sum_{k=i}^m A_{ik} X_{kj} + \sum_{k=1}^j X_{ik} B_{kj} = C_{ij}. | 
 |  * \f] | 
 |  * This can be re-arranged to yield: | 
 |  * \f[ | 
 |  *     X_{ij} = \frac{1}{A_{ii} + B_{jj}} \Bigl( C_{ij} | 
 |  *     - \sum_{k=i+1}^m A_{ik} X_{kj} - \sum_{k=1}^{j-1} X_{ik} B_{kj} \Bigr). | 
 |  * \f] | 
 |  * It is assumed that A and B are such that the numerator is never zero (otherwise the Sylvester equation | 
 |  * does not have a unique solution). In that case, these equations can be evaluated in the order | 
 |  * \f$ i=m,\ldots,1 \f$ and \f$ j=1,\ldots,n \f$. | 
 |  */ | 
 | template <typename MatrixType> | 
 | MatrixType matrix_function_solve_triangular_sylvester(const MatrixType& A, const MatrixType& B, const MatrixType& C) { | 
 |   eigen_assert(A.rows() == A.cols()); | 
 |   eigen_assert(A.isUpperTriangular()); | 
 |   eigen_assert(B.rows() == B.cols()); | 
 |   eigen_assert(B.isUpperTriangular()); | 
 |   eigen_assert(C.rows() == A.rows()); | 
 |   eigen_assert(C.cols() == B.rows()); | 
 |  | 
 |   typedef typename MatrixType::Scalar Scalar; | 
 |  | 
 |   Index m = A.rows(); | 
 |   Index n = B.rows(); | 
 |   MatrixType X(m, n); | 
 |  | 
 |   for (Index i = m - 1; i >= 0; --i) { | 
 |     for (Index j = 0; j < n; ++j) { | 
 |       // Compute AX = \sum_{k=i+1}^m A_{ik} X_{kj} | 
 |       Scalar AX; | 
 |       if (i == m - 1) { | 
 |         AX = 0; | 
 |       } else { | 
 |         Matrix<Scalar, 1, 1> AXmatrix = A.row(i).tail(m - 1 - i) * X.col(j).tail(m - 1 - i); | 
 |         AX = AXmatrix(0, 0); | 
 |       } | 
 |  | 
 |       // Compute XB = \sum_{k=1}^{j-1} X_{ik} B_{kj} | 
 |       Scalar XB; | 
 |       if (j == 0) { | 
 |         XB = 0; | 
 |       } else { | 
 |         Matrix<Scalar, 1, 1> XBmatrix = X.row(i).head(j) * B.col(j).head(j); | 
 |         XB = XBmatrix(0, 0); | 
 |       } | 
 |  | 
 |       X(i, j) = (C(i, j) - AX - XB) / (A(i, i) + B(j, j)); | 
 |     } | 
 |   } | 
 |   return X; | 
 | } | 
 |  | 
 | /** \brief Compute part of matrix function above block diagonal. | 
 |  * | 
 |  * This routine completes the computation of \p fT, denoting a matrix function applied to the triangular | 
 |  * matrix \p T. It assumes that the block diagonal part of \p fT has already been computed. The part below | 
 |  * the diagonal is zero, because \p T is upper triangular. | 
 |  */ | 
 | template <typename MatrixType, typename VectorType> | 
 | void matrix_function_compute_above_diagonal(const MatrixType& T, const VectorType& blockStart, | 
 |                                             const VectorType& clusterSize, MatrixType& fT) { | 
 |   typedef internal::traits<MatrixType> Traits; | 
 |   typedef typename MatrixType::Scalar Scalar; | 
 |   static const int Options = MatrixType::Options; | 
 |   typedef Matrix<Scalar, Dynamic, Dynamic, Options, Traits::RowsAtCompileTime, Traits::ColsAtCompileTime> DynMatrixType; | 
 |  | 
 |   for (Index k = 1; k < clusterSize.rows(); k++) { | 
 |     for (Index i = 0; i < clusterSize.rows() - k; i++) { | 
 |       // compute (i, i+k) block | 
 |       DynMatrixType A = T.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i)); | 
 |       DynMatrixType B = -T.block(blockStart(i + k), blockStart(i + k), clusterSize(i + k), clusterSize(i + k)); | 
 |       DynMatrixType C = fT.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i)) * | 
 |                         T.block(blockStart(i), blockStart(i + k), clusterSize(i), clusterSize(i + k)); | 
 |       C -= T.block(blockStart(i), blockStart(i + k), clusterSize(i), clusterSize(i + k)) * | 
 |            fT.block(blockStart(i + k), blockStart(i + k), clusterSize(i + k), clusterSize(i + k)); | 
 |       for (Index m = i + 1; m < i + k; m++) { | 
 |         C += fT.block(blockStart(i), blockStart(m), clusterSize(i), clusterSize(m)) * | 
 |              T.block(blockStart(m), blockStart(i + k), clusterSize(m), clusterSize(i + k)); | 
 |         C -= T.block(blockStart(i), blockStart(m), clusterSize(i), clusterSize(m)) * | 
 |              fT.block(blockStart(m), blockStart(i + k), clusterSize(m), clusterSize(i + k)); | 
 |       } | 
 |       fT.block(blockStart(i), blockStart(i + k), clusterSize(i), clusterSize(i + k)) = | 
 |           matrix_function_solve_triangular_sylvester(A, B, C); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /** \ingroup MatrixFunctions_Module | 
 |  * \brief Class for computing matrix functions. | 
 |  * \tparam  MatrixType  type of the argument of the matrix function, | 
 |  *                      expected to be an instantiation of the Matrix class template. | 
 |  * \tparam  AtomicType  type for computing matrix function of atomic blocks. | 
 |  * \tparam  IsComplex   used internally to select correct specialization. | 
 |  * | 
 |  * This class implements the Schur-Parlett algorithm for computing matrix functions. The spectrum of the | 
 |  * matrix is divided in clustered of eigenvalues that lies close together. This class delegates the | 
 |  * computation of the matrix function on every block corresponding to these clusters to an object of type | 
 |  * \p AtomicType and uses these results to compute the matrix function of the whole matrix. The class | 
 |  * \p AtomicType should have a \p compute() member function for computing the matrix function of a block. | 
 |  * | 
 |  * \sa class MatrixFunctionAtomic, class MatrixLogarithmAtomic | 
 |  */ | 
 | template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex> | 
 | struct matrix_function_compute { | 
 |   /** \brief Compute the matrix function. | 
 |    * | 
 |    * \param[in]  A       argument of matrix function, should be a square matrix. | 
 |    * \param[in]  atomic  class for computing matrix function of atomic blocks. | 
 |    * \param[out] result  the function \p f applied to \p A, as | 
 |    * specified in the constructor. | 
 |    * | 
 |    * See MatrixBase::matrixFunction() for details on how this computation | 
 |    * is implemented. | 
 |    */ | 
 |   template <typename AtomicType, typename ResultType> | 
 |   static void run(const MatrixType& A, AtomicType& atomic, ResultType& result); | 
 | }; | 
 |  | 
 | /** \internal \ingroup MatrixFunctions_Module | 
 |  * \brief Partial specialization of MatrixFunction for real matrices | 
 |  * | 
 |  * This converts the real matrix to a complex matrix, compute the matrix function of that matrix, and then | 
 |  * converts the result back to a real matrix. | 
 |  */ | 
 | template <typename MatrixType> | 
 | struct matrix_function_compute<MatrixType, 0> { | 
 |   template <typename MatA, typename AtomicType, typename ResultType> | 
 |   static void run(const MatA& A, AtomicType& atomic, ResultType& result) { | 
 |     typedef internal::traits<MatrixType> Traits; | 
 |     typedef typename Traits::Scalar Scalar; | 
 |     static const int Rows = Traits::RowsAtCompileTime, Cols = Traits::ColsAtCompileTime; | 
 |     static const int MaxRows = Traits::MaxRowsAtCompileTime, MaxCols = Traits::MaxColsAtCompileTime; | 
 |  | 
 |     typedef std::complex<Scalar> ComplexScalar; | 
 |     typedef Matrix<ComplexScalar, Rows, Cols, 0, MaxRows, MaxCols> ComplexMatrix; | 
 |  | 
 |     ComplexMatrix CA = A.template cast<ComplexScalar>(); | 
 |     ComplexMatrix Cresult; | 
 |     matrix_function_compute<ComplexMatrix>::run(CA, atomic, Cresult); | 
 |     result = Cresult.real(); | 
 |   } | 
 | }; | 
 |  | 
 | /** \internal \ingroup MatrixFunctions_Module | 
 |  * \brief Partial specialization of MatrixFunction for complex matrices | 
 |  */ | 
 | template <typename MatrixType> | 
 | struct matrix_function_compute<MatrixType, 1> { | 
 |   template <typename MatA, typename AtomicType, typename ResultType> | 
 |   static void run(const MatA& A, AtomicType& atomic, ResultType& result) { | 
 |     typedef internal::traits<MatrixType> Traits; | 
 |  | 
 |     // compute Schur decomposition of A | 
 |     const ComplexSchur<MatrixType> schurOfA(A); | 
 |     eigen_assert(schurOfA.info() == Success); | 
 |     MatrixType T = schurOfA.matrixT(); | 
 |     MatrixType U = schurOfA.matrixU(); | 
 |  | 
 |     // partition eigenvalues into clusters of ei'vals "close" to each other | 
 |     std::list<std::list<Index> > clusters; | 
 |     matrix_function_partition_eigenvalues(T.diagonal(), clusters); | 
 |  | 
 |     // compute size of each cluster | 
 |     Matrix<Index, Dynamic, 1> clusterSize; | 
 |     matrix_function_compute_cluster_size(clusters, clusterSize); | 
 |  | 
 |     // blockStart[i] is row index at which block corresponding to i-th cluster starts | 
 |     Matrix<Index, Dynamic, 1> blockStart; | 
 |     matrix_function_compute_block_start(clusterSize, blockStart); | 
 |  | 
 |     // compute map so that eivalToCluster[i] = j means that i-th ei'val is in j-th cluster | 
 |     Matrix<Index, Dynamic, 1> eivalToCluster; | 
 |     matrix_function_compute_map(T.diagonal(), clusters, eivalToCluster); | 
 |  | 
 |     // compute permutation which groups ei'vals in same cluster together | 
 |     Matrix<Index, Traits::RowsAtCompileTime, 1> permutation; | 
 |     matrix_function_compute_permutation(blockStart, eivalToCluster, permutation); | 
 |  | 
 |     // permute Schur decomposition | 
 |     matrix_function_permute_schur(permutation, U, T); | 
 |  | 
 |     // compute result | 
 |     MatrixType fT;  // matrix function applied to T | 
 |     matrix_function_compute_block_atomic(T, atomic, blockStart, clusterSize, fT); | 
 |     matrix_function_compute_above_diagonal(T, blockStart, clusterSize, fT); | 
 |     result = U * (fT.template triangularView<Upper>() * U.adjoint()); | 
 |   } | 
 | }; | 
 |  | 
 | }  // end of namespace internal | 
 |  | 
 | /** \ingroup MatrixFunctions_Module | 
 |  * | 
 |  * \brief Proxy for the matrix function of some matrix (expression). | 
 |  * | 
 |  * \tparam Derived  Type of the argument to the matrix function. | 
 |  * | 
 |  * This class holds the argument to the matrix function until it is assigned or evaluated for some other | 
 |  * reason (so the argument should not be changed in the meantime). It is the return type of | 
 |  * matrixBase::matrixFunction() and related functions and most of the time this is the only way it is used. | 
 |  */ | 
 | template <typename Derived> | 
 | class MatrixFunctionReturnValue : public ReturnByValue<MatrixFunctionReturnValue<Derived> > { | 
 |  public: | 
 |   typedef typename Derived::Scalar Scalar; | 
 |   typedef typename internal::stem_function<Scalar>::type StemFunction; | 
 |  | 
 |  protected: | 
 |   typedef typename internal::ref_selector<Derived>::type DerivedNested; | 
 |  | 
 |  public: | 
 |   /** \brief Constructor. | 
 |    * | 
 |    * \param[in] A  %Matrix (expression) forming the argument of the matrix function. | 
 |    * \param[in] f  Stem function for matrix function under consideration. | 
 |    */ | 
 |   MatrixFunctionReturnValue(const Derived& A, StemFunction f) : m_A(A), m_f(f) {} | 
 |  | 
 |   /** \brief Compute the matrix function. | 
 |    * | 
 |    * \param[out] result \p f applied to \p A, where \p f and \p A are as in the constructor. | 
 |    */ | 
 |   template <typename ResultType> | 
 |   inline void evalTo(ResultType& result) const { | 
 |     typedef typename internal::nested_eval<Derived, 10>::type NestedEvalType; | 
 |     typedef internal::remove_all_t<NestedEvalType> NestedEvalTypeClean; | 
 |     typedef internal::traits<NestedEvalTypeClean> Traits; | 
 |     typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar; | 
 |     typedef Matrix<ComplexScalar, Dynamic, Dynamic, 0, Traits::RowsAtCompileTime, Traits::ColsAtCompileTime> | 
 |         DynMatrixType; | 
 |  | 
 |     typedef internal::MatrixFunctionAtomic<DynMatrixType> AtomicType; | 
 |     AtomicType atomic(m_f); | 
 |  | 
 |     internal::matrix_function_compute<typename NestedEvalTypeClean::PlainObject>::run(m_A, atomic, result); | 
 |   } | 
 |  | 
 |   Index rows() const { return m_A.rows(); } | 
 |   Index cols() const { return m_A.cols(); } | 
 |  | 
 |  private: | 
 |   const DerivedNested m_A; | 
 |   StemFunction* m_f; | 
 | }; | 
 |  | 
 | namespace internal { | 
 | template <typename Derived> | 
 | struct traits<MatrixFunctionReturnValue<Derived> > { | 
 |   typedef typename Derived::PlainObject ReturnType; | 
 | }; | 
 | }  // namespace internal | 
 |  | 
 | /********** MatrixBase methods **********/ | 
 |  | 
 | template <typename Derived> | 
 | const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::matrixFunction( | 
 |     typename internal::stem_function<typename internal::traits<Derived>::Scalar>::type f) const { | 
 |   eigen_assert(rows() == cols()); | 
 |   return MatrixFunctionReturnValue<Derived>(derived(), f); | 
 | } | 
 |  | 
 | template <typename Derived> | 
 | const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sin() const { | 
 |   eigen_assert(rows() == cols()); | 
 |   typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; | 
 |   return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_sin<ComplexScalar>); | 
 | } | 
 |  | 
 | template <typename Derived> | 
 | const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cos() const { | 
 |   eigen_assert(rows() == cols()); | 
 |   typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; | 
 |   return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_cos<ComplexScalar>); | 
 | } | 
 |  | 
 | template <typename Derived> | 
 | const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sinh() const { | 
 |   eigen_assert(rows() == cols()); | 
 |   typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; | 
 |   return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_sinh<ComplexScalar>); | 
 | } | 
 |  | 
 | template <typename Derived> | 
 | const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cosh() const { | 
 |   eigen_assert(rows() == cols()); | 
 |   typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; | 
 |   return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_cosh<ComplexScalar>); | 
 | } | 
 |  | 
 | }  // end namespace Eigen | 
 |  | 
 | #endif  // EIGEN_MATRIX_FUNCTION_H |