768 lines
23 KiB
C++
768 lines
23 KiB
C++
// (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/math/tools/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
|
|
#endif
|
|
|
|
namespace 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 = boost::math::get<N>(data);
|
|
s.push_back(val);
|
|
|
|
typedef boost::integral_constant<int, N+1> next_value;
|
|
typedef boost::integral_constant<bool, (boost::math::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, (boost::math::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>());
|
|
}
|
|
|
|
} // detail
|
|
|
|
template <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;
|
|
}
|
|
}
|
|
break;
|
|
case power_series:
|
|
{
|
|
BOOST_ASSERT(arg1.n1 < arg1.n2);
|
|
|
|
typedef float random_type;
|
|
typedef typename boost::mpl::if_<
|
|
::boost::is_floating_point<T>,
|
|
T, long double>::type power_type;
|
|
|
|
std::tr1::mt19937 rnd;
|
|
std::tr1::uniform_real<random_type> ur_a(1.0, 2.0);
|
|
std::tr1::variate_generator<std::tr1::mt19937, std::tr1::uniform_real<random_type> > gen(rnd, ur_a);
|
|
|
|
for(int power = arg1.n1; power <= arg1.n2; ++power)
|
|
{
|
|
random_type r = gen();
|
|
power_type p = ldexp(static_cast<power_type>(r), power);
|
|
points.insert(truncate_to_float(real_cast<float>(arg1.z1 + p)));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
BOOST_ASSERT(0 == "Invalid parameter_info object");
|
|
// Assert will fail if get here.
|
|
// Triggers warning 4130) // '==' : logical operation on address of string constant.
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prompt a user for information on a parameter range:
|
|
//
|
|
template <class T>
|
|
bool get_user_parameter_info(parameter_info<T>& info, const char* param_name)
|
|
{
|
|
#ifdef BOOST_MSVC
|
|
# pragma warning(push)
|
|
# pragma warning(disable: 4127)
|
|
#endif
|
|
std::string line;
|
|
do{
|
|
std::cout << "What kind of distribution do you require for parameter " << param_name << "?\n"
|
|
"Choices are:\n"
|
|
" r Random values in a half open range\n"
|
|
" p Evenly spaced periodic values in a half open range\n"
|
|
" e Exponential power series at a particular point: a + 2^b for some range of b\n"
|
|
"[Default=r]";
|
|
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
|
|
if(line == "r")
|
|
{
|
|
info.type = random_in_range;
|
|
break;
|
|
}
|
|
else if(line == "p")
|
|
{
|
|
info.type = periodic_in_range;
|
|
break;
|
|
}
|
|
else if(line == "e")
|
|
{
|
|
info.type = power_series;
|
|
break;
|
|
}
|
|
else if(line == "")
|
|
{
|
|
info.type = random_in_range;
|
|
break;
|
|
}
|
|
//
|
|
// Ooops, not a valid input....
|
|
//
|
|
std::cout << "Sorry don't recognise \"" << line << "\" as a valid input\n"
|
|
"do you want to try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "n")
|
|
return false;
|
|
else if(line == "y")
|
|
continue;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}while(true);
|
|
|
|
switch(info.type & ~dummy_param)
|
|
{
|
|
case random_in_range:
|
|
case periodic_in_range:
|
|
// get start and end points of range:
|
|
do{
|
|
std::cout << "Data will be in the half open range a <= x < b,\n"
|
|
"enter value for the start point fo the range [default=0]:";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "")
|
|
{
|
|
info.z1 = 0;
|
|
break;
|
|
}
|
|
try{
|
|
info.z1 = boost::lexical_cast<T>(line);
|
|
break;
|
|
}
|
|
catch(const boost::bad_lexical_cast&)
|
|
{
|
|
std::cout << "Sorry, that was not valid input, try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
}while(true);
|
|
do{
|
|
std::cout << "Enter value for the end point fo the range [default=1]:";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "")
|
|
{
|
|
info.z2 = 1;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
info.z2 = boost::lexical_cast<T>(line);
|
|
}
|
|
catch(const boost::bad_lexical_cast&)
|
|
{
|
|
std::cout << "Sorry, that was not valid input, try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
}
|
|
if(info.z1 >= info.z2)
|
|
{
|
|
std::cout << "The end point of the range was <= the start point\n"
|
|
"try a different value for the endpoint [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
break;
|
|
}while(true);
|
|
do{
|
|
// get the number of points:
|
|
std::cout << "How many data points do you want?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
try{
|
|
info.n1 = boost::lexical_cast<int>(line);
|
|
info.n2 = 0;
|
|
if(info.n1 <= 0)
|
|
{
|
|
std::cout << "The number of points should be > 0\n"
|
|
"try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
catch(const boost::bad_lexical_cast&)
|
|
{
|
|
std::cout << "Sorry, that was not valid input, try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
}while(true);
|
|
break;
|
|
case power_series:
|
|
// get start and end points of range:
|
|
info.z2 = 0;
|
|
do{
|
|
std::cout << "Data will be in the form a + r*2^b\n"
|
|
"for random value r,\n"
|
|
"enter value for the point a [default=0]:";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "")
|
|
{
|
|
info.z1 = 0;
|
|
break;
|
|
}
|
|
try{
|
|
info.z1 = boost::lexical_cast<T>(line);
|
|
break;
|
|
}
|
|
catch(const boost::bad_lexical_cast&)
|
|
{
|
|
std::cout << "Sorry, that was not valid input, try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
}while(true);
|
|
|
|
do{
|
|
std::cout << "Data will be in the form a + r*2^b\n"
|
|
"for random value r,\n"
|
|
"enter value for the starting exponent b:";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
try{
|
|
info.n1 = boost::lexical_cast<int>(line);
|
|
break;
|
|
}
|
|
catch(const boost::bad_lexical_cast&)
|
|
{
|
|
std::cout << "Sorry, that was not valid input, try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
}while(true);
|
|
|
|
do{
|
|
std::cout << "Data will be in the form a + r*2^b\n"
|
|
"for random value r,\n"
|
|
"enter value for the ending exponent b:";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
try{
|
|
info.n2 = boost::lexical_cast<int>(line);
|
|
break;
|
|
}
|
|
catch(const boost::bad_lexical_cast&)
|
|
{
|
|
std::cout << "Sorry, that was not valid input, try again [y/n]?";
|
|
std::getline(std::cin, line);
|
|
boost::algorithm::trim(line);
|
|
if(line == "y")
|
|
continue;
|
|
if(line == "n")
|
|
return false;
|
|
std::cout << "Sorry don't recognise that either, giving up...\n\n";
|
|
return false;
|
|
}
|
|
}while(true);
|
|
|
|
break;
|
|
default:
|
|
BOOST_ASSERT(0); // should never get here!!
|
|
}
|
|
|
|
return true;
|
|
#ifdef BOOST_MSVC
|
|
# pragma warning(pop)
|
|
#endif
|
|
}
|
|
|
|
template <class charT, class traits, class T>
|
|
inline std::basic_ostream<charT, traits>& write_csv(std::basic_ostream<charT, traits>& os,
|
|
const test_data<T>& data)
|
|
{
|
|
const charT defarg[] = { ',', ' ', '\0' };
|
|
return write_csv(os, data, defarg);
|
|
}
|
|
|
|
template <class charT, class traits, class T>
|
|
std::basic_ostream<charT, traits>& write_csv(std::basic_ostream<charT, traits>& os,
|
|
const test_data<T>& data,
|
|
const charT* separator)
|
|
{
|
|
typedef typename test_data<T>::const_iterator it_type;
|
|
typedef typename test_data<T>::value_type value_type;
|
|
typedef typename value_type::const_iterator value_type_iterator;
|
|
it_type a, b;
|
|
a = data.begin();
|
|
b = data.end();
|
|
while(a != b)
|
|
{
|
|
value_type_iterator x, y;
|
|
bool sep = false;
|
|
x = a->begin();
|
|
y = a->end();
|
|
while(x != y)
|
|
{
|
|
if(sep)
|
|
os << separator;
|
|
os << *x;
|
|
sep = true;
|
|
++x;
|
|
}
|
|
os << std::endl;
|
|
++a;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
template <class T>
|
|
std::ostream& write_code(std::ostream& os,
|
|
const test_data<T>& data,
|
|
const char* name)
|
|
{
|
|
typedef typename test_data<T>::const_iterator it_type;
|
|
typedef typename test_data<T>::value_type value_type;
|
|
typedef typename value_type::const_iterator value_type_iterator;
|
|
|
|
BOOST_ASSERT(os.good());
|
|
|
|
it_type a, b;
|
|
a = data.begin();
|
|
b = data.end();
|
|
if(a == b)
|
|
return os;
|
|
|
|
os << "#ifndef SC_\n# define SC_(x) static_cast<T>(BOOST_JOIN(x, L))\n#endif\n"
|
|
" static const boost::array<boost::array<T, "
|
|
<< a->size() << ">, " << data.size() << "> " << name << " = {{\n";
|
|
|
|
while(a != b)
|
|
{
|
|
if(a != data.begin())
|
|
os << ", \n";
|
|
|
|
value_type_iterator x, y;
|
|
x = a->begin();
|
|
y = a->end();
|
|
os << " { ";
|
|
while(x != y)
|
|
{
|
|
if(x != a->begin())
|
|
os << ", ";
|
|
os << "SC_(" << *x << ")";
|
|
++x;
|
|
}
|
|
os << " }";
|
|
++a;
|
|
}
|
|
os << "\n }};\n//#undef SC_\n\n";
|
|
return os;
|
|
}
|
|
|
|
} // namespace tools
|
|
} // namespace math
|
|
} // namespace boost
|
|
|
|
#ifdef BOOST_MSVC
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
|
|
#endif // BOOST_MATH_TOOLS_TEST_DATA_HPP
|
|
|
|
|