test_data.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. // (C) Copyright John Maddock 2006.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_TOOLS_TEST_DATA_HPP
  6. #define BOOST_MATH_TOOLS_TEST_DATA_HPP
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <boost/math/tools/config.hpp>
  11. #include <boost/assert.hpp>
  12. #ifdef BOOST_MSVC
  13. # pragma warning(push)
  14. # pragma warning(disable: 4127 4701 4512)
  15. # pragma warning(disable: 4130) // '==' : logical operation on address of string constant.
  16. #endif
  17. #include <boost/algorithm/string/trim.hpp>
  18. #include <boost/lexical_cast.hpp>
  19. #ifdef BOOST_MSVC
  20. #pragma warning(pop)
  21. #endif
  22. #include <boost/type_traits/is_floating_point.hpp>
  23. #include <boost/type_traits/is_convertible.hpp>
  24. #include <boost/type_traits/integral_constant.hpp>
  25. #include <boost/tr1/random.hpp>
  26. #include <boost/math/tools/tuple.hpp>
  27. #include <boost/math/tools/real_cast.hpp>
  28. #include <set>
  29. #include <vector>
  30. #include <iostream>
  31. #ifdef BOOST_MSVC
  32. # pragma warning(push)
  33. # pragma warning(disable: 4130) // '==' : logical operation on address of string constant.
  34. // Used as a warning with BOOST_ASSERT
  35. #endif
  36. namespace boost{ namespace math{ namespace tools{
  37. enum parameter_type
  38. {
  39. random_in_range = 0,
  40. periodic_in_range = 1,
  41. power_series = 2,
  42. dummy_param = 0x80
  43. };
  44. parameter_type operator | (parameter_type a, parameter_type b)
  45. {
  46. return static_cast<parameter_type>((int)a|(int)b);
  47. }
  48. parameter_type& operator |= (parameter_type& a, parameter_type b)
  49. {
  50. a = static_cast<parameter_type>(a|b);
  51. return a;
  52. }
  53. //
  54. // If type == random_in_range then
  55. // z1 and r2 are the endpoints of the half open range and n1 is the number of points.
  56. //
  57. // If type == periodic_in_range then
  58. // z1 and r2 are the endpoints of the half open range and n1 is the number of points.
  59. //
  60. // If type == power_series then
  61. // n1 and n2 are the endpoints of the exponents (closed range) and z1 is the basis.
  62. //
  63. // If type & dummy_param then this data is ignored and not stored in the output, it
  64. // is passed to the generator function however which can do with it as it sees fit.
  65. //
  66. template <class T>
  67. struct parameter_info
  68. {
  69. parameter_type type;
  70. T z1, z2;
  71. int n1, n2;
  72. };
  73. template <class T>
  74. inline parameter_info<T> make_random_param(T start_range, T end_range, int n_points)
  75. {
  76. parameter_info<T> result = { random_in_range, start_range, end_range, n_points, 0 };
  77. return result;
  78. }
  79. template <class T>
  80. inline parameter_info<T> make_periodic_param(T start_range, T end_range, int n_points)
  81. {
  82. parameter_info<T> result = { periodic_in_range, start_range, end_range, n_points, 0 };
  83. return result;
  84. }
  85. template <class T>
  86. inline parameter_info<T> make_power_param(T basis, int start_exponent, int end_exponent)
  87. {
  88. parameter_info<T> result = { power_series, basis, 0, start_exponent, end_exponent };
  89. return result;
  90. }
  91. namespace detail{
  92. template <class Seq, class Item, int N>
  93. inline void unpack_and_append_tuple(Seq& s,
  94. const Item& data,
  95. const boost::integral_constant<int, N>&,
  96. const boost::false_type&)
  97. {
  98. // termimation condition nothing to do here
  99. }
  100. template <class Seq, class Item, int N>
  101. inline void unpack_and_append_tuple(Seq& s,
  102. const Item& data,
  103. const boost::integral_constant<int, N>&,
  104. const boost::true_type&)
  105. {
  106. // extract the N'th element, append, and recurse:
  107. typedef typename Seq::value_type value_type;
  108. value_type val = boost::math::get<N>(data);
  109. s.push_back(val);
  110. typedef boost::integral_constant<int, N+1> next_value;
  111. typedef boost::integral_constant<bool, (boost::math::tuple_size<Item>::value > N+1)> terminate;
  112. unpack_and_append_tuple(s, data, next_value(), terminate());
  113. }
  114. template <class Seq, class Item>
  115. inline void unpack_and_append(Seq& s, const Item& data, const boost::true_type&)
  116. {
  117. s.push_back(data);
  118. }
  119. template <class Seq, class Item>
  120. inline void unpack_and_append(Seq& s, const Item& data, const boost::false_type&)
  121. {
  122. // Item had better be a tuple-like type or we've had it!!!!
  123. typedef boost::integral_constant<int, 0> next_value;
  124. typedef boost::integral_constant<bool, (boost::math::tuple_size<Item>::value > 0)> terminate;
  125. unpack_and_append_tuple(s, data, next_value(), terminate());
  126. }
  127. template <class Seq, class Item>
  128. inline void unpack_and_append(Seq& s, const Item& data)
  129. {
  130. typedef typename Seq::value_type value_type;
  131. unpack_and_append(s, data, ::boost::is_convertible<Item, value_type>());
  132. }
  133. } // detail
  134. template <class T>
  135. class test_data
  136. {
  137. public:
  138. typedef std::vector<T> row_type;
  139. typedef row_type value_type;
  140. private:
  141. typedef std::set<row_type> container_type;
  142. public:
  143. typedef typename container_type::reference reference;
  144. typedef typename container_type::const_reference const_reference;
  145. typedef typename container_type::iterator iterator;
  146. typedef typename container_type::const_iterator const_iterator;
  147. typedef typename container_type::difference_type difference_type;
  148. typedef typename container_type::size_type size_type;
  149. // creation:
  150. test_data(){}
  151. template <class F>
  152. test_data(F func, const parameter_info<T>& arg1)
  153. {
  154. insert(func, arg1);
  155. }
  156. // insertion:
  157. template <class F>
  158. test_data& insert(F func, const parameter_info<T>& arg1)
  159. {
  160. // generate data for single argument functor F
  161. typedef typename std::set<T>::const_iterator it_type;
  162. std::set<T> points;
  163. create_test_points(points, arg1);
  164. it_type a = points.begin();
  165. it_type b = points.end();
  166. row_type row;
  167. while(a != b)
  168. {
  169. if((arg1.type & dummy_param) == 0)
  170. row.push_back(*a);
  171. try{
  172. // domain_error exceptions from func are swallowed
  173. // and this data point is ignored:
  174. boost::math::tools::detail::unpack_and_append(row, func(*a));
  175. m_data.insert(row);
  176. }
  177. catch(const std::domain_error&){}
  178. row.clear();
  179. ++a;
  180. }
  181. return *this;
  182. }
  183. template <class F>
  184. test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2)
  185. {
  186. // generate data for 2-argument functor F
  187. typedef typename std::set<T>::const_iterator it_type;
  188. std::set<T> points1, points2;
  189. create_test_points(points1, arg1);
  190. create_test_points(points2, arg2);
  191. it_type a = points1.begin();
  192. it_type b = points1.end();
  193. row_type row;
  194. while(a != b)
  195. {
  196. it_type c = points2.begin();
  197. it_type d = points2.end();
  198. while(c != d)
  199. {
  200. if((arg1.type & dummy_param) == 0)
  201. row.push_back(*a);
  202. if((arg2.type & dummy_param) == 0)
  203. row.push_back(*c);
  204. try{
  205. // domain_error exceptions from func are swallowed
  206. // and this data point is ignored:
  207. detail::unpack_and_append(row, func(*a, *c));
  208. m_data.insert(row);
  209. }
  210. catch(const std::domain_error&){}
  211. row.clear();
  212. ++c;
  213. }
  214. ++a;
  215. }
  216. return *this;
  217. }
  218. template <class F>
  219. test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2, const parameter_info<T>& arg3)
  220. {
  221. // generate data for 3-argument functor F
  222. typedef typename std::set<T>::const_iterator it_type;
  223. std::set<T> points1, points2, points3;
  224. create_test_points(points1, arg1);
  225. create_test_points(points2, arg2);
  226. create_test_points(points3, arg3);
  227. it_type a = points1.begin();
  228. it_type b = points1.end();
  229. row_type row;
  230. while(a != b)
  231. {
  232. it_type c = points2.begin();
  233. it_type d = points2.end();
  234. while(c != d)
  235. {
  236. it_type e = points3.begin();
  237. it_type f = points3.end();
  238. while(e != f)
  239. {
  240. if((arg1.type & dummy_param) == 0)
  241. row.push_back(*a);
  242. if((arg2.type & dummy_param) == 0)
  243. row.push_back(*c);
  244. if((arg3.type & dummy_param) == 0)
  245. row.push_back(*e);
  246. try{
  247. // domain_error exceptions from func are swallowed
  248. // and this data point is ignored:
  249. detail::unpack_and_append(row, func(*a, *c, *e));
  250. m_data.insert(row);
  251. }
  252. catch(const std::domain_error&){}
  253. row.clear();
  254. ++e;
  255. }
  256. ++c;
  257. }
  258. ++a;
  259. }
  260. return *this;
  261. }
  262. void clear(){ m_data.clear(); }
  263. // access:
  264. iterator begin() { return m_data.begin(); }
  265. iterator end() { return m_data.end(); }
  266. const_iterator begin()const { return m_data.begin(); }
  267. const_iterator end()const { return m_data.end(); }
  268. bool operator==(const test_data& d)const{ return m_data == d.m_data; }
  269. bool operator!=(const test_data& d)const{ return m_data != d.m_data; }
  270. void swap(test_data& other){ m_data.swap(other.m_data); }
  271. size_type size()const{ return m_data.size(); }
  272. size_type max_size()const{ return m_data.max_size(); }
  273. bool empty()const{ return m_data.empty(); }
  274. bool operator < (const test_data& dat)const{ return m_data < dat.m_data; }
  275. bool operator <= (const test_data& dat)const{ return m_data <= dat.m_data; }
  276. bool operator > (const test_data& dat)const{ return m_data > dat.m_data; }
  277. bool operator >= (const test_data& dat)const{ return m_data >= dat.m_data; }
  278. private:
  279. void create_test_points(std::set<T>& points, const parameter_info<T>& arg1);
  280. std::set<row_type> m_data;
  281. static float extern_val;
  282. static float truncate_to_float(float const * pf);
  283. static float truncate_to_float(float c){ return truncate_to_float(&c); }
  284. };
  285. //
  286. // This code exists to bemuse the compiler's optimizer and force a
  287. // truncation to float-precision only:
  288. //
  289. template <class T>
  290. inline float test_data<T>::truncate_to_float(float const * pf)
  291. {
  292. BOOST_MATH_STD_USING
  293. int expon;
  294. float f = floor(ldexp(frexp(*pf, &expon), 22));
  295. f = ldexp(f, expon - 22);
  296. return f;
  297. //extern_val = *pf;
  298. //return *pf;
  299. }
  300. template <class T>
  301. float test_data<T>::extern_val = 0;
  302. template <class T>
  303. void test_data<T>::create_test_points(std::set<T>& points, const parameter_info<T>& arg1)
  304. {
  305. BOOST_MATH_STD_USING
  306. //
  307. // Generate a set of test points as requested, try and generate points
  308. // at only float precision: otherwise when testing float versions of functions
  309. // there will be a rounding error in our input values which throws off the results
  310. // (Garbage in garbage out etc).
  311. //
  312. switch(arg1.type & 0x7F)
  313. {
  314. case random_in_range:
  315. {
  316. BOOST_ASSERT(arg1.z1 < arg1.z2);
  317. BOOST_ASSERT(arg1.n1 > 0);
  318. typedef float random_type;
  319. std::tr1::mt19937 rnd;
  320. std::tr1::uniform_real<random_type> ur_a(real_cast<random_type>(arg1.z1), real_cast<random_type>(arg1.z2));
  321. std::tr1::variate_generator<std::tr1::mt19937, std::tr1::uniform_real<random_type> > gen(rnd, ur_a);
  322. for(int i = 0; i < arg1.n1; ++i)
  323. {
  324. random_type r = gen();
  325. points.insert(truncate_to_float(r));
  326. }
  327. }
  328. break;
  329. case periodic_in_range:
  330. {
  331. BOOST_ASSERT(arg1.z1 < arg1.z2);
  332. BOOST_ASSERT(arg1.n1 > 0);
  333. float interval = real_cast<float>((arg1.z2 - arg1.z1) / arg1.n1);
  334. T val = arg1.z1;
  335. while(val < arg1.z2)
  336. {
  337. points.insert(truncate_to_float(real_cast<float>(val)));
  338. val += interval;
  339. }
  340. }
  341. break;
  342. case power_series:
  343. {
  344. BOOST_ASSERT(arg1.n1 < arg1.n2);
  345. typedef float random_type;
  346. typedef typename boost::mpl::if_<
  347. ::boost::is_floating_point<T>,
  348. T, long double>::type power_type;
  349. std::tr1::mt19937 rnd;
  350. std::tr1::uniform_real<random_type> ur_a(1.0, 2.0);
  351. std::tr1::variate_generator<std::tr1::mt19937, std::tr1::uniform_real<random_type> > gen(rnd, ur_a);
  352. for(int power = arg1.n1; power <= arg1.n2; ++power)
  353. {
  354. random_type r = gen();
  355. power_type p = ldexp(static_cast<power_type>(r), power);
  356. points.insert(truncate_to_float(real_cast<float>(arg1.z1 + p)));
  357. }
  358. }
  359. break;
  360. default:
  361. BOOST_ASSERT(0 == "Invalid parameter_info object");
  362. // Assert will fail if get here.
  363. // Triggers warning 4130) // '==' : logical operation on address of string constant.
  364. }
  365. }
  366. //
  367. // Prompt a user for information on a parameter range:
  368. //
  369. template <class T>
  370. bool get_user_parameter_info(parameter_info<T>& info, const char* param_name)
  371. {
  372. #ifdef BOOST_MSVC
  373. # pragma warning(push)
  374. # pragma warning(disable: 4127)
  375. #endif
  376. std::string line;
  377. do{
  378. std::cout << "What kind of distribution do you require for parameter " << param_name << "?\n"
  379. "Choices are:\n"
  380. " r Random values in a half open range\n"
  381. " p Evenly spaced periodic values in a half open range\n"
  382. " e Exponential power series at a particular point: a + 2^b for some range of b\n"
  383. "[Default=r]";
  384. std::getline(std::cin, line);
  385. boost::algorithm::trim(line);
  386. if(line == "r")
  387. {
  388. info.type = random_in_range;
  389. break;
  390. }
  391. else if(line == "p")
  392. {
  393. info.type = periodic_in_range;
  394. break;
  395. }
  396. else if(line == "e")
  397. {
  398. info.type = power_series;
  399. break;
  400. }
  401. else if(line == "")
  402. {
  403. info.type = random_in_range;
  404. break;
  405. }
  406. //
  407. // Ooops, not a valid input....
  408. //
  409. std::cout << "Sorry don't recognise \"" << line << "\" as a valid input\n"
  410. "do you want to try again [y/n]?";
  411. std::getline(std::cin, line);
  412. boost::algorithm::trim(line);
  413. if(line == "n")
  414. return false;
  415. else if(line == "y")
  416. continue;
  417. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  418. return false;
  419. }while(true);
  420. switch(info.type & ~dummy_param)
  421. {
  422. case random_in_range:
  423. case periodic_in_range:
  424. // get start and end points of range:
  425. do{
  426. std::cout << "Data will be in the half open range a <= x < b,\n"
  427. "enter value for the start point fo the range [default=0]:";
  428. std::getline(std::cin, line);
  429. boost::algorithm::trim(line);
  430. if(line == "")
  431. {
  432. info.z1 = 0;
  433. break;
  434. }
  435. try{
  436. info.z1 = boost::lexical_cast<T>(line);
  437. break;
  438. }
  439. catch(const boost::bad_lexical_cast&)
  440. {
  441. std::cout << "Sorry, that was not valid input, try again [y/n]?";
  442. std::getline(std::cin, line);
  443. boost::algorithm::trim(line);
  444. if(line == "y")
  445. continue;
  446. if(line == "n")
  447. return false;
  448. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  449. return false;
  450. }
  451. }while(true);
  452. do{
  453. std::cout << "Enter value for the end point fo the range [default=1]:";
  454. std::getline(std::cin, line);
  455. boost::algorithm::trim(line);
  456. if(line == "")
  457. {
  458. info.z2 = 1;
  459. }
  460. else
  461. {
  462. try
  463. {
  464. info.z2 = boost::lexical_cast<T>(line);
  465. }
  466. catch(const boost::bad_lexical_cast&)
  467. {
  468. std::cout << "Sorry, that was not valid input, try again [y/n]?";
  469. std::getline(std::cin, line);
  470. boost::algorithm::trim(line);
  471. if(line == "y")
  472. continue;
  473. if(line == "n")
  474. return false;
  475. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  476. return false;
  477. }
  478. }
  479. if(info.z1 >= info.z2)
  480. {
  481. std::cout << "The end point of the range was <= the start point\n"
  482. "try a different value for the endpoint [y/n]?";
  483. std::getline(std::cin, line);
  484. boost::algorithm::trim(line);
  485. if(line == "y")
  486. continue;
  487. if(line == "n")
  488. return false;
  489. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  490. return false;
  491. }
  492. break;
  493. }while(true);
  494. do{
  495. // get the number of points:
  496. std::cout << "How many data points do you want?";
  497. std::getline(std::cin, line);
  498. boost::algorithm::trim(line);
  499. try{
  500. info.n1 = boost::lexical_cast<int>(line);
  501. info.n2 = 0;
  502. if(info.n1 <= 0)
  503. {
  504. std::cout << "The number of points should be > 0\n"
  505. "try again [y/n]?";
  506. std::getline(std::cin, line);
  507. boost::algorithm::trim(line);
  508. if(line == "y")
  509. continue;
  510. if(line == "n")
  511. return false;
  512. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  513. return false;
  514. }
  515. break;
  516. }
  517. catch(const boost::bad_lexical_cast&)
  518. {
  519. std::cout << "Sorry, that was not valid input, try again [y/n]?";
  520. std::getline(std::cin, line);
  521. boost::algorithm::trim(line);
  522. if(line == "y")
  523. continue;
  524. if(line == "n")
  525. return false;
  526. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  527. return false;
  528. }
  529. }while(true);
  530. break;
  531. case power_series:
  532. // get start and end points of range:
  533. info.z2 = 0;
  534. do{
  535. std::cout << "Data will be in the form a + r*2^b\n"
  536. "for random value r,\n"
  537. "enter value for the point a [default=0]:";
  538. std::getline(std::cin, line);
  539. boost::algorithm::trim(line);
  540. if(line == "")
  541. {
  542. info.z1 = 0;
  543. break;
  544. }
  545. try{
  546. info.z1 = boost::lexical_cast<T>(line);
  547. break;
  548. }
  549. catch(const boost::bad_lexical_cast&)
  550. {
  551. std::cout << "Sorry, that was not valid input, try again [y/n]?";
  552. std::getline(std::cin, line);
  553. boost::algorithm::trim(line);
  554. if(line == "y")
  555. continue;
  556. if(line == "n")
  557. return false;
  558. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  559. return false;
  560. }
  561. }while(true);
  562. do{
  563. std::cout << "Data will be in the form a + r*2^b\n"
  564. "for random value r,\n"
  565. "enter value for the starting exponent b:";
  566. std::getline(std::cin, line);
  567. boost::algorithm::trim(line);
  568. try{
  569. info.n1 = boost::lexical_cast<int>(line);
  570. break;
  571. }
  572. catch(const boost::bad_lexical_cast&)
  573. {
  574. std::cout << "Sorry, that was not valid input, try again [y/n]?";
  575. std::getline(std::cin, line);
  576. boost::algorithm::trim(line);
  577. if(line == "y")
  578. continue;
  579. if(line == "n")
  580. return false;
  581. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  582. return false;
  583. }
  584. }while(true);
  585. do{
  586. std::cout << "Data will be in the form a + r*2^b\n"
  587. "for random value r,\n"
  588. "enter value for the ending exponent b:";
  589. std::getline(std::cin, line);
  590. boost::algorithm::trim(line);
  591. try{
  592. info.n2 = boost::lexical_cast<int>(line);
  593. break;
  594. }
  595. catch(const boost::bad_lexical_cast&)
  596. {
  597. std::cout << "Sorry, that was not valid input, try again [y/n]?";
  598. std::getline(std::cin, line);
  599. boost::algorithm::trim(line);
  600. if(line == "y")
  601. continue;
  602. if(line == "n")
  603. return false;
  604. std::cout << "Sorry don't recognise that either, giving up...\n\n";
  605. return false;
  606. }
  607. }while(true);
  608. break;
  609. default:
  610. BOOST_ASSERT(0); // should never get here!!
  611. }
  612. return true;
  613. #ifdef BOOST_MSVC
  614. # pragma warning(pop)
  615. #endif
  616. }
  617. template <class charT, class traits, class T>
  618. inline std::basic_ostream<charT, traits>& write_csv(std::basic_ostream<charT, traits>& os,
  619. const test_data<T>& data)
  620. {
  621. const charT defarg[] = { ',', ' ', '\0' };
  622. return write_csv(os, data, defarg);
  623. }
  624. template <class charT, class traits, class T>
  625. std::basic_ostream<charT, traits>& write_csv(std::basic_ostream<charT, traits>& os,
  626. const test_data<T>& data,
  627. const charT* separator)
  628. {
  629. typedef typename test_data<T>::const_iterator it_type;
  630. typedef typename test_data<T>::value_type value_type;
  631. typedef typename value_type::const_iterator value_type_iterator;
  632. it_type a, b;
  633. a = data.begin();
  634. b = data.end();
  635. while(a != b)
  636. {
  637. value_type_iterator x, y;
  638. bool sep = false;
  639. x = a->begin();
  640. y = a->end();
  641. while(x != y)
  642. {
  643. if(sep)
  644. os << separator;
  645. os << *x;
  646. sep = true;
  647. ++x;
  648. }
  649. os << std::endl;
  650. ++a;
  651. }
  652. return os;
  653. }
  654. template <class T>
  655. std::ostream& write_code(std::ostream& os,
  656. const test_data<T>& data,
  657. const char* name)
  658. {
  659. typedef typename test_data<T>::const_iterator it_type;
  660. typedef typename test_data<T>::value_type value_type;
  661. typedef typename value_type::const_iterator value_type_iterator;
  662. BOOST_ASSERT(os.good());
  663. it_type a, b;
  664. a = data.begin();
  665. b = data.end();
  666. if(a == b)
  667. return os;
  668. os << "#ifndef SC_\n# define SC_(x) static_cast<T>(BOOST_JOIN(x, L))\n#endif\n"
  669. " static const boost::array<boost::array<T, "
  670. << a->size() << ">, " << data.size() << "> " << name << " = {{\n";
  671. while(a != b)
  672. {
  673. if(a != data.begin())
  674. os << ", \n";
  675. value_type_iterator x, y;
  676. x = a->begin();
  677. y = a->end();
  678. os << " { ";
  679. while(x != y)
  680. {
  681. if(x != a->begin())
  682. os << ", ";
  683. os << "SC_(" << *x << ")";
  684. ++x;
  685. }
  686. os << " }";
  687. ++a;
  688. }
  689. os << "\n }};\n//#undef SC_\n\n";
  690. return os;
  691. }
  692. } // namespace tools
  693. } // namespace math
  694. } // namespace boost
  695. #ifdef BOOST_MSVC
  696. #pragma warning(pop)
  697. #endif
  698. #endif // BOOST_MATH_TOOLS_TEST_DATA_HPP