mirror of
https://github.com/boostorg/random.git
synced 2026-01-19 04:22:17 +00:00
This commit was manufactured by cvs2svn to create branch 'SPIRIT_1_6'.
[SVN r23968]
This commit is contained in:
170
histogram.cpp
170
histogram.cpp
@@ -1,170 +0,0 @@
|
||||
/* boost histogram.cpp graphical verification of distribution functions
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* This test program allows to visibly examine the results of the
|
||||
* distribution functions.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <boost/random.hpp>
|
||||
|
||||
|
||||
void plot_histogram(const std::vector<int>& slots, int samples,
|
||||
double from, double to)
|
||||
{
|
||||
int m = *std::max_element(slots.begin(), slots.end());
|
||||
const int nRows = 20;
|
||||
std::cout.setf(std::ios::fixed|std::ios::left);
|
||||
std::cout.precision(5);
|
||||
for(int r = 0; r < nRows; r++) {
|
||||
double y = ((nRows - r) * double(m))/(nRows * samples);
|
||||
std::cout << std::setw(10) << y << " ";
|
||||
for(unsigned int col = 0; col < slots.size(); col++) {
|
||||
char out = ' ';
|
||||
if(slots[col]/double(samples) >= y)
|
||||
out = 'x';
|
||||
std::cout << out;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::setw(12) << " "
|
||||
<< std::setw(10) << from;
|
||||
std::cout.setf(std::ios::right, std::ios::adjustfield);
|
||||
std::cout << std::setw(slots.size()-10) << to << std::endl;
|
||||
}
|
||||
|
||||
// I am not sure whether these two should be in the library as well
|
||||
|
||||
// maintain sum of NumberGenerator results
|
||||
template<class NumberGenerator,
|
||||
class Sum = typename NumberGenerator::result_type>
|
||||
class sum_result
|
||||
{
|
||||
public:
|
||||
typedef NumberGenerator base_type;
|
||||
typedef typename base_type::result_type result_type;
|
||||
explicit sum_result(const base_type & g) : gen(g), _sum(0) { }
|
||||
result_type operator()() { result_type r = gen(); _sum += r; return r; }
|
||||
base_type & base() { return gen; }
|
||||
Sum sum() const { return _sum; }
|
||||
void reset() { _sum = 0; }
|
||||
private:
|
||||
base_type gen;
|
||||
Sum _sum;
|
||||
};
|
||||
|
||||
|
||||
// maintain square sum of NumberGenerator results
|
||||
template<class NumberGenerator,
|
||||
class Sum = typename NumberGenerator::result_type>
|
||||
class squaresum_result
|
||||
{
|
||||
public:
|
||||
typedef NumberGenerator base_type;
|
||||
typedef typename base_type::result_type result_type;
|
||||
explicit squaresum_result(const base_type & g) : gen(g), _sum(0) { }
|
||||
result_type operator()() { result_type r = gen(); _sum += r*r; return r; }
|
||||
base_type & base() { return gen; }
|
||||
Sum squaresum() const { return _sum; }
|
||||
void reset() { _sum = 0; }
|
||||
private:
|
||||
base_type gen;
|
||||
Sum _sum;
|
||||
};
|
||||
|
||||
|
||||
template<class RNG>
|
||||
void histogram(RNG base, int samples, double from, double to,
|
||||
const std::string & name)
|
||||
{
|
||||
typedef squaresum_result<sum_result<RNG, double>, double > SRNG;
|
||||
SRNG gen((sum_result<RNG, double>(base)));
|
||||
const int nSlots = 60;
|
||||
std::vector<int> slots(nSlots,0);
|
||||
for(int i = 0; i < samples; i++) {
|
||||
double val = gen();
|
||||
if(val < from || val >= to) // early check avoids overflow
|
||||
continue;
|
||||
int slot = int((val-from)/(to-from) * nSlots);
|
||||
if(slot < 0 || slot > (int)slots.size())
|
||||
continue;
|
||||
slots[slot]++;
|
||||
}
|
||||
std::cout << name << std::endl;
|
||||
plot_histogram(slots, samples, from, to);
|
||||
double mean = gen.base().sum() / samples;
|
||||
std::cout << "mean: " << mean
|
||||
<< " sigma: " << std::sqrt(gen.squaresum()/samples-mean*mean)
|
||||
<< "\n" << std::endl;
|
||||
}
|
||||
|
||||
template<class PRNG, class Dist>
|
||||
inline boost::variate_generator<PRNG&, Dist> make_gen(PRNG & rng, Dist d)
|
||||
{
|
||||
return boost::variate_generator<PRNG&, Dist>(rng, d);
|
||||
}
|
||||
|
||||
template<class PRNG>
|
||||
void histograms()
|
||||
{
|
||||
PRNG rng;
|
||||
using namespace boost;
|
||||
histogram(make_gen(rng, uniform_smallint<>(0, 5)), 100000, -1, 6,
|
||||
"uniform_smallint(0,5)");
|
||||
histogram(make_gen(rng, uniform_int<>(0, 5)), 100000, -1, 6,
|
||||
"uniform_int(0,5)");
|
||||
histogram(make_gen(rng, uniform_real<>(0,1)), 100000, -0.5, 1.5,
|
||||
"uniform_real(0,1)");
|
||||
histogram(make_gen(rng, bernoulli_distribution<>(0.2)), 100000, -0.5, 1.5,
|
||||
"bernoulli(0.2)");
|
||||
histogram(make_gen(rng, binomial_distribution<>(4, 0.2)), 100000, -1, 5,
|
||||
"binomial(4, 0.2)");
|
||||
histogram(make_gen(rng, triangle_distribution<>(1, 2, 8)), 100000, 0, 10,
|
||||
"triangle(1,2,8)");
|
||||
histogram(make_gen(rng, geometric_distribution<>(5.0/6.0)), 100000, 0, 10,
|
||||
"geometric(5/6)");
|
||||
histogram(make_gen(rng, exponential_distribution<>(0.3)), 100000, 0, 10,
|
||||
"exponential(0.3)");
|
||||
histogram(make_gen(rng, cauchy_distribution<>()), 100000, -5, 5,
|
||||
"cauchy");
|
||||
histogram(make_gen(rng, lognormal_distribution<>(3, 2)), 100000, 0, 10,
|
||||
"lognormal");
|
||||
histogram(make_gen(rng, normal_distribution<>()), 100000, -3, 3,
|
||||
"normal");
|
||||
histogram(make_gen(rng, normal_distribution<>(0.5, 0.5)), 100000, -3, 3,
|
||||
"normal(0.5, 0.5)");
|
||||
histogram(make_gen(rng, poisson_distribution<>(1.5)), 100000, 0, 5,
|
||||
"poisson(1.5)");
|
||||
histogram(make_gen(rng, poisson_distribution<>(10)), 100000, 0, 20,
|
||||
"poisson(10)");
|
||||
histogram(make_gen(rng, gamma_distribution<>(0.5)), 100000, 0, 0.5,
|
||||
"gamma(0.5)");
|
||||
histogram(make_gen(rng, gamma_distribution<>(1)), 100000, 0, 3,
|
||||
"gamma(1)");
|
||||
histogram(make_gen(rng, gamma_distribution<>(2)), 100000, 0, 6,
|
||||
"gamma(2)");
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
histograms<boost::mt19937>();
|
||||
// histograms<boost::lagged_fibonacci607>();
|
||||
}
|
||||
|
||||
161
index.html
161
index.html
@@ -1,161 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
|
||||
<title>Boost Random Number Library</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<table border="1" bgcolor="#007F7F" cellpadding="2">
|
||||
<tr>
|
||||
<td bgcolor="#FFFFFF"><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td>
|
||||
<td><a href="../../index.htm"><font face="Arial,Helvetica" color="#FFFFFF"><big>Home</big></font></a></td>
|
||||
<td><a href="../libraries.htm"><font face="Arial,Helvetica" color="#FFFFFF"><big>Libraries</big></font></a></td>
|
||||
<td><a href="../../people/people.htm"><font face="Arial,Helvetica" color="#FFFFFF"><big>People</big></font></a></td>
|
||||
<td><a href="../../more/faq.htm"><font face="Arial,Helvetica" color="#FFFFFF"><big>FAQ</big></font></a></td>
|
||||
<td><a href="../../more/index.htm"><font face="Arial,Helvetica" color="#FFFFFF"><big>More</big></font></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h1>Boost Random Number Library</h1>
|
||||
|
||||
Random numbers are useful in a variety of applications. The Boost
|
||||
Random Number Library (Boost.Random for short) provides a vast variety
|
||||
of generators and distributions to produce random numbers having
|
||||
useful properties, such as uniform distribution.
|
||||
<p>
|
||||
You should read the
|
||||
<a href="random-concepts.html">concepts documentation</a>
|
||||
for an introduction and the definition of the basic concepts. For a
|
||||
quick start, it may be sufficient to have a look at <a
|
||||
href="random_demo.cpp">random_demo.cpp</a>.
|
||||
<p>
|
||||
For a very quick start, here's an example:
|
||||
<pre>
|
||||
boost::mt19937 rng; // produces randomness out of thin air
|
||||
// see pseudo-random number generators
|
||||
boost::uniform_int<> six(1,6) // distribution that maps to 1..6
|
||||
// see random number distributions
|
||||
boost::variate_generator<boost::mt19937, boost::uniform_int<> >
|
||||
die(rng, six); // glues randomness with mapping
|
||||
int x = die(); // simulate rolling a die
|
||||
</pre>
|
||||
|
||||
<h2>Library Organization</h2>
|
||||
|
||||
The library is separated into several header files, all within the
|
||||
<code>boost/random/</code> directory. Additionally, a convenience
|
||||
header file which includes all other headers in
|
||||
<code>boost/random/</code> is available as
|
||||
<code><a href="../../boost/random.hpp">boost/random.hpp</a></code>.
|
||||
<p>
|
||||
|
||||
A front-end class template called <code>variate_generate</code> is
|
||||
provided; please read the
|
||||
<a href="random-variate.html">documentation</a> about it.
|
||||
<ul>
|
||||
<li><code><a href="../../boost/random/variate_generator.hpp">boost/random/variate_generator.hpp</a></code>
|
||||
</ul>
|
||||
|
||||
Several random number generators are available in the following
|
||||
header files; please read the
|
||||
<a href="random-generators.html">documentation</a> about these.
|
||||
|
||||
<ul>
|
||||
<li><code><a href="../../boost/random/linear_congruential.hpp">boost/random/linear_congruential.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/additive_combine.hpp">boost/random/additive_combine.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/inversive_congruential.hpp">boost/random/inversive_congruential.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/shuffle_output.hpp">boost/random/shuffle_output.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/mersenne_twister.hpp">boost/random/mersenne_twister.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/lagged_fibonacci.hpp">boost/random/lagged_fibonacci.hpp</a></code>
|
||||
</ul>
|
||||
|
||||
|
||||
Similarly, several random number distributions are available in the
|
||||
following header files; please read the
|
||||
<a href="random-distributions.html">documentation</a> about these.
|
||||
|
||||
<ul>
|
||||
<li><code><a href="../../boost/random/uniform_smallint.hpp">boost/random/uniform_smallint.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/uniform_int.hpp">boost/random/uniform_int.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/uniform_01.hpp">boost/random/uniform_01.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/uniform_real.hpp">boost/random/uniform_real.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/triangle_distribution.hpp">boost/random/triangle_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/bernoulli_distribution.hpp">boost/random/bernoulli_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/cauchy_distribution.hpp">boost/random/cauchy_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/exponential_distribution.hpp">boost/random/exponential_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/geometric_distribution.hpp">boost/random/geometric_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/normal_distribution.hpp">boost/random/normal_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/lognormal_distribution.hpp">boost/random/lognormal_distribution.hpp</a></code>
|
||||
<li><code><a href="../../boost/random/uniform_on_sphere.hpp">boost/random/uniform_on_sphere.hpp</a></code>
|
||||
</ul>
|
||||
|
||||
Additionally, non-deterministic random number generators are available
|
||||
in the header
|
||||
<code><a href="../../boost/nondet_random.hpp"><boost/nondet_random.hpp></a></code>.
|
||||
<a href="nondet_random.html">Documentation</a> is also available.
|
||||
|
||||
<p>
|
||||
|
||||
In order to map the interface of the generators and distribution functions
|
||||
to other concepts, some <a href="random-misc.html">decorators</a> are available.
|
||||
|
||||
<h2>Tests</h2>
|
||||
|
||||
An extensive test suite for the pseudo-random number generators and
|
||||
distributions is available as
|
||||
<a href="random_test.cpp">random_test.cpp</a>.
|
||||
<p>
|
||||
Some <a href="random-performance.html">performance results</a> obtained
|
||||
using <a href="random_speed.cpp">random_speed.cpp</a> are also available.
|
||||
|
||||
<h2>Rationale</h2>
|
||||
|
||||
The methods for generating and evaluating deterministic and
|
||||
non-deterministic random numbers differ radically. Furthermore, due
|
||||
to the inherent deterministic design of present-day computers, it is
|
||||
often difficult to implement non-deterministic random number
|
||||
generation facilities. Thus, the random number library is split into
|
||||
separate header files, mirroring the two different application
|
||||
domains.
|
||||
|
||||
|
||||
<h2>History and Acknowledgements</h2>
|
||||
|
||||
In November 1999, Jeet Sukumaran proposed a framework based on virtual
|
||||
functions, and later sketched a template-based approach. Ed Brey
|
||||
pointed out that Microsoft Visual C++ does not support in-class member
|
||||
initializations and suggested the <code>enum</code> workaround. Dave
|
||||
Abrahams highlighted quantization issues.
|
||||
<p>
|
||||
The first public release of this random number library materialized in
|
||||
March 2000 after extensive discussions on the boost mailing list.
|
||||
Many thanks to Beman Dawes for his original <code>min_rand</code>
|
||||
class, portability fixes, documentation suggestions, and general
|
||||
guidance. Harry Erwin sent a header file which provided additional
|
||||
insight into the requirements. Ed Brey and Beman Dawes wanted an
|
||||
iterator-like interface.
|
||||
<p>
|
||||
Beman Dawes managed the formal review, during which Matthias Troyer,
|
||||
Csaba Szepesvari, and Thomas Holenstein gave detailed comments. The
|
||||
reviewed version became an official part of boost on 17 June 2000.
|
||||
<p>
|
||||
Gary Powell contributed suggestions for code cleanliness. Dave
|
||||
Abrahams and Howard Hinnant suggested to move the basic generator
|
||||
templates from namespace <code>boost::detail</code> to
|
||||
<code>boost::random</code>.
|
||||
<p>
|
||||
Ed Brey asked to remove superfluous warnings and helped with
|
||||
<code>uint64_t</code> handling. Andreas Scherer tested with MSVC.
|
||||
Matthias Troyer contributed a lagged Fibonacci generator. Michael
|
||||
Stevens found a bug in the copy semantics of normal_distribution and
|
||||
suggested documentation improvements.
|
||||
<p>
|
||||
<hr>
|
||||
<a href="../../people/jens_maurer.htm">Jens Maurer</a>,
|
||||
2001-08-31
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,84 +0,0 @@
|
||||
/* integrate.hpp header file
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Revision history
|
||||
* 01 April 2001: Modified to use new <boost/limits.hpp> header. (JMaddock)
|
||||
*/
|
||||
|
||||
#ifndef INTEGRATE_HPP
|
||||
#define INTEGRATE_HPP
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
|
||||
template<class UnaryFunction>
|
||||
inline typename UnaryFunction::result_type
|
||||
trapezoid(UnaryFunction f, typename UnaryFunction::argument_type a,
|
||||
typename UnaryFunction::argument_type b, int n)
|
||||
{
|
||||
typename UnaryFunction::result_type tmp = 0;
|
||||
for(int i = 1; i <= n-1; ++i)
|
||||
tmp += f(a+(b-a)/n*i);
|
||||
return (b-a)/2/n * (f(a) + f(b) + 2*tmp);
|
||||
}
|
||||
|
||||
template<class UnaryFunction>
|
||||
inline typename UnaryFunction::result_type
|
||||
simpson(UnaryFunction f, typename UnaryFunction::argument_type a,
|
||||
typename UnaryFunction::argument_type b, int n)
|
||||
{
|
||||
typename UnaryFunction::result_type tmp1 = 0;
|
||||
for(int i = 1; i <= n-1; ++i)
|
||||
tmp1 += f(a+(b-a)/n*i);
|
||||
typename UnaryFunction::result_type tmp2 = 0;
|
||||
for(int i = 1; i <= n ; ++i)
|
||||
tmp2 += f(a+(b-a)/2/n*(2*i-1));
|
||||
|
||||
return (b-a)/6/n * (f(a) + f(b) + 2*tmp1 + 4*tmp2);
|
||||
}
|
||||
|
||||
// compute b so that f(b) = y; assume f is monotone increasing
|
||||
template<class UnaryFunction>
|
||||
inline typename UnaryFunction::argument_type
|
||||
invert_monotone_inc(UnaryFunction f, typename UnaryFunction::result_type y,
|
||||
typename UnaryFunction::argument_type lower = -1,
|
||||
typename UnaryFunction::argument_type upper = 1)
|
||||
{
|
||||
while(upper-lower > 1e-6) {
|
||||
double middle = (upper+lower)/2;
|
||||
if(f(middle) > y)
|
||||
upper = middle;
|
||||
else
|
||||
lower = middle;
|
||||
}
|
||||
return (upper+lower)/2;
|
||||
}
|
||||
|
||||
// compute b so that I(f(x), a, b) == y
|
||||
template<class UnaryFunction>
|
||||
inline typename UnaryFunction::argument_type
|
||||
quantil(UnaryFunction f, typename UnaryFunction::argument_type a,
|
||||
typename UnaryFunction::result_type y,
|
||||
typename UnaryFunction::argument_type step)
|
||||
{
|
||||
typedef typename UnaryFunction::result_type result_type;
|
||||
if(y >= 1.0)
|
||||
return std::numeric_limits<result_type>::infinity();
|
||||
typename UnaryFunction::argument_type b = a;
|
||||
for(result_type result = 0; result < y; b += step)
|
||||
result += step*f(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
#endif /* INTEGRATE_HPP */
|
||||
@@ -1,131 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
|
||||
<title>Boost RNG Library - Non-Deterministic Random Number Generators</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
|
||||
align="center" width="277" height="86">Header
|
||||
<a href="../../boost/nondet_random.hpp"><boost/nondet_random.hpp></a></h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#synopsis">Synopsis</a>
|
||||
<li><a href="#random_device">Class <code>random_device</code></a>
|
||||
<li><a href="#performance">Performance</a>
|
||||
</ul>
|
||||
|
||||
<h2><a name="synopsis">Header</a><code><boost/nondet_random.hpp></code>
|
||||
Synopsis</h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
class random_device;
|
||||
} // namespace boost
|
||||
</pre>
|
||||
|
||||
|
||||
<h2><a name="random_device">Class <code>random_device</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
class random_device : noncopyable
|
||||
{
|
||||
public:
|
||||
typedef unsigned int result_type;
|
||||
static const bool has_fixed_range = true;
|
||||
static const result_type min_value = /* implementation defined */;
|
||||
static const result_type max_value = /* implementation defined */;
|
||||
result_type min() const;
|
||||
result_type max() const;
|
||||
explicit random_device(const std::string& token = default_token);
|
||||
~random_device();
|
||||
double entropy() const;
|
||||
unsigned int operator()();
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Class <code>random_device</code> models a
|
||||
<a href="random-concepts.html#nondet-rng">non-deterministic random number
|
||||
generator</a>.
|
||||
It uses one or more implementation-defined stochastic processes to
|
||||
generate a sequence of uniformly distributed non-deterministic random
|
||||
numbers. For those environments where a non-deterministic random
|
||||
number generator is not available, class <code>random_device</code>
|
||||
must not be implemented. See
|
||||
<blockquote>
|
||||
"Randomness Recommendations for Security", D. Eastlake, S.
|
||||
Crocker, J. Schiller, Network Working Group, RFC 1750, December 1994
|
||||
</blockquote>
|
||||
for further discussions.
|
||||
|
||||
<p>
|
||||
<em>Note:</em> Some operating systems abstract the computer hardware
|
||||
enough to make it difficult to non-intrusively monitor stochastic
|
||||
processes. However, several do provide a special device for exactly
|
||||
this purpose. It seems to be impossible to emulate the functionality
|
||||
using Standard C++ only, so users should be aware that this class may
|
||||
not be available on all platforms.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>explicit random_device(const std::string& token = default_token)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a <code>random_device</code>,
|
||||
optionally using the given <code>token</code> as an access
|
||||
specification (for example, a URL) to some implementation-defined
|
||||
service for monitoring a stochastic process.
|
||||
|
||||
<pre> double entropy() const</pre>
|
||||
<strong>Returns:</strong> An entropy estimate for the random numbers
|
||||
returned by operator(), in the range <code>min()</code> to
|
||||
log<sub>2</sub>( <code>max()</code>+1). A deterministic random
|
||||
number generator (e.g. a pseudo-random number engine) has entropy 0.
|
||||
<br>
|
||||
<strong>Throws:</strong> Nothing.
|
||||
|
||||
|
||||
<h3>Implementation Note for Linux</h3>
|
||||
|
||||
On the Linux operating system, <code>token</code> is interpreted as a
|
||||
filesystem path. It is assumed that this path denotes an operating
|
||||
system pseudo-device which generates a stream of non-deterministic
|
||||
random numbers. The pseudo-device should never signal an error or
|
||||
end-of-file. Otherwise, <code>std::ios_base::failure</code> is
|
||||
thrown. By default, <code>random_device</code> uses the
|
||||
<code>/dev/urandom</code> pseudo-device to retrieve the random
|
||||
numbers. Another option would be to specify the
|
||||
<code>/dev/random</code> pseudo-device, which blocks on reads if the
|
||||
entropy pool has no more random bits available.
|
||||
|
||||
|
||||
<h2><a name="performance">Performance</a></h2>
|
||||
|
||||
The test program <a href="nondet_random_speed.cpp">nondet_random_speed.cpp</a>
|
||||
measures the execution times of the
|
||||
<a href="../../boost/nondet_random.hpp">nondet_random.hpp</a> implementation of the above
|
||||
algorithms in a tight loop. The performance has been evaluated on a
|
||||
Pentium Pro 200 MHz with gcc 2.95.2, Linux 2.2.13, glibc 2.1.2.
|
||||
|
||||
<p>
|
||||
<table border=1>
|
||||
<tr><th>class</th><th>time per invocation [usec]</th></tr>
|
||||
<tr><td>random_device</td><td>92.0</td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
The measurement error is estimated at +/- 1 usec.
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
Jens Maurer, 2000-06-19
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,69 +0,0 @@
|
||||
/* boost nondet_random_speed.cpp performance test
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/timer.hpp>
|
||||
#include <boost/nondet_random.hpp>
|
||||
|
||||
// set to your CPU frequency in MHz
|
||||
static const double cpu_frequency = 200 * 1e6;
|
||||
|
||||
static void show_elapsed(double end, int iter, const std::string & name)
|
||||
{
|
||||
double usec = end/iter*1e6;
|
||||
double cycles = usec * cpu_frequency/1e6;
|
||||
std::cout << name << ": "
|
||||
<< usec*1e3 << " nsec/loop = "
|
||||
<< cycles << " CPU cycles"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
template<class Result, class RNG>
|
||||
static void timing(RNG & rng, int iter, const std::string& name)
|
||||
{
|
||||
volatile Result tmp; // make sure we're not optimizing too much
|
||||
boost::timer t;
|
||||
for(int i = 0; i < iter; i++)
|
||||
tmp = rng();
|
||||
show_elapsed(t.elapsed(), iter, name);
|
||||
}
|
||||
|
||||
template<class RNG>
|
||||
void run(int iter, const std::string & name)
|
||||
{
|
||||
RNG rng;
|
||||
timing<long>(rng, iter, name);
|
||||
}
|
||||
|
||||
int main(int argc, char*argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
std::cerr << "usage: " << argv[0] << " iterations" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iter = std::atoi(argv[1]);
|
||||
|
||||
#ifdef __linux__
|
||||
boost::random_device dev;
|
||||
timing<unsigned int>(dev, iter, "random_device");
|
||||
#else
|
||||
#error The non-deterministic random device is currently available on Linux only.
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,429 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
|
||||
<title>Boost Random Number Library Concepts</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1>Random Number Generator Library Concepts</h1>
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
Random numbers are required in a number of different problem domains,
|
||||
such as
|
||||
<ul>
|
||||
<li>numerics (simulation, Monte-Carlo integration)
|
||||
<li>games (non-deterministic enemy behavior)
|
||||
<li>security (key generation)
|
||||
<li>testing (random coverage in white-box tests)
|
||||
</ul>
|
||||
|
||||
The Boost Random Number Generator Library provides a framework
|
||||
for random number generators with well-defined properties so that the
|
||||
generators can be used in the demanding numerics and security domains.
|
||||
|
||||
For a general introduction to random numbers in numerics, see
|
||||
<blockquote>
|
||||
"Numerical Recipes in C: The art of scientific computing", William
|
||||
H. Press, Saul A. Teukolsky, William A. Vetterling, Brian P. Flannery,
|
||||
2nd ed., 1992, pp. 274-328
|
||||
</blockquote>
|
||||
|
||||
Depending on the requirements of the problem domain, different
|
||||
variations of random number generators are appropriate:
|
||||
|
||||
<ul>
|
||||
<li>non-deterministic random number generator
|
||||
<li>pseudo-random number generator
|
||||
<li>quasi-random number generator
|
||||
</ul>
|
||||
|
||||
All variations have some properties in common, these concepts (in the
|
||||
STL sense) are called NumberGenerator and
|
||||
UniformRandomNumberGenerator. Each concept will be defined in a
|
||||
subsequent section.
|
||||
|
||||
<p>
|
||||
|
||||
The goals for this library are the following:
|
||||
<ul>
|
||||
<li>allow easy integration of third-party random-number generators
|
||||
<li>define a validation interface for the generators
|
||||
<li>provide easy-to-use front-end classes which model popular
|
||||
distributions
|
||||
<li>provide maximum efficiency
|
||||
<li>allow control on quantization effects in front-end processing
|
||||
(not yet done)
|
||||
</ul>
|
||||
|
||||
|
||||
<h2><a name="number_generator">Number Generator</a></h2>
|
||||
|
||||
A number generator is a <em>function object</em> (std:20.3
|
||||
[lib.function.objects]) that takes zero arguments. Each call to
|
||||
<code>operator()</code> returns a number.
|
||||
|
||||
|
||||
In the following table, <code>X</code> denotes a number generator
|
||||
class returning objects of type <code>T</code>, and <code>u</code> is
|
||||
a value of <code>X</code>.
|
||||
|
||||
<p>
|
||||
|
||||
<table border=1>
|
||||
<tr><th colspan=3 align=center><code>NumberGenerator</code>
|
||||
requirements</th></tr>
|
||||
<tr><td>expression</td><td>return type</td>
|
||||
<td>pre/post-condition</td></tr>
|
||||
<tr><td><code>X::result_type</code></td><td>T</td>
|
||||
<td><code>std::numeric_limits<T>::is_specialized</code> is true,
|
||||
<code>T</code> is <code>LessThanComparable</code></td></tr>
|
||||
<tr><td><code>u.operator()()</code></td><td>T</td><td>-</td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
||||
<em>Note:</em> The NumberGenerator requirements do not impose any
|
||||
restrictions on the characteristics of the returned numbers.
|
||||
|
||||
|
||||
<h2><a name="uniform-rng">Uniform Random Number Generator</a></h2>
|
||||
|
||||
A uniform random number generator is a NumberGenerator that provides a
|
||||
sequence of random numbers uniformly distributed on a given range.
|
||||
The range can be compile-time fixed or available (only) after run-time
|
||||
construction of the object.
|
||||
|
||||
<p>
|
||||
The <em>tight lower bound</em> of some (finite) set S is the (unique)
|
||||
member l in S, so that for all v in S, l <= v holds. Likewise, the
|
||||
<em>tight upper bound</em> of some (finite) set S is the (unique)
|
||||
member u in S, so that for all v in S, v <= u holds.
|
||||
|
||||
<p>
|
||||
In the following table, <code>X</code> denotes a number generator
|
||||
class returning objects of type <code>T</code>, and <code>v</code> is
|
||||
a const value of <code>X</code>.
|
||||
|
||||
<p>
|
||||
|
||||
<table border=1>
|
||||
<tr><th colspan=3 align=center><code>UniformRandomNumberGenerator</code>
|
||||
requirements</th></tr>
|
||||
<tr><td>expression</td><td>return type</td>
|
||||
<td>pre/post-condition</td></tr>
|
||||
<tr><td><code>X::has_fixed_range</code></td><td><code>bool</code></td>
|
||||
<td>compile-time constant; if <code>true</code>, the range on which
|
||||
the random numbers are uniformly distributed is known at compile-time
|
||||
and members <code>min_value</code> and <code>max_value</code>
|
||||
exist. <em>Note:</em> This flag may also be <code>false</code> due to
|
||||
compiler limitations.</td></tr>
|
||||
<tr><td><code>X::min_value</code></td><td><code>T</code></td>
|
||||
<td>compile-time constant; <code>min_value</code> is equal to
|
||||
<code>v.min()</code></td></tr>
|
||||
<tr><td><code>X::max_value</code></td><td><code>T</code></td>
|
||||
<td>compile-time constant; <code>max_value</code> is equal to
|
||||
<code>v.max()</code></td></tr>
|
||||
<tr><td><code>v.min()</code></td><td><code>T</code></td>
|
||||
<td>tight lower bound on the set of all values returned by
|
||||
<code>operator()</code>. The return value of this function shall not
|
||||
change during the lifetime of the object.</td></tr>
|
||||
<tr><td><code>v.max()</code></td><td><code>T</code></td>
|
||||
<td>if <code>std::numeric_limits<T>::is_integer</code>, tight
|
||||
upper bound on the set of all values returned by
|
||||
<code>operator()</code>, otherwise, the smallest representable number
|
||||
larger than the tight upper bound on the set of all values returned by
|
||||
<code>operator()</code>. In any case, the return value of this
|
||||
function shall not change during the lifetime of the
|
||||
object.</code></td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
The member functions <code>min</code>, <code>max</code>, and
|
||||
<code>operator()</code> shall have amortized constant time complexity.
|
||||
|
||||
<p>
|
||||
<em>Note:</em> For integer generators (i.e. integer <code>T</code>),
|
||||
the generated values <code>x</code> fulfill <code>min() <= x <=
|
||||
max()</code>, for non-integer generators (i.e. non-integer
|
||||
<code>T</code>), the generated values <code>x</code> fulfill
|
||||
<code>min() <= x < max()</code>.
|
||||
<br>
|
||||
<em>Rationale:</em> The range description with <code>min</code> and
|
||||
<code>max</code> serves two purposes. First, it allows scaling of the
|
||||
values to some canonical range, such as [0..1). Second, it describes
|
||||
the significant bits of the values, which may be relevant for further
|
||||
processing.
|
||||
<br>
|
||||
The range is a closed interval [min,max] for integers, because the
|
||||
underlying type may not be able to represent the half-open interval
|
||||
[min,max+1). It is a half-open interval [min, max) for non-integers,
|
||||
because this is much more practical for borderline cases of continuous
|
||||
distributions.
|
||||
<p>
|
||||
|
||||
<em>Note:</em> The UniformRandomNumberGenerator concept does not
|
||||
require <code>operator()(long)</code> and thus it does not fulfill the
|
||||
RandomNumberGenerator (std:25.2.11 [lib.alg.random.shuffle])
|
||||
requirements. Use the
|
||||
<a href="random-misc.html#random_number_generator"><code>random_number_generator</code></a>
|
||||
adapter for that.
|
||||
<br>
|
||||
|
||||
<em>Rationale:</em> <code>operator()(long)</code> is not provided,
|
||||
because mapping the output of some generator with integer range to a
|
||||
different integer range is not trivial.
|
||||
|
||||
|
||||
<h2><a name="nondet-rng">Non-deterministic Uniform Random Number
|
||||
Generator</a></h2>
|
||||
|
||||
A non-deterministic uniform random number generator is a
|
||||
UniformRandomNumberGenerator that is based on some stochastic process.
|
||||
Thus, it provides a sequence of truly-random numbers. Examples for
|
||||
such processes are nuclear decay, noise of a Zehner diode, tunneling
|
||||
of quantum particles, rolling a die, drawing from an urn, and tossing
|
||||
a coin. Depending on the environment, inter-arrival times of network
|
||||
packets or keyboard events may be close approximations of stochastic
|
||||
processes.
|
||||
<p>
|
||||
|
||||
The class
|
||||
<code><a href="nondet_random.html#random_device">random_device</a></code>
|
||||
is a model for a non-deterministic random number generator.
|
||||
|
||||
<p>
|
||||
|
||||
<em>Note:</em> This type of random-number generator is useful for
|
||||
security applications, where it is important to prevent that an
|
||||
outside attacker guesses the numbers and thus obtains your
|
||||
encryption or authentication key. Thus, models of this concept should
|
||||
be cautious not to leak any information, to the extent possible by the
|
||||
environment. For example, it might be advisable to explicitly clear
|
||||
any temporary storage as soon as it is no longer needed.
|
||||
|
||||
|
||||
<h2><a name="pseudo-rng">Pseudo-Random Number Generator</a></h2>
|
||||
|
||||
A pseudo-random number generator is a UniformRandomNumberGenerator
|
||||
which provides a deterministic sequence of pseudo-random numbers,
|
||||
based on some algorithm and internal state. Linear congruential and
|
||||
inversive congruential generators are examples of such pseudo-random
|
||||
number generators. Often, these generators are very sensitive to
|
||||
their parameters. In order to prevent wrong implementations from
|
||||
being used, an external testsuite should check that the generated
|
||||
sequence and the validation value provided do indeed match.
|
||||
<p>
|
||||
|
||||
Donald E. Knuth gives an extensive overview on pseudo-random number
|
||||
generation in his book "The Art of Computer Programming, Vol. 2, 3rd
|
||||
edition, Addison-Wesley, 1997". The descriptions for the specific
|
||||
generators contain additional references.
|
||||
<p>
|
||||
|
||||
<em>Note:</em> Because the state of a pseudo-random number generator
|
||||
is necessarily finite, the sequence of numbers returned by the
|
||||
generator will loop eventually.
|
||||
|
||||
<p>
|
||||
In addition to the UniformRandomNumberGenerator requirements, a
|
||||
pseudo-random number generator has some additional requirements. In
|
||||
the following table, <code>X</code> denotes a pseudo-random number
|
||||
generator class returning objects of type <code>T</code>,
|
||||
<code>x</code> is a value of <code>T</code>, <code>u</code> is a value
|
||||
of <code>X</code>, and <code>v</code> is a <code>const</code> value of
|
||||
<code>X</code>.
|
||||
|
||||
<p>
|
||||
|
||||
<table border=1>
|
||||
<tr><th colspan=3 align=center><code>PseudoRandomNumberGenerator</code>
|
||||
requirements</th></tr>
|
||||
<tr><td>expression</td><td>return type</td>
|
||||
<td>pre/post-condition</td></tr>
|
||||
<tr><td><code>X()</code></td><td>-</td>
|
||||
<td>creates a generator in some implementation-defined
|
||||
state. <em>Note:</em> Several generators thusly created may possibly
|
||||
produce dependent or identical sequences of random numbers.</td></tr>
|
||||
<tr><td><code>explicit X(...)</code></td><td>-</td>
|
||||
<td>creates a generator with user-provided state; the implementation
|
||||
shall specify the constructor argument(s)</td></tr>
|
||||
<tr><td><code>u.seed(...)</code></td><td>void</td>
|
||||
<td>sets the current state according to the argument(s); at least
|
||||
functions with the same signature as the non-default
|
||||
constructor(s) shall be provided.
|
||||
<tr><td><code>X::validation(x)</code></td><td><code>bool</code></td>
|
||||
<td>compares the pre-computed and hardcoded 10001th element in the
|
||||
generator's random number sequence with <code>x</code>. The generator
|
||||
must have been constructed by its default constructor and
|
||||
<code>seed</code> must not have been called for the validation to
|
||||
be meaningful.
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
||||
<em>Note:</em> The <code>seed</code> member function is similar to the
|
||||
<code>assign</code> member function in STL containers. However, the
|
||||
naming did not seem appropriate.
|
||||
|
||||
<p>
|
||||
|
||||
Classes which model a pseudo-random number generator shall also model
|
||||
EqualityComparable, i.e. implement <code>operator==</code>. Two
|
||||
pseudo-random number generators are defined to be <em>equivalent</em>
|
||||
if they both return an identical sequence of numbers starting from a
|
||||
given state.
|
||||
<p>
|
||||
Classes which model a pseudo-random number generator should also model
|
||||
the Streamable concept, i.e. implement <code>operator<<</code>
|
||||
and <code>operator>></code>. If so,
|
||||
<code>operator<<</code> writes all current state of the
|
||||
pseudo-random number generator to the given <code>ostream</code> so
|
||||
that <code>operator>></code> can restore the state at a later
|
||||
time. The state shall be written in a platform-independent manner,
|
||||
but it is assumed that the <code>locale</code>s used for writing and
|
||||
reading be the same.
|
||||
|
||||
The pseudo-random number generator with the restored state and the
|
||||
original at the just-written state shall be equivalent.
|
||||
<p>
|
||||
|
||||
Classes which model a pseudo-random number generator may also model
|
||||
the CopyConstructible and Assignable concepts. However, note that the
|
||||
sequences of the original and the copy are strongly correlated (in
|
||||
fact, they are identical), which may make them unsuitable for some
|
||||
problem domains. Thus, copying pseudo-random number generators is
|
||||
discouraged; they should always be passed by (non-<code>const</code>)
|
||||
reference.
|
||||
|
||||
<p>
|
||||
|
||||
The classes
|
||||
<code><a href="random-generators.html#rand48">rand48</a></code>,
|
||||
<code><a href="random-generators.html#linear_congruential">minstd_rand</a></code>,
|
||||
and
|
||||
<code><a href="random-generators.html#mersenne_twister">mt19937</a></code>
|
||||
are models for a pseudo-random number generator.
|
||||
|
||||
<p>
|
||||
<em>Note:</em> This type of random-number generator is useful for
|
||||
numerics, games and testing. The non-zero arguments constructor(s)
|
||||
and the <code>seed()</code> member function(s) allow for a
|
||||
user-provided state to be installed in the generator. This is useful
|
||||
for debugging Monte-Carlo algorithms and analyzing particular test
|
||||
scenarios. The Streamable concept allows to save/restore the state of
|
||||
the generator, for example to re-run a test suite at a later time.
|
||||
|
||||
<h2><a name="random-dist">Random Distribution</a></h2>
|
||||
|
||||
A radom distribution produces random numbers distributed according to
|
||||
some distribution, given uniformly distributed random values as input.
|
||||
|
||||
In the following table, <code>X</code> denotes a random distribution
|
||||
class returning objects of type <code>T</code>, <code>u</code> is a
|
||||
value of <code>X</code>, <code>x</code> is a (possibly const)
|
||||
value of <code>X</code>, and <code>e</code> is an lvalue of an
|
||||
arbitrary type that meets the requirements of a uniform random number
|
||||
generator, returning values of type <code>U</code>.
|
||||
<p>
|
||||
|
||||
|
||||
<table border=1>
|
||||
<tr>
|
||||
<th colspan=4 align=center>Random distribution requirements
|
||||
(in addition to number generator,
|
||||
<code>CopyConstructible</code>, and <code>Assignable</code>)</th>
|
||||
<tr><td>expression</td><td>return type</td>
|
||||
<td>pre/post-condition</td>
|
||||
<td>complexity</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>X::input_type</code></td>
|
||||
<td>U</td>
|
||||
<td>-</td>
|
||||
<td>compile-time</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>u.reset()</code></td>
|
||||
<td><code>void</code></td>
|
||||
<td>subsequent uses of <code>u</code> do not depend on values
|
||||
produced by <code>e</code> prior to invoking <code>reset</code>.</td>
|
||||
<td>constant</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>u(e)</code></td>
|
||||
<td><code>T</code></td>
|
||||
<td>the sequence of numbers returned by successive invocations with
|
||||
the same object <code>e</code> is randomly distributed with some
|
||||
probability density function p(x)</td>
|
||||
<td>amortized constant number of invocations of <code>e</code></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>os << x</code></td>
|
||||
<td><code>std::ostream&</code></td>
|
||||
<td>writes a textual representation for the parameters and additional
|
||||
internal data of the distribution <code>x</code> to <code>os</code>.
|
||||
<br>
|
||||
post: The <code>os.<em>fmtflags</em></code> and fill character are
|
||||
unchanged.</td>
|
||||
<td>O(size of state)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>is >> u</code></td>
|
||||
<td><code>std::istream&</code></td>
|
||||
<td>restores the parameters and additional internal data of the
|
||||
distribution <code>u</code>.
|
||||
<br>
|
||||
pre: <code>is</code> provides a textual representation that was
|
||||
previously written by <code>operator<<</code>
|
||||
<br>
|
||||
post: The <code>is.<em>fmtflags</em></code> are unchanged.</td>
|
||||
<td>O(size of state)</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<p>
|
||||
|
||||
Additional requirements: The sequence of numbers produced by
|
||||
repeated invocations of <code>x(e)</code> does not change whether or
|
||||
not <code>os << x</code> is invoked between any of the
|
||||
invocations <code>x(e)</code>. If a textual representation
|
||||
is written using <code>os << x</code> and that representation
|
||||
is restored into the same or a different object <code>y</code> of the
|
||||
same type using <code>is >> y</code>, repeated invocations of
|
||||
<code>y(e)</code> produce the same sequence of random numbers as would
|
||||
repeated invocations of <code>x(e)</code>.
|
||||
<p>
|
||||
|
||||
<h2><a name="quasi-rng">Quasi-Random Number Generators</a></h2>
|
||||
|
||||
A quasi-random number generator is a Number Generator which provides a
|
||||
deterministic sequence of numbers, based on some algorithm and
|
||||
internal state. The numbers do not have any statistical properties
|
||||
(such as uniform distribution or independence of successive values).
|
||||
|
||||
<p>
|
||||
|
||||
<em>Note:</em> Quasi-random number generators are useful for
|
||||
Monte-Carlo integrations where specially crafted sequences of random
|
||||
numbers will make the approximation converge faster.
|
||||
|
||||
<p>
|
||||
|
||||
<em>[Does anyone have a model?]</em>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
Jens Maurer, 2000-02-23
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,796 +0,0 @@
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
|
||||
<title>Boost Random Number Library Distributions</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1>Random Number Library Distributions</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a>
|
||||
<li><a href="#synopsis">Synopsis</a>
|
||||
<li><a href="#uniform_smallint">Class template
|
||||
<code>uniform_smallint</code></a>
|
||||
<li><a href="#uniform_int">Class template <code>uniform_int</code></a>
|
||||
<li><a href="#uniform_01">Class template <code>uniform_01</code></a>
|
||||
<li><a href="#uniform_real">Class template
|
||||
<code>uniform_real</code></a>
|
||||
<li><a href="#bernoulli_distribution">Class template
|
||||
<code>bernoulli_distribution</code></a>
|
||||
<li><a href="#geometric_distribution">Class template
|
||||
<code>geometric_distribution</code></a>
|
||||
<li><a href="#triangle_distribution">Class template
|
||||
<code>triangle_distribution</code></a>
|
||||
<li><a href="#exponential_distribution">Class template
|
||||
<code>exponential_distribution</code></a>
|
||||
<li><a href="#normal_distribution">Class template
|
||||
<code>normal_distribution</code></a>
|
||||
<li><a href="#lognormal_distribution">Class template
|
||||
<code>lognormal_distribution</code></a>
|
||||
<li><a href="#uniform_on_sphere">Class template
|
||||
<code>uniform_on_sphere</code></a>
|
||||
</ul>
|
||||
|
||||
<h2><a name="intro">Introduction</a></h2>
|
||||
|
||||
In addition to the <a href="random-generators.html">random number
|
||||
generators</a>, this library provides distribution functions which map
|
||||
one distribution (often a uniform distribution provided by some
|
||||
generator) to another.
|
||||
|
||||
<p>
|
||||
Usually, there are several possible implementations of any given
|
||||
mapping. Often, there is a choice between using more space, more
|
||||
invocations of the underlying source of random numbers, or more
|
||||
time-consuming arithmetic such as trigonometric functions. This
|
||||
interface description does not mandate any specific implementation.
|
||||
However, implementations which cannot reach certain values of the
|
||||
specified distribution or otherwise do not converge statistically to
|
||||
it are not acceptable.
|
||||
|
||||
<p>
|
||||
<table border="1">
|
||||
<tr><th>distribution</th><th>explanation</th><th>example</th></tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#uniform_smallint">uniform_smallint</a></code></td>
|
||||
<td>discrete uniform distribution on a small set of integers (much
|
||||
smaller than the range of the underlying generator)</td>
|
||||
<td>drawing from an urn</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#uniform_int">uniform_int</a></code></td>
|
||||
<td>discrete uniform distribution on a set of integers; the underlying
|
||||
generator may be called several times to gather enough randomness for
|
||||
the output</td>
|
||||
<td>drawing from an urn</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#uniform_01">uniform_01</a></code></td>
|
||||
<td>continuous uniform distribution on the range [0,1); important
|
||||
basis for other distributions</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#uniform_real">uniform_real</a></code></td>
|
||||
<td>continuous uniform distribution on some range [min, max) of real
|
||||
numbers</td>
|
||||
<td>for the range [0, 2pi): randomly dropping a stick and measuring
|
||||
its angle in radiants (assuming the angle is uniformly
|
||||
distributed)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#bernoulli_distribution">bernoulli_distribution</a></code></td>
|
||||
<td>Bernoulli experiment: discrete boolean valued distribution with
|
||||
configurable probability</td>
|
||||
<td>tossing a coin (p=0.5)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#geometric_distribution">geometric_distribution</a></code></td>
|
||||
<td>measures distance between outcomes of repeated Bernoulli experiments</td>
|
||||
<td>throwing a die several times and counting the number of tries
|
||||
until a "6" appears for the first time</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#triangle_distribution">triangle_distribution</a></code></td>
|
||||
<td>?</td>
|
||||
<td>?</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#exponential_distribution">exponential_distribution</a></code></td>
|
||||
<td>exponential distribution</td>
|
||||
<td>measuring the inter-arrival time of alpha particles emitted by
|
||||
radioactive matter</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#normal_distribution">normal_distribution</a></code></td>
|
||||
<td>counts outcomes of (infinitely) repeated Bernoulli experiments</td>
|
||||
<td>tossing a coin 10000 times and counting how many front sides are shown</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#lognormal_distribution">lognormal_distribution</a></code></td>
|
||||
<td>lognormal distribution (sometimes used in simulations)</td>
|
||||
<td>measuring the job completion time of an assembly line worker</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a href="#uniform_on_sphere">uniform_on_sphere</a></code></td>
|
||||
<td>uniform distribution on a unit sphere of arbitrary dimension</td>
|
||||
<td>choosing a random point on Earth (assumed to be a sphere) where to
|
||||
spend the next vacations</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
||||
The template parameters of the distribution functions are always in
|
||||
the order
|
||||
<ul>
|
||||
<li>Underlying source of random numbers
|
||||
<li>If applicable, return type, with a default to a reasonable type.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<em>The distribution functions no longer satisfy the input iterator
|
||||
requirements (std:24.1.1 [lib.input.iterators]), because this is
|
||||
redundant given the Generator interface and imposes a run-time
|
||||
overhead on all users. Moreover, a Generator interface appeals to
|
||||
random number generation as being more "natural". Use an
|
||||
<a href="../utility/iterator_adaptors.htm">iterator adaptor</a>
|
||||
if you need to wrap any of the generators in an input iterator
|
||||
interface.</em>
|
||||
<p>
|
||||
|
||||
All of the distribution functions described below store a non-const
|
||||
reference to the underlying source of random numbers. Therefore, the
|
||||
distribution functions are not Assignable. However, they are
|
||||
CopyConstructible. Copying a distribution function will copy the
|
||||
parameter values. Furthermore, both the copy and the original will
|
||||
refer to the same underlying source of random numbers. Therefore,
|
||||
both the copy and the original will obtain their underlying random
|
||||
numbers from a single sequence.
|
||||
|
||||
<p>
|
||||
In this description, I have refrained from documenting those members
|
||||
in detail which are already defined in the
|
||||
<a href="random-concepts.html">concept documentation</a>.
|
||||
|
||||
|
||||
<h2><a name="synopsis">Synopsis of the distributions</a> available from header
|
||||
<code><boost/random.hpp></code> </h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template<class IntType = int>
|
||||
class uniform_smallint;
|
||||
template<class IntType = int>
|
||||
class uniform_int;
|
||||
template<class RealType = double>
|
||||
class uniform_01;
|
||||
template<class RealType = double>
|
||||
class uniform_real;
|
||||
|
||||
// discrete distributions
|
||||
template<class RealType = double>
|
||||
class bernoulli_distribution;
|
||||
template<class IntType = int>
|
||||
class geometric_distribution;
|
||||
|
||||
// continuous distributions
|
||||
template<class RealType = double>
|
||||
class triangle_distribution;
|
||||
template<class RealType = double>
|
||||
class exponential_distribution;
|
||||
template<class RealType = double>
|
||||
class normal_distribution;
|
||||
template<class RealType = double>
|
||||
class lognormal_distribution;
|
||||
template<class RealType = double,
|
||||
class Cont = std::vector<RealType> >
|
||||
class uniform_on_sphere;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2><a name="uniform_smallint">Class template
|
||||
<code>uniform_smallint</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/uniform_smallint.hpp">boost/random/uniform_smallint.hpp</a>>
|
||||
|
||||
template<class IntType = int>
|
||||
class uniform_smallint
|
||||
{
|
||||
public:
|
||||
typedef IntType input_type;
|
||||
typedef IntType result_type;
|
||||
static const bool has_fixed_range = false;
|
||||
uniform_smallint(IntType min, IntType max);
|
||||
result_type min() const;
|
||||
result_type max() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
The distribution function <code>uniform_smallint</code> models a
|
||||
<a href="random-concepts.html#random-dist">random distribution</a>.
|
||||
On each invocation, it returns a random integer value
|
||||
uniformly distributed in the set of integer numbers {min, min+1,
|
||||
min+2, ..., max}. It assumes that the desired range (max-min+1) is
|
||||
small compared to the range of the underlying source of random
|
||||
numbers and thus makes no attempt to limit quantization errors.
|
||||
<p>
|
||||
Let r<sub>out</sub>=(max-min+1) the desired range of integer numbers,
|
||||
and let r<sub>base</sub> be the range of the underlying source of
|
||||
random numbers. Then, for the uniform distribution, the theoretical
|
||||
probability for any number i in the range r<sub>out</sub> will be
|
||||
p<sub>out</sub>(i) = 1/r<sub>out</sub>. Likewise, assume a uniform
|
||||
distribution on r<sub>base</sub> for the underlying source of random
|
||||
numbers, i.e. p<sub>base</sub>(i) = 1/r<sub>base</sub>. Let
|
||||
p<sub>out_s</sub>(i) denote the random distribution generated by
|
||||
<code>uniform_smallint</code>. Then the sum over all i in
|
||||
r<sub>out</sub> of (p<sub>out_s</sub>(i)/p<sub>out</sub>(i)
|
||||
-1)<sup>2</sup> shall not exceed
|
||||
r<sub>out</sub>/r<sub>base</sub><sup>2</sup> (r<sub>base</sub> mod
|
||||
r<sub>out</sub>)(r<sub>out</sub> - r<sub>base</sub> mod
|
||||
r<sub>out</sub>).
|
||||
<p>
|
||||
|
||||
The template parameter <code>IntType</code> shall denote an
|
||||
integer-like value type.
|
||||
|
||||
<p>
|
||||
<em>Note:</em> The property above is the square sum of the relative
|
||||
differences in probabilities between the desired uniform distribution
|
||||
p<sub>out</sub>(i) and the generated distribution
|
||||
p<sub>out_s</sub>(i). The property can be fulfilled with the
|
||||
calculation (base_rng mod r<sub>out</sub>), as follows: Let r =
|
||||
r<sub>base</sub> mod r<sub>out</sub>. The base distribution on
|
||||
r<sub>base</sub> is folded onto the range r<sub>out</sub>. The
|
||||
numbers i < r have assigned (r<sub>base</sub> div
|
||||
r<sub>out</sub>)+1 numbers of the base distribution, the rest has only
|
||||
(r<sub>base</sub> div r<sub>out</sub>). Therefore,
|
||||
p<sub>out_s</sub>(i) = ((r<sub>base</sub> div r<sub>out</sub>)+1) /
|
||||
r<sub>base</sub> for i < r and p<sub>out_s</sub>(i) =
|
||||
(r<sub>base</sub> div r<sub>out</sub>)/r<sub>base</sub> otherwise.
|
||||
Substituting this in the above sum formula leads to the desired
|
||||
result.
|
||||
<p>
|
||||
<em>Note:</em> The upper bound for (r<sub>base</sub> mod r<sub>out</sub>)(r<sub>out</sub> - r<sub>base</sub>
|
||||
mod r<sub>out</sub>) is r<sub>out</sub><sup>2</sup>/4. Regarding the upper bound for the square
|
||||
sum of the relative quantization error of r<sub>out</sub><sup>3</sup>/(4*r<sub>base</sub><sup>2</sup>), it
|
||||
seems wise to either choose r<sub>base</sub> so that r<sub>base</sub> > 10*r<sub>out</sub><sup>2</sup> or
|
||||
ensure that r<sub>base</sub> is divisible by r<sub>out</sub>.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>uniform_smallint(IntType min, IntType max)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a <code>uniform_smallint</code>
|
||||
functor. <code>min</code> and <code>max</code> are the lower and upper
|
||||
bounds of the output range, respectively.
|
||||
|
||||
|
||||
<h2><a name="uniform_int">Class template <code>uniform_int</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/uniform_int.hpp">boost/random/uniform_int.hpp</a>>
|
||||
|
||||
template<class IntType = int>
|
||||
class uniform_int
|
||||
{
|
||||
public:
|
||||
typedef IntType input_type;
|
||||
typedef IntType result_type;
|
||||
static const bool has_fixed_range = false;
|
||||
explicit uniform_int(IntType min = 0, IntType max = 9);
|
||||
result_type min() const;
|
||||
result_type max() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng, result_type n);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
The distribution function <code>uniform_int</code> models a
|
||||
<a href="random-concepts.html#random-dist">random distribution</a>.
|
||||
On each invocation, it returns a random integer
|
||||
value uniformly distributed in the set of integer numbers
|
||||
{min, min+1, min+2, ..., max}.
|
||||
<p>
|
||||
|
||||
The template parameter <code>IntType</code> shall denote an
|
||||
integer-like value type.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre> uniform_int(IntType min = 0, IntType max = 9)</pre>
|
||||
<strong>Requires:</strong> min <= max
|
||||
<br>
|
||||
<strong>Effects:</strong> Constructs a <code>uniform_int</code>
|
||||
object. <code>min</code> and <code>max</code> are the parameters of
|
||||
the distribution.
|
||||
|
||||
<pre> result_type min() const</pre>
|
||||
<strong>Returns:</strong> The "min" parameter of the distribution.
|
||||
|
||||
<pre> result_type max() const</pre>
|
||||
<strong>Returns:</strong> The "max" parameter of the distribution.
|
||||
|
||||
<pre> result_type operator()(UniformRandomNumberGenerator& urng, result_type
|
||||
n)</pre>
|
||||
<strong>Returns:</strong> A uniform random number x in the range 0
|
||||
<= x < n. <em>[Note: This allows a
|
||||
<code>variate_generator</code> object with a <code>uniform_int</code>
|
||||
distribution to be used with std::random_shuffe, see
|
||||
[lib.alg.random.shuffle]. ]</em>
|
||||
|
||||
|
||||
<h2><a name="uniform_01">Class template <code>uniform_01</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/uniform_01.hpp">boost/random/uniform_01.hpp</a>>
|
||||
|
||||
template<class UniformRandomNumberGenerator, class RealType = double>
|
||||
class uniform_01
|
||||
{
|
||||
public:
|
||||
typedef UniformRandomNumberGenerator base_type;
|
||||
typedef RealType result_type;
|
||||
static const bool has_fixed_range = false;
|
||||
explicit uniform_01(base_type & rng);
|
||||
result_type operator()();
|
||||
result_type min() const;
|
||||
result_type max() const;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
The distribution function <code>uniform_01</code> models a
|
||||
<a href="random-concepts.html#random-dist">random distribution</a>.
|
||||
On each invocation, it returns a random floating-point value uniformly
|
||||
distributed in the range [0..1).
|
||||
|
||||
The value is computed using
|
||||
<code>std::numeric_limits<RealType>::digits</code> random binary
|
||||
digits, i.e. the mantissa of the floating-point value is completely
|
||||
filled with random bits. [<em>Note:</em> Should this be configurable?]
|
||||
|
||||
<p>
|
||||
The template parameter <code>RealType</code> shall denote a float-like
|
||||
value type with support for binary operators +, -, and /. It must be
|
||||
large enough to hold floating-point numbers of value
|
||||
<code>rng.max()-rng.min()+1</code>.
|
||||
<p>
|
||||
<code>base_type::result_type</code> must be a number-like value type,
|
||||
it must support <code>static_cast<></code> to
|
||||
<code>RealType</code> and binary operator -.
|
||||
|
||||
<p>
|
||||
|
||||
<em>Note:</em> The current implementation is buggy, because it may not
|
||||
fill all of the mantissa with random bits. I'm unsure how to fill a
|
||||
(to-be-invented) <code>boost::bigfloat</code> class with random bits
|
||||
efficiently. It's probably time for a traits class.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>explicit uniform_01(base_type & rng)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a <code>uniform_01</code> functor
|
||||
with the given uniform random number generator as the underlying
|
||||
source of random numbers.
|
||||
|
||||
|
||||
<h2><a name="uniform_real">Class template <code>uniform_real</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/uniform_real.hpp">boost/random/uniform_real.hpp</a>>
|
||||
|
||||
template<class RealType = double>
|
||||
class uniform_real
|
||||
{
|
||||
public:
|
||||
typedef RealType input_type;
|
||||
typedef RealType result_type;
|
||||
static const bool has_fixed_range = false;
|
||||
uniform_real(RealType min = RealType(0), RealType max = RealType(1));
|
||||
result_type min() const;
|
||||
result_type max() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
The distribution function <code>uniform_real</code> models a
|
||||
<a href="random-concepts.html#random-dist">random distribution</a>.
|
||||
On each invocation, it returns a random floating-point
|
||||
value uniformly distributed in the range [min..max). The value is
|
||||
computed using
|
||||
<code>std::numeric_limits<RealType>::digits</code> random binary
|
||||
digits, i.e. the mantissa of the floating-point value is completely
|
||||
filled with random bits.
|
||||
<p>
|
||||
|
||||
<em>Note:</em> The current implementation is buggy, because it may not
|
||||
fill all of the mantissa with random bits.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre> uniform_real(RealType min = RealType(0), RealType max = RealType(1))</pre>
|
||||
<strong>Requires:</strong> min <= max
|
||||
<br>
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>uniform_real</code> object; <code>min</code> and
|
||||
<code>max</code> are the parameters of the distribution.
|
||||
|
||||
<pre> result_type min() const</pre>
|
||||
<strong>Returns:</strong> The "min" parameter of the distribution.
|
||||
|
||||
<pre> result_type max() const</pre>
|
||||
<strong>Returns:</strong> The "max" parameter of the distribution.
|
||||
|
||||
|
||||
<h2><a name="bernoulli_distribution">Class template
|
||||
<code>bernoulli_distribution</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/bernoulli_distribution.hpp">boost/random/bernoulli_distribution.hpp</a>>
|
||||
|
||||
template<class RealType = double>
|
||||
class bernoulli_distribution
|
||||
{
|
||||
public:
|
||||
typedef int input_type;
|
||||
typedef bool result_type;
|
||||
|
||||
explicit bernoulli_distribution(const RealType& p = RealType(0.5));
|
||||
RealType p() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>bernoulli_distribution</code>
|
||||
model a <a href="random-concepts.html#random-dist">random
|
||||
distribution</a>. Such a random distribution produces
|
||||
<code>bool</code> values distributed with probabilities P(true) = p
|
||||
and P(false) = 1-p. p is the parameter of the distribution.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre> bernoulli_distribution(const RealType& p = RealType(0.5))</pre>
|
||||
|
||||
<strong>Requires:</strong> 0 <= p <= 1
|
||||
<br>
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>bernoulli_distribution</code> object. <code>p</code> is the
|
||||
parameter of the distribution.
|
||||
|
||||
<pre> RealType p() const</pre>
|
||||
<strong>Returns:</strong> The "p" parameter of the distribution.
|
||||
|
||||
|
||||
<h2><a name="geometric_distribution">Class template
|
||||
<code>geometric_distribution</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/geometric_distribution.hpp">boost/random/geometric_distribution.hpp</a>>
|
||||
|
||||
template<class UniformRandomNumberGenerator, class IntType = int>
|
||||
class geometric_distribution
|
||||
{
|
||||
public:
|
||||
typedef RealType input_type;
|
||||
typedef IntType result_type;
|
||||
|
||||
explicit geometric_distribution(const RealType& p = RealType(0.5));
|
||||
RealType p() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>geometric_distribution</code>
|
||||
model a
|
||||
<a href="random-concepts.html#random-dist">random distribution</a>.
|
||||
A <code>geometric_distribution</code> random distribution produces
|
||||
integer values <em>i</em> >= 1 with p(i) = (1-p) * p<sup>i-1</sup>.
|
||||
p is the parameter of the distribution.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre> geometric_distribution(const RealType& p = RealType(0.5))</pre>
|
||||
|
||||
<strong>Requires:</strong> 0 < p < 1
|
||||
<br>
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>geometric_distribution</code> object; <code>p</code> is the
|
||||
parameter of the distribution.
|
||||
|
||||
<pre> RealType p() const</pre>
|
||||
<strong>Returns:</strong> The "p" parameter of the distribution.
|
||||
|
||||
|
||||
<h2><a name="triangle_distribution">Class template
|
||||
<code>triangle_distribution</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/triangle_distribution.hpp">boost/random/triangle_distribution.hpp</a>>
|
||||
|
||||
template<class RealType = double>
|
||||
class triangle_distribution
|
||||
{
|
||||
public:
|
||||
typedef RealType input_type;
|
||||
typedef RealType result_type;
|
||||
triangle_distribution(result_type a, result_type b, result_type c);
|
||||
result_type a() const;
|
||||
result_type b() const;
|
||||
result_type c() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>triangle_distribution</code>
|
||||
model a <a href="random-concepts.html#random-dist">random
|
||||
distribution</a>. The returned floating-point values <code>x</code>
|
||||
satisfy <code>a <= x <= c</code>; <code>x</code> has a triangle
|
||||
distribution, where <code>b</code> is the most probable value for
|
||||
<code>x</code>.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>triangle_distribution(result_type a, result_type b, result_type c)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>triangle_distribution</code> functor. <code>a, b, c</code> are
|
||||
the parameters for the distribution.
|
||||
<p>
|
||||
|
||||
|
||||
<h2><a name="exponential_distribution">Class template
|
||||
<code>exponential_distribution</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/exponential_distribution.hpp">boost/random/exponential_distribution.hpp</a>>
|
||||
|
||||
template<class RealType = double>
|
||||
class exponential_distribution
|
||||
{
|
||||
public:
|
||||
typedef RealType input_type;
|
||||
typedef RealType result_type;
|
||||
explicit exponential_distribution(const result_type& lambda);
|
||||
RealType lambda() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>exponential_distribution</code>
|
||||
model a <a href="random-concepts.html#random-dist">random
|
||||
distribution</a>. Such a distribution produces random numbers x >
|
||||
0 distributed with probability density function p(x) = lambda *
|
||||
exp(-lambda * x), where lambda is the parameter of the distribution.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre> exponential_distribution(const result_type& lambda = result_type(1))</pre>
|
||||
<strong>Requires:</strong> lambda > 0
|
||||
<br>
|
||||
<strong>Effects:</strong> Constructs an
|
||||
<code>exponential_distribution</code> object with <code>rng</code> as
|
||||
the reference to the underlying source of random
|
||||
numbers. <code>lambda</code> is the parameter for the distribution.
|
||||
|
||||
<pre> RealType lambda() const</pre>
|
||||
<strong>Returns:</strong> The "lambda" parameter of the distribution.
|
||||
|
||||
|
||||
<h2><a name="normal_distribution">Class template
|
||||
<code>normal_distribution</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/normal_distribution.hpp">boost/random/normal_distribution.hpp</a>>
|
||||
|
||||
template<class RealType = double>
|
||||
class normal_distribution
|
||||
{
|
||||
public:
|
||||
typedef RealType input_type;
|
||||
typedef RealType result_type;
|
||||
explicit normal_distribution(const result_type& mean = 0,
|
||||
const result_type& sigma = 1);
|
||||
RealType mean() const;
|
||||
RealType sigma() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>normal_distribution</code>
|
||||
model a <a href="random-concepts.html#random-dist">random
|
||||
distribution</a>. Such a distribution produces random numbers x
|
||||
distributed with probability density function p(x) =
|
||||
1/sqrt(2*pi*sigma) * exp(- (x-mean)<sup>2</sup> /
|
||||
(2*sigma<sup>2</sup>) ), where mean and sigma are the parameters of
|
||||
the distribution.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>
|
||||
explicit normal_distribution(const result_type& mean = 0,
|
||||
const result_type& sigma = 1);
|
||||
</pre>
|
||||
|
||||
<strong>Requires:</strong> sigma > 0
|
||||
<br>
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>normal_distribution</code> object; <code>mean</code> and
|
||||
<code>sigma</code> are the parameters for the distribution.
|
||||
|
||||
<pre> RealType mean() const</pre>
|
||||
<strong>Returns:</strong> The "mean" parameter of the distribution.
|
||||
|
||||
<pre> RealType sigma() const</pre>
|
||||
<strong>Returns:</strong> The "sigma" parameter of the distribution.
|
||||
|
||||
|
||||
<h2><a name="lognormal_distribution">Class template
|
||||
<code>lognormal_distribution</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/lognormal_distribution.hpp">boost/random/lognormal_distribution.hpp</a>>
|
||||
|
||||
template<class RealType = double>
|
||||
class lognormal_distribution
|
||||
{
|
||||
public:
|
||||
typedef typename normal_distribution<RealType>::input_type
|
||||
typedef RealType result_type;
|
||||
explicit lognormal_distribution(const result_type& mean = 1.0,
|
||||
const result_type& sigma = 1.0);
|
||||
RealType& mean() const;
|
||||
RealType& sigma() const;
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
result_type operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>lognormal_distribution</code>
|
||||
model a <a href="random-concepts.html#random-dist">random
|
||||
distribution</a>. Such a distribution produces random numbers
|
||||
with p(x) = 1/(x * normal_sigma * sqrt(2*pi)) * exp(
|
||||
-(log(x)-normal_mean)<sup>2</sup> / (2*normal_sigma<sup>2</sup>) )
|
||||
for x > 0,
|
||||
where normal_mean = log(mean<sup>2</sup>/sqrt(sigma<sup>2</sup>
|
||||
+ mean<sup>2</sup>))
|
||||
and normal_sigma = sqrt(log(1 + sigma<sup>2</sup>/mean<sup>2</sup>)).
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>lognormal_distribution(const result_type& mean,
|
||||
const result_type& sigma)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>lognormal_distribution</code> functor. <code>mean</code> and
|
||||
<code>sigma</code> are the mean and standard deviation of the
|
||||
lognormal distribution.
|
||||
<p>
|
||||
|
||||
|
||||
<h2><a name="uniform_on_sphere">Class template
|
||||
<code>uniform_on_sphere</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/uniform_on_sphere.hpp">boost/random/uniform_on_sphere.hpp</a>>
|
||||
|
||||
template<class RealType = double,
|
||||
class Cont = std::vector<RealType> >
|
||||
class uniform_on_sphere
|
||||
{
|
||||
public:
|
||||
typedef RealType input_type;
|
||||
typedef Cont result_type;
|
||||
explicit uniform_on_sphere(int dim = 2);
|
||||
void reset();
|
||||
template<class UniformRandomNumberGenerator>
|
||||
const result_type & operator()(UniformRandomNumberGenerator& urng);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>uniform_on_sphere</code> model a
|
||||
<a href="random-concepts.html#random-dist">random distribution</a>.
|
||||
Such a distribution produces random numbers uniformly distributed on
|
||||
the unit sphere of arbitrary dimension <code>dim</code>. The
|
||||
<code>Cont</code> template parameter must be a STL-like container type
|
||||
with <code>begin</code> and <code>end</code> operations returning
|
||||
non-const ForwardIterators of type <code>Cont::iterator</code>.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>explicit uniform_on_sphere(int dim = 2)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a <code>uniform_on_sphere</code>
|
||||
functor. <code>dim</code> is the dimension of the sphere.
|
||||
<p>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
Jens Maurer, 2003-10-25
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,93 +0,0 @@
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
|
||||
<title>Boost Random Number Generator Library (Miscellaneous)</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1>Random Number Generator Library --- Miscellaneous Decorators</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#random_number_generator">Class template
|
||||
<code>random_number_generator</code></a>
|
||||
<li><a href="#generator_iterator">Class template
|
||||
<code>generator_iterator</code></a>
|
||||
</ul>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
These decorator class templates allow adaptation of the random number
|
||||
generators and distribution functions to concepts found in the C++
|
||||
Standard Library, in particular the RandomNumberGenerator and the
|
||||
InputIterator concepts. The latter adaptation is useful, because the
|
||||
the basic random number generators do not implement the InputIterator
|
||||
requirements per se, in contrast to the distribution functions.
|
||||
|
||||
|
||||
<h2><a name="synopsis">Synopsis</a> of miscellaneous decorators in
|
||||
header <code><boost/random.hpp></code></h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template<class UniformRandomNumberGenerator, class IntType = long>
|
||||
class random_number_generator;
|
||||
template<class Generator>
|
||||
class generator_iterator;
|
||||
} // namespace boost
|
||||
</pre>
|
||||
|
||||
|
||||
<h2><a name="random_number_generator">Class template
|
||||
<code>random_number_generator</code></a></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
<pre>
|
||||
template<class UniformRandomNumberGenerator, class IntType = long>
|
||||
class random_number_generator
|
||||
{
|
||||
public:
|
||||
typedef UniformRandomNumberGenerator base_type;
|
||||
typedef IntType argument_type;
|
||||
typedef IntType result_type;
|
||||
random_number_generator(base_type & rng);
|
||||
result_type operator()(argument_type n);
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantiations of class template <code>random_number_generator</code>
|
||||
model a RandomNumberGenerator (std:25.2.11 [lib.alg.random.shuffle]).
|
||||
On each invocation, it returns a uniformly distributed integer in
|
||||
the range [0..<code>n</code>).
|
||||
<p>
|
||||
The template parameter <code>IntType</code> shall denote some
|
||||
integer-like value type.
|
||||
<p>
|
||||
|
||||
<em>Note:</em> I consider it unfortunate that the C++ Standard uses
|
||||
the name RandomNumberGenerator for something rather specific.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
<pre>random_number_generator(base_type & rng)</pre>
|
||||
|
||||
<strong>Effects:</strong> Constructs a
|
||||
<code>random_number_generator</code> functor with the given uniform
|
||||
random number generator as the underlying source of random numbers.
|
||||
|
||||
<pre>result_type operator()(argument_type n)</pre>
|
||||
|
||||
<strong>Returns:</strong> The value of
|
||||
<code>uniform_int<base_type>(rng, 0, n-1)()</code>.
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
Jens Maurer, 2001-11-19
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,241 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Boost Random Number Library Performance</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1>Random Number Library Performance</h1>
|
||||
|
||||
For some people, performance of random number generation is an
|
||||
important consideration when choosing a random number generator or a
|
||||
particular distribution function. This page provides numerous
|
||||
performance tests with the wide variety of generators and
|
||||
distributions available in the boost library.
|
||||
<p>
|
||||
The performance has been evaluated on a Pentium Pro 200 MHz with gcc
|
||||
2.95.2, Linux 2.2.13, glibc 2.1.2. The speed is reported in million
|
||||
random numbers per second (M rn/sec), generated in a tight loop.
|
||||
<p>
|
||||
|
||||
|
||||
<h2>Basic Generators</h2>
|
||||
|
||||
<table border="1">
|
||||
|
||||
<tr>
|
||||
<th>generator</th>
|
||||
<th>M rn/sec</th>
|
||||
<th>time per random number [usec]</th>
|
||||
<th>relative speed compared to fastest [percent]</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>rand48</td>
|
||||
<td>5.38</td>
|
||||
<td>0.183</td>
|
||||
<td>61%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>rand48 run-time configurable</td>
|
||||
<td>1.48</td>
|
||||
<td>0.677</td>
|
||||
<td>17%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>lrand48 glibc 2.1.2</td>
|
||||
<td>1.19</td>
|
||||
<td>0.843</td>
|
||||
<td>13%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>minstd_rand</td>
|
||||
<td>2.39</td>
|
||||
<td>0.318</td>
|
||||
<td>35%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>ecuyer1988</td>
|
||||
<td>1.12</td>
|
||||
<td>0.892</td>
|
||||
<td>13%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>kreutzer1986</td>
|
||||
<td>3.87</td>
|
||||
<td>0.258</td>
|
||||
<td>43%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>hellekalek1995 (inversive)</td>
|
||||
<td>0.20</td>
|
||||
<td>5.12</td>
|
||||
<td>2%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>mt11213b</td>
|
||||
<td>6.07</td>
|
||||
<td>0.165</td>
|
||||
<td>68%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>mt19937</td>
|
||||
<td>6.06</td>
|
||||
<td>0.165</td>
|
||||
<td>68%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>mt19937 original</td>
|
||||
<td>5.33</td>
|
||||
<td>0.188</td>
|
||||
<td>60%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>lagged_fibonacci607</td>
|
||||
<td>8.90</td>
|
||||
<td>0.112</td>
|
||||
<td>100%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>lagged_fibonacci4423</td>
|
||||
<td>8.54</td>
|
||||
<td>0.117</td>
|
||||
<td>96%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>lagged_fibonacci19937</td>
|
||||
<td>7.49</td>
|
||||
<td>0.133</td>
|
||||
<td>84%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>lagged_fibonacci23209</td>
|
||||
<td>6.63</td>
|
||||
<td>0.151</td>
|
||||
<td>74%</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>lagged_fibonacci44497</td>
|
||||
<td>4.01</td>
|
||||
<td>0.250</td>
|
||||
<td>45%</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<p>
|
||||
Note that the lagged Fibonacci generators produce floating-point
|
||||
numbers, whereas all others produce integers.
|
||||
|
||||
<h2>Distributions</h2>
|
||||
|
||||
<table border="1">
|
||||
|
||||
<tr>
|
||||
<th>[M rn/sec]</th>
|
||||
<th>minstd_rand</th>
|
||||
<th>kreutzer1986</th>
|
||||
<th>mt19937</th>
|
||||
<th>lagged_fibonacci607</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>uniform_smallint</th>
|
||||
<td>1.26</td>
|
||||
<td>1.55</td>
|
||||
<td>1.93</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>uniform_01</th>
|
||||
<td>1.79</td>
|
||||
<td>1.88</td>
|
||||
<td>3.03</td>
|
||||
<td>7.74</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>uniform_real</th>
|
||||
<td>1.74</td>
|
||||
<td>1.56</td>
|
||||
<td>2.34</td>
|
||||
<td>6.62</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>geometric</th>
|
||||
<td>0.593</td>
|
||||
<td>0.629</td>
|
||||
<td>0.753</td>
|
||||
<td>0.916</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>triangle</th>
|
||||
<td>0.97</td>
|
||||
<td>1.02</td>
|
||||
<td>1.35</td>
|
||||
<td>1.31</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>exponential</th>
|
||||
<td>0.849</td>
|
||||
<td>0.828</td>
|
||||
<td>0.887</td>
|
||||
<td>1.53</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>normal (polar method)</th>
|
||||
<td>0.608</td>
|
||||
<td>0.626</td>
|
||||
<td>0.738</td>
|
||||
<td>0.755</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>lognormal</th>
|
||||
<td>0.417</td>
|
||||
<td>0.442</td>
|
||||
<td>0.470</td>
|
||||
<td>0.481</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>uniform_on_sphere</th>
|
||||
<td>0.154</td>
|
||||
<td>0.155</td>
|
||||
<td>0.174</td>
|
||||
<td>0.218</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<p>
|
||||
Note that the lagged Fibonacci generator is at least 2.5 times faster
|
||||
than the Mersenne twister when generating uniformly distributed
|
||||
floating-point numbers. For more sophisticated distributions, the
|
||||
speed improvement is less. Note however that these distributions have
|
||||
not been optimized for speed, yet.
|
||||
<p>
|
||||
<hr>
|
||||
Jens Maurer, 2001-04-15
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,144 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
|
||||
<title>Boost Random Number Library Variate Generator</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1>Boost Random Number Library Variate Generator</h1>
|
||||
|
||||
A random variate generator is used to join a random number generator
|
||||
together with a random number distribution.
|
||||
Boost.Random provides a vast choice of
|
||||
<a href="random-generators.html">generators</a>
|
||||
as well as
|
||||
<a href="random-distributions.html">distributions</a>
|
||||
.
|
||||
|
||||
|
||||
<h2><a name="variate_generator">Class template <code>variate_generator</code></h2>
|
||||
|
||||
<h3>Synopsis</h3>
|
||||
<pre>
|
||||
#include <<a href="../../boost/random/variate_generator.hpp">boost/random/variate_generator.hpp</a>>
|
||||
|
||||
template<class Engine, class Distribution>
|
||||
class variate_generator
|
||||
{
|
||||
public:
|
||||
typedef Engine engine_type;
|
||||
typedef Distribution distribution_type;
|
||||
typedef typename Distribution::result_type result_type;
|
||||
|
||||
variate_generator(Engine e, Distribution d);
|
||||
|
||||
result_type operator()();
|
||||
template<class T>
|
||||
result_type operator()(T value);
|
||||
|
||||
engine_value_type& engine();
|
||||
const engine_value_type& engine() const;
|
||||
|
||||
result_type min() const;
|
||||
result_type max() const;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Description</h3>
|
||||
|
||||
Instantations of class template <code>variate_generator</code> model a
|
||||
<a href="random-concepts.html#number_generator">number generator</a>.
|
||||
<p>
|
||||
The argument for the template parameter <code>Engine</code> shall be
|
||||
of the form U, U&, or U*, where U models a uniform random number
|
||||
generator. Then, the member <code>engine_value_type</code> names U
|
||||
(not the pointer or reference to U).
|
||||
<p>
|
||||
|
||||
Specializations of <code>variate_generator</code> satisfy the
|
||||
requirements of CopyConstructible. They also satisfy the requirements
|
||||
of Assignable unless the template parameter Engine is of the form U&.
|
||||
<p>
|
||||
|
||||
The complexity of all functions specified in this section is
|
||||
constant. No function described in this section except the constructor
|
||||
throws an exception.
|
||||
|
||||
<pre> variate_generator(engine_type eng, distribution_type d)</pre>
|
||||
<strong>Effects:</strong> Constructs a <code>variate_generator</code>
|
||||
object with the associated uniform random number generator
|
||||
<code>eng</code> and the associated random distribution
|
||||
<code>d</code>.
|
||||
<br>
|
||||
<strong>Throws:</strong> If and what the copy constructor of Engine or
|
||||
Distribution throws.
|
||||
|
||||
<pre> result_type operator()()</pre>
|
||||
<strong>Returns:</strong> <code>distribution()(e)</code>
|
||||
<br>
|
||||
<strong>Notes:</strong> The sequence of numbers produced by the
|
||||
uniform random number generator <code>e</code>, s<sub>e</sub>, is
|
||||
obtained from the sequence of numbers produced by the associated
|
||||
uniform random number generator <code>eng</code>, s<sub>eng</sub>, as
|
||||
follows: Consider the values of
|
||||
<code>numeric_limits<<em>T</em>>::is_integer</code> for
|
||||
<code><em>T</em></code> both <code>Distribution::input_type</code> and
|
||||
<code>engine_value_type::result_type</code>. If the values for both
|
||||
types are <code>true</code>, then s<sub>e</sub> is identical to
|
||||
s<sub>eng</sub>. Otherwise, if the values for both types are
|
||||
<code>false</code>, then the numbers in s<sub>eng</sub> are divided by
|
||||
<code>engine().max()-engine().min()</code> to obtain the
|
||||
numbers in s<sub>e</sub>. Otherwise, if the value for
|
||||
<code>engine_value_type::result_type</code> is <code>true</code> and
|
||||
the value for <code>Distribution::input_type</code> is
|
||||
<code>false</code>, then the numbers in s<sub>eng</sub> are divided by
|
||||
<code>engine().max()-engine().min()+1</code> to obtain the
|
||||
numbers in s<sub>e</sub>. Otherwise, the mapping from s<sub>eng</sub>
|
||||
to s<sub>e</sub> is implementation-defined. In all cases, an implicit
|
||||
conversion from <code>engine_value_type::result_type</code> to
|
||||
<code>Distribution::input_type</code> is performed. If such a
|
||||
conversion does not exist, the program is ill-formed.
|
||||
|
||||
<pre> template<class T> result_type operator()(T value)</pre>
|
||||
<strong>Returns:</strong> <code>distribution()(e, value)</code>. For
|
||||
the semantics of <code>e</code>, see the description of
|
||||
<code>operator()()</code>.
|
||||
|
||||
<pre> engine_value_type& engine()</pre>
|
||||
<strong>Returns:</strong> A reference to the associated uniform random
|
||||
number generator.
|
||||
|
||||
<pre> const engine_value_type& engine() const</pre>
|
||||
<strong>Returns:</strong> A reference to the associated uniform random
|
||||
number generator.
|
||||
|
||||
<pre> distribution_type& distribution()</pre>
|
||||
<strong>Returns:</strong> A reference to the associated random
|
||||
distribution.
|
||||
|
||||
<pre> const distribution_type& distribution() const</pre>
|
||||
<strong>Returns:</strong> A reference to the associated random
|
||||
distribution.
|
||||
|
||||
<pre> result_type min() const</pre>
|
||||
<strong>Precondition:</strong> <code>distribution().min()</code> is
|
||||
well-formed
|
||||
<br>
|
||||
<strong>Returns:</strong> <code>distribution().min()</code>
|
||||
|
||||
<pre> result_type max() const</pre>
|
||||
<strong>Precondition:</strong> <code>distribution().max()</code> is
|
||||
well-formed
|
||||
<br>
|
||||
<strong>Returns:</strong> <code>distribution().max()</code>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<a href="../../people/jens_maurer.htm">Jens Maurer</a>,
|
||||
2003-10-25
|
||||
|
||||
</body>
|
||||
</html>
|
||||
133
random_demo.cpp
133
random_demo.cpp
@@ -1,133 +0,0 @@
|
||||
/* boost random_demo.cpp profane demo
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* A short demo program how to use the random number library.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <ctime> // std::time
|
||||
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
#include <boost/random/uniform_real.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
|
||||
// Sun CC doesn't handle boost::iterator_adaptor yet
|
||||
#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530)
|
||||
#include <boost/generator_iterator.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std {
|
||||
using ::time;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This is a typedef for a random number generator.
|
||||
// Try boost::mt19937 or boost::ecuyer1988 instead of boost::minstd_rand
|
||||
typedef boost::minstd_rand base_generator_type;
|
||||
|
||||
// This is a reproducible simulation experiment. See main().
|
||||
void experiment(base_generator_type & generator)
|
||||
{
|
||||
// Define a uniform random number distribution of integer values between
|
||||
// 1 and 6 inclusive.
|
||||
typedef boost::uniform_int<> distribution_type;
|
||||
typedef boost::variate_generator<base_generator_type, distribution_type> gen_type;
|
||||
gen_type die_gen(generator, distribution_type(1, 6));
|
||||
|
||||
#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530)
|
||||
// If you want to use an STL iterator interface, use iterator_adaptors.hpp.
|
||||
// Unfortunately, this doesn't work on SunCC yet.
|
||||
boost::generator_iterator<gen_type> die(&die_gen);
|
||||
for(int i = 0; i < 10; i++)
|
||||
std::cout << *die++ << " ";
|
||||
std::cout << '\n';
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Define a random number generator and initialize it with a reproducible
|
||||
// seed.
|
||||
// (The seed is unsigned, otherwise the wrong overload may be selected
|
||||
// when using mt19937 as the base_generator_type.)
|
||||
base_generator_type generator(42u);
|
||||
|
||||
std::cout << "10 samples of a uniform distribution in [0..1):\n";
|
||||
|
||||
// Define a uniform random number distribution which produces "double"
|
||||
// values between 0 and 1 (0 inclusive, 1 exclusive).
|
||||
boost::uniform_real<> uni_dist(0,1);
|
||||
boost::variate_generator<base_generator_type&, boost::uniform_real<> > uni(generator, uni_dist);
|
||||
|
||||
std::cout.setf(std::ios::fixed);
|
||||
// You can now retrieve random numbers from that distribution by means
|
||||
// of a STL Generator interface, i.e. calling the generator as a zero-
|
||||
// argument function.
|
||||
for(int i = 0; i < 10; i++)
|
||||
std::cout << uni() << '\n';
|
||||
|
||||
/*
|
||||
* Change seed to something else.
|
||||
*
|
||||
* Caveat: std::time(0) is not a very good truly-random seed. When
|
||||
* called in rapid succession, it could return the same values, and
|
||||
* thus the same random number sequences could ensue. If not the same
|
||||
* values are returned, the values differ only slightly in the
|
||||
* lowest bits. A linear congruential generator with a small factor
|
||||
* wrapped in a uniform_smallint (see experiment) will produce the same
|
||||
* values for the first few iterations. This is because uniform_smallint
|
||||
* takes only the highest bits of the generator, and the generator itself
|
||||
* needs a few iterations to spread the initial entropy from the lowest bits
|
||||
* to the whole state.
|
||||
*/
|
||||
generator.seed(static_cast<unsigned int>(std::time(0)));
|
||||
|
||||
std::cout << "\nexperiment: roll a die 10 times:\n";
|
||||
|
||||
// You can save a generator's state by copy construction.
|
||||
base_generator_type saved_generator = generator;
|
||||
|
||||
// When calling other functions which take a generator or distribution
|
||||
// as a parameter, make sure to always call by reference (or pointer).
|
||||
// Calling by value invokes the copy constructor, which means that the
|
||||
// sequence of random numbers at the caller is disconnected from the
|
||||
// sequence at the callee.
|
||||
experiment(generator);
|
||||
|
||||
std::cout << "redo the experiment to verify it:\n";
|
||||
experiment(saved_generator);
|
||||
|
||||
// After that, both generators are equivalent
|
||||
assert(generator == saved_generator);
|
||||
|
||||
// as a degenerate case, you can set min = max for uniform_int
|
||||
boost::uniform_int<> degen_dist(4,4);
|
||||
boost::variate_generator<base_generator_type&, boost::uniform_int<> > deg(generator, degen_dist);
|
||||
std::cout << deg() << " " << deg() << " " << deg() << std::endl;
|
||||
|
||||
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
{
|
||||
// You can save the generator state for future use. You can read the
|
||||
// state back in at any later time using operator>>.
|
||||
std::ofstream file("rng.saved", std::ofstream::trunc);
|
||||
file << generator;
|
||||
}
|
||||
#endif
|
||||
// Some compilers don't pay attention to std:3.6.1/5 and issue a
|
||||
// warning here if "return 0;" is omitted.
|
||||
return 0;
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/* boost random_device.cpp implementation
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <boost/nondet_random.hpp>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
// A definition is required even for integral static constants
|
||||
const bool boost::random_device::has_fixed_range;
|
||||
const boost::random_device::result_type boost::random_device::min_value;
|
||||
const boost::random_device::result_type boost::random_device::max_value;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
// the default is the unlimited capacity device, using some secure hash
|
||||
// try "/dev/random" for blocking when the entropy pool has drained
|
||||
const char * const boost::random_device::default_token = "/dev/urandom";
|
||||
|
||||
/*
|
||||
* This uses the POSIX interface for unbuffered reading.
|
||||
* Using buffered std::istream would consume entropy which may
|
||||
* not actually be used. Entropy is a precious good we avoid
|
||||
* wasting.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && defined(_CXXRT_STD_NAME)
|
||||
// I have severe difficulty to get the POSIX includes to work with
|
||||
// -fhonor-std and Dietmar Kühl's standard C++ library. Hack around that
|
||||
// problem for now.
|
||||
extern "C" {
|
||||
static const int O_RDONLY = 0;
|
||||
extern int open(const char *__file, int __oflag, ...);
|
||||
extern int read(int __fd, __ptr_t __buf, size_t __nbytes);
|
||||
extern int close(int __fd);
|
||||
}
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h> // open
|
||||
#include <unistd.h> // read, close
|
||||
#endif
|
||||
|
||||
#include <errno.h> // errno
|
||||
#include <string.h> // strerror
|
||||
#include <stdexcept> // std::invalid_argument
|
||||
|
||||
|
||||
class boost::random_device::impl
|
||||
{
|
||||
public:
|
||||
impl(const std::string & token) : path(token) {
|
||||
fd = open(token.c_str(), O_RDONLY);
|
||||
if(fd < 0)
|
||||
error("cannot open");
|
||||
}
|
||||
|
||||
~impl() { if(close(fd) < 0) error("could not close"); }
|
||||
|
||||
unsigned int next() {
|
||||
unsigned int result;
|
||||
long sz = read(fd, reinterpret_cast<char *>(&result), sizeof(result));
|
||||
if(sz == -1)
|
||||
error("error while reading");
|
||||
else if(sz != sizeof(result)) {
|
||||
errno = 0;
|
||||
error("EOF while reading");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void error(const std::string & msg) {
|
||||
throw std::invalid_argument("boost::random_device: " + msg +
|
||||
" random-number pseudo-device " + path +
|
||||
": " + strerror(errno));
|
||||
}
|
||||
const std::string path;
|
||||
int fd;
|
||||
};
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
|
||||
boost::random_device::random_device(const std::string& token)
|
||||
: pimpl(new impl(token))
|
||||
{
|
||||
assert((std::numeric_limits<result_type>::max)() == max_value);
|
||||
}
|
||||
|
||||
boost::random_device::~random_device()
|
||||
{
|
||||
// the complete class impl is now visible, so we're safe
|
||||
// (see comment in random.hpp)
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
double boost::random_device::entropy() const
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
unsigned int boost::random_device::operator()()
|
||||
{
|
||||
return pimpl->next();
|
||||
}
|
||||
371
random_speed.cpp
371
random_speed.cpp
@@ -1,371 +0,0 @@
|
||||
/* boost random_speed.cpp performance measurements
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/progress.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
/*
|
||||
* Configuration Section
|
||||
*/
|
||||
|
||||
// define if your C library supports the non-standard drand48 family
|
||||
#undef HAVE_DRAND48
|
||||
|
||||
// define if you have the original mt19937int.c (with commented out main())
|
||||
#undef HAVE_MT19937INT_C
|
||||
|
||||
// set to your CPU frequency in MHz
|
||||
static const double cpu_frequency = 200 * 1e6;
|
||||
|
||||
/*
|
||||
* End of Configuration Section
|
||||
*/
|
||||
|
||||
/*
|
||||
* General portability note:
|
||||
* MSVC mis-compiles explicit function template instantiations.
|
||||
* For example, f<A>() and f<B>() are both compiled to call f<A>().
|
||||
* BCC is unable to implicitly convert a "const char *" to a std::string
|
||||
* when using explicit function template instantiations.
|
||||
*
|
||||
* Therefore, avoid explicit function template instantiations.
|
||||
*/
|
||||
|
||||
// provides a run-time configurable linear congruential generator, just
|
||||
// for comparison
|
||||
template<class IntType>
|
||||
class linear_congruential
|
||||
{
|
||||
public:
|
||||
typedef IntType result_type;
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
|
||||
|
||||
linear_congruential(IntType x0, IntType a, IntType c, IntType m)
|
||||
: _x(x0), _a(a), _c(c), _m(m) { }
|
||||
// compiler-generated copy ctor and assignment operator are fine
|
||||
void seed(IntType x0, IntType a, IntType c, IntType m)
|
||||
{ _x = x0; _a = a; _c = c; _m = m; }
|
||||
void seed(IntType x0) { _x = x0; }
|
||||
result_type operator()() { _x = (_a*_x+_c) % _m; return _x; }
|
||||
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _c == 0 ? 1 : 0; }
|
||||
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _m -1; }
|
||||
|
||||
private:
|
||||
IntType _x, _a, _c, _m;
|
||||
};
|
||||
|
||||
|
||||
// simplest "random" number generator possible, to check on overhead
|
||||
class counting
|
||||
{
|
||||
public:
|
||||
typedef int result_type;
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
|
||||
|
||||
counting() : _x(0) { }
|
||||
result_type operator()() { return ++_x; }
|
||||
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 1; }
|
||||
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::numeric_limits<result_type>::max)(); }
|
||||
|
||||
private:
|
||||
int _x;
|
||||
};
|
||||
|
||||
|
||||
// decoration of variate_generator to make it runtime-exchangeable
|
||||
// for speed comparison
|
||||
template<class Ret>
|
||||
class RandomGenBase
|
||||
{
|
||||
public:
|
||||
virtual Ret operator()() = 0;
|
||||
virtual ~RandomGenBase() { }
|
||||
};
|
||||
|
||||
template<class URNG, class Dist, class Ret = typename Dist::result_type>
|
||||
class DynamicRandomGenerator
|
||||
: public RandomGenBase<Ret>
|
||||
{
|
||||
public:
|
||||
DynamicRandomGenerator(URNG& urng, const Dist& d) : _rng(urng, d) { }
|
||||
Ret operator()() { return _rng(); }
|
||||
private:
|
||||
boost::variate_generator<URNG&, Dist> _rng;
|
||||
};
|
||||
|
||||
template<class Ret>
|
||||
class GenericRandomGenerator
|
||||
{
|
||||
public:
|
||||
typedef Ret result_type;
|
||||
|
||||
GenericRandomGenerator() { };
|
||||
void set(boost::shared_ptr<RandomGenBase<Ret> > p) { _p = p; }
|
||||
// takes over ownership
|
||||
void set(RandomGenBase<Ret> * p) { _p.reset(p); }
|
||||
Ret operator()() { return (*_p)(); }
|
||||
private:
|
||||
boost::shared_ptr<RandomGenBase<Ret> > _p;
|
||||
};
|
||||
|
||||
|
||||
// start implementation of measuring timing
|
||||
|
||||
void show_elapsed(double end, int iter, const std::string & name)
|
||||
{
|
||||
double usec = end/iter*1e6;
|
||||
double cycles = usec * cpu_frequency/1e6;
|
||||
std::cout << name << ": "
|
||||
<< usec*1e3 << " nsec/loop = "
|
||||
<< cycles << " CPU cycles"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<class RNG>
|
||||
void timing(RNG & rng, int iter, const std::string& name)
|
||||
{
|
||||
// make sure we're not optimizing too much
|
||||
volatile typename RNG::result_type tmp;
|
||||
boost::timer t;
|
||||
for(int i = 0; i < iter; i++)
|
||||
tmp = rng();
|
||||
show_elapsed(t.elapsed(), iter, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
// overload for using a copy, allows more concise invocation
|
||||
template<class RNG>
|
||||
void timing(RNG rng, int iter, const std::string& name)
|
||||
{
|
||||
// make sure we're not optimizing too much
|
||||
volatile typename RNG::result_type tmp;
|
||||
boost::timer t;
|
||||
for(int i = 0; i < iter; i++)
|
||||
tmp = rng();
|
||||
show_elapsed(t.elapsed(), iter, name);
|
||||
}
|
||||
|
||||
template<class RNG>
|
||||
void timing_sphere(RNG rng, int iter, const std::string & name)
|
||||
{
|
||||
boost::timer t;
|
||||
for(int i = 0; i < iter; i++) {
|
||||
// the special return value convention of uniform_on_sphere saves 20% CPU
|
||||
const std::vector<double> & tmp = rng();
|
||||
(void) tmp[0];
|
||||
}
|
||||
show_elapsed(t.elapsed(), iter, name);
|
||||
}
|
||||
|
||||
template<class RNG>
|
||||
void run(int iter, const std::string & name, const RNG &)
|
||||
{
|
||||
std::cout << (RNG::has_fixed_range ? "fixed-range " : "");
|
||||
// BCC has trouble with string autoconversion for explicit specializations
|
||||
timing(RNG(), iter, std::string(name));
|
||||
}
|
||||
|
||||
#ifdef HAVE_DRAND48
|
||||
// requires non-standard C library support for srand48/lrand48
|
||||
void run(int iter, const std::string & name, int)
|
||||
{
|
||||
std::srand48(1);
|
||||
timing(&std::lrand48, iter, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MT19937INT_C // requires the original mt19937int.c
|
||||
extern "C" void sgenrand(unsigned long);
|
||||
extern "C" unsigned long genrand();
|
||||
|
||||
void run(int iter, const std::string & name, float)
|
||||
{
|
||||
sgenrand(4357);
|
||||
timing(genrand, iter, name, 0u);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class PRNG, class Dist>
|
||||
inline boost::variate_generator<PRNG&, Dist> make_gen(PRNG & rng, Dist d)
|
||||
{
|
||||
return boost::variate_generator<PRNG&, Dist>(rng, d);
|
||||
}
|
||||
|
||||
template<class Gen>
|
||||
void distrib(int iter, const std::string & name, const Gen &)
|
||||
{
|
||||
Gen gen;
|
||||
|
||||
timing(make_gen(gen, boost::uniform_int<>(-2, 4)),
|
||||
iter, name + " uniform_int");
|
||||
|
||||
timing(make_gen(gen, boost::geometric_distribution<>(0.5)),
|
||||
iter, name + " geometric");
|
||||
|
||||
timing(make_gen(gen, boost::binomial_distribution<int>(4, 0.8)),
|
||||
iter, name + " binomial");
|
||||
|
||||
timing(make_gen(gen, boost::poisson_distribution<>(1)),
|
||||
iter, name + " poisson");
|
||||
|
||||
|
||||
timing(make_gen(gen, boost::uniform_real<>(-5.3, 4.8)),
|
||||
iter, name + " uniform_real");
|
||||
|
||||
timing(make_gen(gen, boost::triangle_distribution<>(1, 2, 7)),
|
||||
iter, name + " triangle");
|
||||
|
||||
timing(make_gen(gen, boost::exponential_distribution<>(3)),
|
||||
iter, name + " exponential");
|
||||
|
||||
timing(make_gen(gen, boost::normal_distribution<>()),
|
||||
iter, name + " normal polar");
|
||||
|
||||
timing(make_gen(gen, boost::lognormal_distribution<>()),
|
||||
iter, name + " lognormal");
|
||||
|
||||
timing(make_gen(gen, boost::cauchy_distribution<>()),
|
||||
iter, name + " cauchy");
|
||||
|
||||
timing(make_gen(gen, boost::cauchy_distribution<>()),
|
||||
iter, name + " gamma");
|
||||
|
||||
timing_sphere(make_gen(gen, boost::uniform_on_sphere<>(3)),
|
||||
iter/10, name + " uniform_on_sphere");
|
||||
}
|
||||
|
||||
|
||||
template<class URNG, class Dist>
|
||||
inline boost::shared_ptr<DynamicRandomGenerator<URNG, Dist> >
|
||||
make_dynamic(URNG & rng, const Dist& d)
|
||||
{
|
||||
typedef DynamicRandomGenerator<URNG, Dist> type;
|
||||
return boost::shared_ptr<type>(new type(rng, d));
|
||||
}
|
||||
|
||||
template<class Gen>
|
||||
void distrib_runtime(int iter, const std::string & n, const Gen &)
|
||||
{
|
||||
std::string name = n + " virtual function ";
|
||||
Gen gen;
|
||||
|
||||
GenericRandomGenerator<int> g_int;
|
||||
|
||||
g_int.set(make_dynamic(gen, boost::uniform_int<>(-2,4)));
|
||||
timing(g_int, iter, name + "uniform_int");
|
||||
|
||||
g_int.set(make_dynamic(gen, boost::geometric_distribution<>(0.5)));
|
||||
timing(g_int, iter, name + "geometric");
|
||||
|
||||
g_int.set(make_dynamic(gen, boost::binomial_distribution<>(4, 0.8)));
|
||||
timing(g_int, iter, name + "binomial");
|
||||
|
||||
g_int.set(make_dynamic(gen, boost::poisson_distribution<>(1)));
|
||||
timing(g_int, iter, name + "poisson");
|
||||
|
||||
GenericRandomGenerator<double> g;
|
||||
|
||||
g.set(make_dynamic(gen, boost::uniform_real<>(-5.3, 4.8)));
|
||||
timing(g, iter, name + "uniform_real");
|
||||
|
||||
g.set(make_dynamic(gen, boost::triangle_distribution<>(1, 2, 7)));
|
||||
timing(g, iter, name + "triangle");
|
||||
|
||||
g.set(make_dynamic(gen, boost::exponential_distribution<>(3)));
|
||||
timing(g, iter, name + "exponential");
|
||||
|
||||
g.set(make_dynamic(gen, boost::normal_distribution<>()));
|
||||
timing(g, iter, name + "normal polar");
|
||||
|
||||
g.set(make_dynamic(gen, boost::lognormal_distribution<>()));
|
||||
timing(g, iter, name + "lognormal");
|
||||
|
||||
g.set(make_dynamic(gen, boost::cauchy_distribution<>()));
|
||||
timing(g, iter, name + "cauchy");
|
||||
|
||||
g.set(make_dynamic(gen, boost::gamma_distribution<>(0.4)));
|
||||
timing(g, iter, name + "gamma");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char*argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
std::cerr << "usage: " << argv[0] << " iterations" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// okay, it's ugly, but it's only used here
|
||||
int iter =
|
||||
#ifndef BOOST_NO_STDC_NAMESPACE
|
||||
std::
|
||||
#endif
|
||||
atoi(argv[1]);
|
||||
|
||||
#if !defined(BOOST_NO_INT64_T) && \
|
||||
!defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)
|
||||
run(iter, "rand48", boost::rand48());
|
||||
linear_congruential<boost::uint64_t>
|
||||
lcg48(boost::uint64_t(1)<<16 | 0x330e,
|
||||
boost::uint64_t(0xDEECE66DUL) | (boost::uint64_t(0x5) << 32), 0xB,
|
||||
boost::uint64_t(1)<<48);
|
||||
timing(lcg48, iter, "lrand48 run-time");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DRAND48
|
||||
// requires non-standard C library support for srand48/lrand48
|
||||
run(iter, "lrand48", 0); // coded for lrand48()
|
||||
#endif
|
||||
|
||||
run(iter, "minstd_rand", boost::minstd_rand());
|
||||
run(iter, "ecuyer combined", boost::ecuyer1988());
|
||||
run(iter, "kreutzer1986", boost::kreutzer1986());
|
||||
|
||||
run(iter, "hellekalek1995 (inversive)", boost::hellekalek1995());
|
||||
|
||||
run(iter, "mt11213b", boost::mt11213b());
|
||||
run(iter, "mt19937", boost::mt19937());
|
||||
|
||||
run(iter, "subtract_with_carry", boost::random::ranlux_base());
|
||||
run(iter, "subtract_with_carry_01", boost::random::ranlux_base_01());
|
||||
run(iter, "ranlux3", boost::ranlux3());
|
||||
run(iter, "ranlux4", boost::ranlux4());
|
||||
run(iter, "ranlux3_01", boost::ranlux3_01());
|
||||
run(iter, "ranlux4_01", boost::ranlux4_01());
|
||||
run(iter, "counting", counting());
|
||||
|
||||
#ifdef HAVE_MT19937INT_C
|
||||
// requires the original mt19937int.c
|
||||
run<float>(iter, "mt19937 original"); // coded for sgenrand()/genrand()
|
||||
#endif
|
||||
|
||||
distrib(iter, "counting", counting());
|
||||
distrib_runtime(iter, "counting", counting());
|
||||
|
||||
distrib(iter, "minstd_rand", boost::minstd_rand());
|
||||
|
||||
distrib(iter, "kreutzer1986", boost::kreutzer1986());
|
||||
|
||||
distrib(iter, "mt19937", boost::mt19937());
|
||||
distrib_runtime(iter, "mt19937", boost::mt19937());
|
||||
}
|
||||
539
random_test.cpp
539
random_test.cpp
@@ -1,539 +0,0 @@
|
||||
/* boost random_test.cpp various tests
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
|
||||
#pragma warning( disable : 4786 )
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/test/included/test_exec_monitor.hpp>
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::abs; using ::fabs; using ::pow; }
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* General portability note:
|
||||
* MSVC mis-compiles explicit function template instantiations.
|
||||
* For example, f<A>() and f<B>() are both compiled to call f<A>().
|
||||
* BCC is unable to implicitly convert a "const char *" to a std::string
|
||||
* when using explicit function template instantiations.
|
||||
*
|
||||
* Therefore, avoid explicit function template instantiations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Validate correct implementation
|
||||
*/
|
||||
|
||||
// own run
|
||||
bool check(unsigned long x, const boost::mt11213b&) { return x == 0xa37d3c92; }
|
||||
|
||||
// validation by experiment from mt19937.c
|
||||
bool check(unsigned long x, const boost::mt19937&) { return x == 3346425566U; }
|
||||
|
||||
// validation values from the publications
|
||||
bool check(int x, const boost::minstd_rand0&) { return x == 1043618065; }
|
||||
|
||||
// validation values from the publications
|
||||
bool check(int x, const boost::minstd_rand&) { return x == 399268537; }
|
||||
|
||||
#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
|
||||
// by experiment from lrand48()
|
||||
bool check(unsigned long x, const boost::rand48&) { return x == 1993516219; }
|
||||
#endif
|
||||
|
||||
// ????
|
||||
bool check(unsigned long x, const boost::taus88&) { return x == 3535848941U; }
|
||||
|
||||
// ????
|
||||
bool check(int x, const boost::ecuyer1988&) { return x == 2060321752; }
|
||||
|
||||
// validation by experiment from Harry Erwin's generator.h (private e-mail)
|
||||
bool check(unsigned int x, const boost::kreutzer1986&) { return x == 139726; }
|
||||
|
||||
bool check(double x, const boost::lagged_fibonacci607&) { return std::abs(x-0.401269) < 1e-5; }
|
||||
|
||||
// principal operation validated with CLHEP, values by experiment
|
||||
bool check(unsigned long x, const boost::ranlux3&) { return x == 5957620; }
|
||||
bool check(unsigned long x, const boost::ranlux4&) { return x == 8587295; }
|
||||
|
||||
bool check(float x, const boost::ranlux3_01&)
|
||||
{ return std::abs(x-5957620/std::pow(2.0f,24)) < 1e-6; }
|
||||
bool check(float x, const boost::ranlux4_01&)
|
||||
{ return std::abs(x-8587295/std::pow(2.0f,24)) < 1e-6; }
|
||||
|
||||
bool check(double x, const boost::ranlux64_3_01&)
|
||||
{ return std::abs(x-0.838413) < 1e-6; }
|
||||
bool check(double x, const boost::ranlux64_4_01&)
|
||||
{ return std::abs(x-0.59839) < 1e-6; }
|
||||
|
||||
template<class PRNG>
|
||||
void validate(const std::string & name, const PRNG &)
|
||||
{
|
||||
std::cout << "validating " << name << ": ";
|
||||
PRNG rng; // default ctor
|
||||
for(int i = 0; i < 9999; i++)
|
||||
rng();
|
||||
typename PRNG::result_type val = rng();
|
||||
// make sure the validation function is a static member
|
||||
bool result = check(val, rng);
|
||||
|
||||
// allow for a simple eyeball check for MSVC instantiation brokenness
|
||||
// (if the numbers for all generators are the same, it's obviously broken)
|
||||
std::cout << val << std::endl;
|
||||
BOOST_TEST(result);
|
||||
}
|
||||
|
||||
void validate_all()
|
||||
{
|
||||
using namespace boost;
|
||||
#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
|
||||
validate("rand48", rand48());
|
||||
#endif
|
||||
validate("minstd_rand", minstd_rand());
|
||||
validate("minstd_rand0", minstd_rand0());
|
||||
validate("ecuyer combined", ecuyer1988());
|
||||
validate("mt11213b", mt11213b());
|
||||
validate("mt19937", mt19937());
|
||||
validate("kreutzer1986", kreutzer1986());
|
||||
validate("ranlux3", ranlux3());
|
||||
validate("ranlux4", ranlux4());
|
||||
validate("ranlux3_01", ranlux3_01());
|
||||
validate("ranlux4_01", ranlux4_01());
|
||||
validate("ranlux64_3_01", ranlux64_3_01());
|
||||
validate("ranlux64_4_01", ranlux64_4_01());
|
||||
validate("taus88", taus88());
|
||||
validate("lagged_fibonacci607", lagged_fibonacci607());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check function signatures
|
||||
*/
|
||||
|
||||
template<class URNG, class Dist>
|
||||
void instantiate_dist(URNG& urng, const char * name, const Dist& dist)
|
||||
{
|
||||
// this makes a copy of urng
|
||||
boost::variate_generator<URNG, Dist> gen(urng, dist);
|
||||
|
||||
// this keeps a reference to urng
|
||||
boost::variate_generator<URNG&, Dist> genref(urng, dist);
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
// and here is a pointer to (a copy of) the urng
|
||||
URNG copy = urng;
|
||||
boost::variate_generator<URNG*, Dist> genptr(©, dist);
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < 1000; ++i) {
|
||||
(void) gen();
|
||||
(void) genref();
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
(void) genptr();
|
||||
#endif
|
||||
}
|
||||
typename Dist::result_type g = gen();
|
||||
BOOST_CHECK(std::abs(g - genref()) < 1e-6);
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
BOOST_CHECK(std::abs(g - genptr()) < 1e-6);
|
||||
#endif
|
||||
|
||||
(void) gen.engine();
|
||||
gen.distribution().reset();
|
||||
|
||||
Dist d = dist; // copy ctor
|
||||
d = dist; // copy assignment
|
||||
|
||||
#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
{
|
||||
std::ostringstream file;
|
||||
file << urng << std::endl;
|
||||
file << d;
|
||||
std::istringstream input(file.str());
|
||||
// std::cout << file.str() << std::endl;
|
||||
URNG restored_engine;
|
||||
input >> restored_engine;
|
||||
input >> std::ws;
|
||||
Dist restored_dist;
|
||||
input >> restored_dist;
|
||||
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
|
||||
boost::variate_generator<URNG, Dist> old(urng, d);
|
||||
boost::variate_generator<URNG, Dist> restored(restored_engine, restored_dist);
|
||||
// advance some more so that state is exercised
|
||||
for(int i = 0; i < 1000; ++i) {
|
||||
(void) old();
|
||||
(void) restored();
|
||||
}
|
||||
BOOST_CHECK_MESSAGE((std::abs(old()-restored()) < 0.0001),
|
||||
(std::string(name) + " old == restored_dist"));
|
||||
#endif // BOOST_MSVC
|
||||
}
|
||||
#endif // BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
}
|
||||
|
||||
template<class URNG, class RealType>
|
||||
void instantiate_real_dist(URNG& urng, RealType /* ignored */)
|
||||
{
|
||||
instantiate_dist(urng, "uniform_real",
|
||||
boost::uniform_real<RealType>(0, 2.1));
|
||||
instantiate_dist(urng, "triangle_distribution",
|
||||
boost::triangle_distribution<RealType>(1, 1.5, 7));
|
||||
instantiate_dist(urng, "exponential_distribution",
|
||||
boost::exponential_distribution<RealType>(5));
|
||||
instantiate_dist(urng, "normal_distribution",
|
||||
boost::normal_distribution<RealType>());
|
||||
instantiate_dist(urng, "lognormal_distribution",
|
||||
boost::lognormal_distribution<RealType>(1, 1));
|
||||
instantiate_dist(urng, "cauchy_distribution",
|
||||
boost::cauchy_distribution<RealType>(1));
|
||||
instantiate_dist(urng, "gamma_distribution",
|
||||
boost::gamma_distribution<RealType>(1));
|
||||
}
|
||||
|
||||
template<class URNG, class ResultType>
|
||||
void instantiate_urng(const std::string & s, const URNG &, const ResultType &)
|
||||
{
|
||||
std::cout << "Basic tests for " << s;
|
||||
URNG urng;
|
||||
urng.seed(); // seed() member function
|
||||
int a[URNG::has_fixed_range ? 5 : 10]; // compile-time constant
|
||||
(void) a; // avoid "unused" warning
|
||||
typename URNG::result_type x1 = urng();
|
||||
ResultType x2 = x1;
|
||||
(void) &x2; // avoid "unused" warning
|
||||
|
||||
URNG urng2 = urng; // copy constructor
|
||||
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
|
||||
BOOST_TEST(urng == urng2); // operator==
|
||||
BOOST_TEST(!(urng != urng2)); // operator!=
|
||||
urng();
|
||||
urng2 = urng; // copy assignment
|
||||
BOOST_TEST(urng == urng2);
|
||||
#endif // BOOST_MSVC
|
||||
|
||||
const std::vector<int> v(9999u, 0x41);
|
||||
std::vector<int>::const_iterator it = v.begin();
|
||||
std::vector<int>::const_iterator it_end = v.end();
|
||||
URNG urng3(it, it_end);
|
||||
BOOST_TEST(it != v.begin());
|
||||
std::cout << "; seeding uses " << (it - v.begin()) << " words" << std::endl;
|
||||
|
||||
bool have_exception = false;
|
||||
try {
|
||||
// now check that exceptions are thrown
|
||||
it = v.end();
|
||||
urng3.seed(it, it_end);
|
||||
} catch(std::invalid_argument& x) {
|
||||
have_exception = true;
|
||||
}
|
||||
BOOST_TEST(have_exception);
|
||||
|
||||
// check for min/max members
|
||||
ResultType min = (urng3.min)();
|
||||
(void) &min;
|
||||
ResultType max = (urng3.max)();
|
||||
(void) &max;
|
||||
|
||||
#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
// Streamable concept not supported for broken compilers
|
||||
|
||||
// advance a little so that state is relatively arbitrary
|
||||
for(int i = 0; i < 9307; ++i)
|
||||
urng();
|
||||
urng2 = urng;
|
||||
|
||||
{
|
||||
// narrow stream first
|
||||
std::ostringstream file;
|
||||
file << urng;
|
||||
// move forward
|
||||
urng();
|
||||
// restore old state
|
||||
std::istringstream input(file.str());
|
||||
input >> urng;
|
||||
// std::cout << file.str() << std::endl;
|
||||
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
|
||||
// advance some more so that state is exercised
|
||||
for(int i = 0; i < 10000; ++i) {
|
||||
urng();
|
||||
urng2();
|
||||
}
|
||||
BOOST_TEST(urng == urng2);
|
||||
#endif // BOOST_MSVC
|
||||
}
|
||||
|
||||
urng2 = urng;
|
||||
#if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING)
|
||||
{
|
||||
// then wide stream
|
||||
std::wostringstream file;
|
||||
file << urng;
|
||||
// move forward
|
||||
urng();
|
||||
std::wistringstream input(file.str());
|
||||
input >> urng;
|
||||
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness
|
||||
// advance some more so that state is exercised
|
||||
for(int i = 0; i < 10000; ++i) {
|
||||
urng();
|
||||
urng2();
|
||||
}
|
||||
BOOST_TEST(urng == urng2);
|
||||
#endif // BOOST_MSVC
|
||||
}
|
||||
#endif // BOOST_NO_STD_WSTREAMBUF, BOOST_NO_STD_WSTRING
|
||||
#endif // BOOST_NO_OPERATORS_IN_NAMESPACE etc.
|
||||
|
||||
// instantiate various distributions with this URNG
|
||||
// instantiate_dist(urng, "uniform_smallint", boost::uniform_smallint(0, 11));
|
||||
instantiate_dist(urng, "uniform_int", boost::uniform_int<>(-200, 20000));
|
||||
instantiate_dist(urng, "bernoulli_distribution",
|
||||
boost::bernoulli_distribution<>(0.2));
|
||||
instantiate_dist(urng, "binomial_distribution",
|
||||
boost::binomial_distribution<>(4, 0.2));
|
||||
instantiate_dist(urng, "geometric_distribution",
|
||||
boost::geometric_distribution<>(0.8));
|
||||
instantiate_dist(urng, "poisson_distribution",
|
||||
boost::poisson_distribution<>(1));
|
||||
|
||||
instantiate_real_dist(urng, 1.0f);
|
||||
instantiate_real_dist(urng, 1.0);
|
||||
instantiate_real_dist(urng, 1.0l);
|
||||
|
||||
#if 0
|
||||
// We cannot compare the outcomes before/after save with std::abs(x-y)
|
||||
instantiate_dist("uniform_on_sphere",
|
||||
boost::uniform_on_sphere<URNG>(urng, 2));
|
||||
#endif
|
||||
}
|
||||
|
||||
void instantiate_all()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
|
||||
instantiate_urng("rand48", rand48(), 0);
|
||||
rand48 rnd(boost::int32_t(5));
|
||||
rand48 rnd2(boost::uint64_t(0x80000000) * 42);
|
||||
rnd.seed(boost::int32_t(17));
|
||||
rnd2.seed(boost::uint64_t(0x80000000) * 49);
|
||||
#endif
|
||||
|
||||
instantiate_urng("minstd_rand0", minstd_rand0(), 0);
|
||||
instantiate_urng("minstd_rand", minstd_rand(), 0);
|
||||
minstd_rand mstd(42);
|
||||
mstd.seed(17);
|
||||
|
||||
instantiate_urng("ecuyer1988", ecuyer1988(), 0);
|
||||
instantiate_urng("kreutzer1986", kreutzer1986(), 0);
|
||||
instantiate_urng("hellekalek1995", hellekalek1995(), 0);
|
||||
|
||||
instantiate_urng("mt11213b", mt11213b(), 0u);
|
||||
instantiate_urng("mt19937", mt19937(), 0u);
|
||||
|
||||
mt19937 mt(boost::uint32_t(17)); // needs to be an exact type match for MSVC
|
||||
int i = 42;
|
||||
mt.seed(boost::uint32_t(i));
|
||||
mt19937 mt2(mstd);
|
||||
mt2.seed(mstd);
|
||||
|
||||
|
||||
random_number_generator<mt19937> std_rng(mt2);
|
||||
(void) std_rng(10);
|
||||
|
||||
instantiate_urng("lagged_fibonacci",
|
||||
boost::random::lagged_fibonacci<boost::uint32_t, 24, 607, 273>(),
|
||||
0u);
|
||||
instantiate_urng("lagged_fibonacci607", lagged_fibonacci607(), 0.0);
|
||||
|
||||
instantiate_urng("ranlux3", ranlux3(), 0u);
|
||||
instantiate_urng("ranlux4", ranlux4(), 0u);
|
||||
|
||||
instantiate_urng("ranlux3_01", ranlux3_01(), 0.0f);
|
||||
instantiate_urng("ranlux4_01", ranlux4_01(), 0.0f);
|
||||
|
||||
instantiate_urng("ranlux64_3_01", ranlux64_3_01(), 0.0);
|
||||
instantiate_urng("ranlux64_4_01", ranlux64_4_01(), 0.0);
|
||||
|
||||
instantiate_urng("taus88", taus88(), 0u);
|
||||
}
|
||||
|
||||
/*
|
||||
* A few equidistribution tests
|
||||
*/
|
||||
|
||||
// yet to come...
|
||||
|
||||
template<class Generator>
|
||||
void check_uniform_int(Generator & gen, int iter)
|
||||
{
|
||||
std::cout << "testing uniform_int(" << (gen.min)() << "," << (gen.max)()
|
||||
<< ")" << std::endl;
|
||||
int range = (gen.max)()-(gen.min)()+1;
|
||||
std::vector<int> bucket(range);
|
||||
for(int j = 0; j < iter; j++) {
|
||||
int result = gen();
|
||||
if(result < (gen.min)() || result > (gen.max)())
|
||||
std::cerr << " ... delivers " << result << std::endl;
|
||||
else
|
||||
bucket[result-(gen.min)()]++;
|
||||
}
|
||||
int sum = 0;
|
||||
// use a different variable name "k", because MSVC has broken "for" scoping
|
||||
for(int k = 0; k < range; k++)
|
||||
sum += bucket[k];
|
||||
double avg = static_cast<double>(sum)/range;
|
||||
double threshold = 2*avg/std::sqrt(static_cast<double>(iter));
|
||||
for(int i = 0; i < range; i++) {
|
||||
if(std::fabs(bucket[i] - avg) > threshold) {
|
||||
// 95% confidence interval
|
||||
std::cout << " ... has bucket[" << i << "] = " << bucket[i]
|
||||
<< " (distance " << (bucket[i] - avg) << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Generator>
|
||||
void test_uniform_int(Generator & gen)
|
||||
{
|
||||
typedef boost::uniform_int<int> int_gen;
|
||||
|
||||
// large range => small range (modulo case)
|
||||
typedef boost::variate_generator<Generator&, int_gen> level_one;
|
||||
|
||||
level_one uint12(gen, int_gen(1,2));
|
||||
BOOST_TEST((uint12.distribution().min)() == 1);
|
||||
BOOST_TEST((uint12.distribution().max)() == 2);
|
||||
check_uniform_int(uint12, 100000);
|
||||
level_one uint16(gen, int_gen(1,6));
|
||||
check_uniform_int(uint16, 100000);
|
||||
|
||||
// test chaining to get all cases in operator()
|
||||
|
||||
// identity map
|
||||
typedef boost::variate_generator<level_one&, int_gen> level_two;
|
||||
level_two uint01(uint12, int_gen(0, 1));
|
||||
check_uniform_int(uint01, 100000);
|
||||
|
||||
// small range => larger range
|
||||
level_two uint05(uint12, int_gen(-3, 2));
|
||||
check_uniform_int(uint05, 100000);
|
||||
|
||||
// larger => small range, rejection case
|
||||
typedef boost::variate_generator<level_two&, int_gen> level_three;
|
||||
level_three uint1_4(uint05, int_gen(1, 4));
|
||||
check_uniform_int(uint1_4, 100000);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC) && _MSC_VER <= 1200
|
||||
|
||||
// These explicit instantiations are necessary, otherwise MSVC does
|
||||
// not find the <boost/operators.hpp> inline friends.
|
||||
// We ease the typing with a suitable preprocessor macro.
|
||||
#define INSTANT(x) \
|
||||
template class boost::uniform_smallint<x>; \
|
||||
template class boost::uniform_int<x>; \
|
||||
template class boost::uniform_real<x>; \
|
||||
template class boost::bernoulli_distribution<x>; \
|
||||
template class boost::geometric_distribution<x>; \
|
||||
template class boost::triangle_distribution<x>; \
|
||||
template class boost::exponential_distribution<x>; \
|
||||
template class boost::normal_distribution<x>; \
|
||||
template class boost::uniform_on_sphere<x>; \
|
||||
template class boost::lognormal_distribution<x>;
|
||||
|
||||
INSTANT(boost::minstd_rand0)
|
||||
INSTANT(boost::minstd_rand)
|
||||
INSTANT(boost::ecuyer1988)
|
||||
INSTANT(boost::kreutzer1986)
|
||||
INSTANT(boost::hellekalek1995)
|
||||
INSTANT(boost::mt19937)
|
||||
INSTANT(boost::mt11213b)
|
||||
|
||||
#undef INSTANT
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
|
||||
// testcase by Mario Rütti
|
||||
class ruetti_gen
|
||||
{
|
||||
public:
|
||||
typedef boost::uint64_t result_type;
|
||||
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; }
|
||||
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::numeric_limits<result_type>::max)(); }
|
||||
result_type operator()() { return (max)()-1; }
|
||||
};
|
||||
|
||||
void test_overflow_range()
|
||||
{
|
||||
ruetti_gen gen;
|
||||
boost::variate_generator<ruetti_gen, boost::uniform_int<> >
|
||||
rng(gen, boost::uniform_int<>(0, 10));
|
||||
for (int i=0;i<10;i++)
|
||||
(void) rng();
|
||||
}
|
||||
#else
|
||||
void test_overflow_range()
|
||||
{ }
|
||||
#endif
|
||||
|
||||
int test_main(int, char*[])
|
||||
{
|
||||
|
||||
#if !defined(__INTEL_COMPILER) || !defined(_MSC_VER) || __INTEL_COMPILER > 700
|
||||
instantiate_all();
|
||||
validate_all();
|
||||
boost::mt19937 mt;
|
||||
test_uniform_int(mt);
|
||||
|
||||
// bug report from Ken Mahler: This used to lead to an endless loop.
|
||||
typedef boost::uniform_int<unsigned int> uint_dist;
|
||||
boost::minstd_rand mr;
|
||||
boost::variate_generator<boost::minstd_rand, uint_dist> r2(mr,
|
||||
uint_dist(0, 0xffffffff));
|
||||
r2();
|
||||
r2();
|
||||
|
||||
// bug report from Fernando Cacciola: This used to lead to an endless loop.
|
||||
// also from Douglas Gregor
|
||||
boost::variate_generator<boost::minstd_rand, boost::uniform_int<> > x(mr, boost::uniform_int<>(0, 8361));
|
||||
(void) x();
|
||||
|
||||
// bug report from Alan Stokes and others: this throws an assertion
|
||||
boost::variate_generator<boost::minstd_rand, boost::uniform_int<> > y(mr, boost::uniform_int<>(1,1));
|
||||
std::cout << "uniform_int(1,1) " << y() << ", " << y() << ", " << y()
|
||||
<< std::endl;
|
||||
|
||||
test_overflow_range();
|
||||
|
||||
return 0;
|
||||
#else
|
||||
std::cout << "Intel 7.00 on Win32 loops, so the test is disabled\n";
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
@@ -1,669 +0,0 @@
|
||||
/* statistic_tests.cpp file
|
||||
*
|
||||
* Copyright Jens Maurer 2000, 2002
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Revision history
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE: This is not part of the official boost submission. It exists
|
||||
* only as a collection of ideas.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <math.h> // lgamma is not in namespace std
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/random.hpp>
|
||||
|
||||
#include "statistic_tests.hpp"
|
||||
#include "integrate.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace random {
|
||||
|
||||
// Wikramaratna 1989 ACORN
|
||||
template<class IntType, int k, IntType m, IntType val>
|
||||
class additive_congruential
|
||||
{
|
||||
public:
|
||||
typedef IntType result_type;
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
static const bool has_fixed_range = true;
|
||||
static const result_type min_value = 0;
|
||||
static const result_type max_value = m-1;
|
||||
#else
|
||||
enum {
|
||||
has_fixed_range = true,
|
||||
min_value = 0,
|
||||
max_value = m-1
|
||||
};
|
||||
#endif
|
||||
template<class InputIterator>
|
||||
explicit additive_congruential(InputIterator start) { seed(start); }
|
||||
template<class InputIterator>
|
||||
void seed(InputIterator start)
|
||||
{
|
||||
for(int i = 0; i <= k; ++i, ++start)
|
||||
values[i] = *start;
|
||||
}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
for(int i = 1; i <= k; ++i) {
|
||||
IntType tmp = values[i-1] + values[i];
|
||||
if(tmp >= m)
|
||||
tmp -= m;
|
||||
values[i] = tmp;
|
||||
}
|
||||
return values[k];
|
||||
}
|
||||
result_type validation() const { return val; }
|
||||
private:
|
||||
IntType values[k+1];
|
||||
};
|
||||
|
||||
|
||||
template<class IntType, int r, int s, IntType m, IntType val>
|
||||
class lagged_fibonacci_int
|
||||
{
|
||||
public:
|
||||
typedef IntType result_type;
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
static const bool has_fixed_range = true;
|
||||
static const result_type min_value = 0;
|
||||
static const result_type max_value = m-1;
|
||||
#else
|
||||
enum {
|
||||
has_fixed_range = true,
|
||||
min_value = 0,
|
||||
max_value = m-1
|
||||
};
|
||||
#endif
|
||||
explicit lagged_fibonacci_int(IntType start) { seed(start); }
|
||||
template<class Generator>
|
||||
explicit lagged_fibonacci_int(Generator & gen) { seed(gen); }
|
||||
void seed(IntType start)
|
||||
{
|
||||
linear_congruential<uint32_t, 299375077, 0, 0, 0> init;
|
||||
seed(init);
|
||||
}
|
||||
template<class Generator>
|
||||
void seed(Generator & gen)
|
||||
{
|
||||
assert(r > s);
|
||||
for(int i = 0; i < 607; ++i)
|
||||
values[i] = gen();
|
||||
current = 0;
|
||||
lag = r-s;
|
||||
}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
result_type tmp = values[current] + values[lag];
|
||||
if(tmp >= m)
|
||||
tmp -= m;
|
||||
values[current] = tmp;
|
||||
++current;
|
||||
if(current >= r)
|
||||
current = 0;
|
||||
++lag;
|
||||
if(lag >= r)
|
||||
lag = 0;
|
||||
return tmp;
|
||||
}
|
||||
result_type validation() const { return val; }
|
||||
private:
|
||||
result_type values[r];
|
||||
int current, lag;
|
||||
};
|
||||
|
||||
} // namespace random
|
||||
} // namespace boost
|
||||
|
||||
// distributions from Haertel's dissertation
|
||||
// (additional parameterizations of the basic templates)
|
||||
namespace Haertel {
|
||||
typedef boost::random::linear_congruential<boost::uint64_t, 45965, 453816691,
|
||||
(boost::uint64_t(1)<<31), 0> LCG_Af2;
|
||||
typedef boost::random::linear_congruential<boost::uint64_t, 211936855, 0,
|
||||
(boost::uint64_t(1)<<29)-3, 0> LCG_Die1;
|
||||
typedef boost::random::linear_congruential<boost::uint32_t, 2824527309u, 0,
|
||||
0, 0> LCG_Fis;
|
||||
typedef boost::random::linear_congruential<boost::uint64_t, 950706376u, 0,
|
||||
(boost::uint64_t(1)<<31)-1, 0> LCG_FM;
|
||||
typedef boost::random::linear_congruential<boost::int32_t, 51081, 0,
|
||||
2147483647, 0> LCG_Hae;
|
||||
typedef boost::random::linear_congruential<boost::uint32_t, 69069, 1,
|
||||
0, 0> LCG_VAX;
|
||||
typedef boost::random::inversive_congruential<boost::int64_t, 240318, 197,
|
||||
1000081, 0> NLG_Inv1;
|
||||
typedef boost::random::inversive_congruential<boost::int64_t, 15707262,
|
||||
13262967, (1<<24)-17, 0> NLG_Inv2;
|
||||
typedef boost::random::inversive_congruential<boost::int32_t, 1, 1,
|
||||
2147483647, 0> NLG_Inv4;
|
||||
typedef boost::random::inversive_congruential<boost::int32_t, 1, 2,
|
||||
1<<30, 0> NLG_Inv5;
|
||||
typedef boost::random::additive_congruential<boost::int32_t, 6,
|
||||
(1<<30)-35, 0> MRG_Acorn7;
|
||||
typedef boost::random::lagged_fibonacci_int<boost::uint32_t, 607, 273,
|
||||
0, 0> MRG_Fib2;
|
||||
|
||||
template<class Gen, class T>
|
||||
inline void check_validation(Gen & gen, T value, const std::string & name)
|
||||
{
|
||||
for(int i = 0; i < 100000-1; ++i)
|
||||
gen();
|
||||
if(value != gen())
|
||||
std::cout << name << ": validation failed" << std::endl;
|
||||
}
|
||||
|
||||
// we have validation after 100000 steps with Haertel's generators
|
||||
template<class Gen, class T>
|
||||
void validate(T value, const std::string & name)
|
||||
{
|
||||
Gen gen(1234567);
|
||||
check_validation(gen, value, name);
|
||||
}
|
||||
|
||||
void validate_all()
|
||||
{
|
||||
validate<LCG_Af2>(183269031u, "LCG_Af2");
|
||||
validate<LCG_Die1>(522319944u, "LCG_Die1");
|
||||
validate<LCG_Fis>(-2065162233u, "LCG_Fis");
|
||||
validate<LCG_FM>(581815473u, "LCG_FM");
|
||||
validate<LCG_Hae>(28931709, "LCG_Hae");
|
||||
validate<LCG_VAX>(1508154087u, "LCG_VAX");
|
||||
validate<NLG_Inv2>(6666884, "NLG_Inv2");
|
||||
validate<NLG_Inv4>(1521640076, "NLG_Inv4");
|
||||
validate<NLG_Inv5>(641840839, "NLG_Inv5");
|
||||
static const int acorn7_init[]
|
||||
= { 1234567, 7654321, 246810, 108642, 13579, 97531, 555555 };
|
||||
MRG_Acorn7 acorn7(acorn7_init);
|
||||
check_validation(acorn7, 874294697, "MRG_Acorn7");
|
||||
validate<MRG_Fib2>(1234567u, "MRG_Fib2");
|
||||
}
|
||||
} // namespace Haertel
|
||||
|
||||
|
||||
|
||||
|
||||
double normal_density(double x)
|
||||
{
|
||||
const double pi = 3.14159265358979323846;
|
||||
return 1/std::sqrt(2*pi) * std::exp(-x*x/2);
|
||||
}
|
||||
|
||||
namespace std {
|
||||
#ifdef _CXXRTCF_H__
|
||||
using _CS_swamp::lgamma;
|
||||
#elif defined __SGI_STL_PORT
|
||||
using ::lgamma;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
class chi_square_density : public std::unary_function<double, double>
|
||||
{
|
||||
public:
|
||||
chi_square_density(int freedom)
|
||||
: _exponent( static_cast<double>(freedom)/2-1 ),
|
||||
_factor(1/(std::pow(2, _exponent+1) * std::exp(lgamma(_exponent+1))))
|
||||
{ }
|
||||
|
||||
double operator()(double x)
|
||||
{
|
||||
return _factor*std::pow(x, _exponent)*std::exp(-x/2);
|
||||
}
|
||||
private:
|
||||
double _exponent, _factor;
|
||||
};
|
||||
|
||||
// computes F(x) or F(y) - F(x)
|
||||
class chi_square_probability : public distribution_function<double>
|
||||
{
|
||||
public:
|
||||
chi_square_probability(int freedom) : dens(freedom) {}
|
||||
double operator()(double x) { return operator()(0, x); }
|
||||
double operator()(double x, double y)
|
||||
{ return trapezoid(dens, x, y, 1000); }
|
||||
private:
|
||||
chi_square_density dens;
|
||||
};
|
||||
|
||||
class uniform_distribution : public distribution_function<double>
|
||||
{
|
||||
public:
|
||||
uniform_distribution(double from, double to) : from(from), to(to)
|
||||
{ assert(from < to); }
|
||||
double operator()(double x)
|
||||
{
|
||||
if(x < from)
|
||||
return 0;
|
||||
else if(x > to)
|
||||
return 1;
|
||||
else
|
||||
return (x-from)/(to-from);
|
||||
}
|
||||
double operator()(double x, double delta)
|
||||
{ return operator()(x+delta) - operator()(x); }
|
||||
private:
|
||||
double from, to;
|
||||
};
|
||||
|
||||
class test_environment;
|
||||
|
||||
class test_base
|
||||
{
|
||||
protected:
|
||||
explicit test_base(test_environment & env) : environment(env) { }
|
||||
void check(double val) const;
|
||||
private:
|
||||
test_environment & environment;
|
||||
};
|
||||
|
||||
class equidistribution_test : test_base
|
||||
{
|
||||
public:
|
||||
equidistribution_test(test_environment & env, unsigned int classes,
|
||||
unsigned int high_classes)
|
||||
: test_base(env), classes(classes),
|
||||
test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "equidistribution: " << std::flush;
|
||||
equidistribution_experiment equi(classes);
|
||||
uniform_smallint<RNG> uint_linear(rng, 0, classes-1);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(equi, uint_linear, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(equi, uint_linear, n1), 2*n2));
|
||||
|
||||
std::cout << " 2D: " << std::flush;
|
||||
equidistribution_2d_experiment equi_2d(classes);
|
||||
unsigned int root = static_cast<unsigned int>(std::sqrt(double(classes)));
|
||||
assert(root * root == classes);
|
||||
uniform_smallint<RNG> uint_square(rng, 0, root-1);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(equi_2d, uint_square, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(equi_2d, uint_square, n1), 2*n2));
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int classes;
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class ks_equidistribution_test : test_base
|
||||
{
|
||||
public:
|
||||
ks_equidistribution_test(test_environment & env, unsigned int classes)
|
||||
: test_base(env),
|
||||
test_distrib_chi_square(kolmogorov_smirnov_probability(5000),
|
||||
classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "KS: " << std::flush;
|
||||
// generator_reference_t<RNG> gen_ref(rng);
|
||||
RNG& gen_ref(rng);
|
||||
kolmogorov_experiment ks(n1);
|
||||
uniform_distribution ud((rng.min)(), (rng.max)());
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
ks_experiment_generator(ks, gen_ref, ud), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
ks_experiment_generator(ks, gen_ref, ud), 2*n2));
|
||||
}
|
||||
private:
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class runs_test : test_base
|
||||
{
|
||||
public:
|
||||
runs_test(test_environment & env, unsigned int classes,
|
||||
unsigned int high_classes)
|
||||
: test_base(env), classes(classes),
|
||||
test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "runs: up: " << std::flush;
|
||||
runs_experiment<true> r_up(classes);
|
||||
// generator_reference_t<RNG> gen_ref(rng);
|
||||
RNG& gen_ref(rng);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(r_up, gen_ref, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(r_up, gen_ref, n1), 2*n2));
|
||||
|
||||
std::cout << " down: " << std::flush;
|
||||
runs_experiment<false> r_down(classes);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(r_down, gen_ref, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(r_down, gen_ref, n1), 2*n2));
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int classes;
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class gap_test : test_base
|
||||
{
|
||||
public:
|
||||
gap_test(test_environment & env, unsigned int classes,
|
||||
unsigned int high_classes)
|
||||
: test_base(env), classes(classes),
|
||||
test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "gaps: " << std::flush;
|
||||
gap_experiment gap(classes, 0.2, 0.8);
|
||||
// generator_reference_t<RNG> gen_ref(rng);
|
||||
RNG& gen_ref(rng);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(gap, gen_ref, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(gap, gen_ref, n1), 2*n2));
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int classes;
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class poker_test : test_base
|
||||
{
|
||||
public:
|
||||
poker_test(test_environment & env, unsigned int classes,
|
||||
unsigned int high_classes)
|
||||
: test_base(env), classes(classes),
|
||||
test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "poker: " << std::flush;
|
||||
poker_experiment poker(8, classes);
|
||||
uniform_smallint<RNG> usmall(rng, 0, 7);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(poker, usmall, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(poker, usmall, n1), 2*n2));
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int classes;
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class coupon_collector_test : test_base
|
||||
{
|
||||
public:
|
||||
coupon_collector_test(test_environment & env, unsigned int classes,
|
||||
unsigned int high_classes)
|
||||
: test_base(env), classes(classes),
|
||||
test_distrib_chi_square(chi_square_probability(classes-1), high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "coupon collector: " << std::flush;
|
||||
coupon_collector_experiment coupon(5, classes);
|
||||
|
||||
uniform_smallint<RNG> usmall(rng, 0, 4);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(coupon, usmall, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(coupon, usmall, n1), 2*n2));
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int classes;
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class permutation_test : test_base
|
||||
{
|
||||
public:
|
||||
permutation_test(test_environment & env, unsigned int classes,
|
||||
unsigned int high_classes)
|
||||
: test_base(env), classes(classes),
|
||||
test_distrib_chi_square(chi_square_probability(fac<int>(classes)-1),
|
||||
high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "permutation: " << std::flush;
|
||||
permutation_experiment perm(classes);
|
||||
|
||||
// generator_reference_t<RNG> gen_ref(rng);
|
||||
RNG& gen_ref(rng);
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(perm, gen_ref, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(perm, gen_ref, n1), 2*n2));
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
unsigned int classes;
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class maximum_test : test_base
|
||||
{
|
||||
public:
|
||||
maximum_test(test_environment & env, unsigned int high_classes)
|
||||
: test_base(env),
|
||||
test_distrib_chi_square(kolmogorov_smirnov_probability(1000),
|
||||
high_classes)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "maximum-of-t: " << std::flush;
|
||||
maximum_experiment<RNG> mx(rng, n1, 5);
|
||||
check(run_experiment(test_distrib_chi_square, mx, n2));
|
||||
check(run_experiment(test_distrib_chi_square, mx, 2*n2));
|
||||
std::cout << std::endl;
|
||||
}
|
||||
private:
|
||||
distribution_experiment test_distrib_chi_square;
|
||||
};
|
||||
|
||||
class birthday_test : test_base
|
||||
{
|
||||
public:
|
||||
birthday_test(test_environment & env)
|
||||
: test_base(env)
|
||||
{ }
|
||||
|
||||
template<class RNG>
|
||||
void run(RNG & rng, int n1, int n2)
|
||||
{
|
||||
using namespace boost;
|
||||
std::cout << "birthday spacing: " << std::flush;
|
||||
uniform_int<RNG> uni(rng, 0, (1<<25)-1);
|
||||
birthday_spacing_experiment bsp(4, 512, (1<<25));
|
||||
std::cout << run_experiment(bsp, uni, n1);
|
||||
#if 0
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(perm, gen_ref, n1), n2));
|
||||
check(run_experiment(test_distrib_chi_square,
|
||||
experiment_generator(perm, gen_ref, n1), 2*n2));
|
||||
#endif
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class test_environment
|
||||
{
|
||||
public:
|
||||
static const int classes = 20;
|
||||
explicit test_environment(double confid)
|
||||
: confidence(confid),
|
||||
confidence_chi_square_quantil(quantil(chi_square_density(classes-1), 0, confidence, 1e-4)),
|
||||
test_distrib_chi_square6(chi_square_probability(7-1), classes),
|
||||
ksequi_test(*this, classes),
|
||||
equi_test(*this, 100, classes),
|
||||
rns_test(*this, 7, classes),
|
||||
gp_test(*this, 7, classes),
|
||||
pk_test(*this, 5, classes),
|
||||
cpn_test(*this, 15, classes),
|
||||
perm_test(*this, 5, classes),
|
||||
max_test(*this, classes),
|
||||
bday_test(*this)
|
||||
{
|
||||
std::cout << "Confidence level: " << confid
|
||||
<< "; 1-alpha = " << (1-confid)
|
||||
<< "; chi_square(" << (classes-1)
|
||||
<< ", " << confidence_chi_square_quantil
|
||||
<< ") = "
|
||||
<< chi_square_probability(classes-1)(0, confidence_chi_square_quantil)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
bool check_confidence(double val, double chi_square_conf) const
|
||||
{
|
||||
std::cout << val;
|
||||
bool result = (val <= chi_square_conf);
|
||||
if(!result) {
|
||||
std::cout << "* [";
|
||||
double prob = (val > 10*chi_square_conf ? 1 :
|
||||
chi_square_probability(classes-1)(0, val));
|
||||
std::cout << (1-prob) << "]";
|
||||
}
|
||||
std::cout << " " << std::flush;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool check(double chi_square_value) const
|
||||
{
|
||||
return check_confidence(chi_square_value, confidence_chi_square_quantil);
|
||||
}
|
||||
|
||||
template<class RNG>
|
||||
void run_test(const std::string & name)
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
std::cout << "Running tests on " << name << std::endl;
|
||||
|
||||
RNG rng(1234567);
|
||||
typedef boost::uniform_01<RNG> UGen;
|
||||
|
||||
#if 1
|
||||
ksequi_test.run(rng, 5000, 250);
|
||||
equi_test.run(rng, 5000, 250);
|
||||
rns_test.run(rng, 100000, 250);
|
||||
gp_test.run(rng, 10000, 250);
|
||||
pk_test.run(rng, 5000, 250);
|
||||
cpn_test.run(rng, 500, 250);
|
||||
perm_test.run(rng, 1200, 250);
|
||||
max_test.run(rng, 1000, 250);
|
||||
#endif
|
||||
bday_test.run(rng, 1000, 150);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
double confidence;
|
||||
double confidence_chi_square_quantil;
|
||||
distribution_experiment test_distrib_chi_square6;
|
||||
ks_equidistribution_test ksequi_test;
|
||||
equidistribution_test equi_test;
|
||||
runs_test rns_test;
|
||||
gap_test gp_test;
|
||||
poker_test pk_test;
|
||||
coupon_collector_test cpn_test;
|
||||
permutation_test perm_test;
|
||||
maximum_test max_test;
|
||||
birthday_test bday_test;
|
||||
};
|
||||
|
||||
void test_base::check(double val) const
|
||||
{
|
||||
environment.check(val);
|
||||
}
|
||||
|
||||
void print_ks_table()
|
||||
{
|
||||
std::cout.setf(std::ios::fixed);
|
||||
std::cout.precision(5);
|
||||
static const double all_p[] = { 0.01, 0.05, 0.25, 0.5, 0.75, 0.95, 0.99 };
|
||||
for(int n = 0; n <= 10000; (n < 55 ? ++n : n *= 10)) {
|
||||
std::cout << std::setw(4) << n << " ";
|
||||
for(unsigned int i = 0; i < sizeof(all_p)/sizeof(all_p[0]); ++i) {
|
||||
std::cout << std::setw(8)
|
||||
<< (n == 0 ? all_p[i] :
|
||||
invert_monotone_inc(kolmogorov_smirnov_probability(n), all_p[i], 0, 10))
|
||||
<< " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Haertel::validate_all();
|
||||
test_environment env(0.99);
|
||||
env.run_test<boost::minstd_rand>("minstd_rand");
|
||||
env.run_test<boost::mt19937>("mt19937");
|
||||
env.run_test<Haertel::LCG_Af2>("LCG_Af2");
|
||||
env.run_test<Haertel::LCG_Die1>("LCG_Die1");
|
||||
env.run_test<Haertel::LCG_Fis>("LCG_Fis");
|
||||
env.run_test<Haertel::LCG_FM>("LCG_FM");
|
||||
env.run_test<Haertel::LCG_Hae>("LCG_Hae");
|
||||
env.run_test<Haertel::LCG_VAX>("LCG_VAX");
|
||||
env.run_test<Haertel::NLG_Inv1>("NLG_Inv1");
|
||||
env.run_test<Haertel::NLG_Inv2>("NLG_Inv2");
|
||||
env.run_test<Haertel::NLG_Inv4>("NLG_Inv4");
|
||||
env.run_test<Haertel::NLG_Inv5>("NLG_Inv5");
|
||||
}
|
||||
@@ -1,643 +0,0 @@
|
||||
/* statistic_tests.hpp header file
|
||||
*
|
||||
* Copyright Jens Maurer 2000
|
||||
* Permission to use, copy, modify, sell, and distribute this software
|
||||
* is hereby granted without fee provided that the above copyright notice
|
||||
* appears in all copies and that both that copyright notice and this
|
||||
* permission notice appear in supporting documentation,
|
||||
*
|
||||
* Jens Maurer makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STATISTIC_TESTS_HPP
|
||||
#define STATISTIC_TESTS_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <boost/limits.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
|
||||
namespace std
|
||||
{
|
||||
inline double pow(double a, double b) { return ::pow(a,b); }
|
||||
inline double ceil(double x) { return ::ceil(x); }
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
|
||||
template<class T>
|
||||
inline T fac(int k)
|
||||
{
|
||||
T result = 1;
|
||||
for(T i = 2; i <= k; ++i)
|
||||
result *= i;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T binomial(int n, int k)
|
||||
{
|
||||
if(k < n/2)
|
||||
k = n-k;
|
||||
T result = 1;
|
||||
for(int i = k+1; i<= n; ++i)
|
||||
result *= i;
|
||||
return result / fac<T>(n-k);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T stirling2(int n, int m)
|
||||
{
|
||||
T sum = 0;
|
||||
for(int k = 0; k <= m; ++k)
|
||||
sum += binomial<T>(m, k) * std::pow(double(k), n) *
|
||||
( (m-k)%2 == 0 ? 1 : -1);
|
||||
return sum / fac<T>(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Experiments which create an empirical distribution in classes,
|
||||
* suitable for the chi-square test.
|
||||
*/
|
||||
// std::floor(gen() * classes)
|
||||
|
||||
class experiment_base
|
||||
{
|
||||
public:
|
||||
experiment_base(int cls) : _classes(cls) { }
|
||||
unsigned int classes() const { return _classes; }
|
||||
protected:
|
||||
unsigned int _classes;
|
||||
};
|
||||
|
||||
class equidistribution_experiment : public experiment_base
|
||||
{
|
||||
public:
|
||||
explicit equidistribution_experiment(unsigned int classes)
|
||||
: experiment_base(classes) { }
|
||||
|
||||
template<class NumberGenerator, class Counter>
|
||||
void run(NumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
assert((f.min)() == 0 &&
|
||||
static_cast<unsigned int>((f.max)()) == classes()-1);
|
||||
for(int i = 0; i < n; ++i)
|
||||
count(f());
|
||||
}
|
||||
double probability(int i) const { return 1.0/classes(); }
|
||||
};
|
||||
|
||||
// two-dimensional equidistribution experiment
|
||||
class equidistribution_2d_experiment : public equidistribution_experiment
|
||||
{
|
||||
public:
|
||||
explicit equidistribution_2d_experiment(unsigned int classes)
|
||||
: equidistribution_experiment(classes) { }
|
||||
|
||||
template<class NumberGenerator, class Counter>
|
||||
void run(NumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
unsigned int range = (f.max)()+1;
|
||||
assert((f.min)() == 0 && range*range == classes());
|
||||
for(int i = 0; i < n; ++i) {
|
||||
int y1 = f();
|
||||
int y2 = f();
|
||||
count(y1 + range * y2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// distribution experiment: assume a probability density and
|
||||
// count events so that an equidistribution results.
|
||||
class distribution_experiment : public equidistribution_experiment
|
||||
{
|
||||
public:
|
||||
template<class UnaryFunction>
|
||||
distribution_experiment(UnaryFunction probability , unsigned int classes)
|
||||
: equidistribution_experiment(classes), limit(classes)
|
||||
{
|
||||
for(unsigned int i = 0; i < classes-1; ++i)
|
||||
limit[i] = invert_monotone_inc(probability, (i+1)*0.05, 0, 1000);
|
||||
limit[classes-1] = std::numeric_limits<double>::infinity();
|
||||
if(limit[classes-1] < (std::numeric_limits<double>::max)())
|
||||
limit[classes-1] = (std::numeric_limits<double>::max)();
|
||||
#if 0
|
||||
std::cout << __PRETTY_FUNCTION__ << ": ";
|
||||
for(unsigned int i = 0; i < classes; ++i)
|
||||
std::cout << limit[i] << " ";
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class NumberGenerator, class Counter>
|
||||
void run(NumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
for(int i = 0; i < n; ++i) {
|
||||
limits_type::const_iterator it =
|
||||
std::lower_bound(limit.begin(), limit.end(), f());
|
||||
count(it-limit.begin());
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef std::vector<double> limits_type;
|
||||
limits_type limit;
|
||||
};
|
||||
|
||||
// runs-up/runs-down experiment
|
||||
template<bool up>
|
||||
class runs_experiment : public experiment_base
|
||||
{
|
||||
public:
|
||||
explicit runs_experiment(unsigned int classes) : experiment_base(classes) { }
|
||||
|
||||
template<class UniformRandomNumberGenerator, class Counter>
|
||||
void run(UniformRandomNumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
typedef typename UniformRandomNumberGenerator::result_type result_type;
|
||||
result_type init = (up ? (f.min)() : (f.max)());
|
||||
result_type previous = init;
|
||||
unsigned int length = 0;
|
||||
for(int i = 0; i < n; ++i) {
|
||||
result_type val = f();
|
||||
if(up ? previous <= val : previous >= val) {
|
||||
previous = val;
|
||||
++length;
|
||||
} else {
|
||||
count((std::min)(length, classes())-1);
|
||||
length = 0;
|
||||
previous = init;
|
||||
// don't use this value, so that runs are independent
|
||||
}
|
||||
}
|
||||
}
|
||||
double probability(unsigned int r) const
|
||||
{
|
||||
if(r == classes()-1)
|
||||
return 1.0/fac<double>(classes());
|
||||
else
|
||||
return static_cast<double>(r+1)/fac<double>(r+2);
|
||||
}
|
||||
};
|
||||
|
||||
// gap length experiment
|
||||
class gap_experiment : public experiment_base
|
||||
{
|
||||
public:
|
||||
gap_experiment(unsigned int classes, double alpha, double beta)
|
||||
: experiment_base(classes), alpha(alpha), beta(beta) { }
|
||||
|
||||
template<class UniformRandomNumberGenerator, class Counter>
|
||||
void run(UniformRandomNumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
typedef typename UniformRandomNumberGenerator::result_type result_type;
|
||||
double range = (f.max)() - (f.min)() + 1.0;
|
||||
result_type low = static_cast<result_type>(alpha * range);
|
||||
result_type high = static_cast<result_type>(beta * range);
|
||||
unsigned int length = 0;
|
||||
for(int i = 0; i < n; ) {
|
||||
result_type value = f() - (f.min)();
|
||||
if(value < low || value > high)
|
||||
++length;
|
||||
else {
|
||||
count((std::min)(length, classes()-1));
|
||||
length = 0;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
double probability(unsigned int r) const
|
||||
{
|
||||
double p = beta-alpha;
|
||||
if(r == classes()-1)
|
||||
return std::pow(1-p, static_cast<double>(r));
|
||||
else
|
||||
return p * std::pow(1-p, static_cast<double>(r));
|
||||
}
|
||||
private:
|
||||
double alpha, beta;
|
||||
};
|
||||
|
||||
// poker experiment
|
||||
class poker_experiment : public experiment_base
|
||||
{
|
||||
public:
|
||||
poker_experiment(unsigned int d, unsigned int k)
|
||||
: experiment_base(k), range(d)
|
||||
{
|
||||
assert(range > 1);
|
||||
}
|
||||
|
||||
template<class UniformRandomNumberGenerator, class Counter>
|
||||
void run(UniformRandomNumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
typedef typename UniformRandomNumberGenerator::result_type result_type;
|
||||
assert(std::numeric_limits<result_type>::is_integer);
|
||||
assert((f.min)() == 0);
|
||||
assert((f.max)() == static_cast<result_type>(range-1));
|
||||
std::vector<result_type> v(classes());
|
||||
for(int i = 0; i < n; ++i) {
|
||||
for(unsigned int j = 0; j < classes(); ++j)
|
||||
v[j] = f();
|
||||
std::sort(v.begin(), v.end());
|
||||
result_type prev = v[0];
|
||||
int r = 1; // count different values in v
|
||||
for(unsigned int i = 1; i < classes(); ++i) {
|
||||
if(prev != v[i]) {
|
||||
prev = v[i];
|
||||
++r;
|
||||
}
|
||||
}
|
||||
count(r-1);
|
||||
}
|
||||
}
|
||||
|
||||
double probability(unsigned int r) const
|
||||
{
|
||||
++r; // transform to 1 <= r <= 5
|
||||
double result = range;
|
||||
for(unsigned int i = 1; i < r; ++i)
|
||||
result *= range-i;
|
||||
return result / std::pow(range, static_cast<double>(classes())) *
|
||||
stirling2<double>(classes(), r);
|
||||
}
|
||||
private:
|
||||
unsigned int range;
|
||||
};
|
||||
|
||||
// coupon collector experiment
|
||||
class coupon_collector_experiment : public experiment_base
|
||||
{
|
||||
public:
|
||||
coupon_collector_experiment(unsigned int d, unsigned int cls)
|
||||
: experiment_base(cls), d(d)
|
||||
{
|
||||
assert(d > 1);
|
||||
}
|
||||
|
||||
template<class UniformRandomNumberGenerator, class Counter>
|
||||
void run(UniformRandomNumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
typedef typename UniformRandomNumberGenerator::result_type result_type;
|
||||
assert(std::numeric_limits<result_type>::is_integer);
|
||||
assert((f.min)() == 0);
|
||||
assert((f.max)() == static_cast<result_type>(d-1));
|
||||
std::vector<bool> occurs(d);
|
||||
for(int i = 0; i < n; ++i) {
|
||||
occurs.assign(d, false);
|
||||
unsigned int r = 0; // length of current sequence
|
||||
int q = 0; // number of non-duplicates in current set
|
||||
for(;;) {
|
||||
result_type val = f();
|
||||
++r;
|
||||
if(!occurs[val]) { // new set element
|
||||
occurs[val] = true;
|
||||
++q;
|
||||
if(q == d)
|
||||
break; // one complete set
|
||||
}
|
||||
}
|
||||
count((std::min)(r-d, classes()-1));
|
||||
}
|
||||
}
|
||||
double probability(unsigned int r) const
|
||||
{
|
||||
if(r == classes()-1)
|
||||
return 1-fac<double>(d)/std::pow(d, static_cast<double>(d+classes()-2))*
|
||||
stirling2<double>(d+classes()-2, d);
|
||||
else
|
||||
return fac<double>(d)/std::pow(d, static_cast<double>(d+r)) *
|
||||
stirling2<double>(d+r-1, d-1);
|
||||
}
|
||||
private:
|
||||
int d;
|
||||
};
|
||||
|
||||
// permutation test
|
||||
class permutation_experiment : public equidistribution_experiment
|
||||
{
|
||||
public:
|
||||
permutation_experiment(unsigned int t)
|
||||
: equidistribution_experiment(fac<int>(t)), t(t)
|
||||
{
|
||||
assert(t > 1);
|
||||
}
|
||||
|
||||
template<class UniformRandomNumberGenerator, class Counter>
|
||||
void run(UniformRandomNumberGenerator f, Counter & count, int n) const
|
||||
{
|
||||
typedef typename UniformRandomNumberGenerator::result_type result_type;
|
||||
std::vector<result_type> v(t);
|
||||
for(int i = 0; i < n; ++i) {
|
||||
std::generate_n(v.begin(), t, f);
|
||||
int x = 0;
|
||||
for(int r = t-1; r > 0; r--) {
|
||||
typename std::vector<result_type>::iterator it =
|
||||
std::max_element(v.begin(), v.begin()+r+1);
|
||||
x = (r+1)*x + (it-v.begin());
|
||||
std::iter_swap(it, v.begin()+r);
|
||||
}
|
||||
count(x);
|
||||
}
|
||||
}
|
||||
private:
|
||||
int t;
|
||||
};
|
||||
|
||||
// birthday spacing experiment test
|
||||
class birthday_spacing_experiment : public experiment_base
|
||||
{
|
||||
public:
|
||||
birthday_spacing_experiment(unsigned int d, int n, int m)
|
||||
: experiment_base(d), n(n), m(m)
|
||||
{
|
||||
}
|
||||
|
||||
template<class UniformRandomNumberGenerator, class Counter>
|
||||
void run(UniformRandomNumberGenerator f, Counter & count, int n_total) const
|
||||
{
|
||||
typedef typename UniformRandomNumberGenerator::result_type result_type;
|
||||
assert(std::numeric_limits<result_type>::is_integer);
|
||||
assert((f.min)() == 0);
|
||||
assert((f.max)() == static_cast<result_type>(m-1));
|
||||
|
||||
for(int j = 0; j < n_total; j++) {
|
||||
std::vector<result_type> v(n);
|
||||
std::generate_n(v.begin(), n, f);
|
||||
std::sort(v.begin(), v.end());
|
||||
std::vector<result_type> spacing(n);
|
||||
for(int i = 0; i < n-1; i++)
|
||||
spacing[i] = v[i+1]-v[i];
|
||||
spacing[n-1] = v[0] + m - v[n-1];
|
||||
std::sort(spacing.begin(), spacing.end());
|
||||
unsigned int k = 0;
|
||||
for(int i = 0; i < n-1; ++i) {
|
||||
if(spacing[i] == spacing[i+1])
|
||||
++k;
|
||||
}
|
||||
count((std::min)(k, classes()-1));
|
||||
}
|
||||
}
|
||||
|
||||
double probability(unsigned int r) const
|
||||
{
|
||||
assert(classes() == 4);
|
||||
assert(m == (1<<25));
|
||||
assert(n == 512);
|
||||
static const double prob[] = { 0.368801577, 0.369035243, 0.183471182,
|
||||
0.078691997 };
|
||||
return prob[r];
|
||||
}
|
||||
private:
|
||||
int n, m;
|
||||
};
|
||||
/*
|
||||
* Misc. helper functions.
|
||||
*/
|
||||
|
||||
template<class Float>
|
||||
struct distribution_function
|
||||
{
|
||||
typedef Float result_type;
|
||||
typedef Float argument_type;
|
||||
typedef Float first_argument_type;
|
||||
typedef Float second_argument_type;
|
||||
};
|
||||
|
||||
// computes P(K_n <= t) or P(t1 <= K_n <= t2). See Knuth, 3.3.1
|
||||
class kolmogorov_smirnov_probability : public distribution_function<double>
|
||||
{
|
||||
public:
|
||||
kolmogorov_smirnov_probability(int n)
|
||||
: approx(n > 50), n(n), sqrt_n(std::sqrt(double(n)))
|
||||
{
|
||||
if(!approx)
|
||||
n_n = std::pow(static_cast<double>(n), n);
|
||||
}
|
||||
|
||||
double operator()(double t) const
|
||||
{
|
||||
if(approx) {
|
||||
return 1-std::exp(-2*t*t)*(1-2.0/3.0*t/sqrt_n);
|
||||
} else {
|
||||
t *= sqrt_n;
|
||||
double sum = 0;
|
||||
for(int k = static_cast<int>(std::ceil(t)); k <= n; k++)
|
||||
sum += binomial<double>(n, k) * std::pow(k-t, k) *
|
||||
std::pow(t+n-k, n-k-1);
|
||||
return 1 - t/n_n * sum;
|
||||
}
|
||||
}
|
||||
double operator()(double t1, double t2) const
|
||||
{ return operator()(t2) - operator()(t1); }
|
||||
|
||||
private:
|
||||
bool approx;
|
||||
int n;
|
||||
double sqrt_n;
|
||||
double n_n;
|
||||
};
|
||||
|
||||
/*
|
||||
* Experiments for generators with continuous distribution functions
|
||||
*/
|
||||
class kolmogorov_experiment
|
||||
{
|
||||
public:
|
||||
kolmogorov_experiment(int n) : n(n), ksp(n) { }
|
||||
template<class NumberGenerator, class Distribution>
|
||||
double run(NumberGenerator gen, Distribution distrib) const
|
||||
{
|
||||
const int m = n;
|
||||
typedef std::vector<double> saved_temp;
|
||||
saved_temp a(m,1.0), b(m,0);
|
||||
std::vector<int> c(m,0);
|
||||
for(int i = 0; i < n; ++i) {
|
||||
double val = gen();
|
||||
double y = distrib(val);
|
||||
int k = static_cast<int>(std::floor(m*y));
|
||||
if(k >= m)
|
||||
--k; // should not happen
|
||||
a[k] = (std::min)(a[k], y);
|
||||
b[k] = (std::max)(b[k], y);
|
||||
++c[k];
|
||||
}
|
||||
double kplus = 0, kminus = 0;
|
||||
int j = 0;
|
||||
for(int k = 0; k < m; ++k) {
|
||||
if(c[k] > 0) {
|
||||
kminus = (std::max)(kminus, a[k]-j/static_cast<double>(n));
|
||||
j += c[k];
|
||||
kplus = (std::max)(kplus, j/static_cast<double>(n) - b[k]);
|
||||
}
|
||||
}
|
||||
kplus *= std::sqrt(double(n));
|
||||
kminus *= std::sqrt(double(n));
|
||||
// std::cout << "k+ " << kplus << " k- " << kminus << std::endl;
|
||||
return kplus;
|
||||
}
|
||||
double probability(double x) const
|
||||
{
|
||||
return ksp(x);
|
||||
}
|
||||
private:
|
||||
int n;
|
||||
kolmogorov_smirnov_probability ksp;
|
||||
};
|
||||
|
||||
// maximum-of-t test (KS-based)
|
||||
template<class UniformRandomNumberGenerator>
|
||||
class maximum_experiment
|
||||
{
|
||||
public:
|
||||
typedef UniformRandomNumberGenerator base_type;
|
||||
maximum_experiment(base_type & f, int n, int t) : f(f), ke(n), t(t)
|
||||
{ }
|
||||
|
||||
double operator()() const
|
||||
{
|
||||
double res = ke.run(generator(f, t),
|
||||
std::bind2nd(std::ptr_fun(static_cast<double (*)(double, double)>(&std::pow)), t));
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
struct generator {
|
||||
generator(base_type & f, int t) : f(f), t(t) { }
|
||||
double operator()()
|
||||
{
|
||||
double mx = f();
|
||||
for(int i = 1; i < t; ++i)
|
||||
mx = (std::max)(mx, f());
|
||||
return mx;
|
||||
}
|
||||
private:
|
||||
boost::uniform_01<base_type> f;
|
||||
int t;
|
||||
};
|
||||
base_type & f;
|
||||
kolmogorov_experiment ke;
|
||||
int t;
|
||||
};
|
||||
|
||||
// compute a chi-square value for the distribution approximation error
|
||||
template<class ForwardIterator, class UnaryFunction>
|
||||
typename UnaryFunction::result_type
|
||||
chi_square_value(ForwardIterator first, ForwardIterator last,
|
||||
UnaryFunction probability)
|
||||
{
|
||||
typedef std::iterator_traits<ForwardIterator> iter_traits;
|
||||
typedef typename iter_traits::value_type counter_type;
|
||||
typedef typename UnaryFunction::result_type result_type;
|
||||
unsigned int classes = std::distance(first, last);
|
||||
result_type sum = 0;
|
||||
counter_type n = 0;
|
||||
for(unsigned int i = 0; i < classes; ++first, ++i) {
|
||||
counter_type count = *first;
|
||||
n += count;
|
||||
sum += (count/probability(i)) * count; // avoid overflow
|
||||
}
|
||||
#if 0
|
||||
for(unsigned int i = 0; i < classes; ++i) {
|
||||
// std::cout << (n*probability(i)) << " ";
|
||||
if(n * probability(i) < 5)
|
||||
std::cerr << "Not enough test runs for slot " << i
|
||||
<< " p=" << probability(i) << ", n=" << n
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
// std::cout << std::endl;
|
||||
// throw std::invalid_argument("not enough test runs");
|
||||
|
||||
return sum/n - n;
|
||||
}
|
||||
template<class RandomAccessContainer>
|
||||
class generic_counter
|
||||
{
|
||||
public:
|
||||
explicit generic_counter(unsigned int classes) : container(classes, 0) { }
|
||||
void operator()(int i)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(static_cast<unsigned int>(i) < container.size());
|
||||
++container[i];
|
||||
}
|
||||
typename RandomAccessContainer::const_iterator begin() const
|
||||
{ return container.begin(); }
|
||||
typename RandomAccessContainer::const_iterator end() const
|
||||
{ return container.end(); }
|
||||
|
||||
private:
|
||||
RandomAccessContainer container;
|
||||
};
|
||||
|
||||
// chi_square test
|
||||
template<class Experiment, class Generator>
|
||||
double run_experiment(const Experiment & experiment, Generator gen, int n)
|
||||
{
|
||||
generic_counter<std::vector<int> > v(experiment.classes());
|
||||
experiment.run(gen, v, n);
|
||||
return chi_square_value(v.begin(), v.end(),
|
||||
std::bind1st(std::mem_fun_ref(&Experiment::probability),
|
||||
experiment));
|
||||
}
|
||||
|
||||
// number generator with experiment results (for nesting)
|
||||
template<class Experiment, class Generator>
|
||||
class experiment_generator_t
|
||||
{
|
||||
public:
|
||||
experiment_generator_t(const Experiment & exper, Generator & gen, int n)
|
||||
: experiment(exper), generator(gen), n(n) { }
|
||||
double operator()() { return run_experiment(experiment, generator, n); }
|
||||
private:
|
||||
const Experiment & experiment;
|
||||
Generator & generator;
|
||||
int n;
|
||||
};
|
||||
|
||||
template<class Experiment, class Generator>
|
||||
experiment_generator_t<Experiment, Generator>
|
||||
experiment_generator(const Experiment & e, Generator & gen, int n)
|
||||
{
|
||||
return experiment_generator_t<Experiment, Generator>(e, gen, n);
|
||||
}
|
||||
|
||||
|
||||
template<class Experiment, class Generator, class Distribution>
|
||||
class ks_experiment_generator_t
|
||||
{
|
||||
public:
|
||||
ks_experiment_generator_t(const Experiment & exper, Generator & gen,
|
||||
const Distribution & distrib)
|
||||
: experiment(exper), generator(gen), distribution(distrib) { }
|
||||
double operator()() { return experiment.run(generator, distribution); }
|
||||
private:
|
||||
const Experiment & experiment;
|
||||
Generator & generator;
|
||||
Distribution distribution;
|
||||
};
|
||||
|
||||
template<class Experiment, class Generator, class Distribution>
|
||||
ks_experiment_generator_t<Experiment, Generator, Distribution>
|
||||
ks_experiment_generator(const Experiment & e, Generator & gen,
|
||||
const Distribution & distrib)
|
||||
{
|
||||
return ks_experiment_generator_t<Experiment, Generator, Distribution>
|
||||
(e, gen, distrib);
|
||||
}
|
||||
|
||||
|
||||
#endif /* STATISTIC_TESTS_HPP */
|
||||
|
||||
25
test/Jamfile
25
test/Jamfile
@@ -1,25 +0,0 @@
|
||||
# Boost Random Library test Jamfile
|
||||
|
||||
subproject libs/random/test ;
|
||||
|
||||
# bring in rules for testing
|
||||
import testing ;
|
||||
|
||||
# Make tests run by default.
|
||||
DEPENDS all : test ;
|
||||
|
||||
{
|
||||
# look in BOOST_ROOT for sources first, just in this Jamfile
|
||||
local SEARCH_SOURCE = $(BOOST_ROOT) $(SEARCH_SOURCE) ;
|
||||
|
||||
test-suite "random"
|
||||
:
|
||||
[ run libs/random/random_test.cpp ]
|
||||
[ run libs/random/random_demo.cpp ]
|
||||
# [ run libs/random/nondet_random_speed.cpp ]
|
||||
# [ run libs/random/random_device.cpp ]
|
||||
# [ run libs/random/random_speed.cpp ]
|
||||
# [ run libs/random/statistic_tests.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Boost Random Library test Jamfile
|
||||
|
||||
# bring in rules for testing
|
||||
import testing ;
|
||||
|
||||
project
|
||||
: source-location $(BOOST_ROOT)
|
||||
;
|
||||
{
|
||||
test-suite "random"
|
||||
:
|
||||
[ run libs/random/random_test.cpp ]
|
||||
[ run libs/random/random_demo.cpp ]
|
||||
# [ run libs/random/nondet_random_speed.cpp ]
|
||||
# [ run libs/random/random_device.cpp ]
|
||||
# [ run libs/random/random_speed.cpp ]
|
||||
# [ run libs/random/statistic_tests.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
3518
wg21-proposal.html
3518
wg21-proposal.html
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user