Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / math / include_private / boost / math / tools / test_data.hpp
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
60 parameter_type operator | (parameter_type a, parameter_type b)
61 {
62    return static_cast<parameter_type>((int)a|(int)b);
63 }
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>
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>
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>
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>
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>
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>
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    // termimation condition nothing to do here
139 }
140
141 template <class Seq, class Item, int N>
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>
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>
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>
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:
200    test_data(){}
201    template <class F>
202    test_data(F func, const parameter_info<T>& arg1)
203    {
204       insert(func, arg1);
205    }
206
207    // insertion:
208    template <class F>
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>
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>
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>
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>
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
463    void clear(){ m_data.clear(); }
464
465    // access:
466    iterator begin() { return m_data.begin(); }
467    iterator end() { return m_data.end(); }
468    const_iterator begin()const { return m_data.begin(); }
469    const_iterator end()const { return m_data.end(); }
470    bool operator==(const test_data& d)const{ return m_data == d.m_data; }
471    bool operator!=(const test_data& d)const{ return m_data != d.m_data; }
472    void swap(test_data& other){ m_data.swap(other.m_data); }
473    size_type size()const{ return m_data.size(); }
474    size_type max_size()const{ return m_data.max_size(); }
475    bool empty()const{ return m_data.empty(); }
476
477    bool operator < (const test_data& dat)const{ return m_data < dat.m_data; }
478    bool operator <= (const test_data& dat)const{ return m_data <= dat.m_data; }
479    bool operator > (const test_data& dat)const{ return m_data > dat.m_data; }
480    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);
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>
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>
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>
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>
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>
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>
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