test-ra-dual.C 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // (c) Daniel Llorens - 2015
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. /// @file test-ra-dual.C
  7. /// @brief Using Dual<> with ra:: arrays & expressions.
  8. #include <iostream>
  9. #include <algorithm>
  10. #include <cassert>
  11. #include "ra/format.H"
  12. #include "ra/dual.H"
  13. #include "ra/complex.H"
  14. #include "ra/test.H"
  15. #include "ra/operators.H"
  16. #include "ra/io.H"
  17. using std::cout; using std::endl; using std::flush;
  18. using real = double;
  19. using complex = std::complex<double>;
  20. namespace ra {
  21. // Register our type as a scalar with ra:: . This isn't needed to have
  22. // containers of Dual<>, only to use Dual<>s by themselves as expr terms.
  23. template <class T> constexpr bool is_scalar_def<Dual<T>> = true;
  24. } // namespace ra
  25. #define DEFINE_CASE(N, F, DF) \
  26. struct JOIN(case, N) \
  27. { \
  28. template <class X> static auto f(X x) { return (F); } \
  29. template <class X> static auto df(X x) { return (DF); } \
  30. };
  31. DEFINE_CASE(0, x*cos(x)/sqrt(x),
  32. cos(x)/(2.*sqrt(x))-sqrt(x)*sin(x))
  33. DEFINE_CASE(1, x,
  34. 1.)
  35. DEFINE_CASE(2, 3.*exp(x*x)/x+8.*exp(2.*x)/x,
  36. -3.*exp(x*x)/(x*x)+6.*exp(x*x)+16.*exp(2.*x)/x-8.*exp(2.*x)/(x*x))
  37. DEFINE_CASE(3, cos(pow(exp(x), 4.5)),
  38. -4.5*exp(4.5*x)*sin(exp(4.5*x)))
  39. DEFINE_CASE(4, 1./(x*x),
  40. -2.*x/sqr(x*x))
  41. DEFINE_CASE(5, 1./(2.-x*x),
  42. +2.*x/sqr(2.-x*x))
  43. DEFINE_CASE(6, sinh(x)/cosh(x),
  44. 1./sqr(cosh(x)))
  45. #undef DEFINE_CASE
  46. template <class Case, class X>
  47. void test1(TestRecorder & tr, std::string const & info, X && x, real const rspec=2e-15)
  48. {
  49. tr.info(info, ": f vs Dual")
  50. .test_rel_error(ra::map([](auto && x) { return Case::f(x); }, x),
  51. ra::map([](auto && x) { return Case::f(dual(x, 1.)).re; }, x),
  52. rspec);
  53. tr.info(info, ": df vs Dual")
  54. .test_rel_error(ra::map([](auto && x) { return Case::df(x); }, x),
  55. ra::map([](auto && x) { return Case::f(dual(x, 1.)).du; }, x),
  56. rspec);
  57. }
  58. template <class Case, class D>
  59. void test2(TestRecorder & tr, std::string const & info, D && d, real const rspec=2e-15)
  60. {
  61. tr.info(info, ": f vs Dual")
  62. .test_rel_error(ra::map([](auto && d) { return Case::f(d.re); }, d),
  63. ra::map([](auto && d) { return Case::f(d).re; }, d),
  64. rspec);
  65. tr.info(info, ": df vs Dual")
  66. .test_rel_error(ra::map([](auto && d) { return Case::df(d.re); }, d),
  67. ra::map([](auto && d) { return Case::f(d).du; }, d),
  68. rspec);
  69. }
  70. int main()
  71. {
  72. TestRecorder tr(std::cout);
  73. assert(Dual<real>{3}.du==0.);
  74. assert(dual(3.).du==0.);
  75. #define TESTER(testn, x) \
  76. { \
  77. testn<case0>(tr, "case0", x); \
  78. testn<case1>(tr, "case1", x); \
  79. testn<case2>(tr, "case2", x); \
  80. testn<case3>(tr, "case3", x, 5e-14); \
  81. testn<case4>(tr, "case4", x); \
  82. testn<case5>(tr, "case5", x); \
  83. testn<case6>(tr, "case6", x); \
  84. }
  85. tr.section("args are arrays of real");
  86. TESTER(test1, ra::Big<real>({10}, (ra::_0 + 1) * .1));
  87. tr.section("args are arrays of complex");
  88. TESTER(test1, ra::Big<complex>({10}, (ra::_0 + 1) * .1 + complex(0, 1)));
  89. tr.section("args are arrays of Dual<real>");
  90. TESTER(test2, ra::Big<Dual<real> >({10}, map([](auto x) { return dual(x, 1.); }, (ra::_0 + 1) * .1)));
  91. tr.section("requires is_scalar registration");
  92. TESTER(test2, Dual<real>(1., 1.));
  93. #undef TESTER
  94. tr.section("using ra:: operators on arrays of Dual<real>");
  95. {
  96. auto test3 = [](TestRecorder & tr, std::string const & info, auto && d, real const rspec=2e-15)
  97. {
  98. tr.info(info, ": f vs Dual")
  99. .test_rel_error(ra::map([](auto && d) { return cos(d.re); }, d),
  100. ra::map([](auto && d) { return d.re; }, cos(d)),
  101. rspec);
  102. tr.info(info, ": df vs Dual")
  103. .test_rel_error(ra::map([](auto && d) { return -sin(d.re); }, d),
  104. ra::map([](auto && d) { return d.du; }, cos(d)),
  105. rspec);
  106. };
  107. test3(tr, "Dual<real>",
  108. ra::Big<Dual<real> >({10}, map([](auto x) { return dual(x, 1.); }, (ra::_0 + 1) * .1)));
  109. }
  110. tr.section("TODO define ra:: operators for .re and .du, as real_part(), imag_part() do");
  111. {
  112. }
  113. return tr.summary();
  114. }