matrix_function.cpp
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #include "main.h"
00011 #include <unsupported/Eigen/MatrixFunctions>
00012 
00013 // Variant of VERIFY_IS_APPROX which uses absolute error instead of
00014 // relative error.
00015 #define VERIFY_IS_APPROX_ABS(a, b) VERIFY(test_isApprox_abs(a, b))
00016 
00017 template<typename Type1, typename Type2>
00018 inline bool test_isApprox_abs(const Type1& a, const Type2& b)
00019 {
00020   return ((a-b).array().abs() < test_precision<typename Type1::RealScalar>()).all();
00021 }
00022 
00023 
00024 // Returns a matrix with eigenvalues clustered around 0, 1 and 2.
00025 template<typename MatrixType>
00026 MatrixType randomMatrixWithRealEivals(const typename MatrixType::Index size)
00027 {
00028   typedef typename MatrixType::Index Index;
00029   typedef typename MatrixType::Scalar Scalar;
00030   typedef typename MatrixType::RealScalar RealScalar;
00031   MatrixType diag = MatrixType::Zero(size, size);
00032   for (Index i = 0; i < size; ++i) {
00033     diag(i, i) = Scalar(RealScalar(internal::random<int>(0,2)))
00034       + internal::random<Scalar>() * Scalar(RealScalar(0.01));
00035   }
00036   MatrixType A = MatrixType::Random(size, size);
00037   HouseholderQR<MatrixType> QRofA(A);
00038   return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
00039 }
00040 
00041 template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
00042 struct randomMatrixWithImagEivals
00043 {
00044   // Returns a matrix with eigenvalues clustered around 0 and +/- i.
00045   static MatrixType run(const typename MatrixType::Index size);
00046 };
00047 
00048 // Partial specialization for real matrices
00049 template<typename MatrixType>
00050 struct randomMatrixWithImagEivals<MatrixType, 0>
00051 {
00052   static MatrixType run(const typename MatrixType::Index size)
00053   {
00054     typedef typename MatrixType::Index Index;
00055     typedef typename MatrixType::Scalar Scalar;
00056     MatrixType diag = MatrixType::Zero(size, size);
00057     Index i = 0;
00058     while (i < size) {
00059       Index randomInt = internal::random<Index>(-1, 1);
00060       if (randomInt == 0 || i == size-1) {
00061         diag(i, i) = internal::random<Scalar>() * Scalar(0.01);
00062         ++i;
00063       } else {
00064         Scalar alpha = Scalar(randomInt) + internal::random<Scalar>() * Scalar(0.01);
00065         diag(i, i+1) = alpha;
00066         diag(i+1, i) = -alpha;
00067         i += 2;
00068       }
00069     }
00070     MatrixType A = MatrixType::Random(size, size);
00071     HouseholderQR<MatrixType> QRofA(A);
00072     return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
00073   }
00074 };
00075 
00076 // Partial specialization for complex matrices
00077 template<typename MatrixType>
00078 struct randomMatrixWithImagEivals<MatrixType, 1>
00079 {
00080   static MatrixType run(const typename MatrixType::Index size)
00081   {
00082     typedef typename MatrixType::Index Index;
00083     typedef typename MatrixType::Scalar Scalar;
00084     typedef typename MatrixType::RealScalar RealScalar;
00085     const Scalar imagUnit(0, 1);
00086     MatrixType diag = MatrixType::Zero(size, size);
00087     for (Index i = 0; i < size; ++i) {
00088       diag(i, i) = Scalar(RealScalar(internal::random<Index>(-1, 1))) * imagUnit
00089         + internal::random<Scalar>() * Scalar(RealScalar(0.01));
00090     }
00091     MatrixType A = MatrixType::Random(size, size);
00092     HouseholderQR<MatrixType> QRofA(A);
00093     return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
00094   }
00095 };
00096 
00097 
00098 template<typename MatrixType>
00099 void testMatrixExponential(const MatrixType& A)
00100 {
00101   typedef typename internal::traits<MatrixType>::Scalar Scalar;
00102   typedef typename NumTraits<Scalar>::Real RealScalar;
00103   typedef std::complex<RealScalar> ComplexScalar;
00104 
00105   VERIFY_IS_APPROX(A.exp(), A.matrixFunction(StdStemFunctions<ComplexScalar>::exp));
00106 }
00107 
00108 template<typename MatrixType>
00109 void testMatrixLogarithm(const MatrixType& A)
00110 {
00111   typedef typename internal::traits<MatrixType>::Scalar Scalar;
00112   typedef typename NumTraits<Scalar>::Real RealScalar;
00113 
00114   MatrixType scaledA;
00115   RealScalar maxImagPartOfSpectrum = A.eigenvalues().imag().cwiseAbs().maxCoeff();
00116   if (maxImagPartOfSpectrum >= 0.9 * M_PI)
00117     scaledA = A * 0.9 * M_PI / maxImagPartOfSpectrum;
00118   else
00119     scaledA = A;
00120 
00121   // identity X.exp().log() = X only holds if Im(lambda) < pi for all eigenvalues of X
00122   MatrixType expA = scaledA.exp();
00123   MatrixType logExpA = expA.log();
00124   VERIFY_IS_APPROX(logExpA, scaledA);
00125 }
00126 
00127 template<typename MatrixType>
00128 void testHyperbolicFunctions(const MatrixType& A)
00129 {
00130   // Need to use absolute error because of possible cancellation when
00131   // adding/subtracting expA and expmA.
00132   VERIFY_IS_APPROX_ABS(A.sinh(), (A.exp() - (-A).exp()) / 2);
00133   VERIFY_IS_APPROX_ABS(A.cosh(), (A.exp() + (-A).exp()) / 2);
00134 }
00135 
00136 template<typename MatrixType>
00137 void testGonioFunctions(const MatrixType& A)
00138 {
00139   typedef typename MatrixType::Scalar Scalar;
00140   typedef typename NumTraits<Scalar>::Real RealScalar;
00141   typedef std::complex<RealScalar> ComplexScalar;
00142   typedef Matrix<ComplexScalar, MatrixType::RowsAtCompileTime, 
00143                  MatrixType::ColsAtCompileTime, MatrixType::Options> ComplexMatrix;
00144 
00145   ComplexScalar imagUnit(0,1);
00146   ComplexScalar two(2,0);
00147 
00148   ComplexMatrix Ac = A.template cast<ComplexScalar>();
00149   
00150   ComplexMatrix exp_iA = (imagUnit * Ac).exp();
00151   ComplexMatrix exp_miA = (-imagUnit * Ac).exp();
00152   
00153   ComplexMatrix sinAc = A.sin().template cast<ComplexScalar>();
00154   VERIFY_IS_APPROX_ABS(sinAc, (exp_iA - exp_miA) / (two*imagUnit));
00155   
00156   ComplexMatrix cosAc = A.cos().template cast<ComplexScalar>();
00157   VERIFY_IS_APPROX_ABS(cosAc, (exp_iA + exp_miA) / 2);
00158 }
00159 
00160 template<typename MatrixType>
00161 void testMatrix(const MatrixType& A)
00162 {
00163   testMatrixExponential(A);
00164   testMatrixLogarithm(A);
00165   testHyperbolicFunctions(A);
00166   testGonioFunctions(A);
00167 }
00168 
00169 template<typename MatrixType>
00170 void testMatrixType(const MatrixType& m)
00171 {
00172   // Matrices with clustered eigenvalue lead to different code paths
00173   // in MatrixFunction.h and are thus useful for testing.
00174   typedef typename MatrixType::Index Index;
00175 
00176   const Index size = m.rows();
00177   for (int i = 0; i < g_repeat; i++) {
00178     testMatrix(MatrixType::Random(size, size).eval());
00179     testMatrix(randomMatrixWithRealEivals<MatrixType>(size));
00180     testMatrix(randomMatrixWithImagEivals<MatrixType>::run(size));
00181   }
00182 }
00183 
00184 void test_matrix_function()
00185 {
00186   CALL_SUBTEST_1(testMatrixType(Matrix<float,1,1>()));
00187   CALL_SUBTEST_2(testMatrixType(Matrix3cf()));
00188   CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8)));
00189   CALL_SUBTEST_4(testMatrixType(Matrix2d()));
00190   CALL_SUBTEST_5(testMatrixType(Matrix<double,5,5,RowMajor>()));
00191   CALL_SUBTEST_6(testMatrixType(Matrix4cd()));
00192   CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13)));
00193 }


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:33:01