brintos

brintos / llvm-project-archived public Read only

0
0
Text · 28.2 KiB · 5e5faa2 Raw
968 lines · plain
1//  (C) Copyright John Maddock 2006.2//  Use, modification and distribution are subject to the3//  Boost Software License, Version 1.0. (See accompanying file4//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)5 6#ifndef BOOST_MATH_TOOLS_TEST_DATA_HPP7#define BOOST_MATH_TOOLS_TEST_DATA_HPP8 9#ifdef _MSC_VER10#pragma once11#endif12 13#include <boost/math/tools/config.hpp>14#include <boost/math/tools/assert.hpp>15#ifdef _MSC_VER16#  pragma warning(push)17#  pragma warning(disable: 4127 4701 4512)18#  pragma warning(disable: 4130) // '==' : logical operation on address of string constant.19#endif20#include <boost/algorithm/string/trim.hpp>21#include <boost/lexical_cast.hpp>22#ifdef _MSC_VER23#pragma warning(pop)24#endif25#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_RANDOM29#include <random>30namespace random_ns = std;31#else32#include <boost/random.hpp>33namespace random_ns = boost::random;34#endif35#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 _MSC_VER43#  pragma warning(push)44#  pragma warning(disable: 4130) // '==' : logical operation on address of string constant.45// Used as a warning with BOOST_MATH_ASSERT46#endif47 48namespace boost{ namespace math{ namespace tools{49 50enum parameter_type51{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 = 0x8058};59 60parameter_type operator | (parameter_type a, parameter_type b)61{62   return static_cast<parameter_type>((int)a|(int)b);63}64parameter_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 then72// 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 then75// z1 and r2 are the endpoints of the half open range and n1 is the number of points.76//77// If type == power_series then78// 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 +-z183//84// If type & dummy_param then this data is ignored and not stored in the output, it85// is passed to the generator function however which can do with it as it sees fit.86//87template <class T>88struct parameter_info89{90   parameter_type type;91   T z1, z2;92   int n1, n2;93};94 95template <class T>96inline 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 102template <class T>103inline 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 109template <class T>110inline 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 116template <class T>117inline parameter_info<T> make_single_param(T val)118{119   parameter_info<T> result = { single_value, val };120   return result;121}122 123template <class T>124inline parameter_info<T> make_plus_minus_param(T val)125{126   parameter_info<T> result = { plus_minus_value, val };127   return result;128}129 130namespace detail{131 132template <class Seq, class Item, int N>133inline void unpack_and_append_tuple(Seq&,134                                    const Item&,135                                    const std::integral_constant<int, N>&,136                                    const std::false_type&)137{138   // termination condition nothing to do here139}140 141template <class Seq, class Item, int N>142inline void unpack_and_append_tuple(Seq& s,143                                    const Item& data,144                                    const std::integral_constant<int, N>&,145                                    const std::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 std::integral_constant<int, N+1> next_value;153   typedef std::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 158template <class Seq, class Item>159inline void unpack_and_append(Seq& s, const Item& data, const std::true_type&)160{161   s.push_back(data);162}163 164template <class Seq, class Item>165inline void unpack_and_append(Seq& s, const Item& data, const std::false_type&)166{167   // Item had better be a tuple-like type or we've had it!!!!168   typedef std::integral_constant<int, 0> next_value;169   typedef std::integral_constant<bool, (boost::math::tuple_size<Item>::value > 0)> terminate;170 171   unpack_and_append_tuple(s, data, next_value(), terminate());172}173 174template <class Seq, class Item>175inline void unpack_and_append(Seq& s, const Item& data)176{177   typedef typename Seq::value_type value_type;178   unpack_and_append(s, data, ::std::is_convertible<Item, value_type>());179}180 181} // detail182 183template <class T>184class test_data185{186public:187   typedef std::vector<T> row_type;188   typedef row_type value_type;189private:190   typedef std::set<row_type> container_type;191public: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 F212 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_EXCEPTIONS225         try{226#endif227            // domain_error exceptions from func are swallowed228            // 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_EXCEPTIONS232         }233         catch(const std::domain_error&){}234#endif235         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 F245 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_EXCEPTIONS265            try{266#endif267               // domain_error exceptions from func are swallowed268               // and this data point is ignored:269               detail::unpack_and_append(row, func(*a, *c));270               m_data.insert(row);271#ifndef BOOST_NO_EXCEPTIONS272            }273            catch(const std::domain_error&){}274#endif275            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 F287 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_EXCEPTIONS314               try{315#endif316                  // domain_error exceptions from func are swallowed317                  // 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_EXCEPTIONS321               }322               catch(const std::domain_error&){}323#endif324               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 F338 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_EXCEPTIONS372                  try {373#endif374                     // domain_error exceptions from func are swallowed375                     // 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_EXCEPTIONS379                  }380                  catch (const std::domain_error&) {}381#endif382                  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 F398 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_EXCEPTIONS439                     try {440#endif441                        // domain_error exceptions from func are swallowed442                        // 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_EXCEPTIONS446                     }447                     catch (const std::domain_error&) {}448#endif449                     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 482private: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 a493// truncation to float-precision only:494//495template <class T>496inline float test_data<T>::truncate_to_float(float const * pf)497{498   BOOST_MATH_STD_USING499   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 508template <class T>509float test_data<T>::extern_val = 0;510 511template <class T>512void test_data<T>::create_test_points(std::set<T>& points, const parameter_info<T>& arg1)513{514   BOOST_MATH_STD_USING515   //516   // Generate a set of test points as requested, try and generate points517   // at only float precision: otherwise when testing float versions of functions518   // there will be a rounding error in our input values which throws off the results519   // (Garbage in garbage out etc).520   //521   switch(arg1.type & 0x7F)522   {523   case random_in_range:524      {525         BOOST_MATH_ASSERT(arg1.z1 < arg1.z2);526         BOOST_MATH_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_MATH_ASSERT(arg1.z1 < arg1.z2);542         BOOST_MATH_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_MATH_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_MATH_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//593template <class T>594bool get_user_parameter_info(parameter_info<T>& info, const char* param_name)595{596#ifdef _MSC_VER597#  pragma warning(push)598#  pragma warning(disable: 4127)599#endif600   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_EXCEPTIONS663         try{664#endif665            info.z1 = boost::lexical_cast<T>(line);666            break;667#ifndef BOOST_NO_EXCEPTIONS668         }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#endif682      }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         else692         {693#ifndef BOOST_NO_EXCEPTIONS694            try695            {696#endif697               info.z2 = boost::lexical_cast<T>(line);698#ifndef BOOST_NO_EXCEPTIONS699            }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#endif713         }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_EXCEPTIONS735         try{736#endif737            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_EXCEPTIONS754         }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#endif768      }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_EXCEPTIONS785         try{786#endif787            info.z1 = boost::lexical_cast<T>(line);788            break;789#ifndef BOOST_NO_EXCEPTIONS790         }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#endif804      }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_EXCEPTIONS813         try{814#endif815            info.n1 = boost::lexical_cast<int>(line);816            break;817#ifndef BOOST_NO_EXCEPTIONS818         }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#endif832      }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_EXCEPTIONS841         try{842#endif843            info.n2 = boost::lexical_cast<int>(line);844            break;845#ifndef BOOST_NO_EXCEPTIONS846         }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#endif860      }while(true);861 862      break;863   default:864      BOOST_MATH_ASSERT(0); // should never get here!!865   }866 867   return true;868#ifdef _MSC_VER869#  pragma warning(pop)870#endif871}872 873template <class charT, class traits, class T>874inline 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 881template <class charT, class traits, class T>882std::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 912template <class T>913std::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_MATH_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 std::array<std::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 tools957} // namespace math958} // namespace boost959 960#ifdef _MSC_VER961#pragma warning(pop)962#endif963 964 965#endif // BOOST_MATH_TOOLS_TEST_DATA_HPP966 967 968