test_data.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 768 行 · 第 1/2 页

HPP
768
字号
//  (C) Copyright John Maddock 2006.//  Use, modification and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_MATH_TOOLS_TEST_DATA_HPP#define BOOST_MATH_TOOLS_TEST_DATA_HPP#ifdef _MSC_VER#pragma once#endif#include <boost/math/tools/config.hpp>#include <boost/assert.hpp>#ifdef BOOST_MSVC#  pragma warning(push)#  pragma warning(disable: 4127 4701 4512)#  pragma warning(disable: 4130) // '==' : logical operation on address of string constant.#endif#include <boost/algorithm/string/trim.hpp>#include <boost/lexical_cast.hpp>#ifdef BOOST_MSVC#pragma warning(pop)#endif#include <boost/type_traits/is_floating_point.hpp>#include <boost/type_traits/is_convertible.hpp>#include <boost/type_traits/integral_constant.hpp>#include <boost/tr1/random.hpp>#include <boost/tr1/tuple.hpp>#include <boost/math/tools/real_cast.hpp>#include <set>#include <vector>#include <iostream>#ifdef BOOST_MSVC#  pragma warning(push)#  pragma warning(disable: 4130) // '==' : logical operation on address of string constant.// Used as a warning with BOOST_ASSERT#endifnamespace boost{ namespace math{ namespace tools{enum parameter_type{   random_in_range = 0,   periodic_in_range = 1,   power_series = 2,   dummy_param = 0x80};parameter_type operator | (parameter_type a, parameter_type b){   return static_cast<parameter_type>((int)a|(int)b);}parameter_type& operator |= (parameter_type& a, parameter_type b){   a = static_cast<parameter_type>(a|b);   return a;}//// If type == random_in_range then// z1 and r2 are the endpoints of the half open range and n1 is the number of points.//// If type == periodic_in_range then// z1 and r2 are the endpoints of the half open range and n1 is the number of points.//// If type == power_series then// n1 and n2 are the endpoints of the exponents (closed range) and z1 is the basis.//// If type & dummy_param then this data is ignored and not stored in the output, it// is passed to the generator function however which can do with it as it sees fit.//template <class T>struct parameter_info{   parameter_type type;   T z1, z2;   int n1, n2;};template <class T>inline parameter_info<T> make_random_param(T start_range, T end_range, int n_points){   parameter_info<T> result = { random_in_range, start_range, end_range, n_points, 0 };   return result;}template <class T>inline parameter_info<T> make_periodic_param(T start_range, T end_range, int n_points){   parameter_info<T> result = { periodic_in_range, start_range, end_range, n_points, 0 };   return result;}template <class T>inline parameter_info<T> make_power_param(T basis, int start_exponent, int end_exponent){   parameter_info<T> result = { power_series, basis, 0, start_exponent, end_exponent };   return result;}namespace detail{template <class Seq, class Item, int N>inline void unpack_and_append_tuple(Seq& s,                                    const Item& data,                                    const boost::integral_constant<int, N>&,                                    const boost::false_type&){   // termimation condition nothing to do here}template <class Seq, class Item, int N>inline void unpack_and_append_tuple(Seq& s,                                    const Item& data,                                    const boost::integral_constant<int, N>&,                                    const boost::true_type&){   // extract the N'th element, append, and recurse:   typedef typename Seq::value_type value_type;   value_type val = std::tr1::get<N>(data);   s.push_back(val);   typedef boost::integral_constant<int, N+1> next_value;   typedef boost::integral_constant<bool, (std::tr1::tuple_size<Item>::value > N+1)> terminate;   unpack_and_append_tuple(s, data, next_value(), terminate());}template <class Seq, class Item>inline void unpack_and_append(Seq& s, const Item& data, const boost::true_type&){   s.push_back(data);}template <class Seq, class Item>inline void unpack_and_append(Seq& s, const Item& data, const boost::false_type&){   // Item had better be a tuple-like type or we've had it!!!!   typedef boost::integral_constant<int, 0> next_value;   typedef boost::integral_constant<bool, (std::tr1::tuple_size<Item>::value > 0)> terminate;   unpack_and_append_tuple(s, data, next_value(), terminate());}template <class Seq, class Item>inline void unpack_and_append(Seq& s, const Item& data){   typedef typename Seq::value_type value_type;   unpack_and_append(s, data, ::boost::is_convertible<Item, value_type>());}} // detailtemplate <class T>class test_data{public:   typedef std::vector<T> row_type;   typedef row_type value_type;private:   typedef std::set<row_type> container_type;public:   typedef typename container_type::reference reference;   typedef typename container_type::const_reference const_reference;   typedef typename container_type::iterator iterator;   typedef typename container_type::const_iterator const_iterator;   typedef typename container_type::difference_type difference_type;   typedef typename container_type::size_type size_type;   // creation:   test_data(){}   template <class F>   test_data(F func, const parameter_info<T>& arg1)   {      insert(func, arg1);   }   // insertion:   template <class F>   test_data& insert(F func, const parameter_info<T>& arg1)   {      // generate data for single argument functor F      typedef typename std::set<T>::const_iterator it_type;      std::set<T> points;      create_test_points(points, arg1);      it_type a = points.begin();      it_type b = points.end();      row_type row;      while(a != b)      {         if((arg1.type & dummy_param) == 0)            row.push_back(*a);         try{            // domain_error exceptions from func are swallowed            // and this data point is ignored:            boost::math::tools::detail::unpack_and_append(row, func(*a));            m_data.insert(row);         }         catch(const std::domain_error&){}         row.clear();         ++a;      }      return *this;   }   template <class F>   test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2)   {      // generate data for 2-argument functor F      typedef typename std::set<T>::const_iterator it_type;      std::set<T> points1, points2;      create_test_points(points1, arg1);      create_test_points(points2, arg2);      it_type a = points1.begin();      it_type b = points1.end();      row_type row;      while(a != b)      {         it_type c = points2.begin();         it_type d = points2.end();         while(c != d)         {            if((arg1.type & dummy_param) == 0)               row.push_back(*a);            if((arg2.type & dummy_param) == 0)               row.push_back(*c);            try{               // domain_error exceptions from func are swallowed               // and this data point is ignored:               detail::unpack_and_append(row, func(*a, *c));               m_data.insert(row);            }            catch(const std::domain_error&){}            row.clear();            ++c;         }         ++a;      }      return *this;   }   template <class F>   test_data& insert(F func, const parameter_info<T>& arg1, const parameter_info<T>& arg2, const parameter_info<T>& arg3)   {      // generate data for 3-argument functor F      typedef typename std::set<T>::const_iterator it_type;      std::set<T> points1, points2, points3;      create_test_points(points1, arg1);      create_test_points(points2, arg2);      create_test_points(points3, arg3);      it_type a = points1.begin();      it_type b = points1.end();      row_type row;      while(a != b)      {         it_type c = points2.begin();         it_type d = points2.end();         while(c != d)         {            it_type e = points3.begin();            it_type f = points3.end();            while(e != f)            {               if((arg1.type & dummy_param) == 0)                  row.push_back(*a);               if((arg2.type & dummy_param) == 0)                  row.push_back(*c);               if((arg3.type & dummy_param) == 0)                  row.push_back(*e);               try{                  // domain_error exceptions from func are swallowed                  // and this data point is ignored:                  detail::unpack_and_append(row, func(*a, *c, *e));                  m_data.insert(row);               }               catch(const std::domain_error&){}               row.clear();               ++e;            }            ++c;         }         ++a;      }      return *this;   }   void clear(){ m_data.clear(); }   // access:   iterator begin() { return m_data.begin(); }   iterator end() { return m_data.end(); }   const_iterator begin()const { return m_data.begin(); }   const_iterator end()const { return m_data.end(); }   bool operator==(const test_data& d)const{ return m_data == d.m_data; }   bool operator!=(const test_data& d)const{ return m_data != d.m_data; }   void swap(test_data& other){ m_data.swap(other.m_data); }   size_type size()const{ return m_data.size(); }   size_type max_size()const{ return m_data.max_size(); }   bool empty()const{ return m_data.empty(); }   bool operator < (const test_data& dat)const{ return m_data < dat.m_data; }   bool operator <= (const test_data& dat)const{ return m_data <= dat.m_data; }   bool operator > (const test_data& dat)const{ return m_data > dat.m_data; }   bool operator >= (const test_data& dat)const{ return m_data >= dat.m_data; }private:   void create_test_points(std::set<T>& points, const parameter_info<T>& arg1);   std::set<row_type> m_data;   static float extern_val;   static float truncate_to_float(float const * pf);   static float truncate_to_float(float c){ return truncate_to_float(&c); }};//// This code exists to bemuse the compiler's optimizer and force a// truncation to float-precision only://template <class T>inline float test_data<T>::truncate_to_float(float const * pf){   BOOST_MATH_STD_USING   int expon;   float f = floor(ldexp(frexp(*pf, &expon), 22));   f = ldexp(f, expon - 22);   return f;   //extern_val = *pf;   //return *pf;}template <class T>float test_data<T>::extern_val = 0;template <class T>void test_data<T>::create_test_points(std::set<T>& points, const parameter_info<T>& arg1){   BOOST_MATH_STD_USING   //   // Generate a set of test points as requested, try and generate points   // at only float precision: otherwise when testing float versions of functions   // there will be a rounding error in our input values which throws off the results   // (Garbage in garbage out etc).   //   switch(arg1.type & 0x7F)   {   case random_in_range:      {         BOOST_ASSERT(arg1.z1 < arg1.z2);         BOOST_ASSERT(arg1.n1 > 0);         typedef float random_type;         std::tr1::mt19937 rnd;         std::tr1::uniform_real<random_type> ur_a(real_cast<random_type>(arg1.z1), real_cast<random_type>(arg1.z2));         std::tr1::variate_generator<std::tr1::mt19937, std::tr1::uniform_real<random_type> > gen(rnd, ur_a);         for(int i = 0; i < arg1.n1; ++i)         {            random_type r = gen();            points.insert(truncate_to_float(r));         }     }      break;   case periodic_in_range:      {         BOOST_ASSERT(arg1.z1 < arg1.z2);         BOOST_ASSERT(arg1.n1 > 0);         float interval = real_cast<float>((arg1.z2 - arg1.z1) / arg1.n1);         T val = arg1.z1;         while(val < arg1.z2)         {            points.insert(truncate_to_float(real_cast<float>(val)));            val += interval;         }      }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?