naive_monte_carlo_test.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. * Copyright Nick Thompson, 2017
  3. * Use, modification and distribution are subject to the
  4. * Boost Software License, Version 1.0. (See accompanying file
  5. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #define BOOST_TEST_MODULE naive_monte_carlo_test
  8. #define BOOST_NAIVE_MONTE_CARLO_DEBUG_FAILURES
  9. #include <cmath>
  10. #include <ostream>
  11. #include <boost/lexical_cast.hpp>
  12. #include <boost/type_index.hpp>
  13. #include <boost/test/included/unit_test.hpp>
  14. #include <boost/test/tools/floating_point_comparison.hpp>
  15. #include <boost/math/constants/constants.hpp>
  16. #include <boost/math/quadrature/naive_monte_carlo.hpp>
  17. using std::abs;
  18. using std::vector;
  19. using std::pair;
  20. using boost::math::constants::pi;
  21. using boost::math::quadrature::naive_monte_carlo;
  22. template<class Real>
  23. void test_pi_multithreaded()
  24. {
  25. std::cout << "Testing pi is calculated correctly (multithreaded) using Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  26. auto g = [](std::vector<Real> const & x)->Real {
  27. Real r = x[0]*x[0]+x[1]*x[1];
  28. if (r <= 1) {
  29. return 4;
  30. }
  31. return 0;
  32. };
  33. std::vector<std::pair<Real, Real>> bounds{{Real(0), Real(1)}, {Real(0), Real(1)}};
  34. Real error_goal = 0.0002;
  35. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, error_goal,
  36. /*singular =*/ false,/* threads = */ 2, /* seed = */ 18012);
  37. auto task = mc.integrate();
  38. Real pi_estimated = task.get();
  39. if (abs(pi_estimated - pi<Real>())/pi<Real>() > 0.005) {
  40. std::cout << "Error in estimation of pi too high, function calls: " << mc.calls() << "\n";
  41. std::cout << "Final error estimate : " << mc.current_error_estimate() << "\n";
  42. std::cout << "Error goal : " << error_goal << "\n";
  43. BOOST_CHECK_CLOSE_FRACTION(pi_estimated, pi<Real>(), 0.005);
  44. }
  45. }
  46. template<class Real>
  47. void test_pi()
  48. {
  49. std::cout << "Testing pi is calculated correctly using Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  50. auto g = [](std::vector<Real> const & x)->Real
  51. {
  52. Real r = x[0]*x[0]+x[1]*x[1];
  53. if (r <= 1)
  54. {
  55. return 4;
  56. }
  57. return 0;
  58. };
  59. std::vector<std::pair<Real, Real>> bounds{{Real(0), Real(1)}, {Real(0), Real(1)}};
  60. Real error_goal = (Real) 0.0002;
  61. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, error_goal,
  62. /*singular =*/ false,/* threads = */ 1, /* seed = */ 128402);
  63. auto task = mc.integrate();
  64. Real pi_estimated = task.get();
  65. if (abs(pi_estimated - pi<Real>())/pi<Real>() > 0.005)
  66. {
  67. std::cout << "Error in estimation of pi too high, function calls: " << mc.calls() << "\n";
  68. std::cout << "Final error estimate : " << mc.current_error_estimate() << "\n";
  69. std::cout << "Error goal : " << error_goal << "\n";
  70. BOOST_CHECK_CLOSE_FRACTION(pi_estimated, pi<Real>(), 0.005);
  71. }
  72. }
  73. template<class Real>
  74. void test_constant()
  75. {
  76. std::cout << "Testing constants are integrated correctly using Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  77. auto g = [](std::vector<Real> const &)->Real
  78. {
  79. return 1;
  80. };
  81. std::vector<std::pair<Real, Real>> bounds{{Real(0), Real(1)}, { Real(0), Real(1)}};
  82. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.0001,
  83. /* singular = */ false, /* threads = */ 1, /* seed = */ 87);
  84. auto task = mc.integrate();
  85. Real one = task.get();
  86. BOOST_CHECK_CLOSE_FRACTION(one, 1, 0.001);
  87. BOOST_CHECK_SMALL(mc.current_error_estimate(), std::numeric_limits<Real>::epsilon());
  88. BOOST_CHECK(mc.calls() > 1000);
  89. }
  90. template<class Real>
  91. void test_exception_from_integrand()
  92. {
  93. std::cout << "Testing that a reasonable action is performed by the Monte-Carlo integrator when the integrand throws an exception on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  94. auto g = [](std::vector<Real> const & x)->Real
  95. {
  96. if (x[0] > 0.5 && x[0] < 0.5001)
  97. {
  98. throw std::domain_error("You have done something wrong.\n");
  99. }
  100. return (Real) 1;
  101. };
  102. std::vector<std::pair<Real, Real>> bounds{{ Real(0), Real(1)}, { Real(0), Real(1)}};
  103. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.0001);
  104. auto task = mc.integrate();
  105. bool caught_exception = false;
  106. try
  107. {
  108. Real result = task.get();
  109. // Get rid of unused variable warning:
  110. std::ostream cnull(0);
  111. cnull << result;
  112. }
  113. catch(std::exception const &)
  114. {
  115. caught_exception = true;
  116. }
  117. BOOST_CHECK(caught_exception);
  118. }
  119. template<class Real>
  120. void test_cancel_and_restart()
  121. {
  122. std::cout << "Testing that cancellation and restarting works on naive Monte-Carlo integration on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  123. Real exact = boost::lexical_cast<Real>("1.3932039296856768591842462603255");
  124. BOOST_CONSTEXPR const Real A = 1.0 / (pi<Real>() * pi<Real>() * pi<Real>());
  125. auto g = [&](std::vector<Real> const & x)->Real
  126. {
  127. return A / (1.0 - cos(x[0])*cos(x[1])*cos(x[2]));
  128. };
  129. vector<pair<Real, Real>> bounds{{ Real(0), pi<Real>()}, { Real(0), pi<Real>()}, { Real(0), pi<Real>()}};
  130. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.05, true, 1, 888889);
  131. auto task = mc.integrate();
  132. mc.cancel();
  133. double y = task.get();
  134. // Super low tolerance; because it got canceled so fast:
  135. BOOST_CHECK_CLOSE_FRACTION(y, exact, 1.0);
  136. mc.update_target_error((Real) 0.01);
  137. task = mc.integrate();
  138. y = task.get();
  139. BOOST_CHECK_CLOSE_FRACTION(y, exact, 0.1);
  140. }
  141. template<class Real>
  142. void test_finite_singular_boundary()
  143. {
  144. std::cout << "Testing that finite singular boundaries work on naive Monte-Carlo integration on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  145. using std::pow;
  146. using std::log;
  147. auto g = [](std::vector<Real> const & x)->Real
  148. {
  149. // The first term is singular at x = 0.
  150. // The second at x = 1:
  151. return pow(log(1.0/x[0]), 2) + log1p(-x[0]);
  152. };
  153. vector<pair<Real, Real>> bounds{{Real(0), Real(1)}};
  154. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.01, true, 1, 1922);
  155. auto task = mc.integrate();
  156. double y = task.get();
  157. BOOST_CHECK_CLOSE_FRACTION(y, 1.0, 0.1);
  158. }
  159. template<class Real>
  160. void test_multithreaded_variance()
  161. {
  162. std::cout << "Testing that variance computed by naive Monte-Carlo integration converges to integral formula on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  163. Real exact_variance = (Real) 1/(Real) 12;
  164. auto g = [&](std::vector<Real> const & x)->Real
  165. {
  166. return x[0];
  167. };
  168. vector<pair<Real, Real>> bounds{{ Real(0), Real(1)}};
  169. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, false, 2, 12341);
  170. auto task = mc.integrate();
  171. Real y = task.get();
  172. BOOST_CHECK_CLOSE_FRACTION(y, 0.5, 0.01);
  173. BOOST_CHECK_CLOSE_FRACTION(mc.variance(), exact_variance, 0.05);
  174. }
  175. template<class Real>
  176. void test_variance()
  177. {
  178. std::cout << "Testing that variance computed by naive Monte-Carlo integration converges to integral formula on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  179. Real exact_variance = (Real) 1/(Real) 12;
  180. auto g = [&](std::vector<Real> const & x)->Real
  181. {
  182. return x[0];
  183. };
  184. vector<pair<Real, Real>> bounds{{ Real(0), Real(1)}};
  185. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, false, 1, 12341);
  186. auto task = mc.integrate();
  187. Real y = task.get();
  188. BOOST_CHECK_CLOSE_FRACTION(y, 0.5, 0.01);
  189. BOOST_CHECK_CLOSE_FRACTION(mc.variance(), exact_variance, 0.05);
  190. }
  191. template<class Real, uint64_t dimension>
  192. void test_product()
  193. {
  194. std::cout << "Testing that product functions are integrated correctly by naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  195. auto g = [&](std::vector<Real> const & x)->Real
  196. {
  197. double y = 1;
  198. for (uint64_t i = 0; i < x.size(); ++i)
  199. {
  200. y *= 2*x[i];
  201. }
  202. return y;
  203. };
  204. vector<pair<Real, Real>> bounds(dimension);
  205. for (uint64_t i = 0; i < dimension; ++i)
  206. {
  207. bounds[i] = std::make_pair<Real, Real>(0, 1);
  208. }
  209. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, false, 1, 13999);
  210. auto task = mc.integrate();
  211. Real y = task.get();
  212. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  213. using std::pow;
  214. Real exact_variance = pow(4.0/3.0, dimension) - 1;
  215. BOOST_CHECK_CLOSE_FRACTION(mc.variance(), exact_variance, 0.1);
  216. }
  217. template<class Real, uint64_t dimension>
  218. void test_alternative_rng_1()
  219. {
  220. std::cout << "Testing that alternative RNGs work correctly using naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  221. auto g = [&](std::vector<Real> const & x)->Real
  222. {
  223. double y = 1;
  224. for (uint64_t i = 0; i < x.size(); ++i)
  225. {
  226. y *= 2*x[i];
  227. }
  228. return y;
  229. };
  230. vector<pair<Real, Real>> bounds(dimension);
  231. for (uint64_t i = 0; i < dimension; ++i)
  232. {
  233. bounds[i] = std::make_pair<Real, Real>(0, 1);
  234. }
  235. std::cout << "Testing std::mt19937" << std::endl;
  236. naive_monte_carlo<Real, decltype(g), std::mt19937> mc1(g, bounds, (Real) 0.001, false, 1, 1882);
  237. auto task = mc1.integrate();
  238. Real y = task.get();
  239. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  240. using std::pow;
  241. Real exact_variance = pow(4.0/3.0, dimension) - 1;
  242. BOOST_CHECK_CLOSE_FRACTION(mc1.variance(), exact_variance, 0.05);
  243. std::cout << "Testing std::knuth_b" << std::endl;
  244. naive_monte_carlo<Real, decltype(g), std::knuth_b> mc2(g, bounds, (Real) 0.001, false, 1, 1883);
  245. task = mc2.integrate();
  246. y = task.get();
  247. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  248. std::cout << "Testing std::ranlux48" << std::endl;
  249. naive_monte_carlo<Real, decltype(g), std::ranlux48> mc3(g, bounds, (Real) 0.001, false, 1, 1884);
  250. task = mc3.integrate();
  251. y = task.get();
  252. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  253. }
  254. template<class Real, uint64_t dimension>
  255. void test_alternative_rng_2()
  256. {
  257. std::cout << "Testing that alternative RNGs work correctly using naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  258. auto g = [&](std::vector<Real> const & x)->Real
  259. {
  260. double y = 1;
  261. for (uint64_t i = 0; i < x.size(); ++i)
  262. {
  263. y *= 2*x[i];
  264. }
  265. return y;
  266. };
  267. vector<pair<Real, Real>> bounds(dimension);
  268. for (uint64_t i = 0; i < dimension; ++i)
  269. {
  270. bounds[i] = std::make_pair<Real, Real>(0, 1);
  271. }
  272. std::cout << "Testing std::default_random_engine" << std::endl;
  273. naive_monte_carlo<Real, decltype(g), std::default_random_engine> mc4(g, bounds, (Real) 0.001, false, 1, 1884);
  274. auto task = mc4.integrate();
  275. Real y = task.get();
  276. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  277. std::cout << "Testing std::minstd_rand" << std::endl;
  278. naive_monte_carlo<Real, decltype(g), std::minstd_rand> mc5(g, bounds, (Real) 0.001, false, 1, 1887);
  279. task = mc5.integrate();
  280. y = task.get();
  281. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  282. std::cout << "Testing std::minstd_rand0" << std::endl;
  283. naive_monte_carlo<Real, decltype(g), std::minstd_rand0> mc6(g, bounds, (Real) 0.001, false, 1, 1889);
  284. task = mc6.integrate();
  285. y = task.get();
  286. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  287. }
  288. template<class Real>
  289. void test_upper_bound_infinite()
  290. {
  291. std::cout << "Testing that infinite upper bounds are integrated correctly by naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  292. auto g = [](std::vector<Real> const & x)->Real
  293. {
  294. return 1.0/(x[0]*x[0] + 1.0);
  295. };
  296. vector<pair<Real, Real>> bounds(1);
  297. for (uint64_t i = 0; i < bounds.size(); ++i)
  298. {
  299. bounds[i] = std::make_pair<Real, Real>(0, std::numeric_limits<Real>::infinity());
  300. }
  301. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, true, 1, 8765);
  302. auto task = mc.integrate();
  303. Real y = task.get();
  304. BOOST_CHECK_CLOSE_FRACTION(y, boost::math::constants::half_pi<Real>(), 0.01);
  305. }
  306. template<class Real>
  307. void test_lower_bound_infinite()
  308. {
  309. std::cout << "Testing that infinite lower bounds are integrated correctly by naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  310. auto g = [](std::vector<Real> const & x)->Real
  311. {
  312. return 1.0/(x[0]*x[0] + 1.0);
  313. };
  314. vector<pair<Real, Real>> bounds(1);
  315. for (uint64_t i = 0; i < bounds.size(); ++i)
  316. {
  317. bounds[i] = std::make_pair<Real, Real>(-std::numeric_limits<Real>::infinity(), 0);
  318. }
  319. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, true, 1, 1208);
  320. auto task = mc.integrate();
  321. Real y = task.get();
  322. BOOST_CHECK_CLOSE_FRACTION(y, boost::math::constants::half_pi<Real>(), 0.01);
  323. }
  324. template<class Real>
  325. void test_lower_bound_infinite2()
  326. {
  327. std::cout << "Testing that infinite lower bounds (2) are integrated correctly by naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  328. auto g = [](std::vector<Real> const & x)->Real
  329. {
  330. // If x[0] = inf, this should blow up:
  331. return (x[0]*x[0])/(x[0]*x[0]*x[0]*x[0] + 1.0);
  332. };
  333. vector<pair<Real, Real>> bounds(1);
  334. for (uint64_t i = 0; i < bounds.size(); ++i)
  335. {
  336. bounds[i] = std::make_pair<Real, Real>(-std::numeric_limits<Real>::infinity(), 0);
  337. }
  338. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, true, 1, 1208);
  339. auto task = mc.integrate();
  340. Real y = task.get();
  341. BOOST_CHECK_CLOSE_FRACTION(y, boost::math::constants::half_pi<Real>()/boost::math::constants::root_two<Real>(), 0.01);
  342. }
  343. template<class Real>
  344. void test_double_infinite()
  345. {
  346. std::cout << "Testing that double infinite bounds are integrated correctly by naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  347. auto g = [](std::vector<Real> const & x)->Real
  348. {
  349. return 1.0/(x[0]*x[0] + 1.0);
  350. };
  351. vector<pair<Real, Real>> bounds(1);
  352. for (uint64_t i = 0; i < bounds.size(); ++i)
  353. {
  354. bounds[i] = std::make_pair<Real, Real>(-std::numeric_limits<Real>::infinity(), std::numeric_limits<Real>::infinity());
  355. }
  356. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, (Real) 0.001, true, 1, 1776);
  357. auto task = mc.integrate();
  358. Real y = task.get();
  359. BOOST_CHECK_CLOSE_FRACTION(y, boost::math::constants::pi<Real>(), 0.01);
  360. }
  361. template<class Real, uint64_t dimension>
  362. void test_radovic()
  363. {
  364. // See: Generalized Halton Sequences in 2008: A Comparative Study, function g1:
  365. std::cout << "Testing that the Radovic function is integrated correctly by naive Monte-Carlo on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  366. auto g = [](std::vector<Real> const & x)->Real
  367. {
  368. using std::abs;
  369. Real alpha = (Real)0.01;
  370. Real z = 1;
  371. for (uint64_t i = 0; i < dimension; ++i)
  372. {
  373. z *= (abs(4*x[i]-2) + alpha)/(1+alpha);
  374. }
  375. return z;
  376. };
  377. vector<pair<Real, Real>> bounds(dimension);
  378. for (uint64_t i = 0; i < bounds.size(); ++i)
  379. {
  380. bounds[i] = std::make_pair<Real, Real>(0, 1);
  381. }
  382. Real error_goal = (Real) 0.001;
  383. naive_monte_carlo<Real, decltype(g)> mc(g, bounds, error_goal, false, 1, 1982);
  384. auto task = mc.integrate();
  385. Real y = task.get();
  386. if (abs(y - 1) > 0.01)
  387. {
  388. std::cout << "Error in estimation of Radovic integral too high, function calls: " << mc.calls() << "\n";
  389. std::cout << "Final error estimate: " << mc.current_error_estimate() << std::endl;
  390. std::cout << "Error goal : " << error_goal << std::endl;
  391. std::cout << "Variance estimate : " << mc.variance() << std::endl;
  392. BOOST_CHECK_CLOSE_FRACTION(y, 1, 0.01);
  393. }
  394. }
  395. BOOST_AUTO_TEST_CASE(naive_monte_carlo_test)
  396. {
  397. std::cout << "Default hardware concurrency = " << std::thread::hardware_concurrency() << std::endl;
  398. #if !defined(TEST) || TEST == 1
  399. test_finite_singular_boundary<double>();
  400. test_finite_singular_boundary<float>();
  401. #endif
  402. #if !defined(TEST) || TEST == 2
  403. test_pi<float>();
  404. test_pi<double>();
  405. #endif
  406. #if !defined(TEST) || TEST == 3
  407. test_pi_multithreaded<float>();
  408. test_constant<float>();
  409. #endif
  410. //test_pi<long double>();
  411. #if !defined(TEST) || TEST == 4
  412. test_constant<double>();
  413. //test_constant<long double>();
  414. test_cancel_and_restart<float>();
  415. #endif
  416. #if !defined(TEST) || TEST == 5
  417. test_exception_from_integrand<float>();
  418. test_variance<float>();
  419. #endif
  420. #if !defined(TEST) || TEST == 6
  421. test_variance<double>();
  422. test_multithreaded_variance<double>();
  423. #endif
  424. #if !defined(TEST) || TEST == 7
  425. test_product<float, 1>();
  426. test_product<float, 2>();
  427. #endif
  428. #if !defined(TEST) || TEST == 8
  429. test_product<float, 3>();
  430. test_product<float, 4>();
  431. test_product<float, 5>();
  432. #endif
  433. #if !defined(TEST) || TEST == 9
  434. test_product<float, 6>();
  435. test_product<double, 1>();
  436. #endif
  437. #if !defined(TEST) || TEST == 10
  438. test_product<double, 2>();
  439. #endif
  440. #if !defined(TEST) || TEST == 11
  441. test_product<double, 3>();
  442. test_product<double, 4>();
  443. #endif
  444. #if !defined(TEST) || TEST == 12
  445. test_upper_bound_infinite<float>();
  446. test_upper_bound_infinite<double>();
  447. #endif
  448. #if !defined(TEST) || TEST == 13
  449. test_lower_bound_infinite<float>();
  450. test_lower_bound_infinite<double>();
  451. #endif
  452. #if !defined(TEST) || TEST == 14
  453. test_lower_bound_infinite2<float>();
  454. #endif
  455. #if !defined(TEST) || TEST == 15
  456. test_double_infinite<float>();
  457. test_double_infinite<double>();
  458. #endif
  459. #if !defined(TEST) || TEST == 16
  460. test_radovic<float, 1>();
  461. test_radovic<float, 2>();
  462. #endif
  463. #if !defined(TEST) || TEST == 17
  464. test_radovic<float, 3>();
  465. test_radovic<double, 1>();
  466. #endif
  467. #if !defined(TEST) || TEST == 18
  468. test_radovic<double, 2>();
  469. test_radovic<double, 3>();
  470. #endif
  471. #if !defined(TEST) || TEST == 19
  472. test_radovic<double, 4>();
  473. test_radovic<double, 5>();
  474. #endif
  475. #if !defined(TEST) || TEST == 20
  476. test_alternative_rng_1<float, 3>();
  477. #endif
  478. #if !defined(TEST) || TEST == 21
  479. test_alternative_rng_1<double, 3>();
  480. #endif
  481. #if !defined(TEST) || TEST == 22
  482. test_alternative_rng_2<float, 3>();
  483. #endif
  484. #if !defined(TEST) || TEST == 23
  485. test_alternative_rng_2<double, 3>();
  486. #endif
  487. }