stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,100 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_BERNOULLI_DISTRIBUTION_HPP
#define BOOST_COMPUTE_RANDOM_BERNOULLI_DISTRIBUTION_HPP
#include <boost/assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/function.hpp>
#include <boost/compute/types/fundamental.hpp>
#include <boost/compute/detail/iterator_range_size.hpp>
#include <boost/compute/detail/literal.hpp>
namespace boost {
namespace compute {
///
/// \class bernoulli_distribution
/// \brief Produces random boolean values according to the following
/// discrete probability function with parameter p :
/// P(true/p) = p and P(false/p) = (1 - p)
///
/// The following example shows how to setup a bernoulli distribution to
/// produce random boolean values with parameter p = 0.25
///
/// \snippet test/test_bernoulli_distribution.cpp generate
///
template<class RealType = float>
class bernoulli_distribution
{
public:
/// Creates a new bernoulli distribution
bernoulli_distribution(RealType p = 0.5f)
: m_p(p)
{
}
/// Destroys the bernoulli_distribution object
~bernoulli_distribution()
{
}
/// Returns the value of the parameter p
RealType p() const
{
return m_p;
}
/// Generates bernoulli distributed booleans and stores
/// them in the range [\p first, \p last).
template<class OutputIterator, class Generator>
void generate(OutputIterator first,
OutputIterator last,
Generator &generator,
command_queue &queue)
{
size_t count = detail::iterator_range_size(first, last);
vector<uint_> tmp(count, queue.get_context());
generator.generate(tmp.begin(), tmp.end(), queue);
BOOST_COMPUTE_FUNCTION(bool, scale_random, (const uint_ x),
{
return (convert_RealType(x) / MAX_RANDOM) < PARAM;
});
scale_random.define("PARAM", detail::make_literal(m_p));
scale_random.define("MAX_RANDOM", "UINT_MAX");
scale_random.define(
"convert_RealType", std::string("convert_") + type_name<RealType>()
);
transform(
tmp.begin(), tmp.end(), first, scale_random, queue
);
}
private:
RealType m_p;
BOOST_STATIC_ASSERT_MSG(
boost::is_floating_point<RealType>::value,
"Template argument must be a floating point type"
);
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_BERNOULLI_DISTRIBUTION_HPP
@@ -0,0 +1,24 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_DEFAULT_RANDOM_ENGINE_HPP
#define BOOST_COMPUTE_RANDOM_DEFAULT_RANDOM_ENGINE_HPP
#include <boost/compute/random/mersenne_twister_engine.hpp>
namespace boost {
namespace compute {
typedef mt19937 default_random_engine;
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_DEFAULT_RANDOM_ENGINE_HPP
@@ -0,0 +1,160 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP
#define BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP
#include <numeric>
#include <boost/config.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/function.hpp>
#include <boost/compute/algorithm/accumulate.hpp>
#include <boost/compute/algorithm/copy.hpp>
#include <boost/compute/algorithm/transform.hpp>
#include <boost/compute/detail/literal.hpp>
#include <boost/compute/types/fundamental.hpp>
namespace boost {
namespace compute {
/// \class discrete_distribution
/// \brief Produces random integers on the interval [0, n), where
/// probability of each integer is given by the weight of the ith
/// integer divided by the sum of all weights.
///
/// The following example shows how to setup a discrete distribution to
/// produce 0 and 1 with equal probability
///
/// \snippet test/test_discrete_distribution.cpp generate
///
template<class IntType = uint_>
class discrete_distribution
{
public:
typedef IntType result_type;
/// Creates a new discrete distribution with a single weight p = { 1 }.
/// This distribution produces only zeroes.
discrete_distribution()
: m_probabilities(1, double(1)),
m_scanned_probabilities(1, double(1))
{
}
/// Creates a new discrete distribution with weights given by
/// the range [\p first, \p last).
template<class InputIterator>
discrete_distribution(InputIterator first, InputIterator last)
: m_probabilities(first, last),
m_scanned_probabilities(std::distance(first, last))
{
if(first != last) {
// after this m_scanned_probabilities.back() is a sum of all
// weights from the range [first, last)
std::partial_sum(first, last, m_scanned_probabilities.begin());
std::vector<double>::iterator i = m_probabilities.begin();
std::vector<double>::iterator j = m_scanned_probabilities.begin();
for(; i != m_probabilities.end(); ++i, ++j)
{
// dividing each weight by sum of all weights to
// get probabilities
*i = *i / m_scanned_probabilities.back();
// dividing each partial sum of weights by sum of
// all weights to get partial sums of probabilities
*j = *j / m_scanned_probabilities.back();
}
}
else {
m_probabilities.push_back(double(1));
m_scanned_probabilities.push_back(double(1));
}
}
/// Destroys the discrete_distribution object.
~discrete_distribution()
{
}
/// Returns the probabilities
::std::vector<double> probabilities() const
{
return m_probabilities;
}
/// Returns the minimum potentially generated value.
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
{
return result_type(0);
}
/// Returns the maximum potentially generated value.
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
{
size_t type_max = static_cast<size_t>(
(std::numeric_limits<result_type>::max)()
);
if(m_probabilities.size() - 1 > type_max) {
return (std::numeric_limits<result_type>::max)();
}
return static_cast<result_type>(m_probabilities.size() - 1);
}
/// Generates uniformly distributed integers and stores
/// them to the range [\p first, \p last).
template<class OutputIterator, class Generator>
void generate(OutputIterator first,
OutputIterator last,
Generator &generator,
command_queue &queue)
{
std::string source = "inline IntType scale_random(uint x)\n";
source = source +
"{\n" +
"float rno = convert_float(x) / UINT_MAX;\n";
for(size_t i = 0; i < m_scanned_probabilities.size() - 1; i++)
{
source = source +
"if(rno <= " + detail::make_literal<float>(m_scanned_probabilities[i]) + ")\n" +
" return " + detail::make_literal(i) + ";\n";
}
source = source +
"return " + detail::make_literal(m_scanned_probabilities.size() - 1) + ";\n" +
"}\n";
BOOST_COMPUTE_FUNCTION(IntType, scale_random, (const uint_ x), {});
scale_random.set_source(source);
scale_random.define("IntType", type_name<IntType>());
generator.generate(first, last, scale_random, queue);
}
private:
::std::vector<double> m_probabilities;
::std::vector<double> m_scanned_probabilities;
BOOST_STATIC_ASSERT_MSG(
boost::is_integral<IntType>::value,
"Template argument must be integral"
);
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
@@ -0,0 +1,238 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP
#define BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP
#include <algorithm>
#include <boost/compute/types.hpp>
#include <boost/compute/buffer.hpp>
#include <boost/compute/kernel.hpp>
#include <boost/compute/context.hpp>
#include <boost/compute/program.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/algorithm/transform.hpp>
#include <boost/compute/container/vector.hpp>
#include <boost/compute/detail/iterator_range_size.hpp>
#include <boost/compute/iterator/discard_iterator.hpp>
#include <boost/compute/utility/program_cache.hpp>
namespace boost {
namespace compute {
///
/// \class linear_congruential_engine
/// \brief 'Quick and Dirty' linear congruential engine
///
/// Quick and dirty linear congruential engine to generate low quality
/// random numbers very quickly. For uses in which good quality of random
/// numbers is required(Monte-Carlo Simulations), use other engines like
/// Mersenne Twister instead.
///
template<class T = uint_>
class linear_congruential_engine
{
public:
typedef T result_type;
static const T default_seed = 1;
static const T a = 1099087573;
static const size_t threads = 1024;
/// Creates a new linear_congruential_engine and seeds it with \p value.
explicit linear_congruential_engine(command_queue &queue,
result_type value = default_seed)
: m_context(queue.get_context()),
m_multiplicands(m_context, threads * sizeof(result_type))
{
// setup program
load_program();
// seed state
seed(value, queue);
// generate multiplicands
generate_multiplicands(queue);
}
/// Creates a new linear_congruential_engine object as a copy of \p other.
linear_congruential_engine(const linear_congruential_engine<T> &other)
: m_context(other.m_context),
m_program(other.m_program),
m_seed(other.m_seed),
m_multiplicands(other.m_multiplicands)
{
}
/// Copies \p other to \c *this.
linear_congruential_engine<T>&
operator=(const linear_congruential_engine<T> &other)
{
if(this != &other){
m_context = other.m_context;
m_program = other.m_program;
m_seed = other.m_seed;
m_multiplicands = other.m_multiplicands;
}
return *this;
}
/// Destroys the linear_congruential_engine object.
~linear_congruential_engine()
{
}
/// Seeds the random number generator with \p value.
///
/// \param value seed value for the random-number generator
/// \param queue command queue to perform the operation
///
/// If no seed value is provided, \c default_seed is used.
void seed(result_type value, command_queue &queue)
{
(void) queue;
m_seed = value;
}
/// \overload
void seed(command_queue &queue)
{
seed(default_seed, queue);
}
/// Generates random numbers and stores them to the range [\p first, \p last).
template<class OutputIterator>
void generate(OutputIterator first, OutputIterator last, command_queue &queue)
{
size_t size = detail::iterator_range_size(first, last);
kernel fill_kernel(m_program, "fill");
fill_kernel.set_arg(1, m_multiplicands);
fill_kernel.set_arg(2, first.get_buffer());
size_t offset = 0;
for(;;){
size_t count = 0;
if(size > threads){
count = (std::min)(static_cast<size_t>(threads), size - offset);
}
else {
count = size;
}
fill_kernel.set_arg(0, static_cast<const uint_>(m_seed));
fill_kernel.set_arg(3, static_cast<const uint_>(offset));
queue.enqueue_1d_range_kernel(fill_kernel, 0, count, 0);
offset += count;
if(offset >= size){
break;
}
update_seed(queue);
}
}
/// \internal_
void generate(discard_iterator first, discard_iterator last, command_queue &queue)
{
(void) queue;
size_t size = detail::iterator_range_size(first, last);
uint_ max_mult =
detail::read_single_value<T>(m_multiplicands, threads-1, queue);
while(size >= threads) {
m_seed *= max_mult;
size -= threads;
}
m_seed *=
detail::read_single_value<T>(m_multiplicands, size-1, queue);
}
/// Generates random numbers, transforms them with \p op, and then stores
/// them to the range [\p first, \p last).
template<class OutputIterator, class Function>
void generate(OutputIterator first, OutputIterator last, Function op, command_queue &queue)
{
vector<T> tmp(std::distance(first, last), queue.get_context());
generate(tmp.begin(), tmp.end(), queue);
transform(tmp.begin(), tmp.end(), first, op, queue);
}
/// Generates \p z random numbers and discards them.
void discard(size_t z, command_queue &queue)
{
generate(discard_iterator(0), discard_iterator(z), queue);
}
private:
/// \internal_
/// Generates the multiplicands for each thread
void generate_multiplicands(command_queue &queue)
{
kernel multiplicand_kernel =
m_program.create_kernel("multiplicand");
multiplicand_kernel.set_arg(0, m_multiplicands);
queue.enqueue_task(multiplicand_kernel);
}
/// \internal_
void update_seed(command_queue &queue)
{
m_seed *=
detail::read_single_value<T>(m_multiplicands, threads-1, queue);
}
/// \internal_
void load_program()
{
boost::shared_ptr<program_cache> cache =
program_cache::get_global_cache(m_context);
std::string cache_key =
std::string("__boost_linear_congruential_engine_") + type_name<T>();
const char source[] =
"__kernel void multiplicand(__global uint *multiplicands)\n"
"{\n"
" uint a = 1099087573;\n"
" multiplicands[0] = a;\n"
" for(uint i = 1; i < 1024; i++){\n"
" multiplicands[i] = a * multiplicands[i-1];\n"
" }\n"
"}\n"
"__kernel void fill(const uint seed,\n"
" __global uint *multiplicands,\n"
" __global uint *result,"
" const uint offset)\n"
"{\n"
" const uint i = get_global_id(0);\n"
" result[offset+i] = seed * multiplicands[i];\n"
"}\n";
m_program = cache->get_or_build(cache_key, std::string(), source, m_context);
}
private:
context m_context;
program m_program;
T m_seed;
buffer m_multiplicands;
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP
@@ -0,0 +1,254 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_MERSENNE_TWISTER_ENGINE_HPP
#define BOOST_COMPUTE_RANDOM_MERSENNE_TWISTER_ENGINE_HPP
#include <algorithm>
#include <boost/compute/types.hpp>
#include <boost/compute/buffer.hpp>
#include <boost/compute/kernel.hpp>
#include <boost/compute/context.hpp>
#include <boost/compute/program.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/algorithm/transform.hpp>
#include <boost/compute/container/vector.hpp>
#include <boost/compute/detail/iterator_range_size.hpp>
#include <boost/compute/iterator/discard_iterator.hpp>
#include <boost/compute/utility/program_cache.hpp>
namespace boost {
namespace compute {
/// \class mersenne_twister_engine
/// \brief Mersenne twister pseudorandom number generator.
template<class T>
class mersenne_twister_engine
{
public:
typedef T result_type;
static const T default_seed = 5489U;
static const T n = 624;
static const T m = 397;
/// Creates a new mersenne_twister_engine and seeds it with \p value.
explicit mersenne_twister_engine(command_queue &queue,
result_type value = default_seed)
: m_context(queue.get_context()),
m_state_buffer(m_context, n * sizeof(result_type))
{
// setup program
load_program();
// seed state
seed(value, queue);
}
/// Creates a new mersenne_twister_engine object as a copy of \p other.
mersenne_twister_engine(const mersenne_twister_engine<T> &other)
: m_context(other.m_context),
m_state_index(other.m_state_index),
m_program(other.m_program),
m_state_buffer(other.m_state_buffer)
{
}
/// Copies \p other to \c *this.
mersenne_twister_engine<T>& operator=(const mersenne_twister_engine<T> &other)
{
if(this != &other){
m_context = other.m_context;
m_state_index = other.m_state_index;
m_program = other.m_program;
m_state_buffer = other.m_state_buffer;
}
return *this;
}
/// Destroys the mersenne_twister_engine object.
~mersenne_twister_engine()
{
}
/// Seeds the random number generator with \p value.
///
/// \param value seed value for the random-number generator
/// \param queue command queue to perform the operation
///
/// If no seed value is provided, \c default_seed is used.
void seed(result_type value, command_queue &queue)
{
kernel seed_kernel = m_program.create_kernel("seed");
seed_kernel.set_arg(0, value);
seed_kernel.set_arg(1, m_state_buffer);
queue.enqueue_task(seed_kernel);
m_state_index = 0;
}
/// \overload
void seed(command_queue &queue)
{
seed(default_seed, queue);
}
/// Generates random numbers and stores them to the range [\p first, \p last).
template<class OutputIterator>
void generate(OutputIterator first, OutputIterator last, command_queue &queue)
{
const size_t size = detail::iterator_range_size(first, last);
kernel fill_kernel(m_program, "fill");
fill_kernel.set_arg(0, m_state_buffer);
fill_kernel.set_arg(2, first.get_buffer());
size_t offset = 0;
size_t &p = m_state_index;
for(;;){
size_t count = 0;
if(size > n){
count = (std::min)(static_cast<size_t>(n), size - offset);
}
else {
count = size;
}
fill_kernel.set_arg(1, static_cast<const uint_>(p));
fill_kernel.set_arg(3, static_cast<const uint_>(offset));
queue.enqueue_1d_range_kernel(fill_kernel, 0, count, 0);
p += count;
offset += count;
if(offset >= size){
break;
}
generate_state(queue);
p = 0;
}
}
/// \internal_
void generate(discard_iterator first, discard_iterator last, command_queue &queue)
{
(void) queue;
m_state_index += std::distance(first, last);
}
/// Generates random numbers, transforms them with \p op, and then stores
/// them to the range [\p first, \p last).
template<class OutputIterator, class Function>
void generate(OutputIterator first, OutputIterator last, Function op, command_queue &queue)
{
vector<T> tmp(std::distance(first, last), queue.get_context());
generate(tmp.begin(), tmp.end(), queue);
transform(tmp.begin(), tmp.end(), first, op, queue);
}
/// Generates \p z random numbers and discards them.
void discard(size_t z, command_queue &queue)
{
generate(discard_iterator(0), discard_iterator(z), queue);
}
/// \internal_ (deprecated)
template<class OutputIterator>
void fill(OutputIterator first, OutputIterator last, command_queue &queue)
{
generate(first, last, queue);
}
private:
/// \internal_
void generate_state(command_queue &queue)
{
kernel generate_state_kernel =
m_program.create_kernel("generate_state");
generate_state_kernel.set_arg(0, m_state_buffer);
queue.enqueue_task(generate_state_kernel);
}
/// \internal_
void load_program()
{
boost::shared_ptr<program_cache> cache =
program_cache::get_global_cache(m_context);
std::string cache_key =
std::string("__boost_mersenne_twister_engine_") + type_name<T>();
const char source[] =
"static uint twiddle(uint u, uint v)\n"
"{\n"
" return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1) ^\n"
" ((v & 1U) ? 0x9908B0DFU : 0x0U);\n"
"}\n"
"__kernel void generate_state(__global uint *state)\n"
"{\n"
" const uint n = 624;\n"
" const uint m = 397;\n"
" for(uint i = 0; i < (n - m); i++)\n"
" state[i] = state[i+m] ^ twiddle(state[i], state[i+1]);\n"
" for(uint i = n - m; i < (n - 1); i++)\n"
" state[i] = state[i+m-n] ^ twiddle(state[i], state[i+1]);\n"
" state[n-1] = state[m-1] ^ twiddle(state[n-1], state[0]);\n"
"}\n"
"__kernel void seed(const uint s, __global uint *state)\n"
"{\n"
" const uint n = 624;\n"
" state[0] = s & 0xFFFFFFFFU;\n"
" for(uint i = 1; i < n; i++){\n"
" state[i] = 1812433253U * (state[i-1] ^ (state[i-1] >> 30)) + i;\n"
" state[i] &= 0xFFFFFFFFU;\n"
" }\n"
" generate_state(state);\n"
"}\n"
"static uint random_number(__global uint *state, const uint p)\n"
"{\n"
" uint x = state[p];\n"
" x ^= (x >> 11);\n"
" x ^= (x << 7) & 0x9D2C5680U;\n"
" x ^= (x << 15) & 0xEFC60000U;\n"
" return x ^ (x >> 18);\n"
"}\n"
"__kernel void fill(__global uint *state,\n"
" const uint state_index,\n"
" __global uint *vector,\n"
" const uint offset)\n"
"{\n"
" const uint i = get_global_id(0);\n"
" vector[offset+i] = random_number(state, state_index + i);\n"
"}\n";
m_program = cache->get_or_build(cache_key, std::string(), source, m_context);
}
private:
context m_context;
size_t m_state_index;
program m_program;
buffer m_state_buffer;
};
typedef mersenne_twister_engine<uint_> mt19937;
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_MERSENNE_TWISTER_ENGINE_HPP
@@ -0,0 +1,140 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_NORMAL_DISTRIBUTION_HPP
#define BOOST_COMPUTE_RANDOM_NORMAL_DISTRIBUTION_HPP
#include <limits>
#include <boost/assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/function.hpp>
#include <boost/compute/types/fundamental.hpp>
#include <boost/compute/type_traits/make_vector_type.hpp>
namespace boost {
namespace compute {
/// \class normal_distribution
/// \brief Produces random, normally-distributed floating-point numbers.
///
/// The following example shows how to setup a normal distribution to
/// produce random \c float values centered at \c 5:
///
/// \snippet test/test_normal_distribution.cpp generate
///
/// \see default_random_engine, uniform_real_distribution
template<class RealType = float>
class normal_distribution
{
public:
typedef RealType result_type;
/// Creates a new normal distribution producing numbers with the given
/// \p mean and \p stddev.
normal_distribution(RealType mean = 0.f, RealType stddev = 1.f)
: m_mean(mean),
m_stddev(stddev)
{
}
/// Destroys the normal distribution object.
~normal_distribution()
{
}
/// Returns the mean value of the distribution.
result_type mean() const
{
return m_mean;
}
/// Returns the standard-deviation of the distribution.
result_type stddev() const
{
return m_stddev;
}
/// Returns the minimum value of the distribution.
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
{
return -std::numeric_limits<RealType>::infinity();
}
/// Returns the maximum value of the distribution.
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
{
return std::numeric_limits<RealType>::infinity();
}
/// Generates normally-distributed floating-point numbers and stores
/// them to the range [\p first, \p last).
template<class OutputIterator, class Generator>
void generate(OutputIterator first,
OutputIterator last,
Generator &generator,
command_queue &queue)
{
typedef typename make_vector_type<RealType, 2>::type RealType2;
size_t count = detail::iterator_range_size(first, last);
vector<uint_> tmp(count, queue.get_context());
generator.generate(tmp.begin(), tmp.end(), queue);
BOOST_COMPUTE_FUNCTION(RealType2, box_muller, (const uint2_ x),
{
const RealType one = 1;
const RealType two = 2;
// Use nextafter to push values down into [0,1) range; without this, floating point rounding can
// lead to have x1 = 1, but that would lead to taking the log of 0, which would result in negative
// infinities; by pushing the values off 1 towards 0, we ensure this won't happen.
const RealType x1 = nextafter(x.x / (RealType) UINT_MAX, (RealType) 0);
const RealType x2 = x.y / (RealType) UINT_MAX;
const RealType rho = sqrt(-two * log(one-x1));
const RealType z1 = rho * cos(two * M_PI_F * x2);
const RealType z2 = rho * sin(two * M_PI_F * x2);
return (RealType2)(MEAN, MEAN) + (RealType2)(z1, z2) * (RealType2)(STDDEV, STDDEV);
});
box_muller.define("MEAN", boost::lexical_cast<std::string>(m_mean));
box_muller.define("STDDEV", boost::lexical_cast<std::string>(m_stddev));
box_muller.define("RealType", type_name<RealType>());
box_muller.define("RealType2", type_name<RealType2>());
transform(
make_buffer_iterator<uint2_>(tmp.get_buffer(), 0),
make_buffer_iterator<uint2_>(tmp.get_buffer(), count / 2),
make_buffer_iterator<RealType2>(first.get_buffer(), 0),
box_muller,
queue
);
}
private:
RealType m_mean;
RealType m_stddev;
BOOST_STATIC_ASSERT_MSG(
boost::is_floating_point<RealType>::value,
"Template argument must be a floating point type"
);
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_NORMAL_DISTRIBUTION_HPP
@@ -0,0 +1,311 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2015 Muhammad Junaid Muzammil <mjunaidmuzammil@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_THREEFRY_HPP
#define BOOST_COMPUTE_RANDOM_THREEFRY_HPP
#include <algorithm>
#include <boost/compute/types.hpp>
#include <boost/compute/buffer.hpp>
#include <boost/compute/kernel.hpp>
#include <boost/compute/context.hpp>
#include <boost/compute/program.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/algorithm/transform.hpp>
#include <boost/compute/detail/iterator_range_size.hpp>
#include <boost/compute/utility/program_cache.hpp>
#include <boost/compute/container/vector.hpp>
#include <boost/compute/iterator/discard_iterator.hpp>
namespace boost {
namespace compute {
/// \class threefry_engine
/// \brief Threefry pseudorandom number generator.
template<class T = uint_>
class threefry_engine
{
public:
static const size_t threads = 1024;
typedef T result_type;
/// Creates a new threefry_engine and seeds it with \p value.
explicit threefry_engine(command_queue &queue)
: m_context(queue.get_context())
{
// setup program
load_program();
}
/// Creates a new threefry_engine object as a copy of \p other.
threefry_engine(const threefry_engine<T> &other)
: m_context(other.m_context),
m_program(other.m_program)
{
}
/// Copies \p other to \c *this.
threefry_engine<T>& operator=(const threefry_engine<T> &other)
{
if(this != &other){
m_context = other.m_context;
m_program = other.m_program;
}
return *this;
}
/// Destroys the threefry_engine object.
~threefry_engine()
{
}
private:
/// \internal_
void load_program()
{
boost::shared_ptr<program_cache> cache =
program_cache::get_global_cache(m_context);
std::string cache_key =
std::string("threefry_engine_32x2");
// Copyright 2010-2012, D. E. Shaw Research.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions, and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions, and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of D. E. Shaw Research nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
const char source[] =
"#define THREEFRY2x32_DEFAULT_ROUNDS 20\n"
"#define SKEIN_KS_PARITY_32 0x1BD11BDA\n"
"enum r123_enum_threefry32x2 {\n"
" R_32x2_0_0=13,\n"
" R_32x2_1_0=15,\n"
" R_32x2_2_0=26,\n"
" R_32x2_3_0= 6,\n"
" R_32x2_4_0=17,\n"
" R_32x2_5_0=29,\n"
" R_32x2_6_0=16,\n"
" R_32x2_7_0=24\n"
"};\n"
"static uint RotL_32(uint x, uint N)\n"
"{\n"
" return (x << (N & 31)) | (x >> ((32-N) & 31));\n"
"}\n"
"struct r123array2x32 {\n"
" uint v[2];\n"
"};\n"
"typedef struct r123array2x32 threefry2x32_ctr_t;\n"
"typedef struct r123array2x32 threefry2x32_key_t;\n"
"threefry2x32_ctr_t threefry2x32_R(unsigned int Nrounds, threefry2x32_ctr_t in, threefry2x32_key_t k)\n"
"{\n"
" threefry2x32_ctr_t X;\n"
" uint ks[3];\n"
" uint i; \n"
" ks[2] = SKEIN_KS_PARITY_32;\n"
" for (i=0;i < 2; i++) {\n"
" ks[i] = k.v[i];\n"
" X.v[i] = in.v[i];\n"
" ks[2] ^= k.v[i];\n"
" }\n"
" X.v[0] += ks[0]; X.v[1] += ks[1];\n"
" if(Nrounds>0){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_0_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>1){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_1_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>2){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_2_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>3){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_3_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>3){\n"
" X.v[0] += ks[1]; X.v[1] += ks[2];\n"
" X.v[1] += 1;\n"
" }\n"
" if(Nrounds>4){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_4_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>5){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_5_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>6){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_6_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>7){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_7_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>7){\n"
" X.v[0] += ks[2]; X.v[1] += ks[0];\n"
" X.v[1] += 2;\n"
" }\n"
" if(Nrounds>8){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_0_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>9){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_1_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>10){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_2_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>11){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_3_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>11){\n"
" X.v[0] += ks[0]; X.v[1] += ks[1];\n"
" X.v[1] += 3;\n"
" }\n"
" if(Nrounds>12){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_4_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>13){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_5_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>14){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_6_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>15){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_7_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>15){\n"
" X.v[0] += ks[1]; X.v[1] += ks[2];\n"
" X.v[1] += 4;\n"
" }\n"
" if(Nrounds>16){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_0_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>17){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_1_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>18){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_2_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>19){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_3_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>19){\n"
" X.v[0] += ks[2]; X.v[1] += ks[0];\n"
" X.v[1] += 5;\n"
" }\n"
" if(Nrounds>20){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_4_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>21){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_5_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>22){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_6_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>23){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_7_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>23){\n"
" X.v[0] += ks[0]; X.v[1] += ks[1];\n"
" X.v[1] += 6;\n"
" }\n"
" if(Nrounds>24){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_0_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>25){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_1_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>26){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_2_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>27){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_3_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>27){\n"
" X.v[0] += ks[1]; X.v[1] += ks[2];\n"
" X.v[1] += 7;\n"
" }\n"
" if(Nrounds>28){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_4_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>29){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_5_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>30){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_6_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>31){ X.v[0] += X.v[1]; X.v[1] = RotL_32(X.v[1],R_32x2_7_0); X.v[1] ^= X.v[0]; }\n"
" if(Nrounds>31){\n"
" X.v[0] += ks[2]; X.v[1] += ks[0];\n"
" X.v[1] += 8;\n"
" }\n"
" return X;\n"
"}\n"
"__kernel void generate_rng(__global uint *ctr, __global uint *key, const uint offset) {\n"
" threefry2x32_ctr_t in;\n"
" threefry2x32_key_t k;\n"
" const uint i = get_global_id(0);\n"
" in.v[0] = ctr[2 * (offset + i)];\n"
" in.v[1] = ctr[2 * (offset + i) + 1];\n"
" k.v[0] = key[2 * (offset + i)];\n"
" k.v[1] = key[2 * (offset + i) + 1];\n"
" in = threefry2x32_R(20, in, k);\n"
" ctr[2 * (offset + i)] = in.v[0];\n"
" ctr[2 * (offset + i) + 1] = in.v[1];\n"
"}\n";
m_program = cache->get_or_build(cache_key, std::string(), source, m_context);
}
public:
/// Generates Threefry random numbers using both the counter and key values, and then stores
/// them to the range [\p first_ctr, \p last_ctr).
template<class OutputIterator>
void generate(OutputIterator first_ctr, OutputIterator last_ctr, OutputIterator first_key, OutputIterator last_key, command_queue &queue) {
const size_t size_ctr = detail::iterator_range_size(first_ctr, last_ctr);
const size_t size_key = detail::iterator_range_size(first_key, last_key);
if(!size_ctr || !size_key || (size_ctr != size_key)) {
return;
}
kernel rng_kernel = m_program.create_kernel("generate_rng");
rng_kernel.set_arg(0, first_ctr.get_buffer());
rng_kernel.set_arg(1, first_key.get_buffer());
size_t offset = 0;
for(;;){
size_t count = 0;
size_t size = size_ctr/2;
if(size > threads){
count = (std::min)(static_cast<size_t>(threads), size - offset);
}
else {
count = size;
}
rng_kernel.set_arg(2, static_cast<const uint_>(offset));
queue.enqueue_1d_range_kernel(rng_kernel, 0, count, 0);
offset += count;
if(offset >= size){
break;
}
}
}
template<class OutputIterator>
void generate(OutputIterator first_ctr, OutputIterator last_ctr, command_queue &queue) {
const size_t size_ctr = detail::iterator_range_size(first_ctr, last_ctr);
if(!size_ctr) {
return;
}
boost::compute::vector<uint_> vector_key(size_ctr, m_context);
vector_key.assign(size_ctr, 0, queue);
kernel rng_kernel = m_program.create_kernel("generate_rng");
rng_kernel.set_arg(0, first_ctr.get_buffer());
rng_kernel.set_arg(1, vector_key);
size_t offset = 0;
for(;;){
size_t count = 0;
size_t size = size_ctr/2;
if(size > threads){
count = (std::min)(static_cast<size_t>(threads), size - offset);
}
else {
count = size;
}
rng_kernel.set_arg(2, static_cast<const uint_>(offset));
queue.enqueue_1d_range_kernel(rng_kernel, 0, count, 0);
offset += count;
if(offset >= size){
break;
}
}
}
private:
context m_context;
program m_program;
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_THREEFRY_HPP
@@ -0,0 +1,119 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
#define BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
#include <limits>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/container/vector.hpp>
#include <boost/compute/function.hpp>
#include <boost/compute/types/fundamental.hpp>
#include <boost/compute/algorithm/copy_if.hpp>
#include <boost/compute/algorithm/transform.hpp>
namespace boost {
namespace compute {
/// \class uniform_int_distribution
/// \brief Produces uniformily distributed random integers
///
/// The following example shows how to setup a uniform int distribution to
/// produce random integers 0 and 1.
///
/// \snippet test/test_uniform_int_distribution.cpp generate
///
template<class IntType = uint_>
class uniform_int_distribution
{
public:
typedef IntType result_type;
/// Creates a new uniform distribution producing numbers in the range
/// [\p a, \p b].
explicit uniform_int_distribution(IntType a = 0,
IntType b = (std::numeric_limits<IntType>::max)())
: m_a(a),
m_b(b)
{
}
/// Destroys the uniform_int_distribution object.
~uniform_int_distribution()
{
}
/// Returns the minimum value of the distribution.
result_type a() const
{
return m_a;
}
/// Returns the maximum value of the distribution.
result_type b() const
{
return m_b;
}
/// Generates uniformily distributed integers and stores
/// them to the range [\p first, \p last).
template<class OutputIterator, class Generator>
void generate(OutputIterator first,
OutputIterator last,
Generator &generator,
command_queue &queue)
{
size_t size = std::distance(first, last);
typedef typename Generator::result_type g_result_type;
vector<g_result_type> tmp(size, queue.get_context());
vector<g_result_type> tmp2(size, queue.get_context());
uint_ bound = ((uint_(-1))/(m_b-m_a+1))*(m_b-m_a+1);
buffer_iterator<g_result_type> tmp2_iter;
while(size>0)
{
generator.generate(tmp.begin(), tmp.begin() + size, queue);
tmp2_iter = copy_if(tmp.begin(), tmp.begin() + size, tmp2.begin(),
_1 <= bound, queue);
size = std::distance(tmp2_iter, tmp2.end());
}
BOOST_COMPUTE_FUNCTION(IntType, scale_random, (const g_result_type x),
{
return LO + (x % (HI-LO+1));
});
scale_random.define("LO", boost::lexical_cast<std::string>(m_a));
scale_random.define("HI", boost::lexical_cast<std::string>(m_b));
transform(tmp2.begin(), tmp2.end(), first, scale_random, queue);
}
private:
IntType m_a;
IntType m_b;
BOOST_STATIC_ASSERT_MSG(
boost::is_integral<IntType>::value,
"Template argument must be integral"
);
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
@@ -0,0 +1,116 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
#ifndef BOOST_COMPUTE_RANDOM_UNIFORM_REAL_DISTRIBUTION_HPP
#define BOOST_COMPUTE_RANDOM_UNIFORM_REAL_DISTRIBUTION_HPP
#include <boost/assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/function.hpp>
#include <boost/compute/detail/literal.hpp>
#include <boost/compute/types/fundamental.hpp>
namespace boost {
namespace compute {
/// \class uniform_real_distribution
/// \brief Produces uniformly distributed random floating-point numbers.
///
/// The following example shows how to setup a uniform real distribution to
/// produce random \c float values between \c 1 and \c 100.
///
/// \snippet test/test_uniform_real_distribution.cpp generate
///
/// \see default_random_engine, normal_distribution
template<class RealType = float>
class uniform_real_distribution
{
public:
typedef RealType result_type;
/// Creates a new uniform distribution producing numbers in the range
/// [\p a, \p b).
/// Requires a < b
uniform_real_distribution(RealType a = 0.f, RealType b = 1.f)
: m_a(a),
m_b(b)
{
BOOST_ASSERT(a < b);
}
/// Destroys the uniform_real_distribution object.
~uniform_real_distribution()
{
}
/// Returns the minimum value of the distribution.
result_type a() const
{
return m_a;
}
/// Returns the maximum value of the distribution.
result_type b() const
{
return m_b;
}
/// Generates uniformly distributed floating-point numbers and stores
/// them to the range [\p first, \p last).
template<class OutputIterator, class Generator>
void generate(OutputIterator first,
OutputIterator last,
Generator &generator,
command_queue &queue)
{
BOOST_COMPUTE_FUNCTION(RealType, scale_random, (const uint_ x),
{
return nextafter(LO + (convert_RealType(x) / MAX_RANDOM) * (HI - LO), (RealType) LO);
});
scale_random.define("LO", detail::make_literal(m_a));
scale_random.define("HI", detail::make_literal(m_b));
scale_random.define("MAX_RANDOM", "UINT_MAX");
scale_random.define(
"convert_RealType", std::string("convert_") + type_name<RealType>()
);
scale_random.define("RealType", type_name<RealType>());
generator.generate(
first, last, scale_random, queue
);
}
/// \internal_ (deprecated)
template<class OutputIterator, class Generator>
void fill(OutputIterator first,
OutputIterator last,
Generator &g,
command_queue &queue)
{
generate(first, last, g, queue);
}
private:
RealType m_a;
RealType m_b;
BOOST_STATIC_ASSERT_MSG(
boost::is_floating_point<RealType>::value,
"Template argument must be a floating point type"
);
};
} // end compute namespace
} // end boost namespace
#endif // BOOST_COMPUTE_RANDOM_UNIFORM_REAL_DISTRIBUTION_HPP