00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "matrix_functions.h"
00011
00012 double binom(int n, int k)
00013 {
00014 double res = 1;
00015 for (int i=0; i<k; i++)
00016 res = res * (n-k+i+1) / (i+1);
00017 return res;
00018 }
00019
00020 template <typename T>
00021 T expfn(T x, int)
00022 {
00023 return std::exp(x);
00024 }
00025
00026 template <typename T>
00027 void test2dRotation(double tol)
00028 {
00029 Matrix<T,2,2> A, B, C;
00030 T angle;
00031
00032 A << 0, 1, -1, 0;
00033 for (int i=0; i<=20; i++)
00034 {
00035 angle = static_cast<T>(pow(10, i / 5. - 2));
00036 B << std::cos(angle), std::sin(angle), -std::sin(angle), std::cos(angle);
00037
00038 C = (angle*A).matrixFunction(expfn);
00039 std::cout << "test2dRotation: i = " << i << " error funm = " << relerr(C, B);
00040 VERIFY(C.isApprox(B, static_cast<T>(tol)));
00041
00042 C = (angle*A).exp();
00043 std::cout << " error expm = " << relerr(C, B) << "\n";
00044 VERIFY(C.isApprox(B, static_cast<T>(tol)));
00045 }
00046 }
00047
00048 template <typename T>
00049 void test2dHyperbolicRotation(double tol)
00050 {
00051 Matrix<std::complex<T>,2,2> A, B, C;
00052 std::complex<T> imagUnit(0,1);
00053 T angle, ch, sh;
00054
00055 for (int i=0; i<=20; i++)
00056 {
00057 angle = static_cast<T>((i-10) / 2.0);
00058 ch = std::cosh(angle);
00059 sh = std::sinh(angle);
00060 A << 0, angle*imagUnit, -angle*imagUnit, 0;
00061 B << ch, sh*imagUnit, -sh*imagUnit, ch;
00062
00063 C = A.matrixFunction(expfn);
00064 std::cout << "test2dHyperbolicRotation: i = " << i << " error funm = " << relerr(C, B);
00065 VERIFY(C.isApprox(B, static_cast<T>(tol)));
00066
00067 C = A.exp();
00068 std::cout << " error expm = " << relerr(C, B) << "\n";
00069 VERIFY(C.isApprox(B, static_cast<T>(tol)));
00070 }
00071 }
00072
00073 template <typename T>
00074 void testPascal(double tol)
00075 {
00076 for (int size=1; size<20; size++)
00077 {
00078 Matrix<T,Dynamic,Dynamic> A(size,size), B(size,size), C(size,size);
00079 A.setZero();
00080 for (int i=0; i<size-1; i++)
00081 A(i+1,i) = static_cast<T>(i+1);
00082 B.setZero();
00083 for (int i=0; i<size; i++)
00084 for (int j=0; j<=i; j++)
00085 B(i,j) = static_cast<T>(binom(i,j));
00086
00087 C = A.matrixFunction(expfn);
00088 std::cout << "testPascal: size = " << size << " error funm = " << relerr(C, B);
00089 VERIFY(C.isApprox(B, static_cast<T>(tol)));
00090
00091 C = A.exp();
00092 std::cout << " error expm = " << relerr(C, B) << "\n";
00093 VERIFY(C.isApprox(B, static_cast<T>(tol)));
00094 }
00095 }
00096
00097 template<typename MatrixType>
00098 void randomTest(const MatrixType& m, double tol)
00099 {
00100
00101
00102
00103 typename MatrixType::Index rows = m.rows();
00104 typename MatrixType::Index cols = m.cols();
00105 MatrixType m1(rows, cols), m2(rows, cols), identity = MatrixType::Identity(rows, cols);
00106
00107 typedef typename NumTraits<typename internal::traits<MatrixType>::Scalar>::Real RealScalar;
00108
00109 for(int i = 0; i < g_repeat; i++) {
00110 m1 = MatrixType::Random(rows, cols);
00111
00112 m2 = m1.matrixFunction(expfn) * (-m1).matrixFunction(expfn);
00113 std::cout << "randomTest: error funm = " << relerr(identity, m2);
00114 VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));
00115
00116 m2 = m1.exp() * (-m1).exp();
00117 std::cout << " error expm = " << relerr(identity, m2) << "\n";
00118 VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));
00119 }
00120 }
00121
00122 void test_matrix_exponential()
00123 {
00124 CALL_SUBTEST_2(test2dRotation<double>(1e-13));
00125 CALL_SUBTEST_1(test2dRotation<float>(2e-5));
00126 CALL_SUBTEST_8(test2dRotation<long double>(1e-13));
00127 CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
00128 CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
00129 CALL_SUBTEST_8(test2dHyperbolicRotation<long double>(1e-14));
00130 CALL_SUBTEST_6(testPascal<float>(1e-6));
00131 CALL_SUBTEST_5(testPascal<double>(1e-15));
00132 CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13));
00133 CALL_SUBTEST_7(randomTest(Matrix<double,3,3,RowMajor>(), 1e-13));
00134 CALL_SUBTEST_3(randomTest(Matrix4cd(), 1e-13));
00135 CALL_SUBTEST_4(randomTest(MatrixXd(8,8), 1e-13));
00136 CALL_SUBTEST_1(randomTest(Matrix2f(), 1e-4));
00137 CALL_SUBTEST_5(randomTest(Matrix3cf(), 1e-4));
00138 CALL_SUBTEST_1(randomTest(Matrix4f(), 1e-4));
00139 CALL_SUBTEST_6(randomTest(MatrixXf(8,8), 1e-4));
00140 CALL_SUBTEST_9(randomTest(Matrix<long double,Dynamic,Dynamic>(7,7), 1e-13));
00141 }