test_autodiff_2.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. // Copyright Matthew Pulver 2018 - 2019.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // https://www.boost.org/LICENSE_1_0.txt)
  5. #include "test_autodiff.hpp"
  6. BOOST_AUTO_TEST_SUITE(test_autodiff_2)
  7. BOOST_AUTO_TEST_CASE_TEMPLATE(one_over_one_plus_x_squared, T, all_float_types) {
  8. constexpr std::size_t m = 4;
  9. const T cx(1);
  10. auto f = make_fvar<T, m>(cx);
  11. // f = 1 / ((f *= f) += 1);
  12. f *= f;
  13. f += T(1);
  14. f = f.inverse();
  15. BOOST_CHECK_EQUAL(f.derivative(0u), 0.5);
  16. BOOST_CHECK_EQUAL(f.derivative(1u), -0.5);
  17. BOOST_CHECK_EQUAL(f.derivative(2u), 0.5);
  18. BOOST_CHECK_EQUAL(f.derivative(3u), 0);
  19. BOOST_CHECK_EQUAL(f.derivative(4u), -3);
  20. }
  21. BOOST_AUTO_TEST_CASE_TEMPLATE(exp_test, T, all_float_types) {
  22. using std::exp;
  23. constexpr std::size_t m = 4;
  24. const T cx = 2.0;
  25. const auto x = make_fvar<T, m>(cx);
  26. auto y = exp(x);
  27. for (auto i : boost::irange(m + 1)) {
  28. // std::cout.precision(100);
  29. // std::cout << "y.derivative("<<i<<") = " << y.derivative(i) << ",
  30. // std::exp(cx) = " << std::exp(cx) << std::endl;
  31. BOOST_CHECK_CLOSE_FRACTION(y.derivative(i), exp(cx),
  32. std::numeric_limits<T>::epsilon());
  33. }
  34. }
  35. BOOST_AUTO_TEST_CASE_TEMPLATE(pow, T, bin_float_types) {
  36. const T eps = 201 * std::numeric_limits<T>::epsilon(); // percent
  37. using std::log;
  38. using std::pow;
  39. constexpr std::size_t m = 5;
  40. constexpr std::size_t n = 4;
  41. const T cx = 2.0;
  42. const T cy = 3.0;
  43. const auto x = make_fvar<T, m>(cx);
  44. const auto y = make_fvar<T, m, n>(cy);
  45. auto z0 = pow(x, cy);
  46. BOOST_CHECK_EQUAL(z0.derivative(0u), pow(cx, cy));
  47. BOOST_CHECK_EQUAL(z0.derivative(1u), cy * pow(cx, cy - 1));
  48. BOOST_CHECK_EQUAL(z0.derivative(2u), cy * (cy - 1) * pow(cx, cy - 2));
  49. BOOST_CHECK_EQUAL(z0.derivative(3u),
  50. cy * (cy - 1) * (cy - 2) * pow(cx, cy - 3));
  51. BOOST_CHECK_EQUAL(z0.derivative(4u), 0u);
  52. BOOST_CHECK_EQUAL(z0.derivative(5u), 0u);
  53. auto z1 = pow(cx, y);
  54. BOOST_CHECK_CLOSE(z1.derivative(0u, 0u), pow(cx, cy), eps);
  55. for (auto j : boost::irange(std::size_t(1), n + 1)) {
  56. BOOST_CHECK_CLOSE(z1.derivative(0u, j), pow(log(cx), j) * pow(cx, cy), eps);
  57. }
  58. for (auto i : boost::irange(std::size_t(1), m + 1)) {
  59. for (auto j : boost::irange(n + 1)) {
  60. BOOST_CHECK_EQUAL(z1.derivative(i, j), 0);
  61. }
  62. }
  63. const auto z2 = pow(x, y);
  64. for (auto j : boost::irange(n + 1)) {
  65. BOOST_CHECK_CLOSE(z2.derivative(0u, j), pow(cx, cy) * pow(log(cx), j), eps);
  66. }
  67. for (auto j : boost::irange(n + 1)) {
  68. BOOST_CHECK_CLOSE(z2.derivative(1u, j),
  69. pow(cx, cy - 1) * pow(log(cx), static_cast<int>(j) - 1) *
  70. (cy * log(cx) + j),
  71. eps);
  72. }
  73. BOOST_CHECK_CLOSE(z2.derivative(2u, 0u), pow(cx, cy - 2) * cy * (cy - 1),
  74. eps);
  75. BOOST_CHECK_CLOSE(z2.derivative(2u, 1u),
  76. pow(cx, cy - 2) * (cy * (cy - 1) * log(cx) + 2 * cy - 1),
  77. eps);
  78. for (auto j : boost::irange(std::size_t(2u), n + 1)) {
  79. BOOST_CHECK_CLOSE(z2.derivative(2u, j),
  80. pow(cx, cy - 2) * pow(log(cx), j - 2) *
  81. (j * (2 * cy - 1) * log(cx) + (j - 1) * j +
  82. (cy - 1) * cy * pow(log(cx), 2)),
  83. eps);
  84. }
  85. BOOST_CHECK_CLOSE(z2.derivative(2u, 4u),
  86. pow(cx, cy - 2) * pow(log(cx), 2) *
  87. (4 * (2 * cy - 1) * log(cx) + (4 - 1) * 4 +
  88. (cy - 1) * cy * pow(log(cx), 2)),
  89. eps);
  90. }
  91. // TODO Tests around x=0 or y=0: pow(x,y)
  92. BOOST_AUTO_TEST_CASE_TEMPLATE(pow2, T, bin_float_types) {
  93. const T eps = 4000 * std::numeric_limits<T>::epsilon(); // percent
  94. using std::pow;
  95. constexpr std::size_t m = 5;
  96. constexpr std::size_t n = 5;
  97. const T cx = 2;
  98. const T cy = 5 / 2.0;
  99. const auto x = make_fvar<T, m>(cx);
  100. const auto y = make_fvar<T, 0, n>(cy);
  101. const auto z = pow(x, y);
  102. using namespace boost::math::constants;
  103. // Mathematica: Export["pow.csv", Flatten@Table[ Simplify@D[x^y,{x,i},{y,j}]
  104. // /. {x->2, y->5/2},
  105. // { i, 0, 5 }, { j, 0, 5 } ] ]
  106. // sed -rf pow.sed < pow.csv
  107. // with pow.sed script:
  108. // s/Log\[2\]\^([0-9]+)/pow(ln_two<T>(),\1)/g
  109. // s/Log\[2\]/ln_two<T>()/g
  110. // s/Sqrt\[2\]/root_two<T>()/g
  111. // s/[0-9]\/[0-9]+/\0.0/g
  112. // s/^"/static_cast<T>(/
  113. // s/"$/),/
  114. const T mathematica[]{
  115. static_cast<T>(4 * root_two<T>()),
  116. static_cast<T>(4 * root_two<T>() * ln_two<T>()),
  117. static_cast<T>(4 * root_two<T>() * pow(ln_two<T>(), 2)),
  118. static_cast<T>(4 * root_two<T>() * pow(ln_two<T>(), 3)),
  119. static_cast<T>(4 * root_two<T>() * pow(ln_two<T>(), 4)),
  120. static_cast<T>(4 * root_two<T>() * pow(ln_two<T>(), 5)),
  121. static_cast<T>(5 * root_two<T>()),
  122. static_cast<T>(2 * root_two<T>() * (1 + (5 * ln_two<T>()) / 2)),
  123. static_cast<T>(2 * root_two<T>() * ln_two<T>() *
  124. (2 + (5 * ln_two<T>()) / 2)),
  125. static_cast<T>(2 * root_two<T>() * pow(ln_two<T>(), 2) *
  126. (3 + (5 * ln_two<T>()) / 2)),
  127. static_cast<T>(2 * root_two<T>() * pow(ln_two<T>(), 3) *
  128. (4 + (5 * ln_two<T>()) / 2)),
  129. static_cast<T>(2 * root_two<T>() * pow(ln_two<T>(), 4) *
  130. (5 + (5 * ln_two<T>()) / 2)),
  131. static_cast<T>(15 / (2 * root_two<T>())),
  132. static_cast<T>(root_two<T>() * (4 + (15 * ln_two<T>()) / 4)),
  133. static_cast<T>(root_two<T>() *
  134. (2 + 8 * ln_two<T>() + (15 * pow(ln_two<T>(), 2)) / 4)),
  135. static_cast<T>(root_two<T>() * ln_two<T>() *
  136. (6 + 12 * ln_two<T>() + (15 * pow(ln_two<T>(), 2)) / 4)),
  137. static_cast<T>(root_two<T>() * pow(ln_two<T>(), 2) *
  138. (12 + 16 * ln_two<T>() + (15 * pow(ln_two<T>(), 2)) / 4)),
  139. static_cast<T>(root_two<T>() * pow(ln_two<T>(), 3) *
  140. (20 + 20 * ln_two<T>() + (15 * pow(ln_two<T>(), 2)) / 4)),
  141. static_cast<T>(15 / (8 * root_two<T>())),
  142. static_cast<T>((23 / 4.0 + (15 * ln_two<T>()) / 8) / root_two<T>()),
  143. static_cast<T>(
  144. (9 + (23 * ln_two<T>()) / 2 + (15 * pow(ln_two<T>(), 2)) / 8) /
  145. root_two<T>()),
  146. static_cast<T>((6 + 27 * ln_two<T>() + (69 * pow(ln_two<T>(), 2)) / 4 +
  147. (15 * pow(ln_two<T>(), 3)) / 8) /
  148. root_two<T>()),
  149. static_cast<T>(
  150. (ln_two<T>() * (24 + 54 * ln_two<T>() + 23 * pow(ln_two<T>(), 2) +
  151. (15 * pow(ln_two<T>(), 3)) / 8)) /
  152. root_two<T>()),
  153. static_cast<T>((pow(ln_two<T>(), 2) *
  154. (60 + 90 * ln_two<T>() + (115 * pow(ln_two<T>(), 2)) / 4 +
  155. (15 * pow(ln_two<T>(), 3)) / 8)) /
  156. root_two<T>()),
  157. static_cast<T>(-15 / (32 * root_two<T>())),
  158. static_cast<T>((-1 - (15 * ln_two<T>()) / 16) / (2 * root_two<T>())),
  159. static_cast<T>((7 - 2 * ln_two<T>() - (15 * pow(ln_two<T>(), 2)) / 16) /
  160. (2 * root_two<T>())),
  161. static_cast<T>((24 + 21 * ln_two<T>() - 3 * pow(ln_two<T>(), 2) -
  162. (15 * pow(ln_two<T>(), 3)) / 16) /
  163. (2 * root_two<T>())),
  164. static_cast<T>((24 + 96 * ln_two<T>() + 42 * pow(ln_two<T>(), 2) -
  165. 4 * pow(ln_two<T>(), 3) -
  166. (15 * pow(ln_two<T>(), 4)) / 16) /
  167. (2 * root_two<T>())),
  168. static_cast<T>(
  169. (ln_two<T>() *
  170. (120 + 240 * ln_two<T>() + 70 * pow(ln_two<T>(), 2) -
  171. 5 * pow(ln_two<T>(), 3) - (15 * pow(ln_two<T>(), 4)) / 16)) /
  172. (2 * root_two<T>())),
  173. static_cast<T>(45 / (128 * root_two<T>())),
  174. static_cast<T>((9 / 16.0 + (45 * ln_two<T>()) / 32) /
  175. (4 * root_two<T>())),
  176. static_cast<T>((-25 / 2.0 + (9 * ln_two<T>()) / 8 +
  177. (45 * pow(ln_two<T>(), 2)) / 32) /
  178. (4 * root_two<T>())),
  179. static_cast<T>((-15 - (75 * ln_two<T>()) / 2 +
  180. (27 * pow(ln_two<T>(), 2)) / 16 +
  181. (45 * pow(ln_two<T>(), 3)) / 32) /
  182. (4 * root_two<T>())),
  183. static_cast<T>((60 - 60 * ln_two<T>() - 75 * pow(ln_two<T>(), 2) +
  184. (9 * pow(ln_two<T>(), 3)) / 4 +
  185. (45 * pow(ln_two<T>(), 4)) / 32) /
  186. (4 * root_two<T>())),
  187. static_cast<T>((120 + 300 * ln_two<T>() - 150 * pow(ln_two<T>(), 2) -
  188. 125 * pow(ln_two<T>(), 3) +
  189. (45 * pow(ln_two<T>(), 4)) / 16 +
  190. (45 * pow(ln_two<T>(), 5)) / 32) /
  191. (4 * root_two<T>()))};
  192. std::size_t k = 0;
  193. for (auto i : boost::irange(m + 1)) {
  194. for (auto j : boost::irange(n + 1)) {
  195. BOOST_CHECK_CLOSE(z.derivative(i, j), mathematica[k++], eps);
  196. }
  197. }
  198. }
  199. BOOST_AUTO_TEST_CASE_TEMPLATE(sqrt_test, T, all_float_types) {
  200. using std::pow;
  201. using std::sqrt;
  202. constexpr std::size_t m = 5;
  203. const T cx = 4.0;
  204. auto x = make_fvar<T, m>(cx);
  205. auto y = sqrt(x);
  206. BOOST_CHECK_CLOSE_FRACTION(y.derivative(0u), sqrt(cx),
  207. std::numeric_limits<T>::epsilon());
  208. BOOST_CHECK_CLOSE_FRACTION(y.derivative(1u), 0.5 * pow(cx, -0.5),
  209. std::numeric_limits<T>::epsilon());
  210. BOOST_CHECK_CLOSE_FRACTION(y.derivative(2u), -0.5 * 0.5 * pow(cx, -1.5),
  211. std::numeric_limits<T>::epsilon());
  212. BOOST_CHECK_CLOSE_FRACTION(y.derivative(3u), 0.5 * 0.5 * 1.5 * pow(cx, -2.5),
  213. std::numeric_limits<T>::epsilon());
  214. BOOST_CHECK_CLOSE_FRACTION(y.derivative(4u),
  215. -0.5 * 0.5 * 1.5 * 2.5 * pow(cx, -3.5),
  216. std::numeric_limits<T>::epsilon());
  217. BOOST_CHECK_CLOSE_FRACTION(y.derivative(5u),
  218. 0.5 * 0.5 * 1.5 * 2.5 * 3.5 * pow(cx, -4.5),
  219. std::numeric_limits<T>::epsilon());
  220. x = make_fvar<T, m>(0);
  221. y = sqrt(x);
  222. // std::cout << "sqrt(0) = " << y << std::endl; // (0,inf,-inf,inf,-inf,inf)
  223. BOOST_CHECK_EQUAL(y.derivative(0u), 0);
  224. for (auto i : boost::irange(std::size_t(1), m + 1)) {
  225. BOOST_CHECK_EQUAL(y.derivative(i), (i % 2 == 1 ? 1 : -1) *
  226. std::numeric_limits<T>::infinity());
  227. }
  228. }
  229. BOOST_AUTO_TEST_CASE_TEMPLATE(log_test, T, all_float_types) {
  230. using std::log;
  231. using std::pow;
  232. constexpr std::size_t m = 5;
  233. const T cx = 2.0;
  234. auto x = make_fvar<T, m>(cx);
  235. auto y = log(x);
  236. BOOST_CHECK_CLOSE_FRACTION(y.derivative(0u), log(cx),
  237. std::numeric_limits<T>::epsilon());
  238. BOOST_CHECK_CLOSE_FRACTION(y.derivative(1u), 1 / cx,
  239. std::numeric_limits<T>::epsilon());
  240. BOOST_CHECK_CLOSE_FRACTION(y.derivative(2u), -1 / pow(cx, 2),
  241. std::numeric_limits<T>::epsilon());
  242. BOOST_CHECK_CLOSE_FRACTION(y.derivative(3u), 2 / pow(cx, 3),
  243. std::numeric_limits<T>::epsilon());
  244. BOOST_CHECK_CLOSE_FRACTION(y.derivative(4u), -6 / pow(cx, 4),
  245. std::numeric_limits<T>::epsilon());
  246. BOOST_CHECK_CLOSE_FRACTION(y.derivative(5u), 24 / pow(cx, 5),
  247. std::numeric_limits<T>::epsilon());
  248. x = make_fvar<T, m>(0);
  249. y = log(x);
  250. // std::cout << "log(0) = " << y << std::endl; // log(0) =
  251. // depth(1)(-inf,inf,-inf,inf,-inf,inf)
  252. for (auto i : boost::irange(m + 1)) {
  253. BOOST_CHECK_EQUAL(y.derivative(i), (i % 2 == 1 ? 1 : -1) *
  254. std::numeric_limits<T>::infinity());
  255. }
  256. }
  257. BOOST_AUTO_TEST_CASE_TEMPLATE(ylogx, T, all_float_types) {
  258. using std::log;
  259. using std::pow;
  260. const T eps = 100 * std::numeric_limits<T>::epsilon(); // percent
  261. constexpr std::size_t m = 5;
  262. constexpr std::size_t n = 4;
  263. const T cx = 2.0;
  264. const T cy = 3.0;
  265. const auto x = make_fvar<T, m>(cx);
  266. const auto y = make_fvar<T, m, n>(cy);
  267. auto z = y * log(x);
  268. BOOST_CHECK_EQUAL(z.derivative(0u, 0u), cy * log(cx));
  269. BOOST_CHECK_EQUAL(z.derivative(0u, 1u), log(cx));
  270. BOOST_CHECK_EQUAL(z.derivative(0u, 2u), 0);
  271. BOOST_CHECK_EQUAL(z.derivative(0u, 3u), 0);
  272. BOOST_CHECK_EQUAL(z.derivative(0u, 4u), 0);
  273. for (auto i : boost::irange(1u, static_cast<unsigned>(m + 1))) {
  274. BOOST_CHECK_CLOSE(z.derivative(i, 0u),
  275. pow(-1, i - 1) * boost::math::factorial<T>(i - 1) * cy /
  276. pow(cx, i),
  277. eps);
  278. BOOST_CHECK_CLOSE(
  279. z.derivative(i, 1u),
  280. pow(-1, i - 1) * boost::math::factorial<T>(i - 1) / pow(cx, i), eps);
  281. for (auto j : boost::irange(std::size_t(2), n + 1)) {
  282. BOOST_CHECK_EQUAL(z.derivative(i, j), 0u);
  283. }
  284. }
  285. auto z1 = exp(z);
  286. // RHS is confirmed by
  287. // https://www.wolframalpha.com/input/?i=D%5Bx%5Ey,%7Bx,2%7D,%7By,4%7D%5D+%2F.+%7Bx-%3E2.0,+y-%3E3.0%7D
  288. BOOST_CHECK_CLOSE(z1.derivative(2u, 4u),
  289. pow(cx, cy - 2) * pow(log(cx), 2) *
  290. (4 * (2 * cy - 1) * log(cx) + (4 - 1) * 4 +
  291. (cy - 1) * cy * pow(log(cx), 2)),
  292. eps);
  293. }
  294. BOOST_AUTO_TEST_CASE_TEMPLATE(frexp_test, T, all_float_types) {
  295. using std::exp2;
  296. using std::frexp;
  297. constexpr std::size_t m = 3;
  298. const T cx = 3.5;
  299. const auto x = make_fvar<T, m>(cx);
  300. int exp, testexp;
  301. auto y = frexp(x, &exp);
  302. BOOST_CHECK_EQUAL(y.derivative(0u), frexp(cx, &testexp));
  303. BOOST_CHECK_EQUAL(exp, testexp);
  304. BOOST_CHECK_EQUAL(y.derivative(1u), exp2(-exp));
  305. BOOST_CHECK_EQUAL(y.derivative(2u), 0);
  306. BOOST_CHECK_EQUAL(y.derivative(3u), 0);
  307. }
  308. BOOST_AUTO_TEST_CASE_TEMPLATE(ldexp_test, T, all_float_types) {
  309. BOOST_MATH_STD_USING
  310. using boost::multiprecision::ldexp;
  311. constexpr auto m = 3u;
  312. const T cx = 3.5;
  313. const auto x = make_fvar<T, m>(cx);
  314. constexpr auto exponent = 3;
  315. auto y = ldexp(x, exponent);
  316. BOOST_CHECK_EQUAL(y.derivative(0u), ldexp(cx, exponent));
  317. BOOST_CHECK_EQUAL(y.derivative(1u), exp2(exponent));
  318. BOOST_CHECK_EQUAL(y.derivative(2u), 0);
  319. BOOST_CHECK_EQUAL(y.derivative(3u), 0);
  320. }
  321. BOOST_AUTO_TEST_CASE_TEMPLATE(cos_and_sin, T, bin_float_types) {
  322. using std::cos;
  323. using std::sin;
  324. const T eps = 200 * std::numeric_limits<T>::epsilon(); // percent
  325. constexpr std::size_t m = 5;
  326. const T cx = boost::math::constants::third_pi<T>();
  327. const auto x = make_fvar<T, m>(cx);
  328. auto cos5 = cos(x);
  329. BOOST_CHECK_CLOSE(cos5.derivative(0u), cos(cx), eps);
  330. BOOST_CHECK_CLOSE(cos5.derivative(1u), -sin(cx), eps);
  331. BOOST_CHECK_CLOSE(cos5.derivative(2u), -cos(cx), eps);
  332. BOOST_CHECK_CLOSE(cos5.derivative(3u), sin(cx), eps);
  333. BOOST_CHECK_CLOSE(cos5.derivative(4u), cos(cx), eps);
  334. BOOST_CHECK_CLOSE(cos5.derivative(5u), -sin(cx), eps);
  335. auto sin5 = sin(x);
  336. BOOST_CHECK_CLOSE(sin5.derivative(0u), sin(cx), eps);
  337. BOOST_CHECK_CLOSE(sin5.derivative(1u), cos(cx), eps);
  338. BOOST_CHECK_CLOSE(sin5.derivative(2u), -sin(cx), eps);
  339. BOOST_CHECK_CLOSE(sin5.derivative(3u), -cos(cx), eps);
  340. BOOST_CHECK_CLOSE(sin5.derivative(4u), sin(cx), eps);
  341. BOOST_CHECK_CLOSE(sin5.derivative(5u), cos(cx), eps);
  342. // Test Order = 0 for codecov
  343. auto cos0 = cos(make_fvar<T, 0>(cx));
  344. BOOST_CHECK_CLOSE(cos0.derivative(0u), cos(cx), eps);
  345. auto sin0 = sin(make_fvar<T, 0>(cx));
  346. BOOST_CHECK_CLOSE(sin0.derivative(0u), sin(cx), eps);
  347. }
  348. BOOST_AUTO_TEST_CASE_TEMPLATE(acos_test, T, bin_float_types) {
  349. const T eps = 300 * std::numeric_limits<T>::epsilon(); // percent
  350. using std::acos;
  351. using std::pow;
  352. using std::sqrt;
  353. constexpr std::size_t m = 5;
  354. const T cx = 0.5;
  355. auto x = make_fvar<T, m>(cx);
  356. auto y = acos(x);
  357. BOOST_CHECK_CLOSE(y.derivative(0u), acos(cx), eps);
  358. BOOST_CHECK_CLOSE(y.derivative(1u), -1 / sqrt(1 - cx * cx), eps);
  359. BOOST_CHECK_CLOSE(y.derivative(2u), -cx / pow(1 - cx * cx, 1.5), eps);
  360. BOOST_CHECK_CLOSE(y.derivative(3u),
  361. -(2 * cx * cx + 1) / pow(1 - cx * cx, 2.5), eps);
  362. BOOST_CHECK_CLOSE(y.derivative(4u),
  363. -3 * cx * (2 * cx * cx + 3) / pow(1 - cx * cx, 3.5), eps);
  364. BOOST_CHECK_CLOSE(y.derivative(5u),
  365. -(24 * (cx * cx + 3) * cx * cx + 9) / pow(1 - cx * cx, 4.5),
  366. eps);
  367. }
  368. BOOST_AUTO_TEST_CASE_TEMPLATE(acosh_test, T, bin_float_types) {
  369. const T eps = 300 * std::numeric_limits<T>::epsilon(); // percent
  370. using boost::math::acosh;
  371. constexpr std::size_t m = 5;
  372. const T cx = 2;
  373. auto x = make_fvar<T, m>(cx);
  374. auto y = acosh(x);
  375. // BOOST_CHECK_EQUAL(y.derivative(0) == acosh(cx)); // FAILS! acosh(2) is
  376. // overloaded for integral types
  377. BOOST_CHECK_CLOSE(y.derivative(0u), acosh(static_cast<T>(x)), eps);
  378. BOOST_CHECK_CLOSE(y.derivative(1u),
  379. 1 / boost::math::constants::root_three<T>(), eps);
  380. BOOST_CHECK_CLOSE(y.derivative(2u),
  381. -2 / (3 * boost::math::constants::root_three<T>()), eps);
  382. BOOST_CHECK_CLOSE(y.derivative(3u),
  383. 1 / boost::math::constants::root_three<T>(), eps);
  384. BOOST_CHECK_CLOSE(y.derivative(4u),
  385. -22 / (9 * boost::math::constants::root_three<T>()), eps);
  386. BOOST_CHECK_CLOSE(y.derivative(5u),
  387. 227 / (27 * boost::math::constants::root_three<T>()),
  388. 2 * eps);
  389. }
  390. BOOST_AUTO_TEST_CASE_TEMPLATE(asin_test, T, bin_float_types) {
  391. const T eps = 300 * std::numeric_limits<T>::epsilon(); // percent
  392. using std::asin;
  393. using std::pow;
  394. using std::sqrt;
  395. constexpr std::size_t m = 5;
  396. const T cx = 0.5;
  397. auto x = make_fvar<T, m>(cx);
  398. auto y = asin(x);
  399. BOOST_CHECK_CLOSE(y.derivative(0u), asin(static_cast<T>(x)), eps);
  400. BOOST_CHECK_CLOSE(y.derivative(1u), 1 / sqrt(1 - cx * cx), eps);
  401. BOOST_CHECK_CLOSE(y.derivative(2u), cx / pow(1 - cx * cx, 1.5), eps);
  402. BOOST_CHECK_CLOSE(y.derivative(3u), (2 * cx * cx + 1) / pow(1 - cx * cx, 2.5),
  403. eps);
  404. BOOST_CHECK_CLOSE(y.derivative(4u),
  405. 3 * cx * (2 * cx * cx + 3) / pow(1 - cx * cx, 3.5), eps);
  406. BOOST_CHECK_CLOSE(y.derivative(5u),
  407. (24 * (cx * cx + 3) * cx * cx + 9) / pow(1 - cx * cx, 4.5),
  408. eps);
  409. }
  410. BOOST_AUTO_TEST_CASE_TEMPLATE(asin_infinity, T, all_float_types) {
  411. const T eps = 100 * std::numeric_limits<T>::epsilon(); // percent
  412. constexpr std::size_t m = 5;
  413. auto x = make_fvar<T, m>(1);
  414. auto y = asin(x);
  415. // std::cout << "asin(1) = " << y << std::endl; //
  416. // depth(1)(1.5707963267949,inf,inf,-nan,-nan,-nan)
  417. BOOST_CHECK_CLOSE(y.derivative(0u), boost::math::constants::half_pi<T>(),
  418. eps); // MacOS is not exact
  419. BOOST_CHECK_EQUAL(y.derivative(1u), std::numeric_limits<T>::infinity());
  420. }
  421. BOOST_AUTO_TEST_CASE_TEMPLATE(asin_derivative, T, bin_float_types) {
  422. const T eps = 300 * std::numeric_limits<T>::epsilon(); // percent
  423. using std::pow;
  424. using std::sqrt;
  425. constexpr std::size_t m = 4;
  426. const T cx(0.5);
  427. auto x = make_fvar<T, m>(cx);
  428. auto y = T(1) - x * x;
  429. BOOST_CHECK_EQUAL(y.derivative(0u), 1 - cx * cx);
  430. BOOST_CHECK_EQUAL(y.derivative(1u), -2 * cx);
  431. BOOST_CHECK_EQUAL(y.derivative(2u), -2);
  432. BOOST_CHECK_EQUAL(y.derivative(3u), 0);
  433. BOOST_CHECK_EQUAL(y.derivative(4u), 0);
  434. y = sqrt(y);
  435. BOOST_CHECK_EQUAL(y.derivative(0u), sqrt(1 - cx * cx));
  436. BOOST_CHECK_CLOSE(y.derivative(1u), -cx / sqrt(1 - cx * cx), eps);
  437. BOOST_CHECK_CLOSE(y.derivative(2u), -1 / pow(1 - cx * cx, 1.5), eps);
  438. BOOST_CHECK_CLOSE(y.derivative(3u), -3 * cx / pow(1 - cx * cx, 2.5), eps);
  439. BOOST_CHECK_CLOSE(y.derivative(4u),
  440. -(12 * cx * cx + 3) / pow(1 - cx * cx, 3.5), eps);
  441. y = y.inverse(); // asin'(x) = 1 / sqrt(1-x*x).
  442. BOOST_CHECK_CLOSE(y.derivative(0u), 1 / sqrt(1 - cx * cx), eps);
  443. BOOST_CHECK_CLOSE(y.derivative(1u), cx / pow(1 - cx * cx, 1.5), eps);
  444. BOOST_CHECK_CLOSE(y.derivative(2u), (2 * cx * cx + 1) / pow(1 - cx * cx, 2.5),
  445. eps);
  446. BOOST_CHECK_CLOSE(y.derivative(3u),
  447. 3 * cx * (2 * cx * cx + 3) / pow(1 - cx * cx, 3.5), eps);
  448. BOOST_CHECK_CLOSE(y.derivative(4u),
  449. (24 * (cx * cx + 3) * cx * cx + 9) / pow(1 - cx * cx, 4.5),
  450. eps);
  451. }
  452. BOOST_AUTO_TEST_CASE_TEMPLATE(asinh_test, T, bin_float_types) {
  453. const T eps = 300 * std::numeric_limits<T>::epsilon(); // percent
  454. using boost::math::asinh;
  455. constexpr std::size_t m = 5;
  456. const T cx = 1;
  457. auto x = make_fvar<T, m>(cx);
  458. auto y = asinh(x);
  459. BOOST_CHECK_CLOSE(y.derivative(0u), asinh(static_cast<T>(x)), eps);
  460. BOOST_CHECK_CLOSE(y.derivative(1u), 1 / boost::math::constants::root_two<T>(),
  461. eps);
  462. BOOST_CHECK_CLOSE(y.derivative(2u),
  463. -1 / (2 * boost::math::constants::root_two<T>()), eps);
  464. BOOST_CHECK_CLOSE(y.derivative(3u),
  465. 1 / (4 * boost::math::constants::root_two<T>()), eps);
  466. BOOST_CHECK_CLOSE(y.derivative(4u),
  467. 3 / (8 * boost::math::constants::root_two<T>()), eps);
  468. BOOST_CHECK_CLOSE(y.derivative(5u),
  469. -39 / (16 * boost::math::constants::root_two<T>()), eps);
  470. }
  471. BOOST_AUTO_TEST_CASE_TEMPLATE(atan2_function, T, all_float_types) {
  472. using test_constants = test_constants_t<T>;
  473. static constexpr auto m = test_constants::order;
  474. test_detail::RandomSample<T> x_sampler{-2000, 2000};
  475. test_detail::RandomSample<T> y_sampler{-2000, 2000};
  476. for (auto i : boost::irange(test_constants::n_samples)) {
  477. std::ignore = i;
  478. auto x = x_sampler.next();
  479. auto y = y_sampler.next();
  480. auto autodiff_v = atan2(make_fvar<T, m>(x), make_fvar<T, m>(y));
  481. auto anchor_v = atan2(x, y);
  482. BOOST_CHECK_CLOSE(autodiff_v, anchor_v,
  483. 5000 * test_constants::pct_epsilon());
  484. }
  485. }
  486. BOOST_AUTO_TEST_SUITE_END()