WPILibC++ 2024.3.2
MatrixFunction.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-2011, 2013 Jitse Niesen <jitse@maths.leeds.ac.uk>
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_FUNCTION_H
11#define EIGEN_MATRIX_FUNCTION_H
12
13#include "StemFunction.h"
14
15// IWYU pragma: private
17
18namespace Eigen {
19
20namespace internal {
21
22/** \brief Maximum distance allowed between eigenvalues to be considered "close". */
23static const float matrix_function_separation = 0.1f;
24
25/** \ingroup MatrixFunctions_Module
26 * \class MatrixFunctionAtomic
27 * \brief Helper class for computing matrix functions of atomic matrices.
28 *
29 * Here, an atomic matrix is a triangular matrix whose diagonal entries are close to each other.
30 */
31template <typename MatrixType>
33 public:
34 typedef typename MatrixType::Scalar Scalar;
36
37 /** \brief Constructor
38 * \param[in] f matrix function to compute.
39 */
41
42 /** \brief Compute matrix function of atomic matrix
43 * \param[in] A argument of matrix function, should be upper triangular and atomic
44 * \returns f(A), the matrix function evaluated at the given matrix
45 */
46 MatrixType compute(const MatrixType& A);
47
48 private:
49 StemFunction* m_f;
50};
51
52template <typename MatrixType>
53typename NumTraits<typename MatrixType::Scalar>::Real matrix_function_compute_mu(const MatrixType& A) {
54 typedef typename plain_col_type<MatrixType>::type VectorType;
55 Index rows = A.rows();
56 const MatrixType N = MatrixType::Identity(rows, rows) - A;
57 VectorType e = VectorType::Ones(rows);
58 N.template triangularView<Upper>().solveInPlace(e);
59 return e.cwiseAbs().maxCoeff();
60}
61
62template <typename MatrixType>
63MatrixType MatrixFunctionAtomic<MatrixType>::compute(const MatrixType& A) {
64 // TODO: Use that A is upper triangular
65 typedef typename NumTraits<Scalar>::Real RealScalar;
66 Index rows = A.rows();
67 Scalar avgEival = A.trace() / Scalar(RealScalar(rows));
68 MatrixType Ashifted = A - avgEival * MatrixType::Identity(rows, rows);
69 RealScalar mu = matrix_function_compute_mu(Ashifted);
70 MatrixType F = m_f(avgEival, 0) * MatrixType::Identity(rows, rows);
71 MatrixType P = Ashifted;
72 MatrixType Fincr;
73 for (Index s = 1; double(s) < 1.1 * double(rows) + 10.0; s++) { // upper limit is fairly arbitrary
74 Fincr = m_f(avgEival, static_cast<int>(s)) * P;
75 F += Fincr;
76 P = Scalar(RealScalar(1) / RealScalar(s + 1)) * P * Ashifted;
77
78 // test whether Taylor series converged
79 const RealScalar F_norm = F.cwiseAbs().rowwise().sum().maxCoeff();
80 const RealScalar Fincr_norm = Fincr.cwiseAbs().rowwise().sum().maxCoeff();
81 if (Fincr_norm < NumTraits<Scalar>::epsilon() * F_norm) {
82 RealScalar delta = 0;
83 RealScalar rfactorial = 1;
84 for (Index r = 0; r < rows; r++) {
85 RealScalar mx = 0;
86 for (Index i = 0; i < rows; i++)
87 mx = (std::max)(mx, std::abs(m_f(Ashifted(i, i) + avgEival, static_cast<int>(s + r))));
88 if (r != 0) rfactorial *= RealScalar(r);
89 delta = (std::max)(delta, mx / rfactorial);
90 }
91 const RealScalar P_norm = P.cwiseAbs().rowwise().sum().maxCoeff();
92 if (mu * delta * P_norm < NumTraits<Scalar>::epsilon() * F_norm) // series converged
93 break;
94 }
95 }
96 return F;
97}
98
99/** \brief Find cluster in \p clusters containing some value
100 * \param[in] key Value to find
101 * \returns Iterator to cluster containing \p key, or \c clusters.end() if no cluster in \p m_clusters
102 * contains \p key.
103 */
104template <typename Index, typename ListOfClusters>
105typename ListOfClusters::iterator matrix_function_find_cluster(Index key, ListOfClusters& clusters) {
106 typename std::list<Index>::iterator j;
107 for (typename ListOfClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) {
108 j = std::find(i->begin(), i->end(), key);
109 if (j != i->end()) return i;
110 }
111 return clusters.end();
112}
113
114/** \brief Partition eigenvalues in clusters of ei'vals close to each other
115 *
116 * \param[in] eivals Eigenvalues
117 * \param[out] clusters Resulting partition of eigenvalues
118 *
119 * The partition satisfies the following two properties:
120 * # Any eigenvalue in a certain cluster is at most matrix_function_separation() away from another eigenvalue
121 * in the same cluster.
122 * # The distance between two eigenvalues in different clusters is more than matrix_function_separation().
123 * The implementation follows Algorithm 4.1 in the paper of Davies and Higham.
124 */
125template <typename EivalsType, typename Cluster>
126void matrix_function_partition_eigenvalues(const EivalsType& eivals, std::list<Cluster>& clusters) {
127 typedef typename EivalsType::RealScalar RealScalar;
128 for (Index i = 0; i < eivals.rows(); ++i) {
129 // Find cluster containing i-th ei'val, adding a new cluster if necessary
130 typename std::list<Cluster>::iterator qi = matrix_function_find_cluster(i, clusters);
131 if (qi == clusters.end()) {
132 Cluster l;
133 l.push_back(i);
134 clusters.push_back(l);
135 qi = clusters.end();
136 --qi;
137 }
138
139 // Look for other element to add to the set
140 for (Index j = i + 1; j < eivals.rows(); ++j) {
141 if (abs(eivals(j) - eivals(i)) <= RealScalar(matrix_function_separation) &&
142 std::find(qi->begin(), qi->end(), j) == qi->end()) {
143 typename std::list<Cluster>::iterator qj = matrix_function_find_cluster(j, clusters);
144 if (qj == clusters.end()) {
145 qi->push_back(j);
146 } else {
147 qi->insert(qi->end(), qj->begin(), qj->end());
148 clusters.erase(qj);
149 }
150 }
151 }
152 }
153}
154
155/** \brief Compute size of each cluster given a partitioning */
156template <typename ListOfClusters, typename Index>
157void matrix_function_compute_cluster_size(const ListOfClusters& clusters, Matrix<Index, Dynamic, 1>& clusterSize) {
158 const Index numClusters = static_cast<Index>(clusters.size());
159 clusterSize.setZero(numClusters);
160 Index clusterIndex = 0;
161 for (typename ListOfClusters::const_iterator cluster = clusters.begin(); cluster != clusters.end(); ++cluster) {
162 clusterSize[clusterIndex] = cluster->size();
163 ++clusterIndex;
164 }
165}
166
167/** \brief Compute start of each block using clusterSize */
168template <typename VectorType>
169void matrix_function_compute_block_start(const VectorType& clusterSize, VectorType& blockStart) {
170 blockStart.resize(clusterSize.rows());
171 blockStart(0) = 0;
172 for (Index i = 1; i < clusterSize.rows(); i++) {
173 blockStart(i) = blockStart(i - 1) + clusterSize(i - 1);
174 }
175}
176
177/** \brief Compute mapping of eigenvalue indices to cluster indices */
178template <typename EivalsType, typename ListOfClusters, typename VectorType>
179void matrix_function_compute_map(const EivalsType& eivals, const ListOfClusters& clusters, VectorType& eivalToCluster) {
180 eivalToCluster.resize(eivals.rows());
181 Index clusterIndex = 0;
182 for (typename ListOfClusters::const_iterator cluster = clusters.begin(); cluster != clusters.end(); ++cluster) {
183 for (Index i = 0; i < eivals.rows(); ++i) {
184 if (std::find(cluster->begin(), cluster->end(), i) != cluster->end()) {
185 eivalToCluster[i] = clusterIndex;
186 }
187 }
188 ++clusterIndex;
189 }
190}
191
192/** \brief Compute permutation which groups ei'vals in same cluster together */
193template <typename DynVectorType, typename VectorType>
194void matrix_function_compute_permutation(const DynVectorType& blockStart, const DynVectorType& eivalToCluster,
195 VectorType& permutation) {
196 DynVectorType indexNextEntry = blockStart;
197 permutation.resize(eivalToCluster.rows());
198 for (Index i = 0; i < eivalToCluster.rows(); i++) {
199 Index cluster = eivalToCluster[i];
200 permutation[i] = indexNextEntry[cluster];
201 ++indexNextEntry[cluster];
202 }
203}
204
205/** \brief Permute Schur decomposition in U and T according to permutation */
206template <typename VectorType, typename MatrixType>
207void matrix_function_permute_schur(VectorType& permutation, MatrixType& U, MatrixType& T) {
208 for (Index i = 0; i < permutation.rows() - 1; i++) {
209 Index j;
210 for (j = i; j < permutation.rows(); j++) {
211 if (permutation(j) == i) break;
212 }
213 eigen_assert(permutation(j) == i);
214 for (Index k = j - 1; k >= i; k--) {
215 JacobiRotation<typename MatrixType::Scalar> rotation;
216 rotation.makeGivens(T(k, k + 1), T(k + 1, k + 1) - T(k, k));
217 T.applyOnTheLeft(k, k + 1, rotation.adjoint());
218 T.applyOnTheRight(k, k + 1, rotation);
219 U.applyOnTheRight(k, k + 1, rotation);
220 std::swap(permutation.coeffRef(k), permutation.coeffRef(k + 1));
221 }
222 }
223}
224
225/** \brief Compute block diagonal part of matrix function.
226 *
227 * This routine computes the matrix function applied to the block diagonal part of \p T (which should be
228 * upper triangular), with the blocking given by \p blockStart and \p clusterSize. The matrix function of
229 * each diagonal block is computed by \p atomic. The off-diagonal parts of \p fT are set to zero.
230 */
231template <typename MatrixType, typename AtomicType, typename VectorType>
232void matrix_function_compute_block_atomic(const MatrixType& T, AtomicType& atomic, const VectorType& blockStart,
233 const VectorType& clusterSize, MatrixType& fT) {
234 fT.setZero(T.rows(), T.cols());
235 for (Index i = 0; i < clusterSize.rows(); ++i) {
236 fT.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i)) =
237 atomic.compute(T.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i)));
238 }
239}
240
241/** \brief Solve a triangular Sylvester equation AX + XB = C
242 *
243 * \param[in] A the matrix A; should be square and upper triangular
244 * \param[in] B the matrix B; should be square and upper triangular
245 * \param[in] C the matrix C; should have correct size.
246 *
247 * \returns the solution X.
248 *
249 * 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
250 * equation is
251 * \f[
252 * \sum_{k=i}^m A_{ik} X_{kj} + \sum_{k=1}^j X_{ik} B_{kj} = C_{ij}.
253 * \f]
254 * This can be re-arranged to yield:
255 * \f[
256 * X_{ij} = \frac{1}{A_{ii} + B_{jj}} \Bigl( C_{ij}
257 * - \sum_{k=i+1}^m A_{ik} X_{kj} - \sum_{k=1}^{j-1} X_{ik} B_{kj} \Bigr).
258 * \f]
259 * It is assumed that A and B are such that the numerator is never zero (otherwise the Sylvester equation
260 * does not have a unique solution). In that case, these equations can be evaluated in the order
261 * \f$ i=m,\ldots,1 \f$ and \f$ j=1,\ldots,n \f$.
262 */
263template <typename MatrixType>
264MatrixType matrix_function_solve_triangular_sylvester(const MatrixType& A, const MatrixType& B, const MatrixType& C) {
265 eigen_assert(A.rows() == A.cols());
266 eigen_assert(A.isUpperTriangular());
267 eigen_assert(B.rows() == B.cols());
268 eigen_assert(B.isUpperTriangular());
269 eigen_assert(C.rows() == A.rows());
270 eigen_assert(C.cols() == B.rows());
271
272 typedef typename MatrixType::Scalar Scalar;
273
274 Index m = A.rows();
275 Index n = B.rows();
276 MatrixType X(m, n);
277
278 for (Index i = m - 1; i >= 0; --i) {
279 for (Index j = 0; j < n; ++j) {
280 // Compute AX = \sum_{k=i+1}^m A_{ik} X_{kj}
281 Scalar AX;
282 if (i == m - 1) {
283 AX = 0;
284 } else {
285 Matrix<Scalar, 1, 1> AXmatrix = A.row(i).tail(m - 1 - i) * X.col(j).tail(m - 1 - i);
286 AX = AXmatrix(0, 0);
287 }
288
289 // Compute XB = \sum_{k=1}^{j-1} X_{ik} B_{kj}
290 Scalar XB;
291 if (j == 0) {
292 XB = 0;
293 } else {
294 Matrix<Scalar, 1, 1> XBmatrix = X.row(i).head(j) * B.col(j).head(j);
295 XB = XBmatrix(0, 0);
296 }
297
298 X(i, j) = (C(i, j) - AX - XB) / (A(i, i) + B(j, j));
299 }
300 }
301 return X;
302}
303
304/** \brief Compute part of matrix function above block diagonal.
305 *
306 * This routine completes the computation of \p fT, denoting a matrix function applied to the triangular
307 * matrix \p T. It assumes that the block diagonal part of \p fT has already been computed. The part below
308 * the diagonal is zero, because \p T is upper triangular.
309 */
310template <typename MatrixType, typename VectorType>
311void matrix_function_compute_above_diagonal(const MatrixType& T, const VectorType& blockStart,
312 const VectorType& clusterSize, MatrixType& fT) {
313 typedef internal::traits<MatrixType> Traits;
314 typedef typename MatrixType::Scalar Scalar;
315 static const int Options = MatrixType::Options;
316 typedef Matrix<Scalar, Dynamic, Dynamic, Options, Traits::RowsAtCompileTime, Traits::ColsAtCompileTime> DynMatrixType;
317
318 for (Index k = 1; k < clusterSize.rows(); k++) {
319 for (Index i = 0; i < clusterSize.rows() - k; i++) {
320 // compute (i, i+k) block
321 DynMatrixType A = T.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i));
322 DynMatrixType B = -T.block(blockStart(i + k), blockStart(i + k), clusterSize(i + k), clusterSize(i + k));
323 DynMatrixType C = fT.block(blockStart(i), blockStart(i), clusterSize(i), clusterSize(i)) *
324 T.block(blockStart(i), blockStart(i + k), clusterSize(i), clusterSize(i + k));
325 C -= T.block(blockStart(i), blockStart(i + k), clusterSize(i), clusterSize(i + k)) *
326 fT.block(blockStart(i + k), blockStart(i + k), clusterSize(i + k), clusterSize(i + k));
327 for (Index m = i + 1; m < i + k; m++) {
328 C += fT.block(blockStart(i), blockStart(m), clusterSize(i), clusterSize(m)) *
329 T.block(blockStart(m), blockStart(i + k), clusterSize(m), clusterSize(i + k));
330 C -= T.block(blockStart(i), blockStart(m), clusterSize(i), clusterSize(m)) *
331 fT.block(blockStart(m), blockStart(i + k), clusterSize(m), clusterSize(i + k));
332 }
333 fT.block(blockStart(i), blockStart(i + k), clusterSize(i), clusterSize(i + k)) =
335 }
336 }
337}
338
339/** \ingroup MatrixFunctions_Module
340 * \brief Class for computing matrix functions.
341 * \tparam MatrixType type of the argument of the matrix function,
342 * expected to be an instantiation of the Matrix class template.
343 * \tparam AtomicType type for computing matrix function of atomic blocks.
344 * \tparam IsComplex used internally to select correct specialization.
345 *
346 * This class implements the Schur-Parlett algorithm for computing matrix functions. The spectrum of the
347 * matrix is divided in clustered of eigenvalues that lies close together. This class delegates the
348 * computation of the matrix function on every block corresponding to these clusters to an object of type
349 * \p AtomicType and uses these results to compute the matrix function of the whole matrix. The class
350 * \p AtomicType should have a \p compute() member function for computing the matrix function of a block.
351 *
352 * \sa class MatrixFunctionAtomic, class MatrixLogarithmAtomic
353 */
354template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
356 /** \brief Compute the matrix function.
357 *
358 * \param[in] A argument of matrix function, should be a square matrix.
359 * \param[in] atomic class for computing matrix function of atomic blocks.
360 * \param[out] result the function \p f applied to \p A, as
361 * specified in the constructor.
362 *
363 * See MatrixBase::matrixFunction() for details on how this computation
364 * is implemented.
365 */
366 template <typename AtomicType, typename ResultType>
367 static void run(const MatrixType& A, AtomicType& atomic, ResultType& result);
368};
369
370/** \internal \ingroup MatrixFunctions_Module
371 * \brief Partial specialization of MatrixFunction for real matrices
372 *
373 * This converts the real matrix to a complex matrix, compute the matrix function of that matrix, and then
374 * converts the result back to a real matrix.
375 */
376template <typename MatrixType>
377struct matrix_function_compute<MatrixType, 0> {
378 template <typename MatA, typename AtomicType, typename ResultType>
379 static void run(const MatA& A, AtomicType& atomic, ResultType& result) {
380 typedef internal::traits<MatrixType> Traits;
381 typedef typename Traits::Scalar Scalar;
382 static const int Rows = Traits::RowsAtCompileTime, Cols = Traits::ColsAtCompileTime;
383 static const int MaxRows = Traits::MaxRowsAtCompileTime, MaxCols = Traits::MaxColsAtCompileTime;
384
385 typedef std::complex<Scalar> ComplexScalar;
386 typedef Matrix<ComplexScalar, Rows, Cols, 0, MaxRows, MaxCols> ComplexMatrix;
387
388 ComplexMatrix CA = A.template cast<ComplexScalar>();
389 ComplexMatrix Cresult;
391 result = Cresult.real();
392 }
393};
394
395/** \internal \ingroup MatrixFunctions_Module
396 * \brief Partial specialization of MatrixFunction for complex matrices
397 */
398template <typename MatrixType>
399struct matrix_function_compute<MatrixType, 1> {
400 template <typename MatA, typename AtomicType, typename ResultType>
401 static void run(const MatA& A, AtomicType& atomic, ResultType& result) {
402 typedef internal::traits<MatrixType> Traits;
403
404 // compute Schur decomposition of A
405 const ComplexSchur<MatrixType> schurOfA(A);
406 eigen_assert(schurOfA.info() == Success);
407 MatrixType T = schurOfA.matrixT();
408 MatrixType U = schurOfA.matrixU();
409
410 // partition eigenvalues into clusters of ei'vals "close" to each other
411 std::list<std::list<Index> > clusters;
412 matrix_function_partition_eigenvalues(T.diagonal(), clusters);
413
414 // compute size of each cluster
415 Matrix<Index, Dynamic, 1> clusterSize;
416 matrix_function_compute_cluster_size(clusters, clusterSize);
417
418 // blockStart[i] is row index at which block corresponding to i-th cluster starts
419 Matrix<Index, Dynamic, 1> blockStart;
420 matrix_function_compute_block_start(clusterSize, blockStart);
421
422 // compute map so that eivalToCluster[i] = j means that i-th ei'val is in j-th cluster
423 Matrix<Index, Dynamic, 1> eivalToCluster;
424 matrix_function_compute_map(T.diagonal(), clusters, eivalToCluster);
425
426 // compute permutation which groups ei'vals in same cluster together
427 Matrix<Index, Traits::RowsAtCompileTime, 1> permutation;
428 matrix_function_compute_permutation(blockStart, eivalToCluster, permutation);
429
430 // permute Schur decomposition
431 matrix_function_permute_schur(permutation, U, T);
432
433 // compute result
434 MatrixType fT; // matrix function applied to T
435 matrix_function_compute_block_atomic(T, atomic, blockStart, clusterSize, fT);
436 matrix_function_compute_above_diagonal(T, blockStart, clusterSize, fT);
437 result = U * (fT.template triangularView<Upper>() * U.adjoint());
438 }
439};
440
441} // end of namespace internal
442
443/** \ingroup MatrixFunctions_Module
444 *
445 * \brief Proxy for the matrix function of some matrix (expression).
446 *
447 * \tparam Derived Type of the argument to the matrix function.
448 *
449 * This class holds the argument to the matrix function until it is assigned or evaluated for some other
450 * reason (so the argument should not be changed in the meantime). It is the return type of
451 * matrixBase::matrixFunction() and related functions and most of the time this is the only way it is used.
452 */
453template <typename Derived>
454class MatrixFunctionReturnValue : public ReturnByValue<MatrixFunctionReturnValue<Derived> > {
455 public:
456 typedef typename Derived::Scalar Scalar;
458
459 protected:
461
462 public:
463 /** \brief Constructor.
464 *
465 * \param[in] A %Matrix (expression) forming the argument of the matrix function.
466 * \param[in] f Stem function for matrix function under consideration.
467 */
468 MatrixFunctionReturnValue(const Derived& A, StemFunction f) : m_A(A), m_f(f) {}
469
470 /** \brief Compute the matrix function.
471 *
472 * \param[out] result \p f applied to \p A, where \p f and \p A are as in the constructor.
473 */
474 template <typename ResultType>
475 inline void evalTo(ResultType& result) const {
476 typedef typename internal::nested_eval<Derived, 10>::type NestedEvalType;
477 typedef internal::remove_all_t<NestedEvalType> NestedEvalTypeClean;
478 typedef internal::traits<NestedEvalTypeClean> Traits;
479 typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
480 typedef Matrix<ComplexScalar, Dynamic, Dynamic, 0, Traits::RowsAtCompileTime, Traits::ColsAtCompileTime>
481 DynMatrixType;
482
484 AtomicType atomic(m_f);
485
487 }
488
489 Index rows() const { return m_A.rows(); }
490 Index cols() const { return m_A.cols(); }
491
492 private:
493 const DerivedNested m_A;
494 StemFunction* m_f;
495};
496
497namespace internal {
498template <typename Derived>
499struct traits<MatrixFunctionReturnValue<Derived> > {
500 typedef typename Derived::PlainObject ReturnType;
501};
502} // namespace internal
503
504/********** MatrixBase methods **********/
505
506template <typename Derived>
507const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::matrixFunction(
508 typename internal::stem_function<typename internal::traits<Derived>::Scalar>::type f) const {
509 eigen_assert(rows() == cols());
510 return MatrixFunctionReturnValue<Derived>(derived(), f);
511}
512
513template <typename Derived>
514const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sin() const {
515 eigen_assert(rows() == cols());
516 typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
517 return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_sin<ComplexScalar>);
518}
519
520template <typename Derived>
521const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cos() const {
522 eigen_assert(rows() == cols());
523 typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
524 return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_cos<ComplexScalar>);
525}
526
527template <typename Derived>
528const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sinh() const {
529 eigen_assert(rows() == cols());
530 typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
531 return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_sinh<ComplexScalar>);
532}
533
534template <typename Derived>
535const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cosh() const {
536 eigen_assert(rows() == cols());
537 typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar;
538 return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_cosh<ComplexScalar>);
539}
540
541} // end namespace Eigen
542
543#endif // EIGEN_MATRIX_FUNCTION_H
Proxy for the matrix function of some matrix (expression).
Definition: MatrixFunction.h:454
internal::ref_selector< Derived >::type DerivedNested
Definition: MatrixFunction.h:460
Index rows() const
Definition: MatrixFunction.h:489
internal::stem_function< Scalar >::type StemFunction
Definition: MatrixFunction.h:457
void evalTo(ResultType &result) const
Compute the matrix function.
Definition: MatrixFunction.h:475
Index cols() const
Definition: MatrixFunction.h:490
Derived::Scalar Scalar
Definition: MatrixFunction.h:456
MatrixFunctionReturnValue(const Derived &A, StemFunction f)
Constructor.
Definition: MatrixFunction.h:468
Helper class for computing matrix functions of atomic matrices.
Definition: MatrixFunction.h:32
MatrixFunctionAtomic(StemFunction f)
Constructor.
Definition: MatrixFunction.h:40
MatrixType::Scalar Scalar
Definition: MatrixFunction.h:34
MatrixType compute(const MatrixType &A)
Compute matrix function of atomic matrix.
Definition: MatrixFunction.h:63
stem_function< Scalar >::type StemFunction
Definition: MatrixFunction.h:35
UnitType abs(const UnitType x) noexcept
Compute absolute value.
Definition: math.h:721
dimensionless::scalar_t sinh(const AngleUnit angle) noexcept
Compute hyperbolic sine.
Definition: math.h:226
dimensionless::scalar_t cosh(const AngleUnit angle) noexcept
Compute hyperbolic cosine.
Definition: math.h:206
dimensionless::scalar_t cos(const AngleUnit angle) noexcept
Compute cosine.
Definition: math.h:61
dimensionless::scalar_t sin(const AngleUnit angle) noexcept
Compute sine.
Definition: math.h:81
void matrix_function_compute_permutation(const DynVectorType &blockStart, const DynVectorType &eivalToCluster, VectorType &permutation)
Compute permutation which groups ei'vals in same cluster together.
Definition: MatrixFunction.h:194
void matrix_function_compute_cluster_size(const ListOfClusters &clusters, Matrix< Index, Dynamic, 1 > &clusterSize)
Compute size of each cluster given a partitioning.
Definition: MatrixFunction.h:157
void matrix_function_compute_block_start(const VectorType &clusterSize, VectorType &blockStart)
Compute start of each block using clusterSize.
Definition: MatrixFunction.h:169
void matrix_function_compute_block_atomic(const MatrixType &T, AtomicType &atomic, const VectorType &blockStart, const VectorType &clusterSize, MatrixType &fT)
Compute block diagonal part of matrix function.
Definition: MatrixFunction.h:232
void matrix_function_permute_schur(VectorType &permutation, MatrixType &U, MatrixType &T)
Permute Schur decomposition in U and T according to permutation.
Definition: MatrixFunction.h:207
static const float matrix_function_separation
Maximum distance allowed between eigenvalues to be considered "close".
Definition: MatrixFunction.h:23
void matrix_function_compute_above_diagonal(const MatrixType &T, const VectorType &blockStart, const VectorType &clusterSize, MatrixType &fT)
Compute part of matrix function above block diagonal.
Definition: MatrixFunction.h:311
void matrix_function_partition_eigenvalues(const EivalsType &eivals, std::list< Cluster > &clusters)
Partition eigenvalues in clusters of ei'vals close to each other.
Definition: MatrixFunction.h:126
MatrixType matrix_function_solve_triangular_sylvester(const MatrixType &A, const MatrixType &B, const MatrixType &C)
Solve a triangular Sylvester equation AX + XB = C.
Definition: MatrixFunction.h:264
void matrix_function_compute_map(const EivalsType &eivals, const ListOfClusters &clusters, VectorType &eivalToCluster)
Compute mapping of eigenvalue indices to cluster indices.
Definition: MatrixFunction.h:179
NumTraits< typenameMatrixType::Scalar >::Real matrix_function_compute_mu(const MatrixType &A)
Definition: MatrixFunction.h:53
ListOfClusters::iterator matrix_function_find_cluster(Index key, ListOfClusters &clusters)
Find cluster in clusters containing some value.
Definition: MatrixFunction.h:105
Definition: MatrixSquareRoot.h:16
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2120
type
Definition: core.h:556
WPI_BASIC_JSON_TPL_DECLARATION void swap(wpi::WPI_BASIC_JSON_TPL &j1, wpi::WPI_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< wpi::WPI_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< wpi::WPI_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.h:5219
static constexpr const unit_t< compound_unit< charge::coulomb, inverse< substance::mol > > > F(N_A *e)
Faraday constant.
static constexpr const charge::coulomb_t e(1.6021766208e-19)
elementary charge.
UnitTypeLhs() max(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs)
Definition: base.h:3417
static void run(const MatA &A, AtomicType &atomic, ResultType &result)
Definition: MatrixFunction.h:379
static void run(const MatA &A, AtomicType &atomic, ResultType &result)
Definition: MatrixFunction.h:401
Class for computing matrix functions.
Definition: MatrixFunction.h:355
static void run(const MatrixType &A, AtomicType &atomic, ResultType &result)
Compute the matrix function.
Derived::PlainObject ReturnType
Definition: MatrixFunction.h:500