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 // Eigen is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 3 of the License, or (at your option) any later version.
00010 //
00011 // Alternatively, you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License as
00013 // published by the Free Software Foundation; either version 2 of
00014 // the License, or (at your option) any later version.
00015 //
00016 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00017 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License and a copy of the GNU General Public License along with
00023 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00024 
00025 #include "main.h"
00026 #include <unsupported/Eigen/MatrixFunctions>
00027 
00028 // Variant of VERIFY_IS_APPROX which uses absolute error instead of
00029 // relative error.
00030 #define VERIFY_IS_APPROX_ABS(a, b) VERIFY(test_isApprox_abs(a, b))
00031 
00032 template<typename Type1, typename Type2>
00033 inline bool test_isApprox_abs(const Type1& a, const Type2& b)
00034 {
00035   return ((a-b).array().abs() < test_precision<typename Type1::RealScalar>()).all();
00036 }
00037 
00038 
00039 // Returns a matrix with eigenvalues clustered around 0, 1 and 2.
00040 template<typename MatrixType>
00041 MatrixType randomMatrixWithRealEivals(const typename MatrixType::Index size)
00042 {
00043   typedef typename MatrixType::Index Index;
00044   typedef typename MatrixType::Scalar Scalar;
00045   typedef typename MatrixType::RealScalar RealScalar;
00046   MatrixType diag = MatrixType::Zero(size, size);
00047   for (Index i = 0; i < size; ++i) {
00048     diag(i, i) = Scalar(RealScalar(internal::random<int>(0,2)))
00049       + internal::random<Scalar>() * Scalar(RealScalar(0.01));
00050   }
00051   MatrixType A = MatrixType::Random(size, size);
00052   HouseholderQR<MatrixType> QRofA(A);
00053   return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
00054 }
00055 
00056 template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
00057 struct randomMatrixWithImagEivals
00058 {
00059   // Returns a matrix with eigenvalues clustered around 0 and +/- i.
00060   static MatrixType run(const typename MatrixType::Index size);
00061 };
00062 
00063 // Partial specialization for real matrices
00064 template<typename MatrixType>
00065 struct randomMatrixWithImagEivals<MatrixType, 0>
00066 {
00067   static MatrixType run(const typename MatrixType::Index size)
00068   {
00069     typedef typename MatrixType::Index Index;
00070     typedef typename MatrixType::Scalar Scalar;
00071     MatrixType diag = MatrixType::Zero(size, size);
00072     Index i = 0;
00073     while (i < size) {
00074       Index randomInt = internal::random<Index>(-1, 1);
00075       if (randomInt == 0 || i == size-1) {
00076         diag(i, i) = internal::random<Scalar>() * Scalar(0.01);
00077         ++i;
00078       } else {
00079         Scalar alpha = Scalar(randomInt) + internal::random<Scalar>() * Scalar(0.01);
00080         diag(i, i+1) = alpha;
00081         diag(i+1, i) = -alpha;
00082         i += 2;
00083       }
00084     }
00085     MatrixType A = MatrixType::Random(size, size);
00086     HouseholderQR<MatrixType> QRofA(A);
00087     return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
00088   }
00089 };
00090 
00091 // Partial specialization for complex matrices
00092 template<typename MatrixType>
00093 struct randomMatrixWithImagEivals<MatrixType, 1>
00094 {
00095   static MatrixType run(const typename MatrixType::Index size)
00096   {
00097     typedef typename MatrixType::Index Index;
00098     typedef typename MatrixType::Scalar Scalar;
00099     typedef typename MatrixType::RealScalar RealScalar;
00100     const Scalar imagUnit(0, 1);
00101     MatrixType diag = MatrixType::Zero(size, size);
00102     for (Index i = 0; i < size; ++i) {
00103       diag(i, i) = Scalar(RealScalar(internal::random<Index>(-1, 1))) * imagUnit
00104         + internal::random<Scalar>() * Scalar(RealScalar(0.01));
00105     }
00106     MatrixType A = MatrixType::Random(size, size);
00107     HouseholderQR<MatrixType> QRofA(A);
00108     return QRofA.householderQ().inverse() * diag * QRofA.householderQ();
00109   }
00110 };
00111 
00112 
00113 template<typename MatrixType>
00114 void testMatrixExponential(const MatrixType& A)
00115 {
00116   typedef typename internal::traits<MatrixType>::Scalar Scalar;
00117   typedef typename NumTraits<Scalar>::Real RealScalar;
00118   typedef std::complex<RealScalar> ComplexScalar;
00119 
00120   VERIFY_IS_APPROX(A.exp(), A.matrixFunction(StdStemFunctions<ComplexScalar>::exp));
00121 }
00122 
00123 template<typename MatrixType>
00124 void testHyperbolicFunctions(const MatrixType& A)
00125 {
00126   // Need to use absolute error because of possible cancellation when
00127   // adding/subtracting expA and expmA.
00128   VERIFY_IS_APPROX_ABS(A.sinh(), (A.exp() - (-A).exp()) / 2);
00129   VERIFY_IS_APPROX_ABS(A.cosh(), (A.exp() + (-A).exp()) / 2);
00130 }
00131 
00132 template<typename MatrixType>
00133 void testGonioFunctions(const MatrixType& A)
00134 {
00135   typedef typename MatrixType::Scalar Scalar;
00136   typedef typename NumTraits<Scalar>::Real RealScalar;
00137   typedef std::complex<RealScalar> ComplexScalar;
00138   typedef Matrix<ComplexScalar, MatrixType::RowsAtCompileTime, 
00139                  MatrixType::ColsAtCompileTime, MatrixType::Options> ComplexMatrix;
00140 
00141   ComplexScalar imagUnit(0,1);
00142   ComplexScalar two(2,0);
00143 
00144   ComplexMatrix Ac = A.template cast<ComplexScalar>();
00145   
00146   ComplexMatrix exp_iA = (imagUnit * Ac).exp();
00147   ComplexMatrix exp_miA = (-imagUnit * Ac).exp();
00148   
00149   ComplexMatrix sinAc = A.sin().template cast<ComplexScalar>();
00150   VERIFY_IS_APPROX_ABS(sinAc, (exp_iA - exp_miA) / (two*imagUnit));
00151   
00152   ComplexMatrix cosAc = A.cos().template cast<ComplexScalar>();
00153   VERIFY_IS_APPROX_ABS(cosAc, (exp_iA + exp_miA) / 2);
00154 }
00155 
00156 template<typename MatrixType>
00157 void testMatrix(const MatrixType& A)
00158 {
00159   testMatrixExponential(A);
00160   testHyperbolicFunctions(A);
00161   testGonioFunctions(A);
00162 }
00163 
00164 template<typename MatrixType>
00165 void testMatrixType(const MatrixType& m)
00166 {
00167   // Matrices with clustered eigenvalue lead to different code paths
00168   // in MatrixFunction.h and are thus useful for testing.
00169   typedef typename MatrixType::Index Index;
00170 
00171   const Index size = m.rows();
00172   for (int i = 0; i < g_repeat; i++) {
00173     testMatrix(MatrixType::Random(size, size).eval());
00174     testMatrix(randomMatrixWithRealEivals<MatrixType>(size));
00175     testMatrix(randomMatrixWithImagEivals<MatrixType>::run(size));
00176   }
00177 }
00178 
00179 void test_matrix_function()
00180 {
00181   CALL_SUBTEST_1(testMatrixType(Matrix<float,1,1>()));
00182   CALL_SUBTEST_2(testMatrixType(Matrix3cf()));
00183   CALL_SUBTEST_3(testMatrixType(MatrixXf(8,8)));
00184   CALL_SUBTEST_4(testMatrixType(Matrix2d()));
00185   CALL_SUBTEST_5(testMatrixType(Matrix<double,5,5,RowMajor>()));
00186   CALL_SUBTEST_6(testMatrixType(Matrix4cd()));
00187   CALL_SUBTEST_7(testMatrixType(MatrixXd(13,13)));
00188 }


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:31:54