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
6 #ifndef BOOST_MATH_TOOLS_TEST_DATA_HPP
7 #define BOOST_MATH_TOOLS_TEST_DATA_HPP
8
9 #ifdef _MSC_VER
10 #pragma once
11 #endif
12
13 #include <boost/math/tools/config.hpp>
14 #include <boost/assert.hpp>
15 #ifdef BOOST_MSVC
16 # pragma warning(push)
17 # pragma warning(disable: 4127 4701 4512)
18 # pragma warning(disable: 4130) // '==' : logical operation on address of string constant.
19 #endif
20 #include <boost/algorithm/string/trim.hpp>
21 #include <boost/lexical_cast.hpp>
22 #ifdef BOOST_MSVC
23 #pragma warning(pop)
24 #endif
25 #include <boost/type_traits/is_floating_point.hpp>
26 #include <boost/type_traits/is_convertible.hpp>
27 #include <boost/type_traits/integral_constant.hpp>
28 #ifndef BOOST_NO_CXX11_HDR_RANDOM
29 #include <random>
30 namespace random_ns = std;
31 #else
32 #include <boost/random.hpp>
33 namespace random_ns = boost::random;
34 #endif
35 #include <boost/math/tools/tuple.hpp>
36 #include <boost/math/tools/real_cast.hpp>
37
38 #include <set>
39 #include <vector>
40 #include <iostream>
41
42 #ifdef BOOST_MSVC
43 # pragma warning(push)
44 # pragma warning(disable: 4130) // '==' : logical operation on address of string constant.
45 // Used as a warning with BOOST_ASSERT
46 #endif
47
48 namespace boost{ namespace math{ namespace tools{
49
50 enum parameter_type
51 {
52 random_in_range = 0,
53 periodic_in_range = 1,
54 power_series = 2,
55 single_value = 3,
56 plus_minus_value = 4,
57 dummy_param = 0x80
58 };
59
operator |(parameter_type a,parameter_type b)60 parameter_type operator | (parameter_type a, parameter_type b)
61 {
62 return static_cast<parameter_type>((int)a|(int)b);
63 }
operator |=(parameter_type & a,parameter_type b)64 parameter_type& operator |= (parameter_type& a, parameter_type b)
65 {
66 a = static_cast<parameter_type>(a|b);
67 return a;
68 }
69
70 //
71 // If type == random_in_range then
72 // z1 and r2 are the endpoints of the half open range and n1 is the number of points.
73 //
74 // If type == periodic_in_range then
75 // z1 and r2 are the endpoints of the half open range and n1 is the number of points.
76 //
77 // If type == power_series then
78 // n1 and n2 are the endpoints of the exponents (closed range) and z1 is the basis.
79 //
80 // If type == single_value then z1 contains the single value to add.
81 //
82 // If type == plus_minus_value then test at +-z1
83 //
84 // If type & dummy_param then this data is ignored and not stored in the output, it
85 // is passed to the generator function however which can do with it as it sees fit.
86 //
87 template <class T>
88 struct parameter_info
89 {
90 parameter_type type;
91 T z1, z2;
92 int n1, n2;
93 };
94
95 template <class T>
make_random_param(T start_range,T end_range,int n_points)96 inline parameter_info<T> make_random_param(T start_range, T end_range, int n_points)
97 {
98 parameter_info<T> result = { random_in_range, start_range, end_range, n_points, 0 };
99 return result;
100 }
101
102 template <class T>
make_periodic_param(T start_range,T end_range,int n_points)103 inline parameter_info<T> make_periodic_param(T start_range, T end_range, int n_points)
104 {
105 parameter_info<T> result = { periodic_in_range, start_range, end_range, n_points, 0 };
106 return result;
107 }
108
109 template <class T>
make_power_param(T basis,int start_exponent,int end_exponent)110 inline parameter_info<T> make_power_param(T basis, int start_exponent, int end_exponent)
111 {
112 parameter_info<T> result = { power_series, basis, 0, start_exponent, end_exponent };
113 return result;
114 }
115
116 template <class T>
make_single_param(T val)117 inline parameter_info<T> make_single_param(T val)
118 {
119 parameter_info<T> result = { single_value, val };
120 return result;
121 }
122
123 template <class T>
make_plus_minus_param(T val)124 inline parameter_info<T> make_plus_minus_param(T val)
125 {
126 parameter_info<T> result = { plus_minus_value, val };
127 return result;
128 }
129
130 namespace detail{
131
132 template <class Seq, class Item, int N>
unpack_and_append_tuple(Seq &,const Item &,const boost::integral_constant<int,N> &,const boost::false_type &)133 inline void unpack_and_append_tuple(Seq&,
134 const Item&,
135 const boost::integral_constant<int, N>&,
136 const boost::false_type&)
137 {
138 // termination condition nothing to do here
139 }
140
141 template <class Seq, class Item, int N>
unpack_and_append_tuple(Seq & s,const Item & data,const boost::integral_constant<int,N> &,const boost::true_type &)142 inline void unpack_and_append_tuple(Seq& s,
143 const Item& data,
144 const boost::integral_constant<int, N>&,
145 const boost::true_type&)
146 {
147 // extract the N'th element, append, and recurse:
148 typedef typename Seq::value_type value_type;
149 value_type val = boost::math::get<N>(data);
150 s.push_back(val);
151
152 typedef boost::integral_constant<int, N+1> next_value;
153 typedef boost::integral_constant<bool, (boost::math::tuple_size<Item>::value > N+1)> terminate;
154
155 unpack_and_append_tuple(s, data, next_value(), terminate());
156 }
157
158 template <class Seq, class Item>
unpack_and_append(Seq & s,const Item & data,const boost::true_type &)159 inline void unpack_and_append(Seq& s, const Item& data, const boost::true_type&)
160 {
161 s.push_back(data);
162 }
163
164 template <class Seq, class Item>
unpack_and_append(Seq & s,const Item & data,const boost::false_type &)165 inline void unpack_and_append(Seq& s, const Item& data, const boost::false_type&)
166 {
167 // Item had better be a tuple-like type or we've had it!!!!
168 typedef boost::integral_constant<int, 0> next_value;
169 typedef boost::integral_constant<bool, (boost::math::tuple_size<Item>::value > 0)> terminate;
170
171 unpack_and_append_tuple(s, data, next_value(), terminate());
172 }
173
174 template <class Seq, class Item>
unpack_and_append(Seq & s,const Item & data)175 inline void unpack_and_append(Seq& s, const Item& data)
176 {
177 typedef typename Seq::value_type value_type;
178 unpack_and_append(s, data, ::boost::is_convertible<Item, value_type>());
179 }
180
181 } // detail
182
183 template <class T>
184 class test_data
185 {
186 public:
187 typedef std::vector<T> row_type;
188 typedef row_type value_type;
189 private:
190 typedef std::set<row_type> container_type;
191 public:
192 typedef typename container_type::reference reference;
193 typedef typename container_type::const_reference const_reference;
194 typedef typename container_type::iterator iterator;
195 typedef typename container_type::const_iterator const_iterator;
196 typedef typename container_type::difference_type difference_type;
197 typedef typename container_type::size_type size_type;
198
199 // creation:
test_data()200 test_data(){}
201 template <class F>
test_data(F func,const parameter_info<T> & arg1)202 test_data(F func, const parameter_info<T>& arg1)
203 {
204 insert(func, arg1);
205 }
206
207 // insertion:
208 template <class F>
insert(F func,const parameter_info<T> & arg1)209 test_data& insert(F func, const parameter_info<T>& arg1)
210 {
211 // generate data for single argument functor F
212
213 typedef typename std::set<T>::const_iterator it_type;
214
215 std::set<T> points;
216 create_test_points(points, arg1);
217 it_type a = points.begin();
218 it_type b = points.end();
219 row_type row;
220 while(a != b)
221 {
222 if((arg1.type & dummy_param) == 0)
223 row.push_back(*a);
224 #ifndef BOOST_NO_EXCEPTIONS
225 try{
226 #endif
227 // domain_error exceptions from func are swallowed
228 // and this data point is ignored:
229 boost::math::tools::detail::unpack_and_append(row, func(*a));
230 m_data.insert(row);
231 #ifndef BOOST_NO_EXCEPTIONS
232 }
233 catch(const std::domain_error&){}
234 #endif
235 row.clear();
236 ++a;
237 }
238 return *this;
239 }
240
241 template <class F>
insert(F func,const parameter_info<T> & arg1,const parameter_info<T> & arg2)242 test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2)
243 {
244 // generate data for 2-argument functor F
245
246 typedef typename std::set<T>::const_iterator it_type;
247
248 std::set<T> points1, points2;
249 create_test_points(points1, arg1);
250 create_test_points(points2, arg2);
251 it_type a = points1.begin();
252 it_type b = points1.end();
253 row_type row;
254 while(a != b)
255 {
256 it_type c = points2.begin();
257 it_type d = points2.end();
258 while(c != d)
259 {
260 if((arg1.type & dummy_param) == 0)
261 row.push_back(*a);
262 if((arg2.type & dummy_param) == 0)
263 row.push_back(*c);
264 #ifndef BOOST_NO_EXCEPTIONS
265 try{
266 #endif
267 // domain_error exceptions from func are swallowed
268 // and this data point is ignored:
269 detail::unpack_and_append(row, func(*a, *c));
270 m_data.insert(row);
271 #ifndef BOOST_NO_EXCEPTIONS
272 }
273 catch(const std::domain_error&){}
274 #endif
275 row.clear();
276 ++c;
277 }
278 ++a;
279 }
280 return *this;
281 }
282
283 template <class F>
insert(F func,const parameter_info<T> & arg1,const parameter_info<T> & arg2,const parameter_info<T> & arg3)284 test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2, const parameter_info<T>& arg3)
285 {
286 // generate data for 3-argument functor F
287
288 typedef typename std::set<T>::const_iterator it_type;
289
290 std::set<T> points1, points2, points3;
291 create_test_points(points1, arg1);
292 create_test_points(points2, arg2);
293 create_test_points(points3, arg3);
294 it_type a = points1.begin();
295 it_type b = points1.end();
296 row_type row;
297 while(a != b)
298 {
299 it_type c = points2.begin();
300 it_type d = points2.end();
301 while(c != d)
302 {
303 it_type e = points3.begin();
304 it_type f = points3.end();
305 while(e != f)
306 {
307 if((arg1.type & dummy_param) == 0)
308 row.push_back(*a);
309 if((arg2.type & dummy_param) == 0)
310 row.push_back(*c);
311 if((arg3.type & dummy_param) == 0)
312 row.push_back(*e);
313 #ifndef BOOST_NO_EXCEPTIONS
314 try{
315 #endif
316 // domain_error exceptions from func are swallowed
317 // and this data point is ignored:
318 detail::unpack_and_append(row, func(*a, *c, *e));
319 m_data.insert(row);
320 #ifndef BOOST_NO_EXCEPTIONS
321 }
322 catch(const std::domain_error&){}
323 #endif
324 row.clear();
325 ++e;
326 }
327 ++c;
328 }
329 ++a;
330 }
331 return *this;
332 }
333
334 template <class F>
insert(F func,const parameter_info<T> & arg1,const parameter_info<T> & arg2,const parameter_info<T> & arg3,const parameter_info<T> & arg4)335 test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2, const parameter_info<T>& arg3, const parameter_info<T>& arg4)
336 {
337 // generate data for 4-argument functor F
338
339 typedef typename std::set<T>::const_iterator it_type;
340
341 std::set<T> points1, points2, points3, points4;
342 create_test_points(points1, arg1);
343 create_test_points(points2, arg2);
344 create_test_points(points3, arg3);
345 create_test_points(points4, arg4);
346 it_type a = points1.begin();
347 it_type b = points1.end();
348 row_type row;
349 while(a != b)
350 {
351 it_type c = points2.begin();
352 it_type d = points2.end();
353 while(c != d)
354 {
355 it_type e = points3.begin();
356 it_type f = points3.end();
357 while(e != f)
358 {
359 it_type g = points4.begin();
360 it_type h = points4.end();
361 while (g != h)
362 {
363 if ((arg1.type & dummy_param) == 0)
364 row.push_back(*a);
365 if ((arg2.type & dummy_param) == 0)
366 row.push_back(*c);
367 if ((arg3.type & dummy_param) == 0)
368 row.push_back(*e);
369 if ((arg4.type & dummy_param) == 0)
370 row.push_back(*g);
371 #ifndef BOOST_NO_EXCEPTIONS
372 try {
373 #endif
374 // domain_error exceptions from func are swallowed
375 // and this data point is ignored:
376 detail::unpack_and_append(row, func(*a, *c, *e, *g));
377 m_data.insert(row);
378 #ifndef BOOST_NO_EXCEPTIONS
379 }
380 catch (const std::domain_error&) {}
381 #endif
382 row.clear();
383 ++g;
384 }
385 ++e;
386 }
387 ++c;
388 }
389 ++a;
390 }
391 return *this;
392 }
393
394 template <class F>
insert(F func,const parameter_info<T> & arg1,const parameter_info<T> & arg2,const parameter_info<T> & arg3,const parameter_info<T> & arg4,const parameter_info<T> & arg5)395 test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2, const parameter_info<T>& arg3, const parameter_info<T>& arg4, const parameter_info<T>& arg5)
396 {
397 // generate data for 5-argument functor F
398
399 typedef typename std::set<T>::const_iterator it_type;
400
401 std::set<T> points1, points2, points3, points4, points5;
402 create_test_points(points1, arg1);
403 create_test_points(points2, arg2);
404 create_test_points(points3, arg3);
405 create_test_points(points4, arg4);
406 create_test_points(points5, arg5);
407 it_type a = points1.begin();
408 it_type b = points1.end();
409 row_type row;
410 while(a != b)
411 {
412 it_type c = points2.begin();
413 it_type d = points2.end();
414 while(c != d)
415 {
416 it_type e = points3.begin();
417 it_type f = points3.end();
418 while(e != f)
419 {
420 it_type g = points4.begin();
421 it_type h = points4.end();
422 while (g != h)
423 {
424 it_type i = points5.begin();
425 it_type j = points5.end();
426 while (i != j)
427 {
428 if ((arg1.type & dummy_param) == 0)
429 row.push_back(*a);
430 if ((arg2.type & dummy_param) == 0)
431 row.push_back(*c);
432 if ((arg3.type & dummy_param) == 0)
433 row.push_back(*e);
434 if ((arg4.type & dummy_param) == 0)
435 row.push_back(*g);
436 if ((arg5.type & dummy_param) == 0)
437 row.push_back(*i);
438 #ifndef BOOST_NO_EXCEPTIONS
439 try {
440 #endif
441 // domain_error exceptions from func are swallowed
442 // and this data point is ignored:
443 detail::unpack_and_append(row, func(*a, *c, *e, *g, *i));
444 m_data.insert(row);
445 #ifndef BOOST_NO_EXCEPTIONS
446 }
447 catch (const std::domain_error&) {}
448 #endif
449 row.clear();
450 ++i;
451 }
452 ++g;
453 }
454 ++e;
455 }
456 ++c;
457 }
458 ++a;
459 }
460 return *this;
461 }
462
clear()463 void clear(){ m_data.clear(); }
464
465 // access:
begin()466 iterator begin() { return m_data.begin(); }
end()467 iterator end() { return m_data.end(); }
begin() const468 const_iterator begin()const { return m_data.begin(); }
end() const469 const_iterator end()const { return m_data.end(); }
operator ==(const test_data & d) const470 bool operator==(const test_data& d)const{ return m_data == d.m_data; }
operator !=(const test_data & d) const471 bool operator!=(const test_data& d)const{ return m_data != d.m_data; }
swap(test_data & other)472 void swap(test_data& other){ m_data.swap(other.m_data); }
size() const473 size_type size()const{ return m_data.size(); }
max_size() const474 size_type max_size()const{ return m_data.max_size(); }
empty() const475 bool empty()const{ return m_data.empty(); }
476
operator <(const test_data & dat) const477 bool operator < (const test_data& dat)const{ return m_data < dat.m_data; }
operator <=(const test_data & dat) const478 bool operator <= (const test_data& dat)const{ return m_data <= dat.m_data; }
operator >(const test_data & dat) const479 bool operator > (const test_data& dat)const{ return m_data > dat.m_data; }
operator >=(const test_data & dat) const480 bool operator >= (const test_data& dat)const{ return m_data >= dat.m_data; }
481
482 private:
483 void create_test_points(std::set<T>& points, const parameter_info<T>& arg1);
484 std::set<row_type> m_data;
485
486 static float extern_val;
487 static float truncate_to_float(float const * pf);
truncate_to_float(float c)488 static float truncate_to_float(float c){ return truncate_to_float(&c); }
489 };
490
491 //
492 // This code exists to bemuse the compiler's optimizer and force a
493 // truncation to float-precision only:
494 //
495 template <class T>
truncate_to_float(float const * pf)496 inline float test_data<T>::truncate_to_float(float const * pf)
497 {
498 BOOST_MATH_STD_USING
499 int expon;
500 float f = floor(ldexp(frexp(*pf, &expon), 22));
501 f = ldexp(f, expon - 22);
502 return f;
503
504 //extern_val = *pf;
505 //return *pf;
506 }
507
508 template <class T>
509 float test_data<T>::extern_val = 0;
510
511 template <class T>
create_test_points(std::set<T> & points,const parameter_info<T> & arg1)512 void test_data<T>::create_test_points(std::set<T>& points, const parameter_info<T>& arg1)
513 {
514 BOOST_MATH_STD_USING
515 //
516 // Generate a set of test points as requested, try and generate points
517 // at only float precision: otherwise when testing float versions of functions
518 // there will be a rounding error in our input values which throws off the results
519 // (Garbage in garbage out etc).
520 //
521 switch(arg1.type & 0x7F)
522 {
523 case random_in_range:
524 {
525 BOOST_ASSERT(arg1.z1 < arg1.z2);
526 BOOST_ASSERT(arg1.n1 > 0);
527 typedef float random_type;
528
529 random_ns::mt19937 rnd;
530 random_ns::uniform_real_distribution<random_type> ur_a(real_cast<random_type>(arg1.z1), real_cast<random_type>(arg1.z2));
531
532 for(int i = 0; i < arg1.n1; ++i)
533 {
534 random_type r = ur_a(rnd);
535 points.insert(truncate_to_float(r));
536 }
537 }
538 break;
539 case periodic_in_range:
540 {
541 BOOST_ASSERT(arg1.z1 < arg1.z2);
542 BOOST_ASSERT(arg1.n1 > 0);
543 float interval = real_cast<float>((arg1.z2 - arg1.z1) / arg1.n1);
544 T val = arg1.z1;
545 while(val < arg1.z2)
546 {
547 points.insert(truncate_to_float(real_cast<float>(val)));
548 val += interval;
549 }
550 }
551 break;
552 case power_series:
553 {
554 BOOST_ASSERT(arg1.n1 < arg1.n2);
555
556 typedef float random_type;
557 typedef typename boost::mpl::if_<
558 ::boost::is_floating_point<T>,
559 T, long double>::type power_type;
560
561 random_ns::mt19937 rnd;
562 random_ns::uniform_real_distribution<random_type> ur_a(1.0, 2.0);
563
564 for(int power = arg1.n1; power <= arg1.n2; ++power)
565 {
566 random_type r = ur_a(rnd);
567 power_type p = ldexp(static_cast<power_type>(r), power);
568 points.insert(truncate_to_float(real_cast<float>(arg1.z1 + p)));
569 }
570 }
571 break;
572 case single_value:
573 {
574 points.insert(truncate_to_float(real_cast<float>(arg1.z1)));
575 break;
576 }
577 case plus_minus_value:
578 {
579 points.insert(truncate_to_float(real_cast<float>(arg1.z1)));
580 points.insert(truncate_to_float(-real_cast<float>(arg1.z1)));
581 break;
582 }
583 default:
584 BOOST_ASSERT(0 == "Invalid parameter_info object");
585 // Assert will fail if get here.
586 // Triggers warning 4130) // '==' : logical operation on address of string constant.
587 }
588 }
589
590 //
591 // Prompt a user for information on a parameter range:
592 //
593 template <class T>
get_user_parameter_info(parameter_info<T> & info,const char * param_name)594 bool get_user_parameter_info(parameter_info<T>& info, const char* param_name)
595 {
596 #ifdef BOOST_MSVC
597 # pragma warning(push)
598 # pragma warning(disable: 4127)
599 #endif
600 std::string line;
601 do{
602 std::cout << "What kind of distribution do you require for parameter " << param_name << "?\n"
603 "Choices are:\n"
604 " r Random values in a half open range\n"
605 " p Evenly spaced periodic values in a half open range\n"
606 " e Exponential power series at a particular point: a + 2^b for some range of b\n"
607 "[Default=r]";
608
609 std::getline(std::cin, line);
610 boost::algorithm::trim(line);
611
612 if(line == "r")
613 {
614 info.type = random_in_range;
615 break;
616 }
617 else if(line == "p")
618 {
619 info.type = periodic_in_range;
620 break;
621 }
622 else if(line == "e")
623 {
624 info.type = power_series;
625 break;
626 }
627 else if(line == "")
628 {
629 info.type = random_in_range;
630 break;
631 }
632 //
633 // Ooops, not a valid input....
634 //
635 std::cout << "Sorry don't recognise \"" << line << "\" as a valid input\n"
636 "do you want to try again [y/n]?";
637 std::getline(std::cin, line);
638 boost::algorithm::trim(line);
639 if(line == "n")
640 return false;
641 else if(line == "y")
642 continue;
643 std::cout << "Sorry don't recognise that either, giving up...\n\n";
644 return false;
645 }while(true);
646
647 switch(info.type & ~dummy_param)
648 {
649 case random_in_range:
650 case periodic_in_range:
651 // get start and end points of range:
652 do{
653 std::cout << "Data will be in the half open range a <= x < b,\n"
654 "enter value for the start point fo the range [default=0]:";
655 std::getline(std::cin, line);
656 boost::algorithm::trim(line);
657 if(line == "")
658 {
659 info.z1 = 0;
660 break;
661 }
662 #ifndef BOOST_NO_EXCEPTIONS
663 try{
664 #endif
665 info.z1 = boost::lexical_cast<T>(line);
666 break;
667 #ifndef BOOST_NO_EXCEPTIONS
668 }
669 catch(const boost::bad_lexical_cast&)
670 {
671 std::cout << "Sorry, that was not valid input, try again [y/n]?";
672 std::getline(std::cin, line);
673 boost::algorithm::trim(line);
674 if(line == "y")
675 continue;
676 if(line == "n")
677 return false;
678 std::cout << "Sorry don't recognise that either, giving up...\n\n";
679 return false;
680 }
681 #endif
682 }while(true);
683 do{
684 std::cout << "Enter value for the end point fo the range [default=1]:";
685 std::getline(std::cin, line);
686 boost::algorithm::trim(line);
687 if(line == "")
688 {
689 info.z2 = 1;
690 }
691 else
692 {
693 #ifndef BOOST_NO_EXCEPTIONS
694 try
695 {
696 #endif
697 info.z2 = boost::lexical_cast<T>(line);
698 #ifndef BOOST_NO_EXCEPTIONS
699 }
700 catch(const boost::bad_lexical_cast&)
701 {
702 std::cout << "Sorry, that was not valid input, try again [y/n]?";
703 std::getline(std::cin, line);
704 boost::algorithm::trim(line);
705 if(line == "y")
706 continue;
707 if(line == "n")
708 return false;
709 std::cout << "Sorry don't recognise that either, giving up...\n\n";
710 return false;
711 }
712 #endif
713 }
714 if(info.z1 >= info.z2)
715 {
716 std::cout << "The end point of the range was <= the start point\n"
717 "try a different value for the endpoint [y/n]?";
718 std::getline(std::cin, line);
719 boost::algorithm::trim(line);
720 if(line == "y")
721 continue;
722 if(line == "n")
723 return false;
724 std::cout << "Sorry don't recognise that either, giving up...\n\n";
725 return false;
726 }
727 break;
728 }while(true);
729 do{
730 // get the number of points:
731 std::cout << "How many data points do you want?";
732 std::getline(std::cin, line);
733 boost::algorithm::trim(line);
734 #ifndef BOOST_NO_EXCEPTIONS
735 try{
736 #endif
737 info.n1 = boost::lexical_cast<int>(line);
738 info.n2 = 0;
739 if(info.n1 <= 0)
740 {
741 std::cout << "The number of points should be > 0\n"
742 "try again [y/n]?";
743 std::getline(std::cin, line);
744 boost::algorithm::trim(line);
745 if(line == "y")
746 continue;
747 if(line == "n")
748 return false;
749 std::cout << "Sorry don't recognise that either, giving up...\n\n";
750 return false;
751 }
752 break;
753 #ifndef BOOST_NO_EXCEPTIONS
754 }
755 catch(const boost::bad_lexical_cast&)
756 {
757 std::cout << "Sorry, that was not valid input, try again [y/n]?";
758 std::getline(std::cin, line);
759 boost::algorithm::trim(line);
760 if(line == "y")
761 continue;
762 if(line == "n")
763 return false;
764 std::cout << "Sorry don't recognise that either, giving up...\n\n";
765 return false;
766 }
767 #endif
768 }while(true);
769 break;
770 case power_series:
771 // get start and end points of range:
772 info.z2 = 0;
773 do{
774 std::cout << "Data will be in the form a + r*2^b\n"
775 "for random value r,\n"
776 "enter value for the point a [default=0]:";
777 std::getline(std::cin, line);
778 boost::algorithm::trim(line);
779 if(line == "")
780 {
781 info.z1 = 0;
782 break;
783 }
784 #ifndef BOOST_NO_EXCEPTIONS
785 try{
786 #endif
787 info.z1 = boost::lexical_cast<T>(line);
788 break;
789 #ifndef BOOST_NO_EXCEPTIONS
790 }
791 catch(const boost::bad_lexical_cast&)
792 {
793 std::cout << "Sorry, that was not valid input, try again [y/n]?";
794 std::getline(std::cin, line);
795 boost::algorithm::trim(line);
796 if(line == "y")
797 continue;
798 if(line == "n")
799 return false;
800 std::cout << "Sorry don't recognise that either, giving up...\n\n";
801 return false;
802 }
803 #endif
804 }while(true);
805
806 do{
807 std::cout << "Data will be in the form a + r*2^b\n"
808 "for random value r,\n"
809 "enter value for the starting exponent b:";
810 std::getline(std::cin, line);
811 boost::algorithm::trim(line);
812 #ifndef BOOST_NO_EXCEPTIONS
813 try{
814 #endif
815 info.n1 = boost::lexical_cast<int>(line);
816 break;
817 #ifndef BOOST_NO_EXCEPTIONS
818 }
819 catch(const boost::bad_lexical_cast&)
820 {
821 std::cout << "Sorry, that was not valid input, try again [y/n]?";
822 std::getline(std::cin, line);
823 boost::algorithm::trim(line);
824 if(line == "y")
825 continue;
826 if(line == "n")
827 return false;
828 std::cout << "Sorry don't recognise that either, giving up...\n\n";
829 return false;
830 }
831 #endif
832 }while(true);
833
834 do{
835 std::cout << "Data will be in the form a + r*2^b\n"
836 "for random value r,\n"
837 "enter value for the ending exponent b:";
838 std::getline(std::cin, line);
839 boost::algorithm::trim(line);
840 #ifndef BOOST_NO_EXCEPTIONS
841 try{
842 #endif
843 info.n2 = boost::lexical_cast<int>(line);
844 break;
845 #ifndef BOOST_NO_EXCEPTIONS
846 }
847 catch(const boost::bad_lexical_cast&)
848 {
849 std::cout << "Sorry, that was not valid input, try again [y/n]?";
850 std::getline(std::cin, line);
851 boost::algorithm::trim(line);
852 if(line == "y")
853 continue;
854 if(line == "n")
855 return false;
856 std::cout << "Sorry don't recognise that either, giving up...\n\n";
857 return false;
858 }
859 #endif
860 }while(true);
861
862 break;
863 default:
864 BOOST_ASSERT(0); // should never get here!!
865 }
866
867 return true;
868 #ifdef BOOST_MSVC
869 # pragma warning(pop)
870 #endif
871 }
872
873 template <class charT, class traits, class T>
write_csv(std::basic_ostream<charT,traits> & os,const test_data<T> & data)874 inline std::basic_ostream<charT, traits>& write_csv(std::basic_ostream<charT, traits>& os,
875 const test_data<T>& data)
876 {
877 const charT defarg[] = { ',', ' ', '\0' };
878 return write_csv(os, data, defarg);
879 }
880
881 template <class charT, class traits, class T>
write_csv(std::basic_ostream<charT,traits> & os,const test_data<T> & data,const charT * separator)882 std::basic_ostream<charT, traits>& write_csv(std::basic_ostream<charT, traits>& os,
883 const test_data<T>& data,
884 const charT* separator)
885 {
886 typedef typename test_data<T>::const_iterator it_type;
887 typedef typename test_data<T>::value_type value_type;
888 typedef typename value_type::const_iterator value_type_iterator;
889 it_type a, b;
890 a = data.begin();
891 b = data.end();
892 while(a != b)
893 {
894 value_type_iterator x, y;
895 bool sep = false;
896 x = a->begin();
897 y = a->end();
898 while(x != y)
899 {
900 if(sep)
901 os << separator;
902 os << *x;
903 sep = true;
904 ++x;
905 }
906 os << std::endl;
907 ++a;
908 }
909 return os;
910 }
911
912 template <class T>
write_code(std::ostream & os,const test_data<T> & data,const char * name)913 std::ostream& write_code(std::ostream& os,
914 const test_data<T>& data,
915 const char* name)
916 {
917 typedef typename test_data<T>::const_iterator it_type;
918 typedef typename test_data<T>::value_type value_type;
919 typedef typename value_type::const_iterator value_type_iterator;
920
921 BOOST_ASSERT(os.good());
922
923 it_type a, b;
924 a = data.begin();
925 b = data.end();
926 if(a == b)
927 return os;
928
929 os << "#ifndef SC_\n# define SC_(x) static_cast<T>(BOOST_JOIN(x, L))\n#endif\n"
930 " static const boost::array<boost::array<T, "
931 << a->size() << ">, " << data.size() << "> " << name << " = {{\n";
932
933 while(a != b)
934 {
935 if(a != data.begin())
936 os << ", \n";
937
938 value_type_iterator x, y;
939 x = a->begin();
940 y = a->end();
941 os << " { ";
942 while(x != y)
943 {
944 if(x != a->begin())
945 os << ", ";
946 os << "SC_(" << *x << ")";
947 ++x;
948 }
949 os << " }";
950 ++a;
951 }
952 os << "\n }};\n//#undef SC_\n\n";
953 return os;
954 }
955
956 } // namespace tools
957 } // namespace math
958 } // namespace boost
959
960 #ifdef BOOST_MSVC
961 #pragma warning(pop)
962 #endif
963
964
965 #endif // BOOST_MATH_TOOLS_TEST_DATA_HPP
966
967
968