diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /libs/random | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'libs/random')
137 files changed, 9404 insertions, 0 deletions
diff --git a/libs/random/build/Jamfile.v2 b/libs/random/build/Jamfile.v2 new file mode 100644 index 0000000000..34d7f2495d --- /dev/null +++ b/libs/random/build/Jamfile.v2 @@ -0,0 +1,18 @@ +# Jamfile.v2 +# +# Copyright (c) 2010 +# Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project /boost/random + : source-location ../src + : requirements <link>shared:<define>BOOST_RANDOM_DYN_LINK + : usage-requirements <link>shared:<define>BOOST_RANDOM_DYN_LINK +; + +lib boost_random : [ glob *.cpp ] ; + +boost-install boost_random ; diff --git a/libs/random/doc/Jamfile.v2 b/libs/random/doc/Jamfile.v2 new file mode 100644 index 0000000000..a5db8b7938 --- /dev/null +++ b/libs/random/doc/Jamfile.v2 @@ -0,0 +1,169 @@ +# Jamfile.v2 +# +# Copyright (c) 2009 +# Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +using quickbook ; +using doxygen ; +using boostbook ; +import regex ; +import os ; +import path ; + +doxygen_files = + additive_combine + bernoulli_distribution + binomial_distribution + cauchy_distribution + chi_squared_distribution + discard_block + discrete_distribution + exponential_distribution + extreme_value_distribution + fisher_f_distribution + gamma_distribution + geometric_distribution + independent_bits + inversive_congruential + lagged_fibonacci + linear_congruential + linear_feedback_shift + lognormal_distribution + mersenne_twister + negative_binomial_distribution + normal_distribution + piecewise_constant_distribution + piecewise_linear_distribution + poisson_distribution + random_device + random_number_generator + ranlux + seed_seq + shuffle_order + # shuffle_output + student_t_distribution + subtract_with_carry + taus88 + triangle_distribution + uniform_01 + uniform_int_distribution + uniform_on_sphere + uniform_real_distribution + uniform_smallint + variate_generator + weibull_distribution + xor_combine +; + +path-constant here : . ; +path-constant boost-root : ../../.. ; + +# Figure out where the root of the boost tree is relative +# to the html directory. +local BOOST_ROOT = [ path.relative-to + [ path.join [ path.pwd ] html ] + [ path.root + [ path.make $(boost-root) ] + [ path.pwd ] ] ] ; + +doxygen reference : + $(here)/../../../boost/random/$(doxygen_files).hpp + $(here)/../../../boost/random.hpp + : + <doxygen:param>EXPAND_ONLY_PREDEF=YES + <doxygen:param>"ALIASES= \\ + xmlnote=\"@xmlonly <note><para> @endxmlonly\" \\ + endxmlnote=\"@xmlonly </para></note> @endxmlonly\" \\ + xmlwarning=\"@xmlonly <warning><para> @endxmlonly\" \\ + endxmlwarning=\"@xmlonly </para></warning> @endxmlonly\" \\ + blockquote=\"@xmlonly <blockquote><para> @endxmlonly\" \\ + endblockquote=\"@xmlonly </para></blockquote> @endxmlonly\" \\ + boost=\"$(BOOST_ROOT)\" \\ + random_distribution=\"@xmlonly <link linkend=\\\"boost_random.reference.concepts.random_distribution\\\">random distribution</link> @endxmlonly\" \\ + pseudo_random_number_generator=\"@xmlonly <link linkend=\\\"boost_random.reference.concepts.pseudo_random_number_generator\\\">pseudo-random number generator</link> @endxmlonly\" \\ + uniform_random_number_generator=\"@xmlonly <link linkend=\\\"boost_random.reference.concepts.uniform_random_number_generator\\\">uniform random number generator</link> @endxmlonly\" \\ + nondeterministic_random_number_generator=\"@xmlonly <link linkend=\\\"boost_random.reference.concepts.non_deterministic_uniform_random_number_generator\\\">non-deterministic random number generator</link> @endxmlonly\" \\ + generators=\"@xmlonly <link linkend=\\\"boost_random.reference.generators\\\">generators</link> @endxmlonly\" \\ + distributions=\"@xmlonly <link linkend=\\\"boost_random.reference.distributions\\\">distributions</link> @endxmlonly\" \\ + additive_combine_engine=\"@xmlonly <classname alt=\\\"boost::random::additive_combine_engine\\\">additive_combine_engine</classname> @endxmlonly\" \\ + discard_block_engine=\"@xmlonly <classname alt=\\\"boost::random::discard_block_engine\\\">discard_block_engine</classname> @endxmlonly\" \\ + lagged_fibonacci_engine=\"@xmlonly<classname alt=\\\"boost::random::lagged_fibonacci_engine\\\">lagged_fibonacci_engine</classname>@endxmlonly\" \\ + subtract_with_carry_01_engine=\"@xmlonly<classname alt=\\\"boost::random::subtract_with_carry_01_engine\\\">subtract_with_carry_01_engine</classname>@endxmlonly\" \\ + linear_congruential_engine=\"@xmlonly<classname alt=\\\"boost::random::linear_congruential_engine\\\">linear_congruential_engine</classname>@endxmlonly\" \\ + minstd_rand=\"@xmlonly <classname alt=\\\"boost::random::minstd_rand\\\">minstd_rand</classname> @endxmlonly\" \\ + minstd_rand0=\"@xmlonly <classname alt=\\\"boost::random::minstd_rand0\\\">minstd_rand0</classname> @endxmlonly\" \\ + rand48=\"@xmlonly <classname alt=\\\"boost::random::rand48\\\">rand48</classname> @endxmlonly\" \\ + mt11213b=\"@xmlonly <classname alt=\\\"boost::random::mt11213b\\\">mt11213b</classname> @endxmlonly\" \\ + mt19937=\"@xmlonly <classname alt=\\\"boost::random::mt19937\\\">mt19937</classname> @endxmlonly\" \\ + ecuyer1988=\"@xmlonly <classname alt=\\\"boost::random::ecuyer1988\\\">ecuyer1988</classname> @endxmlonly\" \\ + lagged_fibonacci607=\"@xmlonly <classname alt=\\\"boost::random::lagged_fibonacci607\\\">lagged_fibonacci607</classname> @endxmlonly\" \\ + lagged_fibonacci44497=\"@xmlonly <classname alt=\\\"boost::random::lagged_fibonacci44497\\\">lagged_fibonacci44497</classname> @endxmlonly\" \\ + bernoulli_distribution=\"@xmlonly <classname alt=\\\"boost::random::bernoulli_distribution\\\">bernoulli_distribution</classname> @endxmlonly\" \\ + cauchy_distribution=\"@xmlonly <classname alt=\\\"boost::random::cauchy_distribution\\\">cauchy_distribution</classname> @endxmlonly\" \\ + uniform_01=\"@xmlonly<classname alt=\\\"boost::random::uniform_01\\\">uniform_01</classname>@endxmlonly\" \\ + random_device=\"@xmlonly<classname alt=\\\"boost::random::random_device\\\">random_device</classname>@endxmlonly\"" + <doxygen:param>HIDE_UNDOC_MEMBERS=NO + <doxygen:param>QUIET=YES + <doxygen:param>WARN_IF_UNDOCUMENTED=NO + <doxygen:param>EXTRACT_PRIVATE=NO + <doxygen:param>ENABLE_PREPROCESSING=YES + <doxygen:param>MACRO_EXPANSION=YES + <doxygen:param>SEARCH_INCLUDES=NO + # Expand macros and clean up a bunch of ugly names + <doxygen:param>"PREDEFINED= \\ + \"BOOST_RANDOM_DOXYGEN=1\" \\ + \"BOOST_PREVENT_MACRO_SUBSTITUTION=\" \\ + \"BOOST_STATIC_ASSERT(x)=\" \\ + \"BOOST_STATIC_CONSTANT(type,value)=static const type value\" \\ + \"UINT64_C(value)=value ## ull\" \\ + \"BOOST_RANDOM_DECL=\" \\ + \"RealType(x)=x\" \\ + \"result_type(x)=x\" \\ + \"p_arg=p\" \\ + \"median_arg=median\" \\ + \"mean_arg=mean\" \\ + \"sigma_arg=sigma\" \\ + \"lambda_arg=lambda\" \\ + \"alpha_arg=alpha\" \\ + \"beta_arg=beta\" \\ + \"a_arg=a\" \\ + \"b_arg=b\" \\ + \"c_arg=c\" \\ + \"t_arg=t\" \\ + \"m_arg=m\" \\ + \"n_arg=n\" \\ + \"s_arg=s\" \\ + \"k_arg=k\" \\ + \"min_arg=min\" \\ + \"max_arg=max\" \\ + \"dim_arg=dim\" \\ + \"parm=param\" \\ + \"aseed=seed\" \\ + \"seed_arg=seed\" \\ + \"BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os,T,t)=template<class CharT, class Traits> friend std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& os, const T& t)\" \\ + \"BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,T,t)=template<class CharT, class Traits> friend std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& is, const T& t)\" \\ + \"BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(T,lhs,rhs)=friend bool operator==(const T& lhs, const T& rhs)\" \\ + \"BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(T)=friend bool operator!=(const T& lhs, const T& rhs) { return !(lhs == rhs); }\" \\ + \"BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self,T,t)=explicit Self(T t)\" \\ + \"BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self,T,t)=template<class T> explicit Self(T& t)\" \\ + \"BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(Self,T,t)=template<class T> explicit Self(T& t)\" \\ + \"BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(Self,T,t)=void seed(T t)\" \\ + \"BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self,T,t)=template<class T> void seed(T& t)\" \\ + \"BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(Self,T,t)=template<class T> void seed(T& t)\"" + <reftitle>"Headers" + <doxygen:xml-imagedir>images/random +; + +xml random : random.qbk : <dependency>reference ; + +boostbook standalone : + random + : + <implicit-dependency>reference + <xsl:param>boost.root=../../../.. + <xsl:param>chunk.section.depth=2 +; diff --git a/libs/random/doc/concepts.qbk b/libs/random/doc/concepts.qbk new file mode 100644 index 0000000000..d001b0eb13 --- /dev/null +++ b/libs/random/doc/concepts.qbk @@ -0,0 +1,246 @@ +[/ + / Copyright (c) 2009 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +[section Introduction] + +Random numbers are required in a number of different problem domains, such as + +* numerics (simulation, Monte-Carlo integration) +* games (non-deterministic enemy behavior) +* security (key generation) +* testing (random coverage in white-box tests) + +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 + +[:"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] + +Depending on the requirements of the problem domain, different variations of +random number generators are appropriate: + +* non-deterministic random number generator +* pseudo-random number generator +* quasi-random number generator + +All variations have some properties in common, the concepts (in the STL +sense) is called __UniformRandomNumberGenerator. This +concept will be defined in a subsequent section. + +The goals for this library are the following: + +* allow easy integration of third-party random-number generators +* provide easy-to-use front-end classes which model popular distributions +* provide maximum efficiency + +[endsect] + +[section Uniform Random Number Generator] + +A uniform random number generator 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. + +The /tight lower bound/ of some (finite) set S is the (unique) member l in S, so +that for all v in S, l <= v holds. Likewise, the /tight upper bound/ of some +(finite) set S is the (unique) member u in S, so that for all v in S, v <= u +holds. + +In the following table, X denotes a number generator class returning objects +of type T, and v is a const value of X. + +[table UniformRandomNumberGenerator requirements + [[expression] [return type] [pre/post-condition]] + [[`X::result_type`] [`T`] [`std::numeric_limits<T>::is_specialized` is + `true`, `T` is __LessThanComparable]] + [[`u.operator()()`] [`T`] [-]] + [[`v.min()`] [`T`] [tight lower bound on the set of all values returned by + `operator()`. The return value of this function shall not + change during the lifetime of the object.]] + [[`v.max()`] [`T`] [if `std::numeric_limits<T>::is_integer`, tight upper + bound on the set of all values returned by `operator()`, + otherwise, the smallest representable number larger than + the tight upper bound on the set of all values returned + by `operator()`. In any case, the return value of this + function shall not change during the lifetime of the + object.]] +] + +The member functions `min`, `max`, and `operator()` shall have amortized +constant time complexity. + +[note For integer generators (i.e. integer `T`), the generated values `x` +fulfill `min() <= x <= max()`, for non-integer generators (i.e. non-integer +`T`), the generated values `x` fulfill `min() <= x < max()`. + +Rationale: The range description with min and max 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. + +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.] + +[note The __UniformRandomNumberGenerator concept does not require +`operator()(long)` and thus it does not fulfill the `RandomNumberGenerator` +(std:25.2.11 \[lib.alg.random.shuffle\]) requirements. Use the +__random_number_generator adapter for that. + +Rationale: `operator()(long)` is not provided, because mapping the output of +some generator with integer range to a different integer range is not trivial.] + +[endsect] + +[section Non-deterministic Uniform Random Number Generator] + +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. + +The class __random_device is a model for a non-deterministic random number +generator. + +[note This type of random-number generator is useful for security +applications, where it is important to prevent an outside attacker from +guessing the numbers and thus obtaining 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.] + +[endsect] + +[section Pseudo-Random Number Generator] + +A pseudo-random number generator is a __UniformRandomNumberGenerator which +provides a deterministic sequence of pseudo-random numbers, based on some +algorithm and internal state. +[classref boost::random::linear_congruential_engine +Linear congruential] and [classref boost::random::inversive_congruential_engine +inversive congruential] generators are examples of such [prng 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. + +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. + +[note Because the state of a pseudo-random number generator is necessarily +finite, the sequence of numbers returned by the generator will loop +eventually.] + +In addition to the __UniformRandomNumberGenerator requirements, +a pseudo-random number generator has some additional requirements. In the +following table, `X` denotes a pseudo-random number generator class returning +objects of type `T`, `x` is a value of `T`, `u` is a value of `X`, and `v` is +a const value of `X`. + +[table PseudoRandomNumberGenerator requirements + [[expression] [return type] [pre/post-condition]] + [[`X()`] [-] [creates a generator in some implementation-defined state. + Note: Several generators thusly created may possibly produce + dependent or identical sequences of random numbers.]] + [[`X(...)`] [-] [creates a generator with user-provided state; the + implementation shall specify the constructor + argument(s)]] + [[`u.seed(...)`] [`void`] [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.]] +] + +[note The seed member function is similar to the assign member function in +STL containers. However, the naming did not seem appropriate.] + +Classes which model a pseudo-random number generator shall also model +__EqualityComparable, i.e. implement `operator==`. Two pseudo-random number +generators are defined to be /equivalent/ if they both return an identical +sequence of numbers starting from a given state. + +Classes which model a pseudo-random number generator should also model the +__Streamable concept, i.e. implement `operator<<` and `operator>>`. If so, +`operator<<` writes all current state of the pseudo-random number generator +to the given `ostream` so that `operator>>` can restore the state at a later +time. The state shall be written in a platform-independent manner, but it is +assumed that the `locales` 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. + +Classes which model a pseudo-random number generator should 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-const) reference. + +The classes __rand48, __minstd_rand, and __mt19937 are models for a +pseudo-random number generator. + +[note This type of random-number generator is useful for numerics, games and +testing. The non-zero arguments constructor(s) and the `seed()` 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.] + +[endsect] + +[section Random Distribution] + +A random distribution produces random numbers distributed according to some +distribution, given uniformly distributed random values as input. In the +following table, `X` denotes a random distribution class returning objects of +type `T`, `u` is a value of `X`, `x` is a (possibly const) value of `X`, and +`e` is an lvalue of an arbitrary type that meets the requirements of a +__UniformRandomNumberGenerator, returning values of type `U`. + +[table Random distribution requirements (in addition to CopyConstructible, and Assignable) + [[expression] [return type] [pre/post-condition] [complexity]] + [[`X::result_type`] [`T`] [-] [compile-time]] + [[`u.reset()`] [`void`] [subsequent uses of `u` do not depend on values + produced by any engine prior to invoking `reset`.] + [constant]] + [[`u(e)`] [`T`] [the sequence of numbers returned by successive invocations + with the same object `e` is randomly distributed with some + probability density function `p(x)`] + [amortized constant number of invocations of `e`]] + [[`os << x`] [`std::ostream&`] [writes a textual representation for the + parameters and additional internal data of + the distribution `x` to `os`. + post: The `os.fmtflags` and fill character + are unchanged.] + [O(size of state)]] + [[`is >> u`] [`std::istream&`] [restores the parameters and additional + internal data of the distribution `u`. + pre: `is` provides a textual representation + that was previously written by `operator<<` + post: The `is.fmtflags` are unchanged.] + [O(size of state)]] +] + +Additional requirements: The sequence of numbers produced by repeated +invocations of `x(e)` does not change whether or not `os << x` is invoked +between any of the invocations `x(e)`. If a textual representation is written +using `os << x` and that representation is restored into the same or a +different object `y` of the same type using `is >> y`, repeated invocations +of `y(e)` produce the same sequence of random numbers as would repeated +invocations of `x(e)`. + +[endsect] diff --git a/libs/random/doc/distribution_performance_linux.qbk b/libs/random/doc/distribution_performance_linux.qbk new file mode 100644 index 0000000000..0d4db8752a --- /dev/null +++ b/libs/random/doc/distribution_performance_linux.qbk @@ -0,0 +1,24 @@ +[table Distributions (Linux) + [[\[M rn/sec\]][minstd_rand][kreutzer1986][mt19937][lagged_fibonacci607]] + [[uniform_int][16.2338][48.7805][21.5517][23.8663]] + [[uniform_smallint][18.9036][114.943][25.3165][74.6269]] + [[bernoulli][21.322][85.4701][23.2558][125]] + [[geometric][9.42507][11.7925][7.38007][15.528]] + [[binomial][13.4953][29.7619][12.7877][38.7597]] + [[negative_binomial][1.69549][2.29305][1.65563][2.45098]] + [[poisson][13.7552][34.1297][13.369][43.8596]] + [[uniform_real][18.2815][44.4444][19.8413][119.048]] + [[uniform_01][21.692][72.4638][17.1233][116.279]] + [[triangle][15.2207][29.3255][11.9904][51.2821]] + [[exponential][10.5374][17.0068][10.8814][22.2222]] + [[normal polar][8.82613][12.9199][9.00901][14.771]] + [[lognormal][6.15764][7.50188][5.68182][8.61326]] + [[chi squared][2.07297][2.8401][2.10926][3.07409]] + [[cauchy][9.18274][14.8368][7.37463][17.3913]] + [[fisher f][1.04646][1.47449][1.08026][1.61186]] + [[student t][1.60927][2.18245][1.65207][2.34192]] + [[gamma][2.1097][2.87439][2.13538][3.01296]] + [[weibull][4.73709][5.77367][4.20521][6.33312]] + [[extreme value][7.40192][10.101][6.23441][11.5741]] + [[uniform_on_sphere][2.22222][2.78552][2.28311][2.7933]] +] diff --git a/libs/random/doc/distribution_performance_windows.qbk b/libs/random/doc/distribution_performance_windows.qbk new file mode 100644 index 0000000000..2a1fce4ed6 --- /dev/null +++ b/libs/random/doc/distribution_performance_windows.qbk @@ -0,0 +1,24 @@ +[table Distributions (Windows) + [[\[M rn/sec\]][minstd_rand][kreutzer1986][mt19937][lagged_fibonacci607]] + [[uniform_int][27.049][79.1139][29.8151][34.8432]] + [[uniform_smallint][31.736][90.3342][33.9213][59.9161]] + [[bernoulli][25.641][56.2114][27.049][62.8141]] + [[geometric][12.8717][18.9645][14.6671][18.5805]] + [[binomial][18.2116][32.2165][19.8491][29.4118]] + [[negative_binomial][2.79065][3.99138][2.73358][3.72898]] + [[poisson][20.0321][37.7074][18.9645][36.4299]] + [[uniform_real][27.6319][78.1861][26.4901][71.2251]] + [[uniform_01][36.63][95.6938][26.3783][85.4701]] + [[triangle][19.4856][43.8982][19.425][36.8324]] + [[exponential][17.0474][32.0513][18.005][28.6205]] + [[normal polar][14.4051][19.7863][13.1354][20.7426]] + [[lognormal][10.8472][13.6968][10.3563][13.7855]] + [[chi squared][3.53957][4.95][3.44448][4.83442]] + [[cauchy][15.1906][23.5682][14.9768][23.31]] + [[fisher f][1.74951][2.45417][1.69854][2.38743]] + [[student t][2.63151][3.75291][2.53872][3.51432]] + [[gamma][3.50275][4.9729][3.35087][4.75195]] + [[weibull][8.96539][11.9161][9.09256][11.6754]] + [[extreme value][12.3274][18.4196][12.5945][17.5623]] + [[uniform_on_sphere][2.83688][3.58038][2.73898][3.60101]] +] diff --git a/libs/random/doc/distributions.qbk b/libs/random/doc/distributions.qbk new file mode 100644 index 0000000000..e6589369a2 --- /dev/null +++ b/libs/random/doc/distributions.qbk @@ -0,0 +1,106 @@ +[/ + / Copyright (c) 2009 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +In addition to the [link boost_random.reference.generators random number generators], +this library provides distribution functions which map one distribution +(often a uniform distribution provided by some generator) to another. + +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. + +[table Uniform Distributions + [[distribution] [explanation] [example]] + [[__uniform_smallint] [discrete uniform distribution on a small set of integers + (much smaller than the range of the underlying + generator)] + [drawing from an urn]] + [[__uniform_int_distribution] [discrete uniform distribution on a set of integers; the + underlying generator may be called several times to gather + enough randomness for the output] + [drawing from an urn]] + [[__uniform_01] [continuous uniform distribution on the range [0,1); + important basis for other distributions] + [-]] + [[__uniform_real_distribution] [continuous uniform distribution on some range [min, max) of + real numbers] + [for the range [0, 2pi): randomly dropping a stick and + measuring its angle in radians (assuming the angle is + uniformly distributed)]] +] + +[table Bernoulli Distributions + [[distribution] [explanation] [example]] + [[__bernoulli_distribution] [Bernoulli experiment: discrete boolean valued + distribution with configurable probability] + [tossing a coin (p=0.5)]] + [[__binomial_distribution] [counts outcomes of repeated Bernoulli + experiments] + [tossing a coin 20 times and counting how many + front sides are shown]] + [[__geometric_distribution] [measures distance between outcomes of repeated + Bernoulli experiments] + [throwing a die several times and counting the + number of tries until a "6" appears for the + first time]] + [[__negative_binomial_distribution] [Counts the number of failures of repeated + Bernoulli experiments required to get some constant + number of successes.] + [flipping a coin and counting the number of + heads that show up before we get 3 tails]] +] + +[table Poisson Distributions + [[distribution] [explanation] [example]] + [[__poisson_distribution][poisson distribution] + [counting the number of alpha particles emitted + by radioactive matter in a fixed period of time]] + [[__exponential_distribution] [exponential distribution] + [measuring the inter-arrival time of alpha + particles emitted by radioactive matter]] + [[__gamma_distribution][gamma distribution][-]] + [[__weibull_distribution] [weibull distribution] [-]] + [[__extreme_value_distribution] [extreme value distribution] [-]] +] + +[table Normal Distributions + [[distribution] [explanation] [example]] + [[__normal_distribution] [counts outcomes of (infinitely) repeated Bernoulli + experiments] + [tossing a coin 10000 times and counting how many + front sides are shown]] + [[__lognormal_distribution] [lognormal distribution (sometimes used in + simulations)] + [measuring the job completion time of an assembly + line worker]] + [[__chi_squared_distribution][chi-squared distribution][-]] + [[__cauchy_distribution][Cauchy distribution][-]] + [[__fisher_f_distribution][Fisher F distribution][-]] + [[__student_t_distribution][Student t distribution][-]] +] + +[table Sampling Distributions + [[distribution] [explanation] [example]] + [[__discrete_distribution][discrete distribution with specific probabilities][rolling an unfair die]] + [[__piecewise_constant_distribution][-][-]] + [[__piecewise_linear_distribution][-][-]] +] + + +[table Miscellaneous Distributions + [[distribution] [explanation] [example]] + [[__triangle_distribution] [triangle distribution] [-]] + [[__uniform_on_sphere] [uniform distribution on a unit sphere of arbitrary + dimension] + [choosing a random point on Earth (assumed to be a + sphere) where to spend the next vacations]] +] diff --git a/libs/random/doc/generator_defs.qbk b/libs/random/doc/generator_defs.qbk new file mode 100644 index 0000000000..abc9d3d75c --- /dev/null +++ b/libs/random/doc/generator_defs.qbk @@ -0,0 +1,37 @@ +[/ + / Copyright (c) 2009 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +[template rand48_speed[] 68%] +[template lrand48_run_time_speed[] 12%] +[template minstd_rand0_speed[] 32%] +[template minstd_rand_speed[] 26%] +[template ecuyer_combined_speed[] 11%] +[template kreutzer1986_speed[] 46%] +[template hellekalek1995__inversive__speed[] 2%] +[template mt11213b_speed[] 95%] +[template mt19937_speed[] 100%] +[template lagged_fibonacci607_speed[] 42%] +[template lagged_fibonacci1279_speed[] 44%] +[template lagged_fibonacci2281_speed[] 44%] +[template lagged_fibonacci3217_speed[] 43%] +[template lagged_fibonacci4423_speed[] 44%] +[template lagged_fibonacci9689_speed[] 44%] +[template lagged_fibonacci19937_speed[] 44%] +[template lagged_fibonacci23209_speed[] 44%] +[template lagged_fibonacci44497_speed[] 44%] +[template subtract_with_carry_speed[] 72%] +[template subtract_with_carry_01_speed[] 54%] +[template ranlux3_speed[] 6%] +[template ranlux4_speed[] 4%] +[template ranlux3_01_speed[] 5%] +[template ranlux4_01_speed[] 2%] +[template ranlux64_3_speed[] 6%] +[template ranlux64_4_speed[] 4%] +[template ranlux64_3_01_speed[] 4%] +[template ranlux64_4_01_speed[] 2%] +[template mt19937ar_c_speed[] 97%] diff --git a/libs/random/doc/generator_performance_linux.qbk b/libs/random/doc/generator_performance_linux.qbk new file mode 100644 index 0000000000..9197b6ee88 --- /dev/null +++ b/libs/random/doc/generator_performance_linux.qbk @@ -0,0 +1,37 @@ +[table Basic Generators (Linux) + [[generator] [M rn/sec] [time per random number \[nsec\]] [relative speed compared to fastest \[percent\]]] + [[rand48][149.254][6.7][59%]] + [[lrand48 run-time][158.73][6.3][63%]] + [[minstd_rand0][22.9885][43.5][9%]] + [[minstd_rand][22.0751][45.3][8%]] + [[ecuyer combined][42.735][23.4][17%]] + [[kreutzer1986][151.515][6.6][60%]] + [[taus88][250][4][100%]] + [[knuth_b][19.6078][51][7%]] + [[hellekalek1995 (inversive)][4.54545][220][1%]] + [[mt11213b][204.082][4.9][81%]] + [[mt19937][204.082][4.9][81%]] + [[mt19937_64][60.6061][16.5][24%]] + [[lagged_fibonacci607][126.582][7.9][50%]] + [[lagged_fibonacci1279][129.87][7.7][51%]] + [[lagged_fibonacci2281][129.87][7.7][51%]] + [[lagged_fibonacci3217][131.579][7.6][52%]] + [[lagged_fibonacci4423][128.205][7.8][51%]] + [[lagged_fibonacci9689][128.205][7.8][51%]] + [[lagged_fibonacci19937][131.579][7.6][52%]] + [[lagged_fibonacci23209][131.579][7.6][52%]] + [[lagged_fibonacci44497][131.579][7.6][52%]] + [[subtract_with_carry][147.059][6.8][58%]] + [[subtract_with_carry_01][105.263][9.5][42%]] + [[ranlux3][15.748][63.5][6%]] + [[ranlux4][9.11577][109.7][3%]] + [[ranlux3_01][10.5708][94.6][4%]] + [[ranlux4_01][6.27353][159.4][2%]] + [[ranlux64_3][15.8983][62.9][6%]] + [[ranlux64_4][9.14913][109.3][3%]] + [[ranlux64_3_01][10.9409][91.4][4%]] + [[ranlux64_4_01][6.32911][158][2%]] + [[ranlux24][15.1976][65.8][6%]] + [[ranlux48][8.88099][112.6][3%]] + [[mt19937ar.c][111.111][9][44%]] +] diff --git a/libs/random/doc/generator_performance_windows.qbk b/libs/random/doc/generator_performance_windows.qbk new file mode 100644 index 0000000000..35d0115390 --- /dev/null +++ b/libs/random/doc/generator_performance_windows.qbk @@ -0,0 +1,37 @@ +[table Basic Generators (Windows) + [[generator] [M rn/sec] [time per random number \[nsec\]] [relative speed compared to fastest \[percent\]]] + [[rand48][152.672][6.55][64%]] + [[lrand48 run-time][24.3724][41.03][10%]] + [[minstd_rand0][39.8248][25.11][16%]] + [[minstd_rand][39.0778][25.59][16%]] + [[ecuyer combined][16.7813][59.59][7%]] + [[kreutzer1986][89.0472][11.23][37%]] + [[taus88][237.53][4.21][100%]] + [[knuth_b][30.8166][32.45][12%]] + [[hellekalek1995 (inversive)][5.28457][189.23][2%]] + [[mt11213b][237.53][4.21][100%]] + [[mt19937][221.239][4.52][93%]] + [[mt19937_64][91.5751][10.92][38%]] + [[lagged_fibonacci607][142.45][7.02][59%]] + [[lagged_fibonacci1279][142.45][7.02][59%]] + [[lagged_fibonacci2281][145.56][6.87][61%]] + [[lagged_fibonacci3217][149.031][6.71][62%]] + [[lagged_fibonacci4423][142.45][7.02][59%]] + [[lagged_fibonacci9689][145.773][6.86][61%]] + [[lagged_fibonacci19937][142.45][7.02][59%]] + [[lagged_fibonacci23209][145.773][6.86][61%]] + [[lagged_fibonacci44497][142.45][7.02][59%]] + [[subtract_with_carry][136.24][7.34][57%]] + [[subtract_with_carry_01][90.3342][11.07][38%]] + [[ranlux3][13.1631][75.97][5%]] + [[ranlux4][7.60398][131.51][3%]] + [[ranlux3_01][8.62738][115.91][3%]] + [[ranlux4_01][4.99625][200.15][2%]] + [[ranlux64_3][13.1631][75.97][5%]] + [[ranlux64_4][7.5861][131.82][3%]] + [[ranlux64_3_01][8.63931][115.75][3%]] + [[ranlux64_4_01][5.01958][199.22][2%]] + [[ranlux24][13.1631][75.97][5%]] + [[ranlux48][7.5861][131.82][3%]] + [[mt19937ar.c][200.401][4.99][84%]] +] diff --git a/libs/random/doc/generators.qbk b/libs/random/doc/generators.qbk new file mode 100644 index 0000000000..d1326cb756 --- /dev/null +++ b/libs/random/doc/generators.qbk @@ -0,0 +1,92 @@ +[/ + / Copyright (c) 2009-2010 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +This library provides several [prng pseudo-random number generators]. The +quality of a [prng pseudo random number generator] crucially depends on both +the algorithm and its parameters. This library implements the algorithms as +class templates with template value parameters, hidden in +`namespace boost::random`. Any particular choice of parameters is represented +as the appropriately specializing `typedef` in `namespace boost`. + +[prng Pseudo-random number generators] should not be constructed (initialized) +frequently during program execution, for two reasons. First, initialization +requires full initialization of the internal state of the generator. Thus, +generators with a lot of internal state (see below) are costly to initialize. +Second, initialization always requires some value used as a "seed" for the +generated sequence. It is usually difficult to obtain several good seed +values. For example, one method to obtain a seed is to determine the current +time at the highest resolution available, e.g. microseconds or nanoseconds. +When the [prng pseudo-random number generator] is initialized again with the +then-current time as the seed, it is likely that this is at a near-constant +(non-random) distance from the time given as the seed for first +initialization. The distance could even be zero if the resolution of the +clock is low, thus the generator re-iterates the same sequence of random +numbers. For some applications, this is inappropriate. + +Note that all [prng pseudo-random number generators] described below are +__CopyConstructible and __Assignable. Copying or assigning a generator will +copy all its internal state, so the original and the copy will generate the +identical sequence of random numbers. Often, such behavior is not wanted. In +particular, beware of the algorithms from the standard library such as +`std::generate`. They take a functor argument by value, thereby invoking the +copy constructor when called. + +The following table gives an overview of some characteristics of the +generators. The cycle length is a rough estimate of the quality of the +generator; the approximate relative speed is a performance measure, higher +numbers mean faster random number generation. + +[table generators + [[generator] [length of cycle] [approx. memory requirements] [approx. speed compared to fastest] [comment]] + [[__minstd_rand0] [2[sup 31]-2] [`sizeof(int32_t)`] [[minstd_rand0_speed]] [-]] + [[__minstd_rand] [2[sup 31]-2] [`sizeof(int32_t)`] [[minstd_rand_speed]] [-]] + [[__rand48][2[sup 48]-1] [`sizeof(uint64_t)`] [[rand48_speed]] [-]] + [[__ecuyer1988] [approx. 2[sup 61]] [`2*sizeof(int32_t)`] [[ecuyer_combined_speed]] [-]] + [[__knuth_b] [?] [`257*sizeof(uint32_t)`] [[knuth_b_speed]] [-]] + [[__kreutzer1986] [?] [`1368*sizeof(uint32_t)`] [[kreutzer1986_speed]] [-]] + [[__taus88] [~2[sup 88]] [`3*sizeof(uint32_t)`] [[taus88_speed]] [-]] + [[__hellekalek1995] [2[sup 31]-1] [`sizeof(int32_t)`] [[hellekalek1995__inversive__speed]] [good uniform distribution in several dimensions]] + [[__mt11213b] [2[sup 11213]-1] [`352*sizeof(uint32_t)`] [[mt11213b_speed]] [good uniform distribution in up to 350 dimensions]] + [[__mt19937] [2[sup 19937]-1] [`625*sizeof(uint32_t)`] [[mt19937_speed]] [good uniform distribution in up to 623 dimensions]] + [[__mt19937_64] [2[sup 19937]-1] [`312*sizeof(uint64_t)`] [[mt19937_64_speed]] [good uniform distribution in up to 311 dimensions]] + [[__lagged_fibonacci607] [~2[sup 32000]] [`607*sizeof(double)`] [[lagged_fibonacci607_speed]] [-]] + [[__lagged_fibonacci1279] [~2[sup 67000]] [`1279*sizeof(double)`] [[lagged_fibonacci1279_speed]] [-]] + [[__lagged_fibonacci2281] [~2[sup 120000]] [`2281*sizeof(double)`] [[lagged_fibonacci2281_speed]] [-]] + [[__lagged_fibonacci3217] [~2[sup 170000]] [`3217*sizeof(double)`] [[lagged_fibonacci3217_speed]] [-]] + [[__lagged_fibonacci4423] [~2[sup 230000]] [`4423*sizeof(double)`] [[lagged_fibonacci4423_speed]] [-]] + [[__lagged_fibonacci9689] [~2[sup 510000]] [`9689*sizeof(double)`] [[lagged_fibonacci9689_speed]] [-]] + [[__lagged_fibonacci19937] [~2[sup 1050000]] [`19937*sizeof(double)`] [[lagged_fibonacci19937_speed]] [-]] + [[__lagged_fibonacci23209] [~2[sup 1200000]] [`23209*sizeof(double)`] [[lagged_fibonacci23209_speed]] [-]] + [[__lagged_fibonacci44497] [~2[sup 2300000]] [`44497*sizeof(double)`] [[lagged_fibonacci44497_speed]] [-]] + [[__ranlux3] [~10[sup 171]] [`24*sizeof(int)`] [[ranlux3_speed]] [-]] + [[__ranlux4] [~10[sup 171]] [`24*sizeof(int)`] [[ranlux4_speed]] [-]] + [[__ranlux64_3] [~10[sup 171]] [`24*sizeof(int64_t)`] [[ranlux64_3_speed]] [-]] + [[__ranlux64_4] [~10[sup 171]] [`24*sizeof(int64_t)`] [[ranlux64_4_speed]] [-]] + [[__ranlux3_01] [~10[sup 171]] [`24*sizeof(float)`] [[ranlux3_speed]] [-]] + [[__ranlux4_01] [~10[sup 171]] [`24*sizeof(float)`] [[ranlux4_speed]] [-]] + [[__ranlux64_3_01] [~10[sup 171]] [`24*sizeof(double)`] [[ranlux64_3_speed]] [-]] + [[__ranlux64_4_01] [~10[sup 171]] [`24*sizeof(double)`] [[ranlux64_4_speed]] [-]] + [[__ranlux24] [~10[sup 171]] [`24*sizeof(uint32_t)`] [[ranlux24_speed]] [-]] + [[__ranlux48] [~10[sup 171]] [`12*sizeof(uint64_t)`] [[ranlux48_speed]] [-]] +] + +As observable from the table, there is generally a quality/performance/memory +trade-off to be decided upon when choosing a random-number generator. The +multitude of generators provided in this library allows the application +programmer to optimize the trade-off with regard to his application domain. +Additionally, employing several fundamentally different random number +generators for a given application of Monte Carlo simulation will improve +the confidence in the results. + +If the names of the generators don't ring any bell and you have no idea +which generator to use, it is reasonable to employ __mt19937 for a start: It +is fast and has acceptable quality. + +[note These random number generators are not intended for use in applications +where non-deterministic random numbers are required. See __random_device +for a choice of (hopefully) non-deterministic random number generators.] diff --git a/libs/random/doc/nondet_random.qbk b/libs/random/doc/nondet_random.qbk new file mode 100644 index 0000000000..edfa635e14 --- /dev/null +++ b/libs/random/doc/nondet_random.qbk @@ -0,0 +1,103 @@ +[/ + / Copyright (c) 2009 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +[section Header <boost/nondet_random.hpp> Synopsis] + + namespace boost { + class random_device; + } // namespace boost + +[endsect] + +[section Class random_device] + +[section Synopsis] + + 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()(); + }; + +[endsect] + +[section Description] + +Class `random_device` models a non-deterministic random number generator. 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 random_device must not be implemented. See + +[:"Randomness Recommendations for Security", D. Eastlake, S. Crocker, +J. Schiller, Network Working Group, RFC 1750, December 1994] + +for further discussions. + +[note 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.] + +[endsect] + +[section Members] + + explicit random_device(const std::string& token = default_token) + +Effects: Constructs a random_device, optionally using the given token as an +access specification (for example, a URL) to some implementation-defined +service for monitoring a stochastic process. + + double entropy() const + +Returns: An entropy estimate for the random numbers returned by `operator()`, +in the range `min()` to `log2(max()+1)`. A deterministic random number +generator (e.g. a pseudo-random number engine) has entropy 0. + +Throws: Nothing. + +[endsect] + +Implementation Note for Linux +On the Linux operating system, token 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, std::ios_base::failure +is thrown. By default, random_device uses the /dev/urandom pseudo-device to +retrieve the random numbers. Another option would be to specify the +/dev/random pseudo-device, which blocks on reads if the entropy pool has no +more random bits available. + +[endsect] + +[section Performance] + +The test program nondet_random_speed.cpp measures the execution times of the +nondet_random.hpp 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. + +[table preformance + [[class] [time per invocation \[usec\]]] + [[random_device] [92.0]] +] + +The measurement error is estimated at +/- 1 usec. + +[endsect] diff --git a/libs/random/doc/performance.qbk b/libs/random/doc/performance.qbk new file mode 100644 index 0000000000..151f74ad74 --- /dev/null +++ b/libs/random/doc/performance.qbk @@ -0,0 +1,28 @@ +[/ + / Copyright (c) 2009 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +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. + +The performance has been evaluated on an Intel(R) Core(TM) i7 +CPU Q 840 @ 1.87GHz, 1867 Mhz with Visual C++ 2010, Microsoft +Windows 7 Professional and with gcc 4.4.5, Ubuntu Linux 2.6.35-25-generic. +The speed is reported in million random numbers +per second (M rn/sec), generated in a tight loop. + +[include generator_performance_linux.qbk] +[include generator_performance_windows.qbk] + +Note that the lagged Fibonacci and ranlux_01 generators produce +floating-point numbers, whereas all others produce integers. + +[include distribution_performance_linux.qbk] +[include distribution_performance_windows.qbk] diff --git a/libs/random/doc/performance_data.qbk b/libs/random/doc/performance_data.qbk new file mode 100644 index 0000000000..c10e42a34c --- /dev/null +++ b/libs/random/doc/performance_data.qbk @@ -0,0 +1,34 @@ +[template rand48_speed[] 64%] +[template lrand48_run_time_speed[] 10%] +[template minstd_rand0_speed[] 16%] +[template minstd_rand_speed[] 16%] +[template ecuyer_combined_speed[] 7%] +[template kreutzer1986_speed[] 37%] +[template taus88_speed[] 100%] +[template knuth_b_speed[] 12%] +[template hellekalek1995__inversive__speed[] 2%] +[template mt11213b_speed[] 100%] +[template mt19937_speed[] 93%] +[template mt19937_64_speed[] 38%] +[template lagged_fibonacci607_speed[] 59%] +[template lagged_fibonacci1279_speed[] 59%] +[template lagged_fibonacci2281_speed[] 61%] +[template lagged_fibonacci3217_speed[] 62%] +[template lagged_fibonacci4423_speed[] 59%] +[template lagged_fibonacci9689_speed[] 61%] +[template lagged_fibonacci19937_speed[] 59%] +[template lagged_fibonacci23209_speed[] 61%] +[template lagged_fibonacci44497_speed[] 59%] +[template subtract_with_carry_speed[] 57%] +[template subtract_with_carry_01_speed[] 38%] +[template ranlux3_speed[] 5%] +[template ranlux4_speed[] 3%] +[template ranlux3_01_speed[] 3%] +[template ranlux4_01_speed[] 2%] +[template ranlux64_3_speed[] 5%] +[template ranlux64_4_speed[] 3%] +[template ranlux64_3_01_speed[] 3%] +[template ranlux64_4_01_speed[] 2%] +[template ranlux24_speed[] 5%] +[template ranlux48_speed[] 3%] +[template mt19937ar_c_speed[] 84%] diff --git a/libs/random/doc/random.qbk b/libs/random/doc/random.qbk new file mode 100644 index 0000000000..3a67ac792b --- /dev/null +++ b/libs/random/doc/random.qbk @@ -0,0 +1,168 @@ +[library Boost.Random + [quickbook 1.5] + [authors [Maurer, Jens]] + [copyright 2000-2005 Jens Maurer, 2009-2010 Steven Watanabe] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] + [purpose A complete system for random number generation] +] + +[template sup[text]'''<superscript>'''[text]'''</superscript>'''] + +[template prng[text] [link boost_random.reference.concepts.pseudo_random_number_generator [text]]] +[template concepts[text] [link boost_random.reference.concepts [text]]] +[template generators[text] [link boost_random.reference.generators [text]]] +[template distributions[text] [link boost_random.reference.distributions [text]]] + +[def __NumberGenerator [link boost_random.reference.concepts.number_generator NumberGenerator]] +[def __UniformRandomNumberGenerator [link boost_random.reference.concepts.uniform_random_number_generator UniformRandomNumberGenerator]] + +[def __CopyConstructible [@boost:/doc/html/CopyConstructible.html CopyConstructible]] +[def __Assignable [@boost:/doc/html/Assignable.html Assignable]] +[def __LessThanComparable [@boost:/doc/html/LessThanComparable.html LessThanComparable]] +[def __EqualityComparable [@boost:/doc/html/EqualityComparable.html EqualityComparable]] +[def __Streamable Streamable] + +[def __random_device [classref boost::random::random_device random_device]] +[def __random_number_generator [classref boost::random::random_number_generator random_number_generator]] +[def __variate_generator [classref boost::random::variate_generator variate_generator]] + +[def __minstd_rand0 [classref boost::random::minstd_rand0 minstd_rand0]] +[def __minstd_rand [classref boost::random::minstd_rand minstd_rand]] +[def __rand48 [classref boost::random::rand48 rand48]] +[def __ecuyer1988 [classref boost::random::ecuyer1988 ecuyer1988]] +[def __kreutzer1986 [classref boost::random::kreutzer1986 kreutzer1986]] +[def __knuth_b [classref boost::random::knuth_b knuth_b]] +[def __taus88 [classref boost::random::taus88 taus88]] +[def __hellekalek1995 [classref boost::random::hellekalek1995 hellekalek1995]] +[def __mt11213b [classref boost::random::mt11213b mt11213b]] +[def __mt19937 [classref boost::random::mt19937 mt19937]] +[def __mt19937_64 [classref boost::random::mt19937_64 mt19937_64]] +[def __lagged_fibonacci607 [classref boost::random::lagged_fibonacci607 lagged_fibonacci607]] +[def __lagged_fibonacci1279 [classref boost::random::lagged_fibonacci1279 lagged_fibonacci1279]] +[def __lagged_fibonacci2281 [classref boost::random::lagged_fibonacci2281 lagged_fibonacci2281]] +[def __lagged_fibonacci3217 [classref boost::random::lagged_fibonacci3217 lagged_fibonacci3217]] +[def __lagged_fibonacci4423 [classref boost::random::lagged_fibonacci4423 lagged_fibonacci4423]] +[def __lagged_fibonacci9689 [classref boost::random::lagged_fibonacci9689 lagged_fibonacci9689]] +[def __lagged_fibonacci19937 [classref boost::random::lagged_fibonacci19937 lagged_fibonacci19937]] +[def __lagged_fibonacci23209 [classref boost::random::lagged_fibonacci23209 lagged_fibonacci23209]] +[def __lagged_fibonacci44497 [classref boost::random::lagged_fibonacci44497 lagged_fibonacci44497]] +[def __ranlux3 [classref boost::random::ranlux3 ranlux3]] +[def __ranlux4 [classref boost::random::ranlux4 ranlux4]] +[def __ranlux64_3 [classref boost::random::ranlux64_3 ranlux64_3]] +[def __ranlux64_4 [classref boost::random::ranlux64_4 ranlux64_4]] +[def __ranlux3_01 [classref boost::random::ranlux3_01 ranlux3_01]] +[def __ranlux4_01 [classref boost::random::ranlux4_01 ranlux4_01]] +[def __ranlux64_3_01 [classref boost::random::ranlux64_3_01 ranlux64_3_01]] +[def __ranlux64_4_01 [classref boost::random::ranlux64_4_01 ranlux64_4_01]] +[def __ranlux24 [classref boost::random::ranlux24 ranlux24]] +[def __ranlux48 [classref boost::random::ranlux48 ranlux48]] + +[def __uniform_smallint [classref boost::random::uniform_smallint uniform_smallint]] +[def __uniform_int_distribution [classref boost::random::uniform_int_distribution uniform_int_distribution]] +[def __uniform_01 [classref boost::random::uniform_01 uniform_01]] +[def __uniform_real_distribution [classref boost::random::uniform_real_distribution uniform_real_distribution]] +[def __bernoulli_distribution [classref boost::random::bernoulli_distribution bernoulli_distribution]] +[def __binomial_distribution [classref boost::random::binomial_distribution binomial_distribution]] +[def __cauchy_distribution [classref boost::random::cauchy_distribution cauchy_distribution]] +[def __discrete_distribution [classref boost::random::discrete_distribution discrete_distribution]] +[def __gamma_distribution [classref boost::random::gamma_distribution gamma_distribution]] +[def __poisson_distribution [classref boost::random::poisson_distribution poisson_distribution]] +[def __geometric_distribution [classref boost::random::geometric_distribution geometric_distribution]] +[def __triangle_distribution [classref boost::random::triangle_distribution triangle_distribution]] +[def __exponential_distribution [classref boost::random::exponential_distribution exponential_distribution]] +[def __normal_distribution [classref boost::random::normal_distribution normal_distribution]] +[def __lognormal_distribution [classref boost::random::lognormal_distribution lognormal_distribution]] +[def __uniform_on_sphere [classref boost::random::uniform_on_sphere uniform_on_sphere]] +[def __weibull_distribution [classref boost::random::weibull_distribution weibull_distribution]] +[def __extreme_value_distribution [classref boost::random::extreme_value_distribution extreme_value_distribution]] +[def __negative_binomial_distribution [classref boost::random::negative_binomial_distribution negative_binomial_distribution]] +[def __student_t_distribution [classref boost::random::student_t_distribution student_t_distribution]] +[def __fisher_f_distribution [classref boost::random::fisher_f_distribution fisher_f_distribution]] +[def __chi_squared_distribution [classref boost::random::chi_squared_distribution chi_squared_distribution]] +[def __piecewise_constant_distribution [classref boost::random::piecewise_constant_distribution piecewise_constant_distribution]] +[def __piecewise_linear_distribution [classref boost::random::piecewise_linear_distribution piecewise_linear_distribution]] + +[include performance_data.qbk] + +[section Introduction] + +Random numbers are useful in a variety of applications. The Boost Random +Number Library (Boost.Random for short) provides a variety of +[generators generators] and [distributions distributions] to produce +random numbers having useful properties, such as uniform distribution. + +You should read the [concepts concepts documentation] for an introduction and the +definition of the basic concepts. For a quick start, it may be sufficient +to have a look at [@boost:/libs/random/example/random_demo.cpp random_demo.cpp]. + +For a very quick start, here's an example: + + ``[classref boost::random::mt19937]`` rng; // produces randomness out of thin air + // see pseudo-random number generators + ``[classref boost::random::uniform_int_distribution]<>`` six(1,6); + // distribution that maps to 1..6 + // see random number distributions + int x = six(rng); // simulate rolling a die + +[endsect] + +[section Tutorial] +[include tutorial.qbk] +[endsect] + +[section Reference] + +[section Concepts] +[include concepts.qbk] +[endsect] + +[section Generators] +[include generators.qbk] +[endsect] + +[section Distributions] +[include distributions.qbk] +[endsect] + +[xinclude reference.xml] + +[endsect] + +[section Performance] +[include performance.qbk] +[endsect] + +[section History and Acknowledgements] + +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 enum workaround. Dave Abrahams highlighted +quantization issues. + +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 min_rand 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. + +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. + +Gary Powell contributed suggestions for code cleanliness. Dave Abrahams +and Howard Hinnant suggested to move the basic generator templates from +`namespace boost::detail` to `boost::random`. + +Ed Brey asked to remove superfluous warnings and helped with `uint64_t` +handling. Andreas Scherer tested with MSVC. Matthias Troyer contributed +a [headerref boost/random/lagged_fibonacci.hpp lagged Fibonacci generator]. +Michael Stevens found a bug in the copy semantics of __normal_distribution +and suggested documentation improvements. + +[endsect] diff --git a/libs/random/doc/tutorial.qbk b/libs/random/doc/tutorial.qbk new file mode 100644 index 0000000000..d14c340e43 --- /dev/null +++ b/libs/random/doc/tutorial.qbk @@ -0,0 +1,28 @@ +[/ + / Copyright (c) 2009 Steven Watanabe + / + / Distributed under the Boost Software License, Version 1.0. (See + / accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) +] + +[section Generating integers in a range] + +[import ../example/die.cpp] +[die] + +[endsect] + +[section Generating integers with different probabilities] + +[import ../example/weighted_die.cpp] +[weighted_die] + +[endsect] + +[section Generating a random password] + +[import ../example/password.cpp] +[password] + +[endsect] diff --git a/libs/random/example/Jamfile.v2 b/libs/random/example/Jamfile.v2 new file mode 100644 index 0000000000..a57fe3f71d --- /dev/null +++ b/libs/random/example/Jamfile.v2 @@ -0,0 +1,12 @@ +# Jamfile.v2 +# +# Copyright (c) 2009 +# Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +run die.cpp ; +run weighted_die.cpp ; +run password.cpp /boost//random ; diff --git a/libs/random/example/die.cpp b/libs/random/example/die.cpp new file mode 100644 index 0000000000..8ed0b8fc13 --- /dev/null +++ b/libs/random/example/die.cpp @@ -0,0 +1,60 @@ +// die.cpp +// +// Copyright (c) 2009 +// Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[die +/*` + For the source of this example see + [@boost://libs/random/example/die.cpp die.cpp]. + First we include the headers we need for __mt19937 + and __uniform_int_distribution. +*/ +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/uniform_int_distribution.hpp> + +/*` + We use __mt19937 with the default seed as a source of + randomness. The numbers produced will be the same + every time the program is run. One common method to + change this is to seed with the current time (`std::time(0)` + defined in ctime). +*/ +boost::random::mt19937 gen; +/*` + [note We are using a /global/ generator object here. This + is important because we don't want to create a new [prng + pseudo-random number generator] at every call] +*/ +/*` + Now we can define a function that simulates an ordinary + six-sided die. +*/ +int roll_die() { + /*<< __mt19937 produces integers in the range [0, 2[sup 32]-1]. + However, we want numbers in the range [1, 6]. The distribution + __uniform_int_distribution performs this transformation. + [warning Contrary to common C++ usage __uniform_int_distribution + does not take a /half-open range/. Instead it takes a /closed range/. + Given the parameters 1 and 6, __uniform_int_distribution can + can produce any of the values 1, 2, 3, 4, 5, or 6.] + >>*/ + boost::random::uniform_int_distribution<> dist(1, 6); + /*<< A distribution is a function object. We generate a random + number by calling `dist` with the generator. + >>*/ + return dist(gen); +} +//] + +#include <iostream> + +int main() { + for(int i = 0; i < 10; ++i) { + std::cout << roll_die() << std::endl; + } +} diff --git a/libs/random/example/password.cpp b/libs/random/example/password.cpp new file mode 100644 index 0000000000..19ab308e58 --- /dev/null +++ b/libs/random/example/password.cpp @@ -0,0 +1,48 @@ +// password.cpp +// +// Copyright (c) 2010 +// Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[password +/*` + For the source of this example see + [@boost://libs/random/example/password.cpp password.cpp]. + + This example demonstrates generating a random 8 character + password. + */ + + +#include <boost/random/random_device.hpp> +#include <boost/random/uniform_int_distribution.hpp> + +int main() { + /*<< We first define the characters that we're going + to allow. This is pretty much just the characters + on a standard keyboard. + >>*/ + std::string chars( + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "1234567890" + "!@#$%^&*()" + "`~-_=+[{]{\\|;:'\",<.>/? "); + /*<< We use __random_device as a source of entropy, since we want + passwords that are not predictable. + >>*/ + boost::random::random_device rng; + /*<< Finally we select 8 random characters from the + string and print them to cout. + >>*/ + boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1); + for(int i = 0; i < 8; ++i) { + std::cout << chars[index_dist(rng)]; + } + std::cout << std::endl; +} + +//] diff --git a/libs/random/example/random_demo.cpp b/libs/random/example/random_demo.cpp new file mode 100644 index 0000000000..9086b921c8 --- /dev/null +++ b/libs/random/example/random_demo.cpp @@ -0,0 +1,110 @@ +/* boost random_demo.cpp profane demo + * + * Copyright Jens Maurer 2000 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: random_demo.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + * 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> +#include <boost/generator_iterator.hpp> + +// 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 you want to use an STL iterator interface, use iterator_adaptors.hpp. + boost::generator_iterator<gen_type> die(&die_gen); + for(int i = 0; i < 10; i++) + std::cout << *die++ << " "; + std::cout << '\n'; +} + +int main() +{ + // Define a random number generator and initialize it with a reproducible + // seed. + base_generator_type generator(42); + + 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; + + { + // 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; + } + + return 0; +} diff --git a/libs/random/example/weighted_die.cpp b/libs/random/example/weighted_die.cpp new file mode 100644 index 0000000000..8dd9c2ac72 --- /dev/null +++ b/libs/random/example/weighted_die.cpp @@ -0,0 +1,55 @@ +// weighted_die.cpp +// +// Copyright (c) 2009 +// Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[weighted_die +/*` + For the source of this example see + [@boost://libs/random/example/weighted_die.cpp weighted_die.cpp]. +*/ +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/discrete_distribution.hpp> + +boost::mt19937 gen; + +/*` + This time, instead of a fair die, the probability of + rolling a 1 is 50% (!). The other five faces are all + equally likely. + + __discrete_distribution works nicely here by allowing + us to assign weights to each of the possible outcomes. + + [tip If your compiler supports `std::initializer_list`, + you can initialize __discrete_distribution directly with + the weights.] +*/ +double probabilities[] = { + 0.5, 0.1, 0.1, 0.1, 0.1, 0.1 +}; +boost::random::discrete_distribution<> dist(probabilities); + +/*` + Now define a function that simulates rolling this die. +*/ +int roll_weighted_die() { + /*<< Add 1 to make sure that the result is in the range [1,6] + instead of [0,5]. + >>*/ + return dist(gen) + 1; +} + +//] + +#include <iostream> + +int main() { + for(int i = 0; i < 10; ++i) { + std::cout << roll_weighted_die() << std::endl; + } +} diff --git a/libs/random/extra/Jamfile.v2 b/libs/random/extra/Jamfile.v2 new file mode 100644 index 0000000000..a0ee2af3b2 --- /dev/null +++ b/libs/random/extra/Jamfile.v2 @@ -0,0 +1,10 @@ +# Jamfile.v2 +# +# Copyright (c) 2009 +# Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0 (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +run test_haertel.cpp ; diff --git a/libs/random/extra/haertel.hpp b/libs/random/extra/haertel.hpp new file mode 100644 index 0000000000..e3907509ef --- /dev/null +++ b/libs/random/extra/haertel.hpp @@ -0,0 +1,156 @@ +/* haertel.hpp file + * + * Copyright Jens Maurer 2000, 2002 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: haertel.hpp 60755 2010-03-22 00:45:06Z steven_watanabe $ + * + * Revision history + */ + +/* + * NOTE: This is not part of the official boost submission. It exists + * only as a collection of ideas. + */ + +#ifndef BOOST_RANDOM_HAERTEL_HPP +#define BOOST_RANDOM_HAERTEL_HPP + +#include <boost/cstdint.hpp> +#include <boost/random/linear_congruential.hpp> +#include <boost/random/inversive_congruential.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; +} // namespace Haertel + +#endif diff --git a/libs/random/extra/test_haertel.cpp b/libs/random/extra/test_haertel.cpp new file mode 100644 index 0000000000..9ae3020d9b --- /dev/null +++ b/libs/random/extra/test_haertel.cpp @@ -0,0 +1,62 @@ +/* haertel.hpp file + * + * Copyright Jens Maurer 2000, 2002 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_haertel.cpp 60755 2010-03-22 00:45:06Z steven_watanabe $ + * + * Revision history + */ + +#include <string> +#include <iostream> + +#include <boost/format.hpp> + +#include "haertel.hpp" + +#define BOOST_TEST_MAIN +#include <boost/test/included/unit_test.hpp> + +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(); + + typename Gen::result_type actual = gen(); + BOOST_CHECK_MESSAGE(value == actual, + boost::str(boost::format("%s: check value == gen() failed [%d != %d]") % + name % value % actual)); +} + +// 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); +} + +BOOST_AUTO_TEST_CASE(test_haertel) +{ + using namespace Haertel; + 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"); + // This currently fails. I don't want to touch it until + // I trace the source of this generator. --SJW + validate<MRG_Fib2>(1234567u, "MRG_Fib2"); +} diff --git a/libs/random/index.html b/libs/random/index.html new file mode 100644 index 0000000000..9c0a8475d6 --- /dev/null +++ b/libs/random/index.html @@ -0,0 +1,14 @@ +<html> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_random.html"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost_random.html">../../doc/html/boost_random.html</a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/nondet_random.html b/libs/random/nondet_random.html new file mode 100644 index 0000000000..d0ae9a8a14 --- /dev/null +++ b/libs/random/nondet_random.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost/random_device.html"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost/random_device.html"> + ../../doc/html/boost/random_device.html + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/performance/Jamfile.v2 b/libs/random/performance/Jamfile.v2 new file mode 100644 index 0000000000..431538589b --- /dev/null +++ b/libs/random/performance/Jamfile.v2 @@ -0,0 +1,18 @@ +mt19937ar-files = [ glob mt19937ar.c ] ; + +if $(mt19937ar-files) +{ + alias mt19937ar : $(mt19937ar-files) : : <define>HAVE_MT19937AR_C ; +} +else +{ + alias mt19937ar ; +} + +exe random_speed.exe : random_speed.cpp mt19937ar : release ; +exe generate_table.exe : generate_table.cpp /boost//regex : <link>static ; +exe nondet_random_speed.exe : nondet_random_speed.cpp /boost//random : release <link>static ; + +install random_speed : random_speed.exe : <install-type>EXE <location>. ; +install nondet_random_speed : nondet_random_speed.exe : <install-type>EXE <location>. ; +install generate_table : generate_table.exe : <install-type>EXE <location>. ; diff --git a/libs/random/performance/generate_table.cpp b/libs/random/performance/generate_table.cpp new file mode 100644 index 0000000000..c899d08f72 --- /dev/null +++ b/libs/random/performance/generate_table.cpp @@ -0,0 +1,133 @@ +// generate_table.cpp +// +// Copyright (c) 2009 +// Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <vector> +#include <utility> +#include <iostream> +#include <cstring> +#include <fstream> +#include <boost/regex.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/hashed_index.hpp> +#include <boost/multi_index/sequenced_index.hpp> + +boost::regex generator_regex("(?:fixed-range )?([^:]+): (\\d+(?:\\.\\d+)?) nsec/loop = \\d+(?:\\.\\d+)? CPU cycles"); +boost::regex distribution_regex("([^\\s]+)( virtual function)? ([^:]+): (\\d+(?:\\.\\d+)?) nsec/loop = \\d+(?:\\.\\d+)? CPU cycles"); + +std::string template_name(std::string arg) { + return boost::regex_replace(arg, boost::regex("[^\\w]"), "_"); +} + +struct compare_second { + template<class Pair> + bool operator()(const Pair& p1, const Pair& p2) const { + return (p1.second < p2.second); + } +}; + +typedef boost::multi_index_container< + std::string, + boost::mpl::vector< + boost::multi_index::sequenced<>, + boost::multi_index::hashed_unique<boost::multi_index::identity<std::string> > + > +> unique_list; + +int main(int argc, char** argv) { + + std::string suffix; + std::string id; + + if(argc >= 2 && std::strcmp(argv[1], "-linux") == 0) { + suffix = "linux"; + id = "Linux"; + } else { + suffix = "windows"; + id = "Windows"; + } + + std::vector<std::pair<std::string, double> > generator_info; + std::string line; + while(std::getline(std::cin, line)) { + boost::smatch match; + if(std::strncmp(line.c_str(), "counting ", 9) == 0) break; + if(boost::regex_match(line, match, generator_regex)) { + std::string generator(match[1]); + double time = boost::lexical_cast<double>(match[2]); + if(generator != "counting") { + generator_info.push_back(std::make_pair(generator, time)); + } + } else { + std::cerr << "oops: " << line << std::endl; + } + } + + double min = std::min_element(generator_info.begin(), generator_info.end(), compare_second())->second; + + std::ofstream generator_defs("performance_data.qbk"); + std::ofstream generator_performance(("generator_performance_" + suffix + ".qbk").c_str()); + generator_performance << "[table Basic Generators (" << id << ")\n"; + generator_performance << " [[generator] [M rn/sec] [time per random number \\[nsec\\]] " + "[relative speed compared to fastest \\[percent\\]]]\n"; + + typedef std::pair<std::string, double> pair_type; + BOOST_FOREACH(const pair_type& pair, generator_info) { + generator_defs << boost::format("[template %s_speed[] %d%%]\n") + % template_name(pair.first) % static_cast<int>(100*min/pair.second); + generator_performance << boost::format(" [[%s][%g][%g][%d%%]]\n") + % pair.first % (1000/pair.second) % pair.second % static_cast<int>(100*min/pair.second); + } + generator_performance << "]\n"; + + std::map<std::pair<std::string, std::string>, double> distribution_info; + unique_list generator_names; + unique_list distribution_names; + do { + boost::smatch match; + if(boost::regex_match(line, match, distribution_regex)) { + if(!match[2].matched && match[1] != "counting") { + std::string generator(match[1]); + std::string distribution(match[3]); + double time = boost::lexical_cast<double>(match[4]); + generator_names.push_back(generator); + distribution_names.push_back(distribution); + distribution_info.insert(std::make_pair(std::make_pair(distribution, generator), time)); + } + } else { + std::cerr << "oops: " << line << std::endl; + } + } while(std::getline(std::cin, line)); + + std::ofstream distribution_performance(("distribution_performance_" + suffix + ".qbk").c_str()); + + distribution_performance << "[table Distributions (" << id << ")\n"; + distribution_performance << " [[\\[M rn/sec\\]]"; + BOOST_FOREACH(const std::string& generator, generator_names) { + distribution_performance << boost::format("[%s]") % generator; + } + distribution_performance << "]\n"; + BOOST_FOREACH(const std::string& distribution, distribution_names) { + distribution_performance << boost::format(" [[%s]") % distribution; + BOOST_FOREACH(const std::string& generator, generator_names) { + std::map<std::pair<std::string, std::string>, double>::iterator pos = + distribution_info.find(std::make_pair(distribution, generator)); + if(pos != distribution_info.end()) { + distribution_performance << boost::format("[%g]") % (1000/pos->second); + } else { + distribution_performance << "[-]"; + } + } + distribution_performance << "]\n"; + } + distribution_performance << "]\n"; +} diff --git a/libs/random/performance/nondet_random_speed.cpp b/libs/random/performance/nondet_random_speed.cpp new file mode 100644 index 0000000000..56a1da8d5f --- /dev/null +++ b/libs/random/performance/nondet_random_speed.cpp @@ -0,0 +1,60 @@ +/* boost nondet_random_speed.cpp performance test + * + * Copyright Jens Maurer 2000 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: nondet_random_speed.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <iostream> +#include <string> +#include <boost/timer.hpp> +#include <boost/random/random_device.hpp> + +// set to your CPU frequency +static const double cpu_frequency = 1.87 * 1e9; + +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]); + + boost::random::random_device dev; + timing<unsigned int>(dev, iter, "random_device"); + + return 0; +} diff --git a/libs/random/performance/random_speed.cpp b/libs/random/performance/random_speed.cpp new file mode 100644 index 0000000000..d1aa32e6c0 --- /dev/null +++ b/libs/random/performance/random_speed.cpp @@ -0,0 +1,399 @@ +/* boost random_speed.cpp performance measurements + * + * Copyright Jens Maurer 2000 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: random_speed.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + */ + +#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 +//#define HAVE_DRAND48 + +// define if you have the original mt19937int.c (with commented out main()) +#undef HAVE_MT19937INT_C + +// define if you have the original mt19937ar.c (with commented out main()) +// #define HAVE_MT19937AR_C + +// set to your CPU frequency +static const double cpu_frequency = 1.87 * 1e9; + +/* + * 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, RNG rng) +{ + std::cout << (RNG::has_fixed_range ? "fixed-range " : ""); + // BCC has trouble with string autoconversion for explicit specializations + + // 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); +} + +#ifdef HAVE_DRAND48 +// requires non-standard C library support for srand48/lrand48 +struct lrand48_ { + static const bool has_fixed_range = false; + typedef long result_type; + lrand48_() { + using namespace std; + srand48(1); + } + result_type operator()() { + using namespace std; + return lrand48(); + } +}; +#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 + +#ifdef HAVE_MT19937AR_C +extern "C" { +void init_genrand(unsigned long s); +unsigned long genrand_int32(void); +} +struct mt19937_c { + static const bool has_fixed_range = false; + mt19937_c() { + init_genrand(5489); + } + typedef unsigned long result_type; + result_type operator()() { + return genrand_int32(); + } +}; +#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::random::uniform_int_distribution<>(-2, 4)), + iter, name + " uniform_int"); + + timing(make_gen(gen, boost::random::uniform_smallint<>(-2, 4)), + iter, name + " uniform_smallint"); + + timing(make_gen(gen, boost::random::bernoulli_distribution<>(0.5)), + iter, name + " bernoulli"); + + timing(make_gen(gen, boost::random::geometric_distribution<>(0.5)), + iter, name + " geometric"); + + timing(make_gen(gen, boost::random::binomial_distribution<int>(4, 0.8)), + iter, name + " binomial"); + + timing(make_gen(gen, boost::random::negative_binomial_distribution<int>(4, 0.8)), + iter, name + " negative_binomial"); + + timing(make_gen(gen, boost::random::poisson_distribution<>(1)), + iter, name + " poisson"); + + + timing(make_gen(gen, boost::random::uniform_real_distribution<>(-5.3, 4.8)), + iter, name + " uniform_real"); + + timing(make_gen(gen, boost::random::uniform_01<>()), + iter, name + " uniform_01"); + + timing(make_gen(gen, boost::random::triangle_distribution<>(1, 2, 7)), + iter, name + " triangle"); + + timing(make_gen(gen, boost::random::exponential_distribution<>(3)), + iter, name + " exponential"); + + timing(make_gen(gen, boost::random::normal_distribution<>()), + iter, name + " normal polar"); + + timing(make_gen(gen, boost::random::lognormal_distribution<>()), + iter, name + " lognormal"); + + timing(make_gen(gen, boost::random::chi_squared_distribution<>(4)), + iter, name + " chi squared"); + + timing(make_gen(gen, boost::random::cauchy_distribution<>()), + iter, name + " cauchy"); + + timing(make_gen(gen, boost::random::fisher_f_distribution<>(4, 5)), + iter, name + " fisher f"); + + timing(make_gen(gen, boost::random::student_t_distribution<>(7)), + iter, name + " student t"); + + timing(make_gen(gen, boost::random::gamma_distribution<>(2.8)), + iter, name + " gamma"); + + timing(make_gen(gen, boost::random::weibull_distribution<>(3)), + iter, name + " weibull"); + + timing(make_gen(gen, boost::random::extreme_value_distribution<>()), + iter, name + " extreme value"); + + timing_sphere(make_gen(gen, boost::random::uniform_on_sphere<>(3)), + iter/10, name + " uniform_on_sphere"); +} + +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", lrand48_()); // coded for lrand48() +#endif + + run(iter, "minstd_rand0", boost::minstd_rand0()); + run(iter, "minstd_rand", boost::minstd_rand()); + run(iter, "ecuyer combined", boost::ecuyer1988()); + run(iter, "kreutzer1986", boost::kreutzer1986()); + run(iter, "taus88", boost::taus88()); + run(iter, "knuth_b", boost::random::knuth_b()); + + run(iter, "hellekalek1995 (inversive)", boost::hellekalek1995()); + + run(iter, "mt11213b", boost::mt11213b()); + run(iter, "mt19937", boost::mt19937()); +#if !defined(BOOST_NO_INT64_T) + run(iter, "mt19937_64", boost::mt19937_64()); +#endif + + run(iter, "lagged_fibonacci607", boost::lagged_fibonacci607()); + run(iter, "lagged_fibonacci1279", boost::lagged_fibonacci1279()); + run(iter, "lagged_fibonacci2281", boost::lagged_fibonacci2281()); + run(iter, "lagged_fibonacci3217", boost::lagged_fibonacci3217()); + run(iter, "lagged_fibonacci4423", boost::lagged_fibonacci4423()); + run(iter, "lagged_fibonacci9689", boost::lagged_fibonacci9689()); + run(iter, "lagged_fibonacci19937", boost::lagged_fibonacci19937()); + run(iter, "lagged_fibonacci23209", boost::lagged_fibonacci23209()); + run(iter, "lagged_fibonacci44497", boost::lagged_fibonacci44497()); + + 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, "ranlux64_3", boost::ranlux3()); + run(iter, "ranlux64_4", boost::ranlux4()); + run(iter, "ranlux64_3_01", boost::ranlux3_01()); + run(iter, "ranlux64_4_01", boost::ranlux4_01()); + run(iter, "ranlux24", boost::ranlux3()); + run(iter, "ranlux48", boost::ranlux4()); + + run(iter, "counting", counting()); + +#ifdef HAVE_MT19937INT_C + // requires the original mt19937int.c + run<float>(iter, "mt19937 original"); // coded for sgenrand()/genrand() +#endif + +#ifdef HAVE_MT19937AR_C + run(iter, "mt19937ar.c", mt19937_c()); +#endif + + distrib(iter, "counting", counting()); + + distrib(iter, "minstd_rand", boost::minstd_rand()); + + distrib(iter, "kreutzer1986", boost::kreutzer1986()); + + distrib(iter, "mt19937", boost::mt19937()); + + distrib(iter, "lagged_fibonacci607", boost::lagged_fibonacci607()); +} diff --git a/libs/random/random-concepts.html b/libs/random/random-concepts.html new file mode 100644 index 0000000000..aea420b192 --- /dev/null +++ b/libs/random/random-concepts.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_random/reference.html#boost_random.reference.concepts"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost_random/reference.html#boost_random.reference.concepts"> + ../../doc/html/boost_random/reference.html#boost_random.reference.concepts + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/random-distributions.html b/libs/random/random-distributions.html new file mode 100644 index 0000000000..605bfa69d4 --- /dev/null +++ b/libs/random/random-distributions.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_random/reference.html#boost_random.reference.distributions"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost_random/reference.html#boost_random.reference.distributions"> + ../../doc/html/boost_random/reference.html#boost_random.reference.distributions + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/random-generators.html b/libs/random/random-generators.html new file mode 100644 index 0000000000..1872c4097f --- /dev/null +++ b/libs/random/random-generators.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_random/reference.html#boost_random.reference.generators"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost_random/reference.html#boost_random.reference.generators"> + ../../doc/html/boost_random/reference.html#boost_random.reference.generators + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/random-misc.html b/libs/random/random-misc.html new file mode 100644 index 0000000000..5b319904bf --- /dev/null +++ b/libs/random/random-misc.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost/random_number_generator.html"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost/random_number_generator.html"> + ../../doc/html/boost/random_number_generator.html + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/random-performance.html b/libs/random/random-performance.html new file mode 100644 index 0000000000..6cbef8dea0 --- /dev/null +++ b/libs/random/random-performance.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_random/performance.html"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost_random/performance.html"> + ../../doc/html/boost_random/performance.html + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/random-variate.html b/libs/random/random-variate.html new file mode 100644 index 0000000000..a5d931feed --- /dev/null +++ b/libs/random/random-variate.html @@ -0,0 +1,17 @@ +<html> + <!-- boostinspect:nounlinked boostinspect:nolink --> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost/variate_generator.html"> + </head> + <body> + Automatic redirection failed, please go to + <a href="../../doc/html/boost/variate_generator.html"> + ../../doc/html/boost/variate_generator.html + </a> + <p>Copyright (c) 2010 Steven Watanabe</p> + <p>Distributed under the Boost Software License, Version 1.0. (See accompanying file + <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>). + </p> + </body> +</html> diff --git a/libs/random/src/random_device.cpp b/libs/random/src/random_device.cpp new file mode 100644 index 0000000000..699a880fdd --- /dev/null +++ b/libs/random/src/random_device.cpp @@ -0,0 +1,217 @@ +/* boost random_device.cpp implementation + * + * Copyright Jens Maurer 2000 + * Copyright Steven Watanabe 2010-2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: random_device.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#define BOOST_RANDOM_SOURCE + +#include <boost/random/random_device.hpp> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/detail/workaround.hpp> +#include <string> + +#if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) +// A definition is required even for integral static constants +const bool boost::random::random_device::has_fixed_range; +#endif + + +#if defined(BOOST_WINDOWS) + +#include <windows.h> +#include <wincrypt.h> +#include <stdexcept> // std::invalid_argument + +#define BOOST_AUTO_LINK_NOMANGLE +#define BOOST_LIB_NAME "Advapi32" +#include <boost/config/auto_link.hpp> + +#ifdef __MINGW32__ + +extern "C" { + +// mingw's wincrypt.h appears to be missing some things +WINADVAPI +BOOL +WINAPI +CryptEnumProvidersA( + DWORD dwIndex, + DWORD *pdwReserved, + DWORD dwFlags, + DWORD *pdwProvType, + LPSTR szProvName, + DWORD *pcbProvName + ); + +} + +#endif + +namespace { + +const char * const default_token = MS_DEF_PROV_A; + +} + +class boost::random::random_device::impl +{ +public: + impl(const std::string & token) : provider(token) { + char buffer[80]; + DWORD type; + DWORD len; + + // Find the type of the provider + for(DWORD i = 0; ; ++i) { + len = sizeof(buffer); + if(!CryptEnumProvidersA(i, NULL, 0, &type, buffer, &len)) { + error("Could not find provider name"); + } + if(buffer == provider) { + break; + } + } + + if(!CryptAcquireContextA(&hProv, NULL, provider.c_str(), type, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + error("Could not acquire CSP context"); + } + } + + ~impl() { + if(!CryptReleaseContext(hProv, 0)) error("Could not release CSP context"); + } + + unsigned int next() { + unsigned int result; + + if(!CryptGenRandom(hProv, sizeof(result), + static_cast<BYTE*>(static_cast<void*>(&result)))) { + error("error while reading"); + } + + return result; + } + +private: + void error(const std::string & msg) { + char buf[80]; + DWORD num = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, + buf, + sizeof(buf), + NULL); + + throw std::invalid_argument("boost::random_device: " + msg + + " Cryptopraphic Service Provider " + provider + + ": " + std::string(&buf[0], &buf[0] + num)); + } + const std::string provider; + HCRYPTPROV hProv; +}; + +#else + +namespace { +// 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 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 Kuhl'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::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 // BOOST_WINDOWS + +BOOST_RANDOM_DECL boost::random::random_device::random_device() + : pimpl(new impl(default_token)) +{} + +BOOST_RANDOM_DECL boost::random::random_device::random_device(const std::string& token) + : pimpl(new impl(token)) +{} + +BOOST_RANDOM_DECL boost::random_device::~random_device() +{ + delete pimpl; +} + +BOOST_RANDOM_DECL double boost::random_device::entropy() const +{ + return 10; +} + +BOOST_RANDOM_DECL unsigned int boost::random_device::operator()() +{ + return pimpl->next(); +} diff --git a/libs/random/test/Jamfile.v2 b/libs/random/test/Jamfile.v2 new file mode 100644 index 0000000000..8cdae2bfa2 --- /dev/null +++ b/libs/random/test/Jamfile.v2 @@ -0,0 +1,126 @@ +# Copyright 2003 Jens Maurer +# Copyright 2009-2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. (See accompany- +# ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Boost Random Library test Jamfile + +# bring in rules for testing +import testing ; + +project /boost/random/test : requirements <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS ; + +run test_const_mod.cpp /boost//unit_test_framework ; +run test_generate_canonical.cpp /boost//unit_test_framework ; +run test_random_number_generator.cpp /boost//unit_test_framework ; +run ../example/random_demo.cpp ; +run test_random_device.cpp /boost//random : : : <link>static : test_random_device ; +run test_random_device.cpp /boost//random : : : <link>shared : test_random_device_dll ; + +run test_minstd_rand0.cpp /boost//unit_test_framework ; +run test_minstd_rand.cpp /boost//unit_test_framework ; +run test_rand48.cpp /boost//unit_test_framework ; +run test_mt11213b.cpp /boost//unit_test_framework ; +run test_mt19937.cpp /boost//unit_test_framework ; +run test_mt19937_64.cpp /boost//unit_test_framework ; +run test_ecuyer1988.cpp /boost//unit_test_framework ; +run test_hellekalek1995.cpp /boost//unit_test_framework ; +run test_linear_feedback_shift.cpp /boost//unit_test_framework ; +run test_taus88.cpp /boost//unit_test_framework ; +run test_kreutzer1986.cpp /boost//unit_test_framework ; +run test_ranlux3.cpp /boost//unit_test_framework ; +run test_ranlux4.cpp /boost//unit_test_framework ; +run test_ranlux3_01.cpp /boost//unit_test_framework ; +run test_ranlux4_01.cpp /boost//unit_test_framework ; +run test_ranlux64_4.cpp /boost//unit_test_framework ; +run test_ranlux64_3.cpp /boost//unit_test_framework ; +run test_ranlux64_3_01.cpp /boost//unit_test_framework ; +run test_ranlux64_4_01.cpp /boost//unit_test_framework ; +run test_ranlux24_base.cpp /boost//unit_test_framework ; +run test_ranlux24.cpp /boost//unit_test_framework ; +run test_ranlux48_base.cpp /boost//unit_test_framework ; +run test_ranlux48.cpp /boost//unit_test_framework ; +run test_knuth_b.cpp /boost//unit_test_framework ; +run test_independent_bits31.cpp /boost//unit_test_framework ; +run test_independent_bits32.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci607.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci1279.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci2281.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci3217.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci4423.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci9689.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci19937.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci23209.cpp /boost//unit_test_framework ; +run test_lagged_fibonacci44497.cpp /boost//unit_test_framework ; + +# Disable by default. These don't add much and the larger +# ones can overflow the stack. +explicit test_lagged_fibonacci1279 test_lagged_fibonacci2281 + test_lagged_fibonacci2281 test_lagged_fibonacci3217 + test_lagged_fibonacci4423 test_lagged_fibonacci9689 + test_lagged_fibonacci19937 test_lagged_fibonacci23209 + test_lagged_fibonacci44497 ; + +run test_seed_seq.cpp /boost//unit_test_framework ; + +run test_binomial.cpp ; +run test_binomial_distribution.cpp /boost//unit_test_framework ; +run test_poisson.cpp ; +run test_poisson_distribution.cpp /boost//unit_test_framework ; +run test_discrete.cpp ; +run test_discrete_distribution.cpp /boost//unit_test_framework ; +run test_gamma.cpp ; +run test_gamma_distribution.cpp /boost//unit_test_framework ; +run test_weibull.cpp ; +run test_weibull_distribution.cpp /boost//unit_test_framework ; +run test_extreme_value.cpp ; +run test_extreme_value_distribution.cpp /boost//unit_test_framework ; +run test_negative_binomial.cpp ; +run test_negative_binomial_distribution.cpp /boost//unit_test_framework ; +run test_chi_squared.cpp ; +run test_chi_squared_distribution.cpp /boost//unit_test_framework ; +run test_fisher_f.cpp ; +run test_fisher_f_distribution.cpp /boost//unit_test_framework ; +run test_student_t.cpp ; +run test_student_t_distribution.cpp /boost//unit_test_framework ; +run test_normal.cpp ; +run test_normal_distribution.cpp /boost//unit_test_framework ; +run test_piecewise_constant.cpp ; +run test_piecewise_constant_distribution.cpp /boost//unit_test_framework ; +run test_piecewise_linear.cpp ; +run test_piecewise_linear_distribution.cpp /boost//unit_test_framework ; +run test_exponential.cpp ; +run test_exponential_distribution.cpp /boost//unit_test_framework ; +run test_bernoulli.cpp ; +run test_bernoulli_distribution.cpp /boost//unit_test_framework ; +run test_cauchy.cpp ; +run test_cauchy_distribution.cpp /boost//unit_test_framework ; +run test_geometric.cpp ; +run test_geometric_distribution.cpp /boost//unit_test_framework ; +run test_lognormal.cpp ; +run test_lognormal_distribution.cpp /boost//unit_test_framework ; +run test_triangle.cpp ; +run test_triangle_distribution.cpp /boost//unit_test_framework ; +run test_uniform_int.cpp ; +run test_uniform_int_distribution.cpp /boost//unit_test_framework ; +run test_uniform_real.cpp ; +run test_uniform_real_distribution.cpp /boost//unit_test_framework ; +run test_uniform_on_sphere_distribution.cpp /boost//unit_test_framework ; +run test_uniform_smallint.cpp ; +run test_uniform_smallint_distribution.cpp /boost//unit_test_framework ; +run test_old_uniform_real.cpp ; +run test_old_uniform_real_distribution.cpp /boost//unit_test_framework ; +run test_old_uniform_int.cpp ; +run test_old_uniform_int_distribution.cpp /boost//unit_test_framework ; + +# run nondet_random_speed.cpp ; +# run random_device.cpp ; +# run random_speed.cpp ; +# run statistic_tests.cpp ; + +exe statistic_tests.exe : statistic_tests.cpp ; +explicit statistic_tests.exe ; + +install statistic_tests : statistic_tests.exe : <install-type>EXE <location>. ; +explicit statistic_tests ; diff --git a/libs/random/test/chi_squared_test.hpp b/libs/random/test/chi_squared_test.hpp new file mode 100644 index 0000000000..46355205c3 --- /dev/null +++ b/libs/random/test/chi_squared_test.hpp @@ -0,0 +1,92 @@ +/* chi_squared_test.hpp header file + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: chi_squared_test.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#ifndef BOOST_RANDOM_TEST_CHI_SQUARED_TEST_HPP_INCLUDED +#define BOOST_RANDOM_TEST_CHI_SQUARED_TEST_HPP_INCLUDED + +#include <vector> + +#include <boost/math/special_functions/pow.hpp> +#include <boost/math/distributions/chi_squared.hpp> + +// This only works for discrete distributions with fixed +// upper and lower bounds. + +template<class IntType> +struct chi_squared_collector { + + static const IntType cutoff = 5; + + chi_squared_collector() + : chi_squared(0), + variables(0), + prev_actual(0), + prev_expected(0), + current_actual(0), + current_expected(0) + {} + + void operator()(IntType actual, double expected) { + current_actual += actual; + current_expected += expected; + + if(current_expected >= cutoff) { + if(prev_expected != 0) { + update(prev_actual, prev_expected); + } + prev_actual = current_actual; + prev_expected = current_expected; + + current_actual = 0; + current_expected = 0; + } + } + + void update(IntType actual, double expected) { + chi_squared += boost::math::pow<2>(actual - expected) / expected; + ++variables; + } + + double cdf() { + if(prev_expected != 0) { + update(prev_actual + current_actual, prev_expected + current_expected); + prev_actual = 0; + prev_expected = 0; + current_actual = 0; + current_expected = 0; + } + if(variables <= 1) { + return 0; + } else { + return boost::math::cdf(boost::math::chi_squared(variables - 1), chi_squared); + } + } + + double chi_squared; + std::size_t variables; + + IntType prev_actual; + double prev_expected; + + IntType current_actual; + double current_expected; +}; + +template<class IntType> +double chi_squared_test(const std::vector<IntType>& results, const std::vector<double>& probabilities, IntType iterations) { + chi_squared_collector<IntType> calc; + for(std::size_t i = 0; i < results.size(); ++i) { + calc(results[i], iterations * probabilities[i]); + } + return calc.cdf(); +} + +#endif diff --git a/libs/random/test/concepts.hpp b/libs/random/test/concepts.hpp new file mode 100644 index 0000000000..b901f56ac9 --- /dev/null +++ b/libs/random/test/concepts.hpp @@ -0,0 +1,210 @@ +/* concepts.hpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: concepts.hpp 72951 2011-07-07 04:57:37Z steven_watanabe $ + * + */ + +#ifndef BOOST_RANDOM_TEST_CONCEPTS_HPP +#define BOOST_RANDOM_TEST_CONCEPTS_HPP + +#include <boost/config.hpp> + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +#include <boost/concept_check.hpp> + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include <boost/concept_archetype.hpp> +#include <boost/concept/requires.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_arithmetic.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/cstdint.hpp> +#include <boost/static_assert.hpp> +#include <istream> +#include <ostream> + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4510) +#pragma warning(disable:4610) +#endif + +namespace boost { +namespace random { +namespace test { + +template<class Base = null_archetype<> > +struct seed_seq_archetype : Base +{ + template<class Iter> + BOOST_CONCEPT_REQUIRES( + ((Mutable_RandomAccessIterator<Iter>)) + ((UnsignedInteger<typename Mutable_RandomAccessIterator<Iter>::value_type>)), + (void)) + generate(Iter, Iter) {} +}; + +template<class R = unsigned, class Base = null_archetype<> > +struct uniform_random_number_generator_archetype : Base +{ + typedef R result_type; + static R min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + static R max BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + R operator()() { return 0; } +}; + +template<class SSeq> +struct SeedSeq +{ +public: + BOOST_CONCEPT_USAGE(SeedSeq) + { + q.generate(rb, re); + } +private: + SSeq q; + mutable_random_access_iterator_archetype<boost::uint32_t> rb, re; +}; + +template<class T> +struct Streamable +{ +public: + BOOST_CONCEPT_USAGE(Streamable) + { + os << x; + is >> v; + wos << x; + wis >> v; + } +private: + const T x; + T v; + + std::istream is; + std::ostream os; + std::wistream wis; + std::wostream wos; +}; + +// Type deduction will fail unless the arguments have the same type. +template <typename T> +void same_type(T const&, T const&) {} + +template <class E> +struct RandomNumberEngine : + DefaultConstructible<E>, + CopyConstructible<E>, + Assignable<E>, + EqualityComparable<E>, + Streamable<E> +{ +public: + typedef typename E::result_type result_type; + + // relaxed from the standard + BOOST_MPL_ASSERT((boost::is_arithmetic<result_type>)); + + // backwards compatibility check + BOOST_STATIC_ASSERT(!E::has_fixed_range); + + // a generator can be used to seed another generator (extension) + BOOST_CONCEPT_ASSERT((SeedSeq<E>)); + + BOOST_CONCEPT_USAGE(RandomNumberEngine) + { + same_type(e(), result_type()); + same_type((E::min)(), result_type()); + same_type((E::max)(), result_type()); + + (void)E(); + (void)E(s); + (void)E(q); + + e.seed(); + e.seed(s); + e.seed(q); + + e.discard(z); + + // extension + (void)E(sb, se); + e.seed(sb, se); + } + +private: + E e; + E v; + const E x; + seed_seq_archetype<> q; + typename detail::seed_type<result_type>::type s; + unsigned long long z; + + input_iterator_archetype<boost::uint32_t> sb, se; +}; + +template<class D> +struct RandomNumberDistribution : + DefaultConstructible<D>, + CopyConstructible<D>, + Assignable<D>, + EqualityComparable<D>, + Streamable<D> +{ +public: + typedef typename D::result_type result_type; + typedef typename D::param_type param_type; + // backwards compatibility + typedef typename D::input_type input_type; + + typedef param_type P; + + BOOST_CONCEPT_ASSERT((DefaultConstructible<P>)); + BOOST_CONCEPT_ASSERT((CopyConstructible<P>)); + BOOST_CONCEPT_ASSERT((Assignable<P>)); + BOOST_CONCEPT_ASSERT((EqualityComparable<P>)); + BOOST_CONCEPT_ASSERT((Streamable<P>)); + + BOOST_MPL_ASSERT((boost::is_same<typename P::distribution_type, D>)); + + BOOST_CONCEPT_USAGE(RandomNumberDistribution) + { + (void)D(p); + d.reset(); + same_type(x.param(), p); + d.param(p); + same_type(d(g), result_type()); + same_type(d(g, p), result_type()); + same_type((x.min)(), result_type()); + same_type((x.max)(), result_type()); + } + +private: + D d; + const D x; + const P p; + uniform_random_number_generator_archetype<> g; +}; + +} +} +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/libs/random/test/histogram.cpp b/libs/random/test/histogram.cpp new file mode 100644 index 0000000000..11ad00c3f3 --- /dev/null +++ b/libs/random/test/histogram.cpp @@ -0,0 +1,165 @@ +/* boost histogram.cpp graphical verification of distribution functions + * + * Copyright Jens Maurer 2000 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: histogram.cpp 60755 2010-03-22 00:45:06Z steven_watanabe $ + * + * 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>(); +} + diff --git a/libs/random/test/integrate.hpp b/libs/random/test/integrate.hpp new file mode 100644 index 0000000000..2bef63ca54 --- /dev/null +++ b/libs/random/test/integrate.hpp @@ -0,0 +1,79 @@ +/* integrate.hpp header file + * + * Copyright Jens Maurer 2000 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: integrate.hpp 60755 2010-03-22 00:45:06Z steven_watanabe $ + * + * 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, class T> +inline T +invert_monotone_inc(UnaryFunction f, typename UnaryFunction::result_type y, + T lower = -1, + T 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 */ diff --git a/libs/random/test/statistic_tests.cpp b/libs/random/test/statistic_tests.cpp new file mode 100644 index 0000000000..ec85882ce4 --- /dev/null +++ b/libs/random/test/statistic_tests.cpp @@ -0,0 +1,503 @@ +/* statistic_tests.cpp file + * + * Copyright Jens Maurer 2000, 2002 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: statistic_tests.cpp 60755 2010-03-22 00:45:06Z steven_watanabe $ + * + * Revision history + */ + +#include <iostream> +#include <iomanip> +#include <string> +#include <functional> +#include <vector> +#include <set> +#include <algorithm> + +#include <boost/cstdint.hpp> +#include <boost/random.hpp> + +#include <boost/math/special_functions/gamma.hpp> + +#include <boost/math/distributions/uniform.hpp> +#include <boost/math/distributions/chi_squared.hpp> +#include <boost/math/distributions/normal.hpp> +#include <boost/math/distributions/triangular.hpp> +#include <boost/math/distributions/cauchy.hpp> +#include <boost/math/distributions/gamma.hpp> +#include <boost/math/distributions/exponential.hpp> +#include <boost/math/distributions/lognormal.hpp> + +#include "statistic_tests.hpp" +#include "integrate.hpp" + +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(boost::math::chi_squared(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); + variate_generator<RNG&, uniform_smallint<> > uint_linear(rng, uniform_smallint<>(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); + variate_generator<RNG&, uniform_smallint<> > uint_square(rng, uniform_smallint<>(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_distribution_test : test_base +{ +public: + ks_distribution_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) + { + boost::math::uniform ud(static_cast<double>((rng.min)()), static_cast<double>((rng.max)())); + run(rng, ud, n1, n2); + } + template<class RNG, class Dist> + void run(RNG & rng, const Dist& dist, int n1, int n2) + { + using namespace boost; + std::cout << "KS: " << std::flush; + kolmogorov_experiment ks(n1); + check_(run_experiment(test_distrib_chi_square, + ks_experiment_generator(ks, rng, dist), n2)); + check_(run_experiment(test_distrib_chi_square, + ks_experiment_generator(ks, rng, dist), 2*n2)); + std::cout << std::endl; + } +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(boost::math::chi_squared(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); + + check_(run_experiment(test_distrib_chi_square, + experiment_generator(r_up, rng, n1), n2)); + check_(run_experiment(test_distrib_chi_square, + experiment_generator(r_up, rng, 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, rng, n1), n2)); + check_(run_experiment(test_distrib_chi_square, + experiment_generator(r_down, rng, 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(boost::math::chi_squared(classes-1), high_classes) + { } + + template<class RNG> + void run(RNG & rng, int n1, int n2) + { + boost::math::uniform ud( + static_cast<double>((rng.min)()), + static_cast<double>((rng.max)()) + + (std::numeric_limits<typename RNG::result_type>::is_integer? 0.0 : 1.0)); + run(rng, ud, n1, n2); + } + + template<class RNG, class Dist> + void run(RNG & rng, const Dist& dist, int n1, int n2) + { + using namespace boost; + std::cout << "gaps: " << std::flush; + gap_experiment gap(classes, dist, 0.2, 0.8); + + check_(run_experiment(test_distrib_chi_square, + experiment_generator(gap, rng, n1), n2)); + check_(run_experiment(test_distrib_chi_square, + experiment_generator(gap, rng, 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(boost::math::chi_squared(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); + variate_generator<RNG&, uniform_smallint<> > usmall(rng, uniform_smallint<>(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(boost::math::chi_squared(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); + + variate_generator<RNG&, uniform_smallint<> > usmall(rng, uniform_smallint<>(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(boost::math::chi_squared(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, unsigned int high_classes) + : test_base(env), + test_distrib_chi_square(boost::math::chi_squared(4-1), high_classes) + { } + + template<class RNG> + void run(RNG & rng, int n1, int n2) + { + using namespace boost; + std::cout << "birthday spacing: " << std::flush; + boost::variate_generator<RNG&, boost::uniform_int<> > uni(rng, boost::uniform_int<>(0, (1<<25)-1)); + birthday_spacing_experiment bsp(4, 512, (1<<25)); + check_(run_experiment(test_distrib_chi_square, + experiment_generator(bsp, uni, n1), n2)); + check_(run_experiment(test_distrib_chi_square, + experiment_generator(bsp, uni, n1), 2*n2)); + std::cout << std::endl; + } +private: + distribution_experiment test_distrib_chi_square; +}; + +#ifdef BOOST_MSVC +#pragma warning(disable:4355) +#endif + +class test_environment +{ +public: + static const int classes = 20; + explicit test_environment(double confid) + : confidence(confid), + confidence_chi_square_quantil(quantile(boost::math::chi_squared(classes-1), confidence)), + test_distrib_chi_square6(boost::math::chi_squared(7-1), classes), + ksdist_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, classes) + { + std::cout << "Confidence level: " << confid + << "; 1-alpha = " << (1-confid) + << "; chi_square(" << (classes-1) + << ", " << confidence_chi_square_quantil + << ") = " + << cdf(boost::math::chi_squared(classes-1), 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 : + cdf(boost::math::chi_squared(classes-1), 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); + + ksdist_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); + bday_test.run(rng, 1000, 150); + + std::cout << std::endl; + } + + template<class RNG, class Dist, class ExpectedDist> + void run_test(const std::string & name, const Dist & dist, const ExpectedDist & expected_dist) + { + using namespace boost; + + std::cout << "Running tests on " << name << std::endl; + + RNG rng; + variate_generator<RNG&, Dist> vgen(rng, dist); + + ksdist_test.run(vgen, expected_dist, 5000, 250); + rns_test.run(vgen, 100000, 250); + gp_test.run(vgen, expected_dist, 10000, 250); + perm_test.run(vgen, 1200, 250); + + std::cout << std::endl; + } + +private: + double confidence; + double confidence_chi_square_quantil; + distribution_experiment test_distrib_chi_square6; + ks_distribution_test ksdist_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); +} + +class program_args +{ +public: + program_args(int argc, char** argv) + { + if(argc > 0) { + names.insert(argv + 1, argv + argc); + } + } + bool check_(const std::string & test_name) const + { + return(names.empty() || names.find(test_name) != names.end()); + } +private: + std::set<std::string> names; +}; + +int main(int argc, char* argv[]) +{ + program_args args(argc, argv); + test_environment env(0.99); + +#define TEST(name) \ + if(args.check_(#name)) \ + env.run_test<boost::name>(#name) + + TEST(minstd_rand0); + TEST(minstd_rand); + TEST(rand48); + TEST(ecuyer1988); + TEST(kreutzer1986); + TEST(taus88); + TEST(hellekalek1995); + TEST(mt11213b); + TEST(mt19937); + TEST(lagged_fibonacci607); + TEST(lagged_fibonacci1279); + TEST(lagged_fibonacci2281); + TEST(lagged_fibonacci3217); + TEST(lagged_fibonacci4423); + TEST(lagged_fibonacci9689); + TEST(lagged_fibonacci19937); + TEST(lagged_fibonacci23209); + TEST(lagged_fibonacci44497); + TEST(ranlux3); + TEST(ranlux4); + +#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) + TEST(ranlux64_3); + TEST(ranlux64_4); +#endif + + TEST(ranlux3_01); + TEST(ranlux4_01); + TEST(ranlux64_3_01); + TEST(ranlux64_4_01); + + if(args.check_("normal")) + env.run_test<boost::mt19937>("normal", boost::normal_distribution<>(), boost::math::normal()); + if(args.check_("triangle")) + env.run_test<boost::mt19937>("triangle", boost::triangle_distribution<>(0, 1, 3), boost::math::triangular(0, 1, 3)); + if(args.check_("cauchy")) + env.run_test<boost::mt19937>("cauchy", boost::cauchy_distribution<>(), boost::math::cauchy()); + if(args.check_("gamma")) + env.run_test<boost::mt19937>("gamma", boost::gamma_distribution<>(1), boost::math::gamma_distribution<>(1)); + if(args.check_("exponential")) + env.run_test<boost::mt19937>("exponential", boost::exponential_distribution<>(), boost::math::exponential()); + if(args.check_("lognormal")) + env.run_test<boost::mt19937>("lognormal", boost::lognormal_distribution<>(1, 1), + boost::math::lognormal(std::log(1.0/std::sqrt(2.0)), std::sqrt(std::log(2.0)))); +} diff --git a/libs/random/test/statistic_tests.hpp b/libs/random/test/statistic_tests.hpp new file mode 100644 index 0000000000..3198f76a33 --- /dev/null +++ b/libs/random/test/statistic_tests.hpp @@ -0,0 +1,709 @@ +/* statistic_tests.hpp header file + * + * Copyright Jens Maurer 2000 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: statistic_tests.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#ifndef STATISTIC_TESTS_HPP +#define STATISTIC_TESTS_HPP + +#include <stdexcept> +#include <iterator> +#include <vector> +#include <boost/limits.hpp> +#include <algorithm> +#include <cmath> + +#include <boost/config.hpp> +#include <boost/bind.hpp> +#include <boost/random/uniform_01.hpp> +#include <boost/random/variate_generator.hpp> + +#include "integrate.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 Distribution> + distribution_experiment(Distribution dist , unsigned int classes) + : equidistribution_experiment(classes), limit(classes) + { + for(unsigned int i = 0; i < classes-1; ++i) + limit[i] = quantile(dist, (i+1)*0.05); + 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; +}; + +template<bool up, bool is_float> +struct runs_direction_helper +{ + template<class T> + static T init(T) + { + return (std::numeric_limits<T>::max)(); + } +}; + +template<> +struct runs_direction_helper<true, true> +{ + template<class T> + static T init(T) + { + return -(std::numeric_limits<T>::max)(); + } +}; + +template<> +struct runs_direction_helper<true, false> +{ + template<class T> + static T init(T) + { + return (std::numeric_limits<T>::min)(); + } +}; + +// 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 NumberGenerator, class Counter> + void run(NumberGenerator & f, Counter & count, int n) const + { + typedef typename NumberGenerator::result_type result_type; + result_type init = + runs_direction_helper< + up, + !std::numeric_limits<result_type>::is_integer + >::init(result_type()); + 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: + template<class Dist> + gap_experiment(unsigned int classes, const Dist & dist, double alpha, double beta) + : experiment_base(classes), alpha(alpha), beta(beta), low(quantile(dist, alpha)), high(quantile(dist, beta)) {} + + template<class NumberGenerator, class Counter> + void run(NumberGenerator & f, Counter & count, int n) const + { + typedef typename NumberGenerator::result_type result_type; + unsigned int length = 0; + for(int i = 0; i < n; ) { + result_type value = f(); + 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; + double low, high; +}; + +// 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(static_cast<double>(d), static_cast<double>(d+classes()-2)) * + stirling2<double>(d+classes()-2, d); + else + return fac<double>(d)/ + std::pow(static_cast<double>(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) { + for(int j = 0; j < t; ++j) { + v[j] = 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 cdf(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; +}; + +inline double cdf(const kolmogorov_smirnov_probability& dist, double val) +{ + return dist.cdf(val); +} + +inline double quantile(const kolmogorov_smirnov_probability& dist, double val) +{ + return invert_monotone_inc(boost::bind(&cdf, dist, _1), val, 0.0, 1000.0); +} + +/* + * 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 = static_cast<double>(gen()); + double y = cdf(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 cdf(ksp, x); + } +private: + int n; + kolmogorov_smirnov_probability ksp; +}; + +struct power_distribution +{ + power_distribution(double t) : t(t) {} + double t; +}; + +double cdf(const power_distribution& dist, double val) +{ + return std::pow(val, dist.t); +} + +// 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 + { + generator gen(f, t); + return ke.run(gen, power_distribution(t)); + } + +private: + struct generator { + generator(base_type & f, int t) : f(f, boost::uniform_01<>()), t(t) { } + double operator()() + { + double mx = f(); + for(int i = 1; i < t; ++i) + mx = (std::max)(mx, f()); + return mx; + } + private: + boost::variate_generator<base_type&, boost::uniform_01<> > 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)); +} + +// chi_square test +template<class Experiment, class Generator> +double run_experiment(const Experiment & experiment, const 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()() const { 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()() const { 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 */ + diff --git a/libs/random/test/test_bernoulli.cpp b/libs/random/test/test_bernoulli.cpp new file mode 100644 index 0000000000..c72a9c4bca --- /dev/null +++ b/libs/random/test/test_bernoulli.cpp @@ -0,0 +1,108 @@ +/* test_bernoulli.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_bernoulli.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/bernoulli_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/uniform_01.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/math/distributions/binomial.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <vector> +#include <iostream> +#include <numeric> + +#include "chi_squared_test.hpp" + +bool do_test(double p, long long max) { + std::cout << "running bernoulli(" << p << ")" << " " << max << " times: " << std::flush; + + boost::math::binomial expected(static_cast<double>(max), p); + + boost::random::bernoulli_distribution<> dist(p); + boost::mt19937 gen; + long long count = 0; + for(long long i = 0; i < max; ++i) { + if(dist(gen)) ++count; + } + + double prob = cdf(expected, count); + + bool result = prob < 0.99 && prob > 0.01; + const char* err = result? "" : "*"; + std::cout << std::setprecision(17) << prob << err << std::endl; + + std::cout << std::setprecision(6); + + return result; +} + +bool do_tests(int repeat, long long trials) { + boost::mt19937 gen; + boost::uniform_01<> rdist; + int errors = 0; + for(int i = 0; i < repeat; ++i) { + if(!do_test(rdist(gen), trials)) { + ++errors; + } + } + if(errors != 0) { + std::cout << "*** " << errors << " errors detected ***" << std::endl; + } + return errors == 0; +} + +int usage() { + std::cerr << "Usage: test_bernoulli_distribution -r <repeat> -t <trials>" << std::endl; + return 2; +} + +template<class T> +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast<T>(argv[0]); + return true; + } else { + return false; + } +} + +int main(int argc, char** argv) { + int repeat = 10; + long long trials = 1000000ll; + + if(argc > 0) { + --argc; + ++argv; + } + while(argc > 0) { + if(argv[0][0] != '-') return usage(); + else if(!handle_option(argc, argv, 'r', repeat) + && !handle_option(argc, argv, 't', trials)) { + return usage(); + } + --argc; + ++argv; + } + + try { + if(do_tests(repeat, trials)) { + return 0; + } else { + return EXIT_FAILURE; + } + } catch(...) { + std::cerr << boost::current_exception_diagnostic_information() << std::endl; + return EXIT_FAILURE; + } +} diff --git a/libs/random/test/test_bernoulli_distribution.cpp b/libs/random/test/test_bernoulli_distribution.cpp new file mode 100644 index 0000000000..945e3f191b --- /dev/null +++ b/libs/random/test/test_bernoulli_distribution.cpp @@ -0,0 +1,32 @@ +/* test_bernoulli_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_bernoulli_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/bernoulli_distribution.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::bernoulli_distribution<> +#define BOOST_RANDOM_ARG1 p +#define BOOST_RANDOM_ARG1_DEFAULT 0.5 +#define BOOST_RANDOM_ARG1_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN false +#define BOOST_RANDOM_DIST0_MAX true +#define BOOST_RANDOM_DIST1_MIN false +#define BOOST_RANDOM_DIST1_MAX true + +#define BOOST_RANDOM_TEST1_PARAMS (0.0) +#define BOOST_RANDOM_TEST1_MIN false +#define BOOST_RANDOM_TEST1_MAX false + +#define BOOST_RANDOM_TEST2_PARAMS (1.0) +#define BOOST_RANDOM_TEST2_MIN true +#define BOOST_RANDOM_TEST2_MAX true + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_binomial.cpp b/libs/random/test/test_binomial.cpp new file mode 100644 index 0000000000..44553afb7f --- /dev/null +++ b/libs/random/test/test_binomial.cpp @@ -0,0 +1,30 @@ +/* test_binomial.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_binomial.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/binomial_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/uniform_01.hpp> +#include <boost/math/distributions/binomial.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::binomial_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME binomial +#define BOOST_MATH_DISTRIBUTION boost::math::binomial +#define BOOST_RANDOM_ARG1_TYPE int +#define BOOST_RANDOM_ARG1_NAME n +#define BOOST_RANDOM_ARG1_DEFAULT 100000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_int<>(0, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME p +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_01<>() +#define BOOST_RANDOM_DISTRIBUTION_MAX n + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_binomial_distribution.cpp b/libs/random/test/test_binomial_distribution.cpp new file mode 100644 index 0000000000..18fe0c6dae --- /dev/null +++ b/libs/random/test/test_binomial_distribution.cpp @@ -0,0 +1,37 @@ +/* test_binomial_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_binomial_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/binomial_distribution.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::binomial_distribution<> +#define BOOST_RANDOM_ARG1 t +#define BOOST_RANDOM_ARG2 p +#define BOOST_RANDOM_ARG1_DEFAULT 1 +#define BOOST_RANDOM_ARG2_DEFAULT 0.5 +#define BOOST_RANDOM_ARG1_VALUE 10 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX 1 +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX 10 +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX 10 + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0 +#define BOOST_RANDOM_TEST1_MAX 1 + +#define BOOST_RANDOM_TEST2_PARAMS (10, 0.25) +#define BOOST_RANDOM_TEST2_MIN 0 +#define BOOST_RANDOM_TEST2_MAX 10 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_cauchy.cpp b/libs/random/test/test_cauchy.cpp new file mode 100644 index 0000000000..0320a997b6 --- /dev/null +++ b/libs/random/test/test_cauchy.cpp @@ -0,0 +1,28 @@ +/* test_cauchy.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_cauchy.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/cauchy_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/cauchy.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::cauchy_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME cauchy +#define BOOST_MATH_DISTRIBUTION boost::math::cauchy +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME median +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(-n, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME sigma +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_cauchy_distribution.cpp b/libs/random/test/test_cauchy_distribution.cpp new file mode 100644 index 0000000000..4856b08865 --- /dev/null +++ b/libs/random/test/test_cauchy_distribution.cpp @@ -0,0 +1,35 @@ +/* test_cauchy_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_cauchy_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/cauchy_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::cauchy_distribution<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 0.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS (-100000.0, 0.000001) +#define BOOST_RANDOM_TEST2_PARAMS (100000.0, 0.000001) +#define BOOST_RANDOM_TEST1_MAX 0.0 +#define BOOST_RANDOM_TEST2_MIN 0.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_chi_squared.cpp b/libs/random/test/test_chi_squared.cpp new file mode 100644 index 0000000000..67839c348c --- /dev/null +++ b/libs/random/test/test_chi_squared.cpp @@ -0,0 +1,24 @@ +/* test_chi_squared.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_chi_squared.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/chi_squared_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/chi_squared.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::chi_squared_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME chi_squared +#define BOOST_MATH_DISTRIBUTION boost::math::chi_squared +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME n +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_chi_squared_distribution.cpp b/libs/random/test/test_chi_squared_distribution.cpp new file mode 100644 index 0000000000..5b6ff15cc0 --- /dev/null +++ b/libs/random/test/test_chi_squared_distribution.cpp @@ -0,0 +1,34 @@ +/* test_chi_squared_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_chi_squared_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/chi_squared_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::chi_squared_distribution<> +#define BOOST_RANDOM_ARG1 n +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0.0 +#define BOOST_RANDOM_TEST1_MAX 100.0 + +#define BOOST_RANDOM_TEST2_PARAMS (10000.0) +#define BOOST_RANDOM_TEST2_MIN 100.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_const_mod.cpp b/libs/random/test/test_const_mod.cpp new file mode 100644 index 0000000000..b3b43575fa --- /dev/null +++ b/libs/random/test/test_const_mod.cpp @@ -0,0 +1,183 @@ +/* test_const_mod.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_const_mod.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/detail/const_mod.hpp> + +#include <boost/cstdint.hpp> +#include <boost/mpl/vector.hpp> + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +typedef boost::mpl::vector< + boost::int8_t, + boost::uint8_t +> int8_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult8, IntType, int8_types) { + for(int i = 0; i < 127; ++i) { + for(int j = 0; j < 127; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 127>::mult(IntType(i), IntType(j))), i * j % 127); + } + } + int modulus = (std::numeric_limits<IntType>::max)() + 1; + for(int i = 0; i < modulus; ++i) { + for(int j = 0; j < modulus; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 0>::mult(IntType(i), IntType(j))), i * j % modulus); + } + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_add8, IntType, int8_types) { + for(int i = 0; i < 127; ++i) { + for(int j = 0; j < 127; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 127>::add(IntType(i), IntType(j))), (i + j) % 127); + } + } + { + const int modulus = boost::integer_traits<IntType>::const_max; + for(int i = 0; i < modulus; ++i) { + for(int j = 0; j < modulus; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, modulus>::add(IntType(i), IntType(j))), (i + j) % modulus); + } + } + } + { + int modulus = (std::numeric_limits<IntType>::max)() + 1; + for(int i = 0; i < modulus; ++i) { + for(int j = 0; j < modulus; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 0>::add(IntType(i), IntType(j))), (i + j) % modulus); + } + } + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult_add8, IntType, int8_types) { + for(int i = 0; i < 127; i += 5) { + for(int j = 0; j < 127; j += 3) { + for(int k = 0; k < 127; k += 3) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 127>::mult_add(IntType(i), IntType(j), IntType(k))), (i * j + k) % 127); + } + } + } + { + int modulus = (std::numeric_limits<IntType>::max)() + 1; + for(int i = 0; i < modulus; i += 5) { + for(int j = 0; j < modulus; j += 3) { + for(int k = 0; k < modulus; k += 3) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 0>::mult_add(IntType(i), IntType(j), IntType(k))), (i * j + k) % modulus); + } + } + } + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_invert8, IntType, int8_types) { + for(int i = 1; i < 127; ++i) { + IntType inverse = boost::random::const_mod<IntType, 127>::invert(IntType(i)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 127>::mult(IntType(i), inverse)), 1); + } + int modulus = (std::numeric_limits<IntType>::max)() + 1; + for(int i = 1; i < modulus; i += 2) { + IntType inverse = boost::random::const_mod<IntType, 0>::invert(IntType(i)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 0>::mult(IntType(i), inverse)), 1); + } +} + +typedef boost::mpl::vector< + boost::int32_t, + boost::uint32_t +> int32_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(0, 2147483562)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(2147483562, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(2147483562, 2147483562)), IntType(1)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(1234567890, 1234657890)), IntType(813106682)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_add32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::add(0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::add(0, 2147483562)), IntType(2147483562)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::add(2147483562, 0)), IntType(2147483562)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::add(2147483562, 2147483562)), IntType(2147483561)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::add(1234567890, 1234657890)), IntType(321742217)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult_add32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult_add(0, 0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult_add(0, 2147483562, 827364)), IntType(827364)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult_add(2147483562, 0, 827364)), IntType(827364)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult_add(2147483562, 2147483562, 2147483562)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult_add(1234567890, 1234657890, 1726384759)), IntType(392007878)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_invert32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::invert(0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult_add(0, 0, 0)), IntType(0)); + IntType inverse; + inverse = boost::random::const_mod<IntType, 2147483563>::invert(2147483562); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(2147483562, inverse)), IntType(1)); + inverse = boost::random::const_mod<IntType, 2147483563>::invert(1234567890); + BOOST_CHECK_EQUAL((boost::random::const_mod<IntType, 2147483563>::mult(1234567890, inverse)), IntType(1)); +} + +#if !defined(BOOST_NO_INT64_T) + +typedef boost::mpl::vector< + boost::int64_t, + boost::uint64_t +> int64_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult64, IntType, int64_types) { + typedef boost::random::const_mod<IntType, INT64_C(2147483563652738498)> const_mod_type; + BOOST_CHECK_EQUAL((const_mod_type::mult(0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((const_mod_type::mult(0, 2147483562)), IntType(0)); + BOOST_CHECK_EQUAL((const_mod_type::mult(2147483562, 0)), IntType(0)); + BOOST_CHECK_EQUAL((const_mod_type::mult(2147483562, 2147483562)), IntType(INT64_C(316718521754730848))); + BOOST_CHECK_EQUAL((const_mod_type::mult(1234567890, 1234657890)), IntType(INT64_C(1524268986129152100))); + BOOST_CHECK_EQUAL((const_mod_type::mult(INT64_C(1234567890726352938), INT64_C(1234657890736453927))), IntType(INT64_C(88656187017794672))); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_add64, IntType, int64_types) { + typedef boost::random::const_mod<IntType, INT64_C(2147483563652738498)> const_mod_type; + BOOST_CHECK_EQUAL((const_mod_type::add(0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((const_mod_type::add(0, 2147483562)), IntType(2147483562)); + BOOST_CHECK_EQUAL((const_mod_type::add(2147483562, 0)), IntType(2147483562)); + BOOST_CHECK_EQUAL((const_mod_type::add(2147483562, 2147483562)), IntType(4294967124U)); + BOOST_CHECK_EQUAL((const_mod_type::add(1234567890, 1234657890)), IntType(2469225780U)); + BOOST_CHECK_EQUAL((const_mod_type::add(INT64_C(1234567890726352938), INT64_C(1234657890736453927))), IntType(INT64_C(321742217810068367))); + BOOST_CHECK_EQUAL((const_mod_type::add(INT64_C(2147483563652738490), 8)), IntType(0)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult_add64, IntType, int64_types) { + typedef boost::random::const_mod<IntType, INT64_C(2147483563652738498)> const_mod_type; + BOOST_CHECK_EQUAL((const_mod_type::mult_add(0, 0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((const_mod_type::mult_add(0, 2147483562, 827364)), IntType(827364)); + BOOST_CHECK_EQUAL((const_mod_type::mult_add(2147483562, 0, 827364)), IntType(827364)); + BOOST_CHECK_EQUAL((const_mod_type::mult_add(2147483562, 2147483562, 2147483562)), IntType(INT64_C(316718523902214410))); + BOOST_CHECK_EQUAL((const_mod_type::mult_add(1234567890, 1234657890, 1726384759)), IntType(INT64_C(1524268987855536859))); + BOOST_CHECK_EQUAL((const_mod_type::mult_add(INT64_C(1234567890726352938), INT64_C(1234657890736453927), INT64_C(1726384759726488649))), IntType(INT64_C(1815040946744283321))); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_invert64, IntType, int64_types) { + typedef boost::random::const_mod<IntType, INT64_C(2147483563652738498)> const_mod_type; + BOOST_CHECK_EQUAL((const_mod_type::invert(0)), IntType(0)); + BOOST_CHECK_EQUAL((const_mod_type::mult_add(0, 0, 0)), IntType(0)); + IntType inverse; + inverse = const_mod_type::invert(INT64_C(7362947769)); + BOOST_CHECK_EQUAL((const_mod_type::mult(INT64_C(7362947769), inverse)), IntType(1)); + inverse = const_mod_type::invert(INT64_C(1263142436887493875)); + BOOST_CHECK_EQUAL((const_mod_type::mult(INT64_C(1263142436887493875), inverse)), IntType(1)); +} + +#endif diff --git a/libs/random/test/test_discrete.cpp b/libs/random/test/test_discrete.cpp new file mode 100644 index 0000000000..f4f5395f33 --- /dev/null +++ b/libs/random/test/test_discrete.cpp @@ -0,0 +1,123 @@ +/* test_poisson.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_discrete.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/discrete_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <vector> +#include <iostream> +#include <numeric> + +#include "chi_squared_test.hpp" + +bool do_test(int n, long long max) { + std::cout << "running discrete(p0, p1, ..., p" << n-1 << ")" << " " << max << " times: " << std::flush; + + std::vector<double> expected; + { + boost::mt19937 egen; + for(int i = 0; i < n; ++i) { + expected.push_back(egen()); + } + double sum = std::accumulate(expected.begin(), expected.end(), 0.0); + for(std::vector<double>::iterator iter = expected.begin(), end = expected.end(); iter != end; ++iter) { + *iter /= sum; + } + } + + boost::random::discrete_distribution<> dist(expected); + boost::mt19937 gen; + std::vector<long long> results(expected.size()); + for(long long i = 0; i < max; ++i) { + ++results[dist(gen)]; + } + + long long sum = std::accumulate(results.begin(), results.end(), 0ll); + if(sum != max) { + std::cout << "*** Failed: incorrect total: " << sum << " ***" << std::endl; + return false; + } + double chsqr = chi_squared_test(results, expected, max); + + bool result = chsqr < 0.99; + const char* err = result? "" : "*"; + std::cout << std::setprecision(17) << chsqr << err << std::endl; + + std::cout << std::setprecision(6); + + return result; +} + +bool do_tests(int repeat, int max_n, long long trials) { + boost::mt19937 gen; + boost::uniform_int<> idist(1, max_n); + int errors = 0; + for(int i = 0; i < repeat; ++i) { + if(!do_test(idist(gen), trials)) { + ++errors; + } + } + if(errors != 0) { + std::cout << "*** " << errors << " errors detected ***" << std::endl; + } + return errors == 0; +} + +int usage() { + std::cerr << "Usage: test_discrete -r <repeat> -n <max n> -t <trials>" << std::endl; + return 2; +} + +template<class T> +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast<T>(argv[0]); + return true; + } else { + return false; + } +} + +int main(int argc, char** argv) { + int repeat = 10; + int max_n = 100000; + long long trials = 1000000ll; + + if(argc > 0) { + --argc; + ++argv; + } + while(argc > 0) { + if(argv[0][0] != '-') return usage(); + else if(!handle_option(argc, argv, 'r', repeat) + && !handle_option(argc, argv, 'n', max_n) + && !handle_option(argc, argv, 't', trials)) { + return usage(); + } + --argc; + ++argv; + } + + try { + if(do_tests(repeat, max_n, trials)) { + return 0; + } else { + return EXIT_FAILURE; + } + } catch(...) { + std::cerr << boost::current_exception_diagnostic_information() << std::endl; + return EXIT_FAILURE; + } +} diff --git a/libs/random/test/test_discrete_distribution.cpp b/libs/random/test/test_discrete_distribution.cpp new file mode 100644 index 0000000000..f505057ccc --- /dev/null +++ b/libs/random/test/test_discrete_distribution.cpp @@ -0,0 +1,168 @@ +/* test_discrete_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_discrete_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/discrete_distribution.hpp> +#include <boost/random/linear_congruential.hpp> +#include <boost/assign/list_of.hpp> +#include <sstream> +#include <vector> +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +using boost::random::test::RandomNumberDistribution; +using boost::random::discrete_distribution; +BOOST_CONCEPT_ASSERT((RandomNumberDistribution< discrete_distribution<> >)); + +struct gen { + double operator()(double arg) { + if(arg < 100) return 100; + else if(arg < 103) return 1; + else if(arg < 107) return 2; + else if(arg < 111) return 1; + else if(arg < 114) return 4; + else return 100; + } +}; + +#define CHECK_PROBABILITIES(actual, expected) \ + do { \ + std::vector<double> _actual = (actual); \ + std::vector<double> _expected = (expected); \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + _actual.begin(), _actual.end(), \ + _expected.begin(), _expected.end()); \ + } while(false) + +using boost::assign::list_of; + +BOOST_AUTO_TEST_CASE(test_constructors) { + boost::random::discrete_distribution<> dist; + CHECK_PROBABILITIES(dist.probabilities(), list_of(1.0)); + +#ifndef BOOST_NO_INITIALIZER_LISTS + boost::random::discrete_distribution<> dist_il = { 1, 2, 1, 4 }; + CHECK_PROBABILITIES(dist_il.probabilities(), list_of(.125)(.25)(.125)(.5)); +#endif + std::vector<double> probs = boost::assign::list_of(1.0)(2.0)(1.0)(4.0); + + boost::random::discrete_distribution<> dist_r(probs); + CHECK_PROBABILITIES(dist_r.probabilities(), list_of(.125)(.25)(.125)(.5)); + + boost::random::discrete_distribution<> dist_it(probs.begin(), probs.end()); + CHECK_PROBABILITIES(dist_it.probabilities(), list_of(.125)(.25)(.125)(.5)); + + boost::random::discrete_distribution<> dist_fun(4, 99, 115, gen()); + CHECK_PROBABILITIES(dist_fun.probabilities(), list_of(.125)(.25)(.125)(.5)); + + boost::random::discrete_distribution<> copy(dist); + BOOST_CHECK_EQUAL(dist, copy); + boost::random::discrete_distribution<> copy_r(dist_r); + BOOST_CHECK_EQUAL(dist_r, copy_r); + + boost::random::discrete_distribution<> notpow2(3, 99, 111, gen()); + BOOST_REQUIRE_EQUAL(notpow2.probabilities().size(), 3u); + BOOST_CHECK_CLOSE_FRACTION(notpow2.probabilities()[0], 0.25, 0.00000000001); + BOOST_CHECK_CLOSE_FRACTION(notpow2.probabilities()[1], 0.50, 0.00000000001); + BOOST_CHECK_CLOSE_FRACTION(notpow2.probabilities()[2], 0.25, 0.00000000001); + boost::random::discrete_distribution<> copy_notpow2(notpow2); + BOOST_CHECK_EQUAL(notpow2, copy_notpow2); +} + +BOOST_AUTO_TEST_CASE(test_param) { + std::vector<double> probs = boost::assign::list_of(1.0)(2.0)(1.0)(4.0); + boost::random::discrete_distribution<> dist(probs); + boost::random::discrete_distribution<>::param_type param = dist.param(); + CHECK_PROBABILITIES(param.probabilities(), list_of(.125)(.25)(.125)(.5)); + boost::random::discrete_distribution<> copy1(param); + BOOST_CHECK_EQUAL(dist, copy1); + boost::random::discrete_distribution<> copy2; + copy2.param(param); + BOOST_CHECK_EQUAL(dist, copy2); + + boost::random::discrete_distribution<>::param_type param_copy = param; + BOOST_CHECK_EQUAL(param, param_copy); + BOOST_CHECK(param == param_copy); + BOOST_CHECK(!(param != param_copy)); + boost::random::discrete_distribution<>::param_type param_default; + CHECK_PROBABILITIES(param_default.probabilities(), list_of(1.0)); + BOOST_CHECK(param != param_default); + BOOST_CHECK(!(param == param_default)); + +#ifndef BOOST_NO_INITIALIZER_LISTS + boost::random::discrete_distribution<>::param_type + parm_il = { 1, 2, 1, 4 }; + CHECK_PROBABILITIES(parm_il.probabilities(), list_of(.125)(.25)(.125)(.5)); +#endif + + boost::random::discrete_distribution<>::param_type parm_r(probs); + CHECK_PROBABILITIES(parm_r.probabilities(), list_of(.125)(.25)(.125)(.5)); + + boost::random::discrete_distribution<>::param_type + parm_it(probs.begin(), probs.end()); + CHECK_PROBABILITIES(parm_it.probabilities(), list_of(.125)(.25)(.125)(.5)); + + boost::random::discrete_distribution<>::param_type + parm_fun(4, 99, 115, gen()); + CHECK_PROBABILITIES(parm_fun.probabilities(), list_of(.125)(.25)(.125)(.5)); +} + +BOOST_AUTO_TEST_CASE(test_min_max) { + std::vector<double> probs = boost::assign::list_of(1.0)(2.0)(1.0); + boost::random::discrete_distribution<> dist; + BOOST_CHECK_EQUAL((dist.min)(), 0); + BOOST_CHECK_EQUAL((dist.max)(), 0); + boost::random::discrete_distribution<> dist_r(probs); + BOOST_CHECK_EQUAL((dist_r.min)(), 0); + BOOST_CHECK_EQUAL((dist_r.max)(), 2); +} + +BOOST_AUTO_TEST_CASE(test_comparison) { + std::vector<double> probs = boost::assign::list_of(1.0)(2.0)(1.0)(4.0); + boost::random::discrete_distribution<> dist; + boost::random::discrete_distribution<> dist_copy(dist); + boost::random::discrete_distribution<> dist_r(probs); + boost::random::discrete_distribution<> dist_r_copy(dist_r); + BOOST_CHECK(dist == dist_copy); + BOOST_CHECK(!(dist != dist_copy)); + BOOST_CHECK(dist_r == dist_r_copy); + BOOST_CHECK(!(dist_r != dist_r_copy)); + BOOST_CHECK(dist != dist_r); + BOOST_CHECK(!(dist == dist_r)); +} + +BOOST_AUTO_TEST_CASE(test_streaming) { + std::vector<double> probs = boost::assign::list_of(1.0)(2.0)(1.0)(4.0); + boost::random::discrete_distribution<> dist(probs); + std::stringstream stream; + stream << dist; + boost::random::discrete_distribution<> restored_dist; + stream >> restored_dist; + BOOST_CHECK_EQUAL(dist, restored_dist); +} + +BOOST_AUTO_TEST_CASE(test_generation) { + std::vector<double> probs = boost::assign::list_of(0.0)(1.0); + boost::minstd_rand0 gen; + boost::random::discrete_distribution<> dist; + boost::random::discrete_distribution<> dist_r(probs); + for(int i = 0; i < 10; ++i) { + int value = dist(gen); + BOOST_CHECK_EQUAL(value, 0); + int value_r = dist_r(gen); + BOOST_CHECK_EQUAL(value_r, 1); + int value_param = dist_r(gen, dist.param()); + BOOST_CHECK_EQUAL(value_param, 0); + int value_r_param = dist(gen, dist_r.param()); + BOOST_CHECK_EQUAL(value_r_param, 1); + } +} diff --git a/libs/random/test/test_distribution.ipp b/libs/random/test/test_distribution.ipp new file mode 100644 index 0000000000..a98f3bdcde --- /dev/null +++ b/libs/random/test/test_distribution.ipp @@ -0,0 +1,290 @@ +/* test_distribution.ipp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_distribution.ipp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/linear_congruential.hpp> +#include <boost/random/lagged_fibonacci.hpp> +#include <sstream> +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +using boost::random::test::RandomNumberDistribution; +BOOST_CONCEPT_ASSERT((RandomNumberDistribution< BOOST_RANDOM_DISTRIBUTION >)); + +BOOST_AUTO_TEST_CASE(test_constructors) { + BOOST_RANDOM_DISTRIBUTION dist; + BOOST_CHECK_EQUAL(dist.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_DEFAULT); +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK_EQUAL(dist.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_DEFAULT); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(dist.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_DEFAULT); +#endif + BOOST_RANDOM_DISTRIBUTION dist_one(BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL(dist_one.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK_EQUAL(dist_one.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_DEFAULT); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(dist_one.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_DEFAULT); +#endif +#ifdef BOOST_RANDOM_ARG2 + BOOST_RANDOM_DISTRIBUTION dist_two(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE); + BOOST_CHECK_EQUAL(dist_two.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL(dist_two.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_VALUE); +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(dist_two.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_DEFAULT); +#endif +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_RANDOM_DISTRIBUTION dist_three(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE, BOOST_RANDOM_ARG3_VALUE); + BOOST_CHECK_EQUAL(dist_three.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL(dist_three.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_VALUE); + BOOST_CHECK_EQUAL(dist_three.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_VALUE); +#endif + BOOST_RANDOM_DISTRIBUTION copy(dist); + BOOST_CHECK_EQUAL(dist, copy); + BOOST_RANDOM_DISTRIBUTION copy_one(dist_one); + BOOST_CHECK_EQUAL(dist_one, copy_one); +#ifdef BOOST_RANDOM_ARG2 + BOOST_RANDOM_DISTRIBUTION copy_two(dist_two); + BOOST_CHECK_EQUAL(dist_two, copy_two); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_RANDOM_DISTRIBUTION copy_three(dist_three); + BOOST_CHECK_EQUAL(dist_three, copy_three); +#endif +} + +BOOST_AUTO_TEST_CASE(test_param) { +#if defined(BOOST_RANDOM_ARG3) + BOOST_RANDOM_DISTRIBUTION dist(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE, BOOST_RANDOM_ARG3_VALUE); +#elif defined(BOOST_RANDOM_ARG2) + BOOST_RANDOM_DISTRIBUTION dist(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE); +#else + BOOST_RANDOM_DISTRIBUTION dist(BOOST_RANDOM_ARG1_VALUE); +#endif + BOOST_RANDOM_DISTRIBUTION::param_type param = dist.param(); + BOOST_CHECK_EQUAL(param.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK_EQUAL(param.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_VALUE); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(param.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_VALUE); +#endif + BOOST_RANDOM_DISTRIBUTION copy1(param); + BOOST_CHECK_EQUAL(dist, copy1); + BOOST_RANDOM_DISTRIBUTION copy2; + copy2.param(param); + BOOST_CHECK_EQUAL(dist, copy2); + + BOOST_RANDOM_DISTRIBUTION::param_type param_copy = param; + BOOST_CHECK_EQUAL(param, param_copy); + BOOST_CHECK(param == param_copy); + BOOST_CHECK(!(param != param_copy)); + BOOST_RANDOM_DISTRIBUTION::param_type param_default; + BOOST_CHECK_EQUAL(param_default.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_DEFAULT); +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK_EQUAL(param_default.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_DEFAULT); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(param_default.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_DEFAULT); +#endif + BOOST_CHECK(param != param_default); + BOOST_CHECK(!(param == param_default)); + BOOST_RANDOM_DISTRIBUTION::param_type param_one(BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL(param_one.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK_EQUAL(param_one.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_DEFAULT); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(param_one.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_DEFAULT); +#endif +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK(param != param_one); + BOOST_CHECK(!(param == param_one)); +#endif + BOOST_CHECK(param_default != param_one); + BOOST_CHECK(!(param_default == param_one)); +#ifdef BOOST_RANDOM_ARG2 + BOOST_RANDOM_DISTRIBUTION::param_type param_two(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE); + BOOST_CHECK_EQUAL(param_two.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL(param_two.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_VALUE); +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK_EQUAL(param_two.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_DEFAULT); +#endif +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_RANDOM_DISTRIBUTION::param_type param_three(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE, BOOST_RANDOM_ARG3_VALUE); + BOOST_CHECK_EQUAL(param_three.BOOST_RANDOM_ARG1(), BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL(param_three.BOOST_RANDOM_ARG2(), BOOST_RANDOM_ARG2_VALUE); + BOOST_CHECK_EQUAL(param_three.BOOST_RANDOM_ARG3(), BOOST_RANDOM_ARG3_VALUE); +#endif +} + +BOOST_AUTO_TEST_CASE(test_min_max) { + BOOST_RANDOM_DISTRIBUTION dist; + BOOST_CHECK_EQUAL((dist.min)(), BOOST_RANDOM_DIST0_MIN); + BOOST_CHECK_EQUAL((dist.max)(), BOOST_RANDOM_DIST0_MAX); + BOOST_RANDOM_DISTRIBUTION dist_one(BOOST_RANDOM_ARG1_VALUE); + BOOST_CHECK_EQUAL((dist_one.min)(), BOOST_RANDOM_DIST1_MIN); + BOOST_CHECK_EQUAL((dist_one.max)(), BOOST_RANDOM_DIST1_MAX); +#ifdef BOOST_RANDOM_ARG2 + BOOST_RANDOM_DISTRIBUTION dist_two(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE); + BOOST_CHECK_EQUAL((dist_two.min)(), BOOST_RANDOM_DIST2_MIN); + BOOST_CHECK_EQUAL((dist_two.max)(), BOOST_RANDOM_DIST2_MAX); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_RANDOM_DISTRIBUTION dist_three(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE, BOOST_RANDOM_ARG3_VALUE); + BOOST_CHECK_EQUAL((dist_three.min)(), BOOST_RANDOM_DIST3_MIN); + BOOST_CHECK_EQUAL((dist_three.max)(), BOOST_RANDOM_DIST3_MAX); +#endif +} + +BOOST_AUTO_TEST_CASE(test_comparison) { + BOOST_RANDOM_DISTRIBUTION dist; + BOOST_RANDOM_DISTRIBUTION dist_copy(dist); + BOOST_RANDOM_DISTRIBUTION dist_one(BOOST_RANDOM_ARG1_VALUE); + BOOST_RANDOM_DISTRIBUTION dist_one_copy(dist_one); +#ifdef BOOST_RANDOM_ARG2 + BOOST_RANDOM_DISTRIBUTION dist_two(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE); + BOOST_RANDOM_DISTRIBUTION dist_two_copy(dist_two); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_RANDOM_DISTRIBUTION dist_three(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE, BOOST_RANDOM_ARG3_VALUE); + BOOST_RANDOM_DISTRIBUTION dist_three_copy(dist_three); +#endif + BOOST_CHECK(dist == dist_copy); + BOOST_CHECK(!(dist != dist_copy)); + BOOST_CHECK(dist_one == dist_one_copy); + BOOST_CHECK(!(dist_one != dist_one_copy)); + BOOST_CHECK(dist != dist_one); + BOOST_CHECK(!(dist == dist_one)); +#ifdef BOOST_RANDOM_ARG2 + BOOST_CHECK(dist_two == dist_two_copy); + BOOST_CHECK(!(dist_two != dist_two_copy)); + BOOST_CHECK(dist != dist_two); + BOOST_CHECK(!(dist == dist_two)); + BOOST_CHECK(dist_one != dist_two); + BOOST_CHECK(!(dist_one == dist_two)); +#endif +#ifdef BOOST_RANDOM_ARG3 + BOOST_CHECK(dist_three == dist_three_copy); + BOOST_CHECK(!(dist_three != dist_three_copy)); + BOOST_CHECK(dist != dist_three); + BOOST_CHECK(!(dist == dist_three)); + BOOST_CHECK(dist_one != dist_three); + BOOST_CHECK(!(dist_one == dist_three)); + BOOST_CHECK(dist_two != dist_three); + BOOST_CHECK(!(dist_two == dist_three)); +#endif +} + +BOOST_AUTO_TEST_CASE(test_streaming) { +#if defined(BOOST_RANDOM_ARG3) + BOOST_RANDOM_DISTRIBUTION dist(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE, BOOST_RANDOM_ARG2_VALUE); +#elif defined(BOOST_RANDOM_ARG2) + BOOST_RANDOM_DISTRIBUTION dist(BOOST_RANDOM_ARG1_VALUE, BOOST_RANDOM_ARG2_VALUE); +#else + BOOST_RANDOM_DISTRIBUTION dist(BOOST_RANDOM_ARG1_VALUE); +#endif + std::stringstream stream; + stream << dist; + BOOST_RANDOM_DISTRIBUTION restored_dist; + stream >> restored_dist; + BOOST_CHECK_EQUAL(dist, restored_dist); +} + +void use(BOOST_RANDOM_DISTRIBUTION::result_type) {} + +BOOST_AUTO_TEST_CASE(test_generation) { + boost::minstd_rand0 gen; + BOOST_RANDOM_DISTRIBUTION dist BOOST_RANDOM_TEST1_PARAMS; + BOOST_RANDOM_DISTRIBUTION dist_two BOOST_RANDOM_TEST2_PARAMS; + typedef BOOST_RANDOM_DISTRIBUTION::result_type result_type; + for(int i = 0; i < 10; ++i) { + result_type value = dist(gen); + use(value); +#ifdef BOOST_RANDOM_TEST1_MIN + BOOST_CHECK_GE(value, BOOST_RANDOM_TEST1_MIN); +#endif +#ifdef BOOST_RANDOM_TEST1_MAX + BOOST_CHECK_LE(value, BOOST_RANDOM_TEST1_MAX); +#endif + result_type value_two = dist_two(gen); + use(value_two); +#ifdef BOOST_RANDOM_TEST2_MIN + BOOST_CHECK_GE(value_two, BOOST_RANDOM_TEST2_MIN); +#endif +#ifdef BOOST_RANDOM_TEST2_MAX + BOOST_CHECK_LE(value_two, BOOST_RANDOM_TEST2_MAX); +#endif + result_type value_param = dist_two(gen, dist.param()); + use(value_param); +#ifdef BOOST_RANDOM_TEST1_MIN + BOOST_CHECK_GE(value_param, BOOST_RANDOM_TEST1_MIN); +#endif +#ifdef BOOST_RANDOM_TEST1_MAX + BOOST_CHECK_LE(value_param, BOOST_RANDOM_TEST1_MAX); +#endif + result_type value_two_param = dist(gen, dist_two.param()); + use(value_two_param); +#ifdef BOOST_RANDOM_TEST2_MIN + BOOST_CHECK_GE(value_two_param, BOOST_RANDOM_TEST2_MIN); +#endif +#ifdef BOOST_RANDOM_TEST2_MAX + BOOST_CHECK_LE(value_two_param, BOOST_RANDOM_TEST2_MAX); +#endif + } +} + +BOOST_AUTO_TEST_CASE(test_generation_float) { + boost::lagged_fibonacci607 gen; + BOOST_RANDOM_DISTRIBUTION dist BOOST_RANDOM_TEST1_PARAMS; + BOOST_RANDOM_DISTRIBUTION dist_two BOOST_RANDOM_TEST2_PARAMS; + typedef BOOST_RANDOM_DISTRIBUTION::result_type result_type; + for(int i = 0; i < 10; ++i) { + result_type value = dist(gen); + use(value); +#ifdef BOOST_RANDOM_TEST1_MIN + BOOST_CHECK_GE(value, BOOST_RANDOM_TEST1_MIN); +#endif +#ifdef BOOST_RANDOM_TEST1_MAX + BOOST_CHECK_LE(value, BOOST_RANDOM_TEST1_MAX); +#endif + result_type value_two = dist_two(gen); + use(value_two); +#ifdef BOOST_RANDOM_TEST2_MIN + BOOST_CHECK_GE(value_two, BOOST_RANDOM_TEST2_MIN); +#endif +#ifdef BOOST_RANDOM_TEST2_MAX + BOOST_CHECK_LE(value_two, BOOST_RANDOM_TEST2_MAX); +#endif + result_type value_param = dist_two(gen, dist.param()); + use(value_param); +#ifdef BOOST_RANDOM_TEST1_MIN + BOOST_CHECK_GE(value_param, BOOST_RANDOM_TEST1_MIN); +#endif +#ifdef BOOST_RANDOM_TEST1_MAX + BOOST_CHECK_LE(value_param, BOOST_RANDOM_TEST1_MAX); +#endif + result_type value_two_param = dist(gen, dist_two.param()); + use(value_two_param); +#ifdef BOOST_RANDOM_TEST2_MIN + BOOST_CHECK_GE(value_two_param, BOOST_RANDOM_TEST2_MIN); +#endif +#ifdef BOOST_RANDOM_TEST2_MAX + BOOST_CHECK_LE(value_two_param, BOOST_RANDOM_TEST2_MAX); +#endif + } +} + diff --git a/libs/random/test/test_ecuyer1988.cpp b/libs/random/test/test_ecuyer1988.cpp new file mode 100644 index 0000000000..1f808c3952 --- /dev/null +++ b/libs/random/test/test_ecuyer1988.cpp @@ -0,0 +1,24 @@ +/* test_ecuyer1988.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ecuyer1988.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/additive_combine.hpp> + +#define BOOST_RANDOM_URNG boost::random::ecuyer1988 + +#define BOOST_RANDOM_SEED_WORDS 2 + +#define BOOST_RANDOM_VALIDATION_VALUE 2060321752U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 1928563088U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 776923198U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x7AE0C087U, 0x948A8A31U, 0xBE5CCBA9U, 0x1316692CU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_exponential.cpp b/libs/random/test/test_exponential.cpp new file mode 100644 index 0000000000..0ad9c5db62 --- /dev/null +++ b/libs/random/test/test_exponential.cpp @@ -0,0 +1,24 @@ +/* test_exponential.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_exponential.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/exponential_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/exponential.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::exponential_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME exponential +#define BOOST_MATH_DISTRIBUTION boost::math::exponential +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME lambda +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.0001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_exponential_distribution.cpp b/libs/random/test/test_exponential_distribution.cpp new file mode 100644 index 0000000000..8563ae67d5 --- /dev/null +++ b/libs/random/test/test_exponential_distribution.cpp @@ -0,0 +1,32 @@ +/* test_exponential_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_exponential_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/exponential_distribution.hpp> + +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::exponential_distribution<> +#define BOOST_RANDOM_ARG1 lambda +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0.0 + +#define BOOST_RANDOM_TEST2_PARAMS (1000.0) +#define BOOST_RANDOM_TEST2_MIN 0.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_extreme_value.cpp b/libs/random/test/test_extreme_value.cpp new file mode 100644 index 0000000000..ca0b817257 --- /dev/null +++ b/libs/random/test/test_extreme_value.cpp @@ -0,0 +1,28 @@ +/* test_extreme_value.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_extreme_value.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/extreme_value_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/extreme_value.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::extreme_value_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME extreme_value +#define BOOST_MATH_DISTRIBUTION boost::math::extreme_value +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME a +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME b +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_extreme_value_distribution.cpp b/libs/random/test/test_extreme_value_distribution.cpp new file mode 100644 index 0000000000..64cf5d9ce8 --- /dev/null +++ b/libs/random/test/test_extreme_value_distribution.cpp @@ -0,0 +1,36 @@ +/* test_extreme_value_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_extreme_value_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/extreme_value_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::extreme_value_distribution<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS (-100.0) +#define BOOST_RANDOM_TEST1_MAX 0 + +#define BOOST_RANDOM_TEST2_PARAMS (100.0) +#define BOOST_RANDOM_TEST2_MIN 0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_fisher_f.cpp b/libs/random/test/test_fisher_f.cpp new file mode 100644 index 0000000000..e4a6a7c071 --- /dev/null +++ b/libs/random/test/test_fisher_f.cpp @@ -0,0 +1,28 @@ +/* test_fisher_f.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_fisher_f.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/fisher_f_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/fisher_f.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::fisher_f_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME fisher_f +#define BOOST_MATH_DISTRIBUTION boost::math::fisher_f +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME m +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME n +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_fisher_f_distribution.cpp b/libs/random/test/test_fisher_f_distribution.cpp new file mode 100644 index 0000000000..b40700492b --- /dev/null +++ b/libs/random/test/test_fisher_f_distribution.cpp @@ -0,0 +1,33 @@ +/* test_fisher_f_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_fisher_f_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/fisher_f_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::fisher_f_distribution<> +#define BOOST_RANDOM_ARG1 m +#define BOOST_RANDOM_ARG2 n +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0.0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0.0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0.0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS (1.0, 2.1) +#define BOOST_RANDOM_TEST2_PARAMS (10.0, 10.0) + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_gamma.cpp b/libs/random/test/test_gamma.cpp new file mode 100644 index 0000000000..2f5391fc19 --- /dev/null +++ b/libs/random/test/test_gamma.cpp @@ -0,0 +1,28 @@ +/* test_gamma.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_gamma.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/gamma_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/gamma.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::gamma_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME gamma +#define BOOST_MATH_DISTRIBUTION boost::math::gamma_distribution<> +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME alpha +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME beta +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_gamma_distribution.cpp b/libs/random/test/test_gamma_distribution.cpp new file mode 100644 index 0000000000..7ed5cf2880 --- /dev/null +++ b/libs/random/test/test_gamma_distribution.cpp @@ -0,0 +1,37 @@ +/* test_gamma_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_gamma_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/gamma_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::gamma_distribution<> +#define BOOST_RANDOM_ARG1 alpha +#define BOOST_RANDOM_ARG2 beta +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0.0 +#define BOOST_RANDOM_TEST1_MAX 100.0 + +#define BOOST_RANDOM_TEST2_PARAMS (1.0, 1000000.0) +#define BOOST_RANDOM_TEST2_MIN 100.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_generate_canonical.cpp b/libs/random/test/test_generate_canonical.cpp new file mode 100644 index 0000000000..ecf7463aa8 --- /dev/null +++ b/libs/random/test/test_generate_canonical.cpp @@ -0,0 +1,103 @@ +/* test_generate_canonical.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_generate_canonical.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/generate_canonical.hpp> + +#include <boost/random/linear_congruential.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/lagged_fibonacci.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +typedef boost::mpl::vector< + boost::random::minstd_rand, + boost::random::mt19937, + boost::random::lagged_fibonacci607 +> engines; + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_float, Engine, engines) +{ + Engine eng; + Engine expected; + for(int i = 0; i < 1000; ++i) { + float val = boost::random::generate_canonical<float, 64>(eng); + BOOST_CHECK_GE(val, 0); + BOOST_CHECK_LT(val, 1); + } + expected.discard(1000); + BOOST_CHECK_EQUAL(eng, expected); + for(int i = 0; i < 1000; ++i) { + float val = boost::random::generate_canonical<float, 12>(eng); + BOOST_CHECK_GE(val, 0); + BOOST_CHECK_LT(val, 1); + } + expected.discard(1000); + BOOST_CHECK_EQUAL(eng, expected); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_double, Engine, engines) +{ + Engine eng; + Engine expected; + for(int i = 0; i < 1000; ++i) { + double val = boost::random::generate_canonical<double, 64>(eng); + BOOST_CHECK_GE(val, 0); + BOOST_CHECK_LT(val, 1); + } + expected.discard(2000); + BOOST_CHECK_EQUAL(eng, expected); + for(int i = 0; i < 1000; ++i) { + double val = boost::random::generate_canonical<double, 12>(eng); + BOOST_CHECK_GE(val, 0); + BOOST_CHECK_LT(val, 1); + } + expected.discard(1000); + BOOST_CHECK_EQUAL(eng, expected); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_long_double, Engine, engines) +{ + Engine eng; + Engine expected; + for(int i = 0; i < 1000; ++i) { + long double val = boost::random::generate_canonical<long double, 60>(eng); + BOOST_CHECK_GE(val, 0); + BOOST_CHECK_LT(val, 1); + } + expected.discard(2000); + BOOST_CHECK_EQUAL(eng, expected); + for(int i = 0; i < 1000; ++i) { + long double val = boost::random::generate_canonical<long double, 12>(eng); + BOOST_CHECK_GE(val, 0); + BOOST_CHECK_LT(val, 1); + } + expected.discard(1000); + BOOST_CHECK_EQUAL(eng, expected); +} + +struct max_engine +{ + typedef boost::uint32_t result_type; + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return ~boost::uint32_t(0); } + result_type operator()() { return (max)(); } +}; + +BOOST_AUTO_TEST_CASE(test_max) +{ + max_engine eng; + BOOST_CHECK_LT((boost::random::generate_canonical<float, 64>(eng)), 1); + BOOST_CHECK_LT((boost::random::generate_canonical<double, 64>(eng)), 1); + BOOST_CHECK_LT((boost::random::generate_canonical<long double, 64>(eng)), 1); +} diff --git a/libs/random/test/test_generator.ipp b/libs/random/test/test_generator.ipp new file mode 100644 index 0000000000..98a6220909 --- /dev/null +++ b/libs/random/test/test_generator.ipp @@ -0,0 +1,246 @@ +/* test_generator.ipp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_generator.ipp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include "concepts.hpp" +#include <boost/random/seed_seq.hpp> + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +using boost::random::test::RandomNumberEngine; +BOOST_CONCEPT_ASSERT((RandomNumberEngine< BOOST_RANDOM_URNG >)); + +typedef BOOST_RANDOM_URNG::result_type result_type; +typedef boost::random::detail::seed_type<result_type>::type seed_type; + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#endif + +template<class Converted, class URNG, class T> +void test_seed_conversion(URNG & urng, const T & t) +{ + Converted c = static_cast<Converted>(t); + if(static_cast<T>(c) == t) { + URNG urng2(c); + std::ostringstream msg; + msg << "Testing seed: type " << typeid(Converted).name() << ", value " << c; + BOOST_CHECK_MESSAGE(urng == urng2, msg.str()); + urng2.seed(c); + BOOST_CHECK_MESSAGE(urng == urng2, msg.str()); + } +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +void test_seed(seed_type value) +{ + BOOST_RANDOM_URNG urng(value); + + // integral types + test_seed_conversion<char>(urng, value); + test_seed_conversion<signed char>(urng, value); + test_seed_conversion<unsigned char>(urng, value); + test_seed_conversion<short>(urng, value); + test_seed_conversion<unsigned short>(urng, value); + test_seed_conversion<int>(urng, value); + test_seed_conversion<unsigned int>(urng, value); + test_seed_conversion<long>(urng, value); + test_seed_conversion<unsigned long>(urng, value); +#if !defined(BOOST_NO_INT64_T) + test_seed_conversion<boost::int64_t>(urng, value); + test_seed_conversion<boost::uint64_t>(urng, value); +#endif + + // floating point types + test_seed_conversion<float>(urng, value); + test_seed_conversion<double>(urng, value); + test_seed_conversion<long double>(urng, value); +} + +BOOST_AUTO_TEST_CASE(test_default_seed) +{ + BOOST_RANDOM_URNG urng; + BOOST_RANDOM_URNG urng2; + urng2(); + BOOST_CHECK_NE(urng, urng2); + urng2.seed(); + BOOST_CHECK_EQUAL(urng, urng2); +} + +BOOST_AUTO_TEST_CASE(test_arithmetic_seed) +{ + test_seed(static_cast<seed_type>(0)); + test_seed(static_cast<seed_type>(127)); + test_seed(static_cast<seed_type>(539157235)); + test_seed(static_cast<seed_type>(~0u)); +} + +BOOST_AUTO_TEST_CASE(test_iterator_seed) +{ + const std::vector<int> v((std::max)(std::size_t(9999u), sizeof(BOOST_RANDOM_URNG) / 4), 0x41); + std::vector<int>::const_iterator it = v.begin(); + std::vector<int>::const_iterator it_end = v.end(); + BOOST_RANDOM_URNG urng(it, it_end); + BOOST_CHECK(it != v.begin()); + std::iterator_traits<std::vector<int>::const_iterator>::difference_type n_words = (it - v.begin()); + BOOST_CHECK_GT(n_words, 0); + BOOST_CHECK_EQUAL(n_words, BOOST_RANDOM_SEED_WORDS); + + it = v.begin(); + BOOST_RANDOM_URNG urng2; + urng2.seed(it, it_end); + std::iterator_traits<std::vector<int>::const_iterator>::difference_type n_words2 = (it - v.begin()); + BOOST_CHECK_EQUAL(n_words, n_words2); + BOOST_CHECK_EQUAL(urng, urng2); + + it = v.end(); + BOOST_CHECK_THROW(BOOST_RANDOM_URNG(it, it_end), std::invalid_argument); + BOOST_CHECK_THROW(urng.seed(it, it_end), std::invalid_argument); + + if(n_words > 1) { + it = v.end(); + --it; + BOOST_CHECK_THROW(BOOST_RANDOM_URNG(it, it_end), std::invalid_argument); + it = v.end(); + --it; + BOOST_CHECK_THROW(urng.seed(it, it_end), std::invalid_argument); + } +} + +BOOST_AUTO_TEST_CASE(test_seed_seq_seed) +{ + boost::random::seed_seq q; + BOOST_RANDOM_URNG urng(q); + BOOST_RANDOM_URNG urng2; + BOOST_CHECK_NE(urng, urng2); + urng2.seed(q); + BOOST_CHECK_EQUAL(urng, urng2); +} + +template<class CharT> +void do_test_streaming(const BOOST_RANDOM_URNG& urng) +{ + BOOST_RANDOM_URNG urng2; + std::basic_ostringstream<CharT> output; + output << urng; + BOOST_CHECK_NE(urng, urng2); + // restore old state + std::basic_istringstream<CharT> input(output.str()); + input >> urng2; + BOOST_CHECK_EQUAL(urng, urng2); +} + +BOOST_AUTO_TEST_CASE(test_streaming) +{ + BOOST_RANDOM_URNG urng; + urng.discard(9307); + do_test_streaming<char>(urng); +#if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING) + do_test_streaming<wchar_t>(urng); +#endif +} + +BOOST_AUTO_TEST_CASE(test_discard) +{ + BOOST_RANDOM_URNG urng; + BOOST_RANDOM_URNG urng2; + BOOST_CHECK_EQUAL(urng, urng2); + for(int i = 0; i < 9307; ++i) + urng(); + BOOST_CHECK_NE(urng, urng2); + urng2.discard(9307); + BOOST_CHECK_EQUAL(urng, urng2); +} + +BOOST_AUTO_TEST_CASE(test_copy) +{ + BOOST_RANDOM_URNG urng; + urng.discard(9307); + { + BOOST_RANDOM_URNG urng2 = urng; + BOOST_CHECK_EQUAL(urng, urng2); + } + { + BOOST_RANDOM_URNG urng2(urng); + BOOST_CHECK_EQUAL(urng, urng2); + } + { + BOOST_RANDOM_URNG urng2; + urng2 = urng; + BOOST_CHECK_EQUAL(urng, urng2); + } +} + +BOOST_AUTO_TEST_CASE(test_min_max) +{ + BOOST_RANDOM_URNG urng; + for(int i = 0; i < 10000; ++i) { + result_type value = urng(); + BOOST_CHECK_GE(value, (BOOST_RANDOM_URNG::min)()); + BOOST_CHECK_LE(value, (BOOST_RANDOM_URNG::max)()); + } +} + +BOOST_AUTO_TEST_CASE(test_comparison) +{ + BOOST_RANDOM_URNG urng; + BOOST_RANDOM_URNG urng2; + BOOST_CHECK(urng == urng2); + BOOST_CHECK(!(urng != urng2)); + urng(); + BOOST_CHECK(urng != urng2); + BOOST_CHECK(!(urng == urng2)); +} + +BOOST_AUTO_TEST_CASE(validate) +{ + BOOST_RANDOM_URNG urng; + for(int i = 0; i < 9999; ++i) { + urng(); + } + BOOST_CHECK_EQUAL(urng(), BOOST_RANDOM_VALIDATION_VALUE); +} + +BOOST_AUTO_TEST_CASE(validate_seed_seq) +{ + boost::random::seed_seq seed; + BOOST_RANDOM_URNG urng(seed); + for(int i = 0; i < 9999; ++i) { + urng(); + } + BOOST_CHECK_EQUAL(urng(), BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE); +} + +BOOST_AUTO_TEST_CASE(validate_iter) +{ + const std::vector<int> v((std::max)(std::size_t(9999u), sizeof(BOOST_RANDOM_URNG) / 4), 0x41); + std::vector<int>::const_iterator it = v.begin(); + std::vector<int>::const_iterator it_end = v.end(); + BOOST_RANDOM_URNG urng(it, it_end); + for(int i = 0; i < 9999; ++i) { + urng(); + } + BOOST_CHECK_EQUAL(urng(), BOOST_RANDOM_ITERATOR_VALIDATION_VALUE); +} + +BOOST_AUTO_TEST_CASE(test_generate) +{ + BOOST_RANDOM_URNG urng; + boost::uint32_t expected[] = BOOST_RANDOM_GENERATE_VALUES; + static const std::size_t N = sizeof(expected)/sizeof(expected[0]); + boost::uint32_t actual[N]; + urng.generate(&actual[0], &actual[0] + N); + BOOST_CHECK_EQUAL_COLLECTIONS(actual, actual + N, expected, expected + N); +} diff --git a/libs/random/test/test_geometric.cpp b/libs/random/test/test_geometric.cpp new file mode 100644 index 0000000000..d8ba2466b5 --- /dev/null +++ b/libs/random/test/test_geometric.cpp @@ -0,0 +1,26 @@ +/* test_geometric.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_geometric.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/geometric_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/geometric.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::geometric_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME geometric +#define BOOST_MATH_DISTRIBUTION boost::math::geometric +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME p +#define BOOST_RANDOM_ARG1_DEFAULT 0.5 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.0001, 0.9999) +#define BOOST_RANDOM_DISTRIBUTION_MAX boost::numeric_cast<int>(-5 / std::log(1-p)) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_geometric_distribution.cpp b/libs/random/test/test_geometric_distribution.cpp new file mode 100644 index 0000000000..833e8f0d5d --- /dev/null +++ b/libs/random/test/test_geometric_distribution.cpp @@ -0,0 +1,31 @@ +/* test_geometric_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_geometric_distribution.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/geometric_distribution.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::geometric_distribution<> +#define BOOST_RANDOM_ARG1 p +#define BOOST_RANDOM_ARG1_DEFAULT 0.5 +#define BOOST_RANDOM_ARG1_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<int>::max)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<int>::max)() + +#define BOOST_RANDOM_TEST1_PARAMS (0.9999) +#define BOOST_RANDOM_TEST1_MIN 0 +#define BOOST_RANDOM_TEST1_MAX 0 + +#define BOOST_RANDOM_TEST2_PARAMS (0.0001) +#define BOOST_RANDOM_TEST2_MIN 1 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_hellekalek1995.cpp b/libs/random/test/test_hellekalek1995.cpp new file mode 100644 index 0000000000..064fceb919 --- /dev/null +++ b/libs/random/test/test_hellekalek1995.cpp @@ -0,0 +1,24 @@ +/* test_mt19937.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_hellekalek1995.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/inversive_congruential.hpp> + +#define BOOST_RANDOM_URNG boost::random::hellekalek1995 + +#define BOOST_RANDOM_SEED_WORDS 1 + +#define BOOST_RANDOM_VALIDATION_VALUE 1187812169U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 1912573642U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 618743552U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x5642A47BU, 0x1F6987E8U, 0xD35860E7U, 0xC8C661ABU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_independent_bits31.cpp b/libs/random/test/test_independent_bits31.cpp new file mode 100644 index 0000000000..0b44730595 --- /dev/null +++ b/libs/random/test/test_independent_bits31.cpp @@ -0,0 +1,26 @@ +/* test_independent_bits31.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_independent_bits31.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/independent_bits.hpp> +#include <boost/random/linear_congruential.hpp> + +typedef boost::random::independent_bits_engine<boost::random::minstd_rand0, 31, boost::uint32_t> independent_bits31; +#define BOOST_RANDOM_URNG independent_bits31 + +#define BOOST_RANDOM_SEED_WORDS 1 + +#define BOOST_RANDOM_VALIDATION_VALUE 26292962U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 364481529U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 1399154219U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC1A63AF0U, 0xD66C0614U, 0xADE076B1U, 0xC1DAE13FU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_independent_bits32.cpp b/libs/random/test/test_independent_bits32.cpp new file mode 100644 index 0000000000..48972e5f04 --- /dev/null +++ b/libs/random/test/test_independent_bits32.cpp @@ -0,0 +1,26 @@ +/* test_independent_bits32.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_independent_bits32.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/independent_bits.hpp> +#include <boost/random/mersenne_twister.hpp> + +typedef boost::random::independent_bits_engine<boost::random::mt19937, 32, boost::uint32_t> independent_bits32; +#define BOOST_RANDOM_URNG independent_bits32 + +#define BOOST_RANDOM_SEED_WORDS 624 + +#define BOOST_RANDOM_VALIDATION_VALUE 4123659995U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 666528879U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3408548740U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xD091BB5CU, 0x22AE9EF6U, 0xE7E1FAEEU, 0xD5C31F79U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_knuth_b.cpp b/libs/random/test/test_knuth_b.cpp new file mode 100644 index 0000000000..df924b0293 --- /dev/null +++ b/libs/random/test/test_knuth_b.cpp @@ -0,0 +1,26 @@ +/* test_knuth_b.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_knuth_b.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/shuffle_order.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::knuth_b + +#define BOOST_RANDOM_SEED_WORDS 1 + +// validation from the C++0x draft (n3090) +#define BOOST_RANDOM_VALIDATION_VALUE 1112339016U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 202352021U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 1692601883U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x5D189C63U, 0xD0544F0EU, 0x15B0E78FU, 0xD814D654U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_kreutzer1986.cpp b/libs/random/test/test_kreutzer1986.cpp new file mode 100644 index 0000000000..0ebbfacfb5 --- /dev/null +++ b/libs/random/test/test_kreutzer1986.cpp @@ -0,0 +1,26 @@ +/* test_kreutzer1986.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_kreutzer1986.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/shuffle_order.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::kreutzer1986 + +#define BOOST_RANDOM_SEED_WORDS 1 + +// validation by experiment from Harry Erwin's generator.h (private e-mail) +#define BOOST_RANDOM_VALIDATION_VALUE 139726U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 589731U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 163138U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x3EADAB08U, 0x85E481CEU, 0xCF84AEA5U, 0x39D4395BU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci.cpp b/libs/random/test/test_lagged_fibonacci.cpp new file mode 100644 index 0000000000..9d4bbe6d55 --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci.cpp @@ -0,0 +1,25 @@ +/* test_lagged_fibonacci.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +typedef boost::random::lagged_fibonacci_engine<boost::uint32_t, 24, 607, 273> lagged_fibonacci; +#define BOOST_RANDOM_URNG lagged_fibonacci + +#define BOOST_RANDOM_SEED_WORDS 607 + +#define BOOST_RANDOM_VALIDATION_VALUE 3543833U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 1364481U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 4372778U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xF61A5094U, 0xFC4BA046U, 0xF1C41E92U, 0x3D82FE61U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci1279.cpp b/libs/random/test/test_lagged_fibonacci1279.cpp new file mode 100644 index 0000000000..8ab1ea220f --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci1279.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci1279.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci1279.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci1279 + +#define BOOST_RANDOM_SEED_WORDS 1279*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.39647253381274083 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.97108839261370505 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.56042480761195179 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x4D102C47U, 0xC4E610D7U, 0xF29333BEU, 0x6E45EBE7U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci19937.cpp b/libs/random/test/test_lagged_fibonacci19937.cpp new file mode 100644 index 0000000000..53235e136d --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci19937.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci19937.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci19937.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci19937 + +#define BOOST_RANDOM_SEED_WORDS 19937*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.24396310480293693 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.95892429604358043 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0029754638678802792 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x5CE9850CU, 0xAA20067BU, 0x4E48643BU, 0xA4A59F4BU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci2281.cpp b/libs/random/test/test_lagged_fibonacci2281.cpp new file mode 100644 index 0000000000..9fdac23578 --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci2281.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci2281.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci2281.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci2281 + +#define BOOST_RANDOM_SEED_WORDS 2281*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.91955231927349246 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.4447517699440553 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.087280273457821522 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x7EB0882AU, 0xCE09BE60U, 0xD53046CFU, 0x93257E41U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci23209.cpp b/libs/random/test/test_lagged_fibonacci23209.cpp new file mode 100644 index 0000000000..566eec4462 --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci23209.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci23209.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci23209.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci23209 + +#define BOOST_RANDOM_SEED_WORDS 23209*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.086299988971202168 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.63611281281476195 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0019836425785868528 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x4301DE0AU, 0xAD2584E3U, 0x7C28463CU, 0x74848542U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci3217.cpp b/libs/random/test/test_lagged_fibonacci3217.cpp new file mode 100644 index 0000000000..8f87e3a354 --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci3217.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci3217.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci3217.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci3217 + +#define BOOST_RANDOM_SEED_WORDS 3217*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.54223093970093927 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.073852702370395207 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.1805114746514036 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x4938F127U, 0x86C65CFEU, 0x65356579U, 0xA6CDC325U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci4423.cpp b/libs/random/test/test_lagged_fibonacci4423.cpp new file mode 100644 index 0000000000..99b3d74a16 --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci4423.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci4423.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci4423.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci4423 + +#define BOOST_RANDOM_SEED_WORDS 4423*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.23188533286820601 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.3872440622693567 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.012893676760814543 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x6D4DBAFU, 0x8039C1A9U, 0x3DA53D58U, 0x95155BE5U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci44497.cpp b/libs/random/test/test_lagged_fibonacci44497.cpp new file mode 100644 index 0000000000..bff33b5eac --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci44497.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci44497.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci44497.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci44497 + +#define BOOST_RANDOM_SEED_WORDS 44497*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.12519369894159738 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.92285669730527431 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0019836425785868528 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x6A2DCEA9U, 0x4668EFB4U, 0x711E352FU, 0xA963C43BU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci607.cpp b/libs/random/test/test_lagged_fibonacci607.cpp new file mode 100644 index 0000000000..79bccea3bb --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci607.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci607.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci607.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci607 + +#define BOOST_RANDOM_SEED_WORDS 607*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.039230772001715764 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.73105942788451372 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.72330291632639643 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x78EB0905U, 0x61766547U, 0xCB507F64U, 0x94FA3EC0U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lagged_fibonacci9689.cpp b/libs/random/test/test_lagged_fibonacci9689.cpp new file mode 100644 index 0000000000..8204b54f5a --- /dev/null +++ b/libs/random/test/test_lagged_fibonacci9689.cpp @@ -0,0 +1,24 @@ +/* test_lagged_fibonacci9689.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lagged_fibonacci9689.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/lagged_fibonacci.hpp> + +#define BOOST_RANDOM_URNG boost::random::lagged_fibonacci9689 + +#define BOOST_RANDOM_SEED_WORDS 9689*2 + +#define BOOST_RANDOM_VALIDATION_VALUE 0.059230573043926427 +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 0.80900890657466462 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0039672851571737056 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x32EF18BEU, 0x79277C11U, 0xA383438U, 0x32155952U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_linear_feedback_shift.cpp b/libs/random/test/test_linear_feedback_shift.cpp new file mode 100644 index 0000000000..e98322fbd3 --- /dev/null +++ b/libs/random/test/test_linear_feedback_shift.cpp @@ -0,0 +1,25 @@ +/* test_linear_feedback_shift.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_linear_feedback_shift.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/linear_feedback_shift.hpp> + +typedef boost::random::linear_feedback_shift_engine<boost::uint32_t, 32, 31, 13, 12> linear_feedback_shift; +#define BOOST_RANDOM_URNG linear_feedback_shift + +#define BOOST_RANDOM_SEED_WORDS 1 + +#define BOOST_RANDOM_VALIDATION_VALUE 981440277U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 3709603036U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3112279337U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x154005U, 0x54005502U, 0x5502BD4U, 0x2BD4005U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_lognormal.cpp b/libs/random/test/test_lognormal.cpp new file mode 100644 index 0000000000..cd92e2e891 --- /dev/null +++ b/libs/random/test/test_lognormal.cpp @@ -0,0 +1,28 @@ +/* test_lognormal.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lognormal.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/lognormal_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/lognormal.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::lognormal_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME lognormal +#define BOOST_MATH_DISTRIBUTION boost::math::lognormal +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME m +#define BOOST_RANDOM_ARG1_DEFAULT 10.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(-n, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME s +#define BOOST_RANDOM_ARG2_DEFAULT 10.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.0001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_lognormal_distribution.cpp b/libs/random/test/test_lognormal_distribution.cpp new file mode 100644 index 0000000000..a27b8baa65 --- /dev/null +++ b/libs/random/test/test_lognormal_distribution.cpp @@ -0,0 +1,36 @@ +/* test_lognormal_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_lognormal_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/lognormal_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::lognormal_distribution<> +#define BOOST_RANDOM_ARG1 m +#define BOOST_RANDOM_ARG2 s +#define BOOST_RANDOM_ARG1_DEFAULT 0.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0.0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0.0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0.0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS (-100.0) +#define BOOST_RANDOM_TEST1_MAX 1 + +#define BOOST_RANDOM_TEST2_PARAMS (100.0) +#define BOOST_RANDOM_TEST2_MIN 1 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_minstd_rand.cpp b/libs/random/test/test_minstd_rand.cpp new file mode 100644 index 0000000000..a59a8c6816 --- /dev/null +++ b/libs/random/test/test_minstd_rand.cpp @@ -0,0 +1,26 @@ +/* test_minstd_rand.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_minstd_rand.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/linear_congruential.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::minstd_rand + +#define BOOST_RANDOM_SEED_WORDS 1 + +// validation values from the publications +#define BOOST_RANDOM_VALIDATION_VALUE 399268537U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 1000962296U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 182651141U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x8400BC8EU, 0xF45B895FU, 0x145F0F91U, 0xE5F8F088U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_minstd_rand0.cpp b/libs/random/test/test_minstd_rand0.cpp new file mode 100644 index 0000000000..86717570f3 --- /dev/null +++ b/libs/random/test/test_minstd_rand0.cpp @@ -0,0 +1,26 @@ +/* test_minstd_rand0.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_minstd_rand0.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/linear_congruential.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::minstd_rand0 + +#define BOOST_RANDOM_SEED_WORDS 1 + +// validation values from the publications +#define BOOST_RANDOM_VALIDATION_VALUE 1043618065U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 1274759829U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 1263181168U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC00041A6U, 0xCD8358EBU, 0x430A4B7AU, 0x31B781ADU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_mt11213b.cpp b/libs/random/test/test_mt11213b.cpp new file mode 100644 index 0000000000..a26ec79b41 --- /dev/null +++ b/libs/random/test/test_mt11213b.cpp @@ -0,0 +1,24 @@ +/* test_mt11213b.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_mt11213b.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/mersenne_twister.hpp> + +#define BOOST_RANDOM_URNG boost::random::mt11213b + +#define BOOST_RANDOM_SEED_WORDS 351 + +#define BOOST_RANDOM_VALIDATION_VALUE 3809585648U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 2936939529U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 2434563197U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xEF3F3F3FU, 0x70082175U, 0xDAF6EAF5U, 0x2A16A63EU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_mt19937.cpp b/libs/random/test/test_mt19937.cpp new file mode 100644 index 0000000000..94928e5ef5 --- /dev/null +++ b/libs/random/test/test_mt19937.cpp @@ -0,0 +1,78 @@ +/* test_mt19937.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_mt19937.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/mersenne_twister.hpp> +#include <algorithm> +#include <vector> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::mt19937 + +#define BOOST_RANDOM_SEED_WORDS 624 + +// validation by experiment from mt19937.c +#define BOOST_RANDOM_VALIDATION_VALUE 4123659995U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 666528879U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3408548740U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xD091BB5CU, 0x22AE9EF6U, 0xE7E1FAEEU, 0xD5C31F79U } + +#include "test_generator.ipp" + +struct seed_seq_0 { + template<class It> + void generate(It begin, It end) const { + std::fill(begin, end, boost::uint32_t(0)); + } +}; + +struct seed_seq_1 { + template<class It> + void generate(It begin, It end) const { + std::fill(begin, end, boost::uint32_t(0)); + *(end - 1) = 1; + } +}; + +BOOST_AUTO_TEST_CASE(test_special_seed) { + { + seed_seq_1 seed; + std::vector<boost::uint32_t> vec(624); + seed.generate(vec.begin(), vec.end()); + + std::vector<boost::uint32_t>::iterator it = vec.begin(); + boost::mt19937 gen1(it, vec.end()); + BOOST_CHECK_EQUAL(gen1(), 0); + BOOST_CHECK_EQUAL(gen1(), 0); + + boost::mt19937 gen2(seed); + BOOST_CHECK_EQUAL(gen2(), 0); + BOOST_CHECK_EQUAL(gen2(), 0); + + BOOST_CHECK_EQUAL(gen1, gen2); + } + { + seed_seq_0 seed; + std::vector<boost::uint32_t> vec(624); + seed.generate(vec.begin(), vec.end()); + + std::vector<boost::uint32_t>::iterator it = vec.begin(); + boost::mt19937 gen1(it, vec.end()); + BOOST_CHECK_EQUAL(gen1(), 1141379330u); + BOOST_CHECK_EQUAL(gen1(), 0); + + boost::mt19937 gen2(seed); + BOOST_CHECK_EQUAL(gen2(), 1141379330u); + BOOST_CHECK_EQUAL(gen2(), 0); + + BOOST_CHECK_EQUAL(gen1, gen2); + } +} diff --git a/libs/random/test/test_mt19937_64.cpp b/libs/random/test/test_mt19937_64.cpp new file mode 100644 index 0000000000..bd3510dee9 --- /dev/null +++ b/libs/random/test/test_mt19937_64.cpp @@ -0,0 +1,26 @@ +/* test_mt119937_64.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_mt19937_64.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/mersenne_twister.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::mt19937_64 + +#define BOOST_RANDOM_SEED_WORDS 624 + +// validation from the C++0x draft (n3090) +#define BOOST_RANDOM_VALIDATION_VALUE UINT64_C(9981545732273789042) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(12176471137395770412) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(13543700832025962283) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xF6F6AEA6U, 0xC96D191CU, 0x8BC80F1CU, 0x401F7AC7U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_negative_binomial.cpp b/libs/random/test/test_negative_binomial.cpp new file mode 100644 index 0000000000..552916f7c9 --- /dev/null +++ b/libs/random/test/test_negative_binomial.cpp @@ -0,0 +1,30 @@ +/* test_negative_binomial.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_negative_binomial.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/negative_binomial_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/uniform_01.hpp> +#include <boost/math/distributions/negative_binomial.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::negative_binomial_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME negative_binomial +#define BOOST_MATH_DISTRIBUTION boost::math::negative_binomial +#define BOOST_RANDOM_ARG1_TYPE int +#define BOOST_RANDOM_ARG1_NAME n +#define BOOST_RANDOM_ARG1_DEFAULT 100000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_int<>(0, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME p +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_01<>() +#define BOOST_RANDOM_DISTRIBUTION_MAX n + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_negative_binomial_distribution.cpp b/libs/random/test/test_negative_binomial_distribution.cpp new file mode 100644 index 0000000000..8bf041db27 --- /dev/null +++ b/libs/random/test/test_negative_binomial_distribution.cpp @@ -0,0 +1,37 @@ +/* test_negative_binomial_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_negative_binomial_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/negative_binomial_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::negative_binomial_distribution<> +#define BOOST_RANDOM_ARG1 k +#define BOOST_RANDOM_ARG2 p +#define BOOST_RANDOM_ARG1_DEFAULT 1 +#define BOOST_RANDOM_ARG2_DEFAULT 0.5 +#define BOOST_RANDOM_ARG1_VALUE 10 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<int>::max)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<int>::max)() +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<int>::max)() + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0 +#define BOOST_RANDOM_TEST1_MAX 10 + +#define BOOST_RANDOM_TEST2_PARAMS (100, 0.5) +#define BOOST_RANDOM_TEST2_MIN 50 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_normal.cpp b/libs/random/test/test_normal.cpp new file mode 100644 index 0000000000..eab52a699a --- /dev/null +++ b/libs/random/test/test_normal.cpp @@ -0,0 +1,28 @@ +/* test_normal.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_normal.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/normal_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/normal.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::normal_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME normal +#define BOOST_MATH_DISTRIBUTION boost::math::normal +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME m +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(-n, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME s +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_normal_distribution.cpp b/libs/random/test/test_normal_distribution.cpp new file mode 100644 index 0000000000..ab3b683785 --- /dev/null +++ b/libs/random/test/test_normal_distribution.cpp @@ -0,0 +1,36 @@ +/* test_normal_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_normal_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/normal_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::normal_distribution<> +#define BOOST_RANDOM_ARG1 mean +#define BOOST_RANDOM_ARG2 sigma +#define BOOST_RANDOM_ARG1_DEFAULT 0.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS (-100.0) +#define BOOST_RANDOM_TEST1_MAX 0 + +#define BOOST_RANDOM_TEST2_PARAMS (100.0) +#define BOOST_RANDOM_TEST2_MIN 0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_old_uniform_int.cpp b/libs/random/test/test_old_uniform_int.cpp new file mode 100644 index 0000000000..7124238e88 --- /dev/null +++ b/libs/random/test/test_old_uniform_int.cpp @@ -0,0 +1,26 @@ +/* test_old_uniform_int.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_old_uniform_int.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_int.hpp> +#include <boost/math/distributions/uniform.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::uniform_int<> +#define BOOST_RANDOM_DISTRIBUTION_NAME uniform_int +#define BOOST_MATH_DISTRIBUTION boost::math::uniform +#define BOOST_RANDOM_ARG1_TYPE int +#define BOOST_RANDOM_ARG1_NAME b +#define BOOST_RANDOM_ARG1_DEFAULT 1000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_int<>(0, n) +#define BOOST_RANDOM_DISTRIBUTION_INIT (0, b) +#define BOOST_MATH_DISTRIBUTION_INIT (0, b+1) +#define BOOST_RANDOM_DISTRIBUTION_MAX b + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_old_uniform_int_distribution.cpp b/libs/random/test/test_old_uniform_int_distribution.cpp new file mode 100644 index 0000000000..27e630ffad --- /dev/null +++ b/libs/random/test/test_old_uniform_int_distribution.cpp @@ -0,0 +1,76 @@ +/* test_old_uniform_int_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_old_uniform_int_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_int.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::uniform_int<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 0 +#define BOOST_RANDOM_ARG2_DEFAULT 9 +#define BOOST_RANDOM_ARG1_VALUE 5 +#define BOOST_RANDOM_ARG2_VALUE 250 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX 9 +#define BOOST_RANDOM_DIST1_MIN 5 +#define BOOST_RANDOM_DIST1_MAX 9 +#define BOOST_RANDOM_DIST2_MIN 5 +#define BOOST_RANDOM_DIST2_MAX 250 + +#define BOOST_RANDOM_TEST1_PARAMS (0, 9) +#define BOOST_RANDOM_TEST1_MIN 0 +#define BOOST_RANDOM_TEST1_MAX 9 + +#define BOOST_RANDOM_TEST2_PARAMS (10, 19) +#define BOOST_RANDOM_TEST2_MIN 10 +#define BOOST_RANDOM_TEST2_MAX 19 + +#include "test_distribution.ipp" + +#define BOOST_RANDOM_UNIFORM_INT boost::uniform_int + +#include "test_uniform_int.ipp" + +#include <algorithm> +#include <boost/random/random_number_generator.hpp> + +// Test that uniform_int<> can be used with std::random_shuffle +// Author: Jos Hickson +BOOST_AUTO_TEST_CASE(test_random_shuffle) +{ + typedef boost::uniform_int<> distribution_type; + typedef boost::variate_generator<boost::mt19937 &, distribution_type> generator_type; + + boost::mt19937 engine1(1234); + boost::mt19937 engine2(1234); + + boost::random::random_number_generator<boost::mt19937> referenceRand(engine1); + + distribution_type dist(0,10); + generator_type testRand(engine2, dist); + + std::vector<int> referenceVec; + + for (int i = 0; i < 200; ++i) { + referenceVec.push_back(i); + } + + std::vector<int> testVec(referenceVec); + + std::random_shuffle(referenceVec.begin(), referenceVec.end(), referenceRand); + std::random_shuffle(testVec.begin(), testVec.end(), testRand); + + BOOST_CHECK_EQUAL_COLLECTIONS( + testVec.begin(), testVec.end(), + referenceVec.begin(), referenceVec.end()); +} diff --git a/libs/random/test/test_old_uniform_real.cpp b/libs/random/test/test_old_uniform_real.cpp new file mode 100644 index 0000000000..84e884b09c --- /dev/null +++ b/libs/random/test/test_old_uniform_real.cpp @@ -0,0 +1,25 @@ +/* test_old_uniform_real.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_old_uniform_real.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/uniform.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::uniform_real<> +#define BOOST_RANDOM_DISTRIBUTION_NAME uniform_real +#define BOOST_MATH_DISTRIBUTION boost::math::uniform +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME b +#define BOOST_RANDOM_ARG1_DEFAULT 1000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0, n) +#define BOOST_RANDOM_DISTRIBUTION_INIT (0, b) +#define BOOST_MATH_DISTRIBUTION_INIT (0, b) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_old_uniform_real_distribution.cpp b/libs/random/test/test_old_uniform_real_distribution.cpp new file mode 100644 index 0000000000..00ad48169a --- /dev/null +++ b/libs/random/test/test_old_uniform_real_distribution.cpp @@ -0,0 +1,38 @@ +/* test_old_uniform_real_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_old_uniform_real_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_real.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::uniform_real<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 0.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE -0.5 +#define BOOST_RANDOM_ARG2_VALUE 1.5 + +#define BOOST_RANDOM_DIST0_MIN 0.0 +#define BOOST_RANDOM_DIST0_MAX 1.0 +#define BOOST_RANDOM_DIST1_MIN -0.5 +#define BOOST_RANDOM_DIST1_MAX 1.0 +#define BOOST_RANDOM_DIST2_MIN -0.5 +#define BOOST_RANDOM_DIST2_MAX 1.5 + +#define BOOST_RANDOM_TEST1_PARAMS (-1.0, 0.0) +#define BOOST_RANDOM_TEST1_MIN -1.0 +#define BOOST_RANDOM_TEST1_MAX 0.0 + +#define BOOST_RANDOM_TEST2_PARAMS +#define BOOST_RANDOM_TEST2_MIN 0.0 +#define BOOST_RANDOM_TEST2_MAX 1.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_piecewise_constant.cpp b/libs/random/test/test_piecewise_constant.cpp new file mode 100644 index 0000000000..909470941b --- /dev/null +++ b/libs/random/test/test_piecewise_constant.cpp @@ -0,0 +1,158 @@ +/* test_piecewise_constant.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_piecewise_constant.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/piecewise_constant_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <boost/range/algorithm/lower_bound.hpp> +#include <boost/range/numeric.hpp> +#include <vector> +#include <iostream> +#include <iomanip> + +#include "statistic_tests.hpp" + +class piecewise_constant +{ +public: + piecewise_constant(const std::vector<double>& intervals, const std::vector<double>& weights) + : intervals(intervals), + cumulative(1, 0.0) + { + boost::partial_sum(weights, std::back_inserter(cumulative)); + for(std::vector<double>::iterator iter = cumulative.begin(), end = cumulative.end(); + iter != end; ++iter) + { + *iter /= cumulative.back(); + } + } + + double cdf(double x) const + { + std::size_t index = boost::lower_bound(intervals, x) - intervals.begin(); + if(index == 0) return 0; + else if(index == intervals.size()) return 1; + else { + double lower_weight = cumulative[index - 1]; + double upper_weight = cumulative[index]; + double lower = intervals[index - 1]; + double upper = intervals[index]; + return lower_weight + (x - lower) / (upper - lower) * (upper_weight - lower_weight); + } + } +private: + std::vector<double> intervals; + std::vector<double> cumulative; +}; + +double cdf(const piecewise_constant& dist, double x) +{ + return dist.cdf(x); +} + +bool do_test(int n, int max) { + std::cout << "running piecewise_constant(p0, p1, ..., p" << n-1 << ")" << " " << max << " times: " << std::flush; + + std::vector<double> weights; + { + boost::mt19937 egen; + for(int i = 0; i < n; ++i) { + weights.push_back(egen()); + } + } + std::vector<double> intervals; + for(int i = 0; i <= n; ++i) { + intervals.push_back(i); + } + + piecewise_constant expected(intervals, weights); + + boost::random::piecewise_constant_distribution<> dist(intervals, weights); + boost::mt19937 gen; + kolmogorov_experiment test(max); + boost::variate_generator<boost::mt19937&, boost::random::piecewise_constant_distribution<> > vgen(gen, dist); + + double prob = test.probability(test.run(vgen, expected)); + + bool result = prob < 0.99; + const char* err = result? "" : "*"; + std::cout << std::setprecision(17) << prob << err << std::endl; + + std::cout << std::setprecision(6); + + return result; +} + +bool do_tests(int repeat, int max_n, int trials) { + boost::mt19937 gen; + boost::uniform_int<> idist(1, max_n); + int errors = 0; + for(int i = 0; i < repeat; ++i) { + if(!do_test(idist(gen), trials)) { + ++errors; + } + } + if(errors != 0) { + std::cout << "*** " << errors << " errors detected ***" << std::endl; + } + return errors == 0; +} + +int usage() { + std::cerr << "Usage: test_piecewise_constant -r <repeat> -n <max n> -t <trials>" << std::endl; + return 2; +} + +template<class T> +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast<T>(argv[0]); + return true; + } else { + return false; + } +} + +int main(int argc, char** argv) { + int repeat = 10; + int max_n = 10; + int trials = 1000000; + + if(argc > 0) { + --argc; + ++argv; + } + while(argc > 0) { + if(argv[0][0] != '-') return usage(); + else if(!handle_option(argc, argv, 'r', repeat) + && !handle_option(argc, argv, 'n', max_n) + && !handle_option(argc, argv, 't', trials)) { + return usage(); + } + --argc; + ++argv; + } + + try { + if(do_tests(repeat, max_n, trials)) { + return 0; + } else { + return EXIT_FAILURE; + } + } catch(...) { + std::cerr << boost::current_exception_diagnostic_information() << std::endl; + return EXIT_FAILURE; + } +} diff --git a/libs/random/test/test_piecewise_constant_distribution.cpp b/libs/random/test/test_piecewise_constant_distribution.cpp new file mode 100644 index 0000000000..6d19a9b6f2 --- /dev/null +++ b/libs/random/test/test_piecewise_constant_distribution.cpp @@ -0,0 +1,246 @@ +/* test_piecewise_constant_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_piecewise_constant_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/piecewise_constant_distribution.hpp> +#include <boost/random/linear_congruential.hpp> +#include <boost/assign/list_of.hpp> +#include <sstream> +#include <vector> +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +using boost::random::test::RandomNumberDistribution; +using boost::random::piecewise_constant_distribution; +BOOST_CONCEPT_ASSERT((RandomNumberDistribution< piecewise_constant_distribution<> >)); + +struct gen { + double operator()(double arg) { + if(arg < 100) return 100; + else if(arg < 103) return 1; + else if(arg < 107) return 2; + else if(arg < 111) return 1; + else if(arg < 114) return 4; + else return 100; + } +}; + +#define CHECK_SEQUENCE(actual, expected) \ + do { \ + std::vector<double> _actual = (actual); \ + std::vector<double> _expected = (expected); \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + _actual.begin(), _actual.end(), \ + _expected.begin(), _expected.end()); \ + } while(false) + +using boost::assign::list_of; + +BOOST_AUTO_TEST_CASE(test_constructors) { + boost::random::piecewise_constant_distribution<> dist; + CHECK_SEQUENCE(dist.densities(), list_of(1.0)); + CHECK_SEQUENCE(dist.intervals(), list_of(0.0)(1.0)); + +#ifndef BOOST_NO_INITIALIZER_LISTS + boost::random::piecewise_constant_distribution<> dist_il = { + { 99, 103, 107, 111, 115 }, + gen() + }; + CHECK_SEQUENCE(dist_il.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(dist_il.densities(), list_of(.03125)(.0625)(.03125)(.125)); + + boost::random::piecewise_constant_distribution<> dist_il2 = { + { 99 }, + gen() + }; + CHECK_SEQUENCE(dist_il2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist_il2.densities(), list_of(1.0)); +#endif + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4); + std::vector<double> intervals2 = boost::assign::list_of(99); + std::vector<double> weights2; + + boost::random::piecewise_constant_distribution<> dist_r(intervals, weights); + CHECK_SEQUENCE(dist_r.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(dist_r.densities(), list_of(.125)(.25)(.125)(.25)); + + boost::random::piecewise_constant_distribution<> + dist_r2(intervals2, weights2); + CHECK_SEQUENCE(dist_r2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist_r2.densities(), list_of(1.0)); + + boost::random::piecewise_constant_distribution<> dist_it( + intervals.begin(), intervals.end(), weights.begin()); + CHECK_SEQUENCE(dist_it.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(dist_it.densities(), list_of(.125)(.25)(.125)(.25)); + + boost::random::piecewise_constant_distribution<> dist_it2( + intervals2.begin(), intervals2.end(), weights2.begin()); + CHECK_SEQUENCE(dist_it2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist_it2.densities(), list_of(1.0)); + + boost::random::piecewise_constant_distribution<> dist_fun(4, 99,115, gen()); + CHECK_SEQUENCE(dist_fun.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(dist_fun.densities(), list_of(.03125)(.0625)(.03125)(.125)); + + boost::random::piecewise_constant_distribution<> + dist_fun2(1, 99, 115, gen()); + CHECK_SEQUENCE(dist_fun2.intervals(), list_of(99)(115)); + CHECK_SEQUENCE(dist_fun2.densities(), list_of(0.0625)); + + boost::random::piecewise_constant_distribution<> copy(dist); + BOOST_CHECK_EQUAL(dist, copy); + boost::random::piecewise_constant_distribution<> copy_r(dist_r); + BOOST_CHECK_EQUAL(dist_r, copy_r); + + boost::random::piecewise_constant_distribution<> notpow2(3, 99, 111, gen()); + BOOST_REQUIRE_EQUAL(notpow2.densities().size(), 3u); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[0], 0.0625, 0.00000000001); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[1], 0.125, 0.00000000001); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[2], 0.0625, 0.00000000001); + boost::random::piecewise_constant_distribution<> copy_notpow2(notpow2); + BOOST_CHECK_EQUAL(notpow2, copy_notpow2); +} + +BOOST_AUTO_TEST_CASE(test_param) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4); + std::vector<double> intervals2 = boost::assign::list_of(0); + std::vector<double> weights2; + boost::random::piecewise_constant_distribution<> dist(intervals, weights); + boost::random::piecewise_constant_distribution<>::param_type + param = dist.param(); + CHECK_SEQUENCE(param.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(param.densities(), list_of(.125)(.25)(.125)(.25)); + boost::random::piecewise_constant_distribution<> copy1(param); + BOOST_CHECK_EQUAL(dist, copy1); + boost::random::piecewise_constant_distribution<> copy2; + copy2.param(param); + BOOST_CHECK_EQUAL(dist, copy2); + + boost::random::piecewise_constant_distribution<>::param_type + param_copy = param; + BOOST_CHECK_EQUAL(param, param_copy); + BOOST_CHECK(param == param_copy); + BOOST_CHECK(!(param != param_copy)); + boost::random::piecewise_constant_distribution<>::param_type param_default; + CHECK_SEQUENCE(param_default.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(param_default.densities(), list_of(1.0)); + BOOST_CHECK(param != param_default); + BOOST_CHECK(!(param == param_default)); + +#ifndef BOOST_NO_INITIALIZER_LISTS + boost::random::piecewise_constant_distribution<>::param_type parm_il = { + { 99, 103, 107, 111, 115 }, + gen() + }; + CHECK_SEQUENCE(parm_il.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(parm_il.densities(), list_of(.03125)(.0625)(.03125)(.125)); + + boost::random::piecewise_constant_distribution<>::param_type parm_il2 = { + { 99 }, + gen() + }; + CHECK_SEQUENCE(parm_il2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(parm_il2.densities(), list_of(1.0)); +#endif + + boost::random::piecewise_constant_distribution<>::param_type + parm_r(intervals, weights); + CHECK_SEQUENCE(parm_r.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(parm_r.densities(), list_of(.125)(.25)(.125)(.25)); + + boost::random::piecewise_constant_distribution<>::param_type + parm_r2(intervals2, weights2); + CHECK_SEQUENCE(parm_r2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(parm_r2.densities(), list_of(1.0)); + + boost::random::piecewise_constant_distribution<>::param_type + parm_it(intervals.begin(), intervals.end(), weights.begin()); + CHECK_SEQUENCE(parm_it.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(parm_it.densities(), list_of(.125)(.25)(.125)(.25)); + + boost::random::piecewise_constant_distribution<>::param_type + parm_it2(intervals2.begin(), intervals2.end(), weights2.begin()); + CHECK_SEQUENCE(parm_it2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(parm_it2.densities(), list_of(1.0)); + + boost::random::piecewise_constant_distribution<>::param_type + parm_fun(4, 99, 115, gen()); + CHECK_SEQUENCE(parm_fun.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(parm_fun.densities(), list_of(.03125)(.0625)(.03125)(.125)); + + boost::random::piecewise_constant_distribution<>::param_type + parm_fun2(1, 99, 115, gen()); + CHECK_SEQUENCE(parm_fun2.intervals(), list_of(99)(115)); + CHECK_SEQUENCE(parm_fun2.densities(), list_of(0.0625)); +} + +BOOST_AUTO_TEST_CASE(test_min_max) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4); + boost::random::piecewise_constant_distribution<> dist; + BOOST_CHECK_EQUAL((dist.min)(), 0.0); + BOOST_CHECK_EQUAL((dist.max)(), 1.0); + boost::random::piecewise_constant_distribution<> dist_r(intervals, weights); + BOOST_CHECK_EQUAL((dist_r.min)(), 0.0); + BOOST_CHECK_EQUAL((dist_r.max)(), 5.0); +} + +BOOST_AUTO_TEST_CASE(test_comparison) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4); + boost::random::piecewise_constant_distribution<> dist; + boost::random::piecewise_constant_distribution<> dist_copy(dist); + boost::random::piecewise_constant_distribution<> dist_r(intervals, weights); + boost::random::piecewise_constant_distribution<> dist_r_copy(dist_r); + BOOST_CHECK(dist == dist_copy); + BOOST_CHECK(!(dist != dist_copy)); + BOOST_CHECK(dist_r == dist_r_copy); + BOOST_CHECK(!(dist_r != dist_r_copy)); + BOOST_CHECK(dist != dist_r); + BOOST_CHECK(!(dist == dist_r)); +} + +BOOST_AUTO_TEST_CASE(test_streaming) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4); + boost::random::piecewise_constant_distribution<> dist(intervals, weights); + std::stringstream stream; + stream << dist; + boost::random::piecewise_constant_distribution<> restored_dist; + stream >> restored_dist; + BOOST_CHECK_EQUAL(dist, restored_dist); +} + +BOOST_AUTO_TEST_CASE(test_generation) { + std::vector<double> intervals = boost::assign::list_of(1)(2); + std::vector<double> weights = boost::assign::list_of(1); + boost::minstd_rand0 gen; + boost::random::piecewise_constant_distribution<> dist; + boost::random::piecewise_constant_distribution<> dist_r(intervals, weights); + for(int i = 0; i < 10; ++i) { + double value = dist(gen); + BOOST_CHECK_GE(value, 0.0); + BOOST_CHECK_LT(value, 1.0); + double value_r = dist_r(gen); + BOOST_CHECK_GE(value_r, 1.0); + BOOST_CHECK_LT(value_r, 2.0); + double value_param = dist_r(gen, dist.param()); + BOOST_CHECK_GE(value_param, 0.0); + BOOST_CHECK_LT(value_param, 1.0); + double value_r_param = dist(gen, dist_r.param()); + BOOST_CHECK_GE(value_r_param, 1.0); + BOOST_CHECK_LT(value_r_param, 2.0); + } +} diff --git a/libs/random/test/test_piecewise_linear.cpp b/libs/random/test/test_piecewise_linear.cpp new file mode 100644 index 0000000000..8a3589fb02 --- /dev/null +++ b/libs/random/test/test_piecewise_linear.cpp @@ -0,0 +1,175 @@ +/* test_piecewise_linear.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_piecewise_linear.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/piecewise_linear_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/variate_generator.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <boost/range/algorithm/lower_bound.hpp> +#include <boost/range/numeric.hpp> +#include <vector> +#include <iostream> +#include <iomanip> + +#include "statistic_tests.hpp" + +class piecewise_linear +{ +public: + piecewise_linear(const std::vector<double>& intervals, const std::vector<double>& weights) + : intervals(intervals), + weights(weights), + cumulative(1, 0.0) + { + for(std::size_t i = 0; i < weights.size() - 1; ++i) { + cumulative.push_back((weights[i] + weights[i + 1]) / 2); + } + boost::partial_sum(cumulative, cumulative.begin()); + double sum = cumulative.back(); + for(std::vector<double>::iterator iter = cumulative.begin(), end = cumulative.end(); + iter != end; ++iter) + { + *iter /= sum; + } + for(std::vector<double>::iterator iter = this->weights.begin(), end = this->weights.end(); + iter != end; ++iter) + { + *iter /= sum; + } + assert(this->weights.size() == this->intervals.size()); + assert(this->weights.size() == this->cumulative.size()); + } + + double cdf(double x) const + { + std::size_t index = boost::lower_bound(intervals, x) - intervals.begin(); + if(index == 0) return 0; + else if(index == intervals.size()) return 1; + else { + double start = cumulative[index - 1]; + double lower_weight = weights[index - 1]; + double upper_weight = weights[index]; + double lower = intervals[index - 1]; + double upper = intervals[index]; + double mid_weight = (lower_weight * (upper - x) + upper_weight * (x - lower)) / (upper - lower); + double segment_area = (x - lower) * (mid_weight + lower_weight) / 2; + return start + segment_area; + } + } +private: + std::vector<double> intervals; + std::vector<double> weights; + std::vector<double> cumulative; +}; + +double cdf(const piecewise_linear& dist, double x) +{ + return dist.cdf(x); +} + +bool do_test(int n, int max) { + std::cout << "running piecewise_linear(p0, p1, ..., p" << n-1 << ")" << " " << max << " times: " << std::flush; + + std::vector<double> weights; + { + boost::mt19937 egen; + for(int i = 0; i < n; ++i) { + weights.push_back(egen()); + } + } + std::vector<double> intervals; + for(int i = 0; i < n; ++i) { + intervals.push_back(i); + } + + piecewise_linear expected(intervals, weights); + + boost::random::piecewise_linear_distribution<> dist(intervals, weights); + boost::mt19937 gen; + kolmogorov_experiment test(max); + boost::variate_generator<boost::mt19937&, boost::random::piecewise_linear_distribution<> > vgen(gen, dist); + + double prob = test.probability(test.run(vgen, expected)); + + bool result = prob < 0.99; + const char* err = result? "" : "*"; + std::cout << std::setprecision(17) << prob << err << std::endl; + + std::cout << std::setprecision(6); + + return result; +} + +bool do_tests(int repeat, int max_n, int trials) { + boost::mt19937 gen; + boost::uniform_int<> idist(2, max_n); + int errors = 0; + for(int i = 0; i < repeat; ++i) { + if(!do_test(idist(gen), trials)) { + ++errors; + } + } + if(errors != 0) { + std::cout << "*** " << errors << " errors detected ***" << std::endl; + } + return errors == 0; +} + +int usage() { + std::cerr << "Usage: test_piecewise_linear -r <repeat> -n <max n> -t <trials>" << std::endl; + return 2; +} + +template<class T> +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast<T>(argv[0]); + return true; + } else { + return false; + } +} + +int main(int argc, char** argv) { + int repeat = 10; + int max_n = 10; + int trials = 1000000; + + if(argc > 0) { + --argc; + ++argv; + } + while(argc > 0) { + if(argv[0][0] != '-') return usage(); + else if(!handle_option(argc, argv, 'r', repeat) + && !handle_option(argc, argv, 'n', max_n) + && !handle_option(argc, argv, 't', trials)) { + return usage(); + } + --argc; + ++argv; + } + + try { + if(do_tests(repeat, max_n, trials)) { + return 0; + } else { + return EXIT_FAILURE; + } + } catch(...) { + std::cerr << boost::current_exception_diagnostic_information() << std::endl; + return EXIT_FAILURE; + } +} diff --git a/libs/random/test/test_piecewise_linear_distribution.cpp b/libs/random/test/test_piecewise_linear_distribution.cpp new file mode 100644 index 0000000000..7818c694ce --- /dev/null +++ b/libs/random/test/test_piecewise_linear_distribution.cpp @@ -0,0 +1,252 @@ +/* test_piecewise_linear_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_piecewise_linear_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/piecewise_linear_distribution.hpp> +#include <boost/random/linear_congruential.hpp> +#include <boost/assign/list_of.hpp> +#include <sstream> +#include <vector> +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +using boost::random::test::RandomNumberDistribution; +using boost::random::piecewise_linear_distribution; +BOOST_CONCEPT_ASSERT((RandomNumberDistribution< piecewise_linear_distribution<> >)); + +struct gen { + double operator()(double arg) { + if(arg < 97) return 100; + else if(arg < 101) return 3; + else if(arg < 105) return 1; + else if(arg < 109) return 2; + else if(arg < 113) return 1; + else if(arg < 117) return 5; + else return 100; + } +}; + +#define CHECK_SEQUENCE(actual, expected) \ + do { \ + std::vector<double> _actual = (actual); \ + std::vector<double> _expected = (expected); \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + _actual.begin(), _actual.end(), \ + _expected.begin(), _expected.end()); \ + } while(false) + +using boost::assign::list_of; + +BOOST_AUTO_TEST_CASE(test_constructors) { + boost::random::piecewise_linear_distribution<> dist; + CHECK_SEQUENCE(dist.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist.densities(), list_of(1.0)(1.0)); + +#ifndef BOOST_NO_INITIALIZER_LISTS + boost::random::piecewise_linear_distribution<> dist_il = { + { 99, 103, 107, 111, 115 }, + gen() + }; + CHECK_SEQUENCE(dist_il.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(dist_il.densities(), + list_of(.09375)(.03125)(0.0625)(.03125)(.15625)); + + boost::random::piecewise_linear_distribution<> dist_il2 = { + { 99 }, + gen() + }; + CHECK_SEQUENCE(dist_il2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist_il2.densities(), list_of(1.0)(1.0)); +#endif + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(3)(1)(2)(1)(2); + std::vector<double> intervals2 = boost::assign::list_of(99); + std::vector<double> weights2 = boost::assign::list_of(2); + + boost::random::piecewise_linear_distribution<> dist_r(intervals, weights); + CHECK_SEQUENCE(dist_r.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(dist_r.densities(), list_of(.375)(.125)(.25)(.125)(.25)); + + boost::random::piecewise_linear_distribution<> + dist_r2(intervals2, weights2); + CHECK_SEQUENCE(dist_r2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist_r2.densities(), list_of(1.0)(1.0)); + + boost::random::piecewise_linear_distribution<> dist_it( + intervals.begin(), intervals.end(), weights.begin()); + CHECK_SEQUENCE(dist_it.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(dist_it.densities(), list_of(.375)(.125)(.25)(.125)(.25)); + + boost::random::piecewise_linear_distribution<> dist_it2( + intervals2.begin(), intervals2.end(), weights2.begin()); + CHECK_SEQUENCE(dist_it2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(dist_it2.densities(), list_of(1.0)(1.0)); + + boost::random::piecewise_linear_distribution<> dist_fun(4, 99,115, gen()); + CHECK_SEQUENCE(dist_fun.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(dist_fun.densities(), + list_of(.09375)(.03125)(0.0625)(.03125)(.15625)); + + boost::random::piecewise_linear_distribution<> + dist_fun2(1, 99, 115, gen()); + CHECK_SEQUENCE(dist_fun2.intervals(), list_of(99)(115)); + CHECK_SEQUENCE(dist_fun2.densities(), list_of(0.046875)(0.078125)); + + boost::random::piecewise_linear_distribution<> copy(dist); + BOOST_CHECK_EQUAL(dist, copy); + boost::random::piecewise_linear_distribution<> copy_r(dist_r); + BOOST_CHECK_EQUAL(dist_r, copy_r); + + boost::random::piecewise_linear_distribution<> notpow2(3, 99, 111, gen()); + BOOST_REQUIRE_EQUAL(notpow2.densities().size(), 4u); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[0], 0.15, 1e-12); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[1], 0.05, 1e-12); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[2], 0.1, 1e-12); + BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[3], 0.05, 1e-12); + boost::random::piecewise_linear_distribution<> copy_notpow2(notpow2); + BOOST_CHECK_EQUAL(notpow2, copy_notpow2); +} + +BOOST_AUTO_TEST_CASE(test_param) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(3)(1)(2)(1)(2); + std::vector<double> intervals2 = boost::assign::list_of(99); + std::vector<double> weights2 = boost::assign::list_of(2); + boost::random::piecewise_linear_distribution<> dist(intervals, weights); + boost::random::piecewise_linear_distribution<>::param_type + param = dist.param(); + CHECK_SEQUENCE(param.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(param.densities(), list_of(.375)(.125)(.25)(.125)(.25)); + boost::random::piecewise_linear_distribution<> copy1(param); + BOOST_CHECK_EQUAL(dist, copy1); + boost::random::piecewise_linear_distribution<> copy2; + copy2.param(param); + BOOST_CHECK_EQUAL(dist, copy2); + + boost::random::piecewise_linear_distribution<>::param_type + param_copy = param; + BOOST_CHECK_EQUAL(param, param_copy); + BOOST_CHECK(param == param_copy); + BOOST_CHECK(!(param != param_copy)); + boost::random::piecewise_linear_distribution<>::param_type param_default; + CHECK_SEQUENCE(param_default.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(param_default.densities(), list_of(1.0)(1.0)); + BOOST_CHECK(param != param_default); + BOOST_CHECK(!(param == param_default)); + +#ifndef BOOST_NO_INITIALIZER_LISTS + boost::random::piecewise_linear_distribution<>::param_type parm_il = { + { 99, 103, 107, 111, 115 }, + gen() + }; + CHECK_SEQUENCE(parm_il.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(parm_il.densities(), + list_of(.09375)(.03125)(0.0625)(.03125)(.15625)); + + boost::random::piecewise_linear_distribution<>::param_type parm_il2 = { + { 99 }, + gen() + }; + CHECK_SEQUENCE(parm_il2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(parm_il2.densities(), list_of(1.0)(1.0)); +#endif + + boost::random::piecewise_linear_distribution<>::param_type + parm_r(intervals, weights); + CHECK_SEQUENCE(parm_r.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(parm_r.densities(), list_of(.375)(.125)(.25)(.125)(.25)); + + boost::random::piecewise_linear_distribution<>::param_type + parm_r2(intervals2, weights2); + CHECK_SEQUENCE(parm_r2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(parm_r2.densities(), list_of(1.0)(1.0)); + + boost::random::piecewise_linear_distribution<>::param_type + parm_it(intervals.begin(), intervals.end(), weights.begin()); + CHECK_SEQUENCE(parm_it.intervals(), list_of(0)(1)(2)(3)(5)); + CHECK_SEQUENCE(parm_it.densities(), list_of(.375)(.125)(.25)(.125)(.25)); + + boost::random::piecewise_linear_distribution<>::param_type + parm_it2(intervals2.begin(), intervals2.end(), weights2.begin()); + CHECK_SEQUENCE(parm_it2.intervals(), list_of(0.0)(1.0)); + CHECK_SEQUENCE(parm_it2.densities(), list_of(1.0)(1.0)); + + boost::random::piecewise_linear_distribution<>::param_type + parm_fun(4, 99, 115, gen()); + CHECK_SEQUENCE(parm_fun.intervals(), list_of(99)(103)(107)(111)(115)); + CHECK_SEQUENCE(parm_fun.densities(), + list_of(.09375)(.03125)(0.0625)(.03125)(.15625)); + + boost::random::piecewise_linear_distribution<>::param_type + parm_fun2(1, 99, 115, gen()); + CHECK_SEQUENCE(parm_fun2.intervals(), list_of(99)(115)); + CHECK_SEQUENCE(parm_fun2.densities(), list_of(0.046875)(0.078125)); +} + +BOOST_AUTO_TEST_CASE(test_min_max) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(3)(1)(2)(1)(2); + boost::random::piecewise_linear_distribution<> dist; + BOOST_CHECK_EQUAL((dist.min)(), 0.0); + BOOST_CHECK_EQUAL((dist.max)(), 1.0); + boost::random::piecewise_linear_distribution<> dist_r(intervals, weights); + BOOST_CHECK_EQUAL((dist_r.min)(), 0.0); + BOOST_CHECK_EQUAL((dist_r.max)(), 5.0); +} + +BOOST_AUTO_TEST_CASE(test_comparison) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(3)(1)(2)(1)(2); + boost::random::piecewise_linear_distribution<> dist; + boost::random::piecewise_linear_distribution<> dist_copy(dist); + boost::random::piecewise_linear_distribution<> dist_r(intervals, weights); + boost::random::piecewise_linear_distribution<> dist_r_copy(dist_r); + BOOST_CHECK(dist == dist_copy); + BOOST_CHECK(!(dist != dist_copy)); + BOOST_CHECK(dist_r == dist_r_copy); + BOOST_CHECK(!(dist_r != dist_r_copy)); + BOOST_CHECK(dist != dist_r); + BOOST_CHECK(!(dist == dist_r)); +} + +BOOST_AUTO_TEST_CASE(test_streaming) { + std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector<double> weights = boost::assign::list_of(3)(1)(2)(1)(2); + boost::random::piecewise_linear_distribution<> dist(intervals, weights); + std::stringstream stream; + stream << dist; + boost::random::piecewise_linear_distribution<> restored_dist; + stream >> restored_dist; + BOOST_CHECK_EQUAL(dist, restored_dist); +} + +BOOST_AUTO_TEST_CASE(test_generation) { + std::vector<double> intervals = boost::assign::list_of(1)(2); + std::vector<double> weights = boost::assign::list_of(1)(1); + boost::minstd_rand0 gen; + boost::random::piecewise_linear_distribution<> dist; + boost::random::piecewise_linear_distribution<> dist_r(intervals, weights); + for(int i = 0; i < 10; ++i) { + double value = dist(gen); + BOOST_CHECK_GE(value, 0.0); + BOOST_CHECK_LT(value, 1.0); + double value_r = dist_r(gen); + BOOST_CHECK_GE(value_r, 1.0); + BOOST_CHECK_LT(value_r, 2.0); + double value_param = dist_r(gen, dist.param()); + BOOST_CHECK_GE(value_param, 0.0); + BOOST_CHECK_LT(value_param, 1.0); + double value_r_param = dist(gen, dist_r.param()); + BOOST_CHECK_GE(value_r_param, 1.0); + BOOST_CHECK_LT(value_r_param, 2.0); + } +} diff --git a/libs/random/test/test_poisson.cpp b/libs/random/test/test_poisson.cpp new file mode 100644 index 0000000000..576d0c381c --- /dev/null +++ b/libs/random/test/test_poisson.cpp @@ -0,0 +1,25 @@ +/* test_poisson.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_poisson.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/poisson_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/poisson.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::poisson_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME poisson +#define BOOST_MATH_DISTRIBUTION boost::math::poisson +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME mean +#define BOOST_RANDOM_ARG1_DEFAULT 100000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(1e-15, n) +#define BOOST_RANDOM_DISTRIBUTION_MAX static_cast<int>(mean * 4) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_poisson_distribution.cpp b/libs/random/test/test_poisson_distribution.cpp new file mode 100644 index 0000000000..c8fd4421c9 --- /dev/null +++ b/libs/random/test/test_poisson_distribution.cpp @@ -0,0 +1,33 @@ +/* test_poisson_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_poisson_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/poisson_distribution.hpp> + +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::poisson_distribution<> +#define BOOST_RANDOM_ARG1 mean +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<int>::max)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<int>::max)() + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0.0 +#define BOOST_RANDOM_TEST1_MAX 10.0 + +#define BOOST_RANDOM_TEST2_PARAMS (1000.0) +#define BOOST_RANDOM_TEST2_MIN 10.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_rand48.cpp b/libs/random/test/test_rand48.cpp new file mode 100644 index 0000000000..19f4f2322e --- /dev/null +++ b/libs/random/test/test_rand48.cpp @@ -0,0 +1,26 @@ +/* test_rand48.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_rand48.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/linear_congruential.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::rand48 + +#define BOOST_RANDOM_SEED_WORDS 2 + +// by experiment from lrand48() +#define BOOST_RANDOM_VALIDATION_VALUE 1993516219U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 1286950069U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 839037874U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55424A4U, 0x3A2CCEF5U, 0x6ADB4A65U, 0x2B019719U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_random_device.cpp b/libs/random/test/test_random_device.cpp new file mode 100644 index 0000000000..f526cfa67b --- /dev/null +++ b/libs/random/test/test_random_device.cpp @@ -0,0 +1,29 @@ +/* boost random_test.cpp various tests + * + * Copyright (c) 2010 Steven Watanabe + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENCE_1_0.txt) + * + * $Id: test_random_device.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + */ + +#include <boost/random/random_device.hpp> + +#include <boost/test/test_tools.hpp> +#include <boost/test/included/test_exec_monitor.hpp> + +int test_main(int, char**) { + boost::random_device rng; + double entropy = rng.entropy(); + BOOST_CHECK_GE(entropy, 0); + for(int i = 0; i < 100; ++i) { + boost::random_device::result_type val = rng(); + BOOST_CHECK_GE(val, (rng.min)()); + BOOST_CHECK_LE(val, (rng.max)()); + } + + boost::uint32_t a[10]; + rng.generate(a, a + 10); + return 0; +} diff --git a/libs/random/test/test_random_number_generator.cpp b/libs/random/test/test_random_number_generator.cpp new file mode 100644 index 0000000000..f76c5f24dc --- /dev/null +++ b/libs/random/test/test_random_number_generator.cpp @@ -0,0 +1,33 @@ +/* boost test_random_number_generator.cpp + * + * Copyright Jens Maurer 2000 + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_random_number_generator.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + */ + +#include <boost/random/random_number_generator.hpp> +#include <boost/random/mersenne_twister.hpp> + +#include <algorithm> +#include <vector> + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE(test_random_shuffle) +{ + boost::mt19937 engine(1234); + boost::random::random_number_generator<boost::mt19937> generator(engine); + + std::vector<int> testVec; + + for (int i = 0; i < 200; ++i) { + testVec.push_back(i); + } + + std::random_shuffle(testVec.begin(), testVec.end(), generator); +} diff --git a/libs/random/test/test_ranlux24.cpp b/libs/random/test/test_ranlux24.cpp new file mode 100644 index 0000000000..587e55e511 --- /dev/null +++ b/libs/random/test/test_ranlux24.cpp @@ -0,0 +1,26 @@ +/* test_ranlux24.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux24.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux24 + +#define BOOST_RANDOM_SEED_WORDS 24 + +// validation from the C++0x draft (n3090) +#define BOOST_RANDOM_VALIDATION_VALUE 9901578U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 10086048U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3888733U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux24_base.cpp b/libs/random/test/test_ranlux24_base.cpp new file mode 100644 index 0000000000..c63c91e671 --- /dev/null +++ b/libs/random/test/test_ranlux24_base.cpp @@ -0,0 +1,25 @@ +/* test_ranlux24_base.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux24_base.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> + +#define BOOST_RANDOM_URNG boost::random::ranlux24_base + +#define BOOST_RANDOM_SEED_WORDS 24 + +// validation from the C++0x draft (n3126). +#define BOOST_RANDOM_VALIDATION_VALUE 7937952U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 14368281U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 7739608U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux3.cpp b/libs/random/test/test_ranlux3.cpp new file mode 100644 index 0000000000..3077e3db84 --- /dev/null +++ b/libs/random/test/test_ranlux3.cpp @@ -0,0 +1,25 @@ +/* test_ranlux3.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux3.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> + +#define BOOST_RANDOM_URNG boost::random::ranlux3 + +#define BOOST_RANDOM_SEED_WORDS 24 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE 5957620U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 11848780U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 11620328U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux3_01.cpp b/libs/random/test/test_ranlux3_01.cpp new file mode 100644 index 0000000000..b99d8bd985 --- /dev/null +++ b/libs/random/test/test_ranlux3_01.cpp @@ -0,0 +1,26 @@ +/* test_ranlux3_01.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux3_01.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux3_01 + +#define BOOST_RANDOM_SEED_WORDS 24 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE 5957620/std::pow(2.0f,24) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 11848780/std::pow(2.0f,24) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 11620328/std::pow(2.0f,24) + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux4.cpp b/libs/random/test/test_ranlux4.cpp new file mode 100644 index 0000000000..5367f3ff19 --- /dev/null +++ b/libs/random/test/test_ranlux4.cpp @@ -0,0 +1,25 @@ +/* test_ranlux4.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux4.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> + +#define BOOST_RANDOM_URNG boost::random::ranlux4 + +#define BOOST_RANDOM_SEED_WORDS 24 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE 8587295U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 10794046U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 4515722U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux48.cpp b/libs/random/test/test_ranlux48.cpp new file mode 100644 index 0000000000..f169782e8e --- /dev/null +++ b/libs/random/test/test_ranlux48.cpp @@ -0,0 +1,26 @@ +/* test_ranlux48.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux48.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::ranlux48 + +#define BOOST_RANDOM_SEED_WORDS 24 + +// validation from the C++0x draft (n3090) +#define BOOST_RANDOM_VALIDATION_VALUE UINT64_C(249142670248501) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(130319672235788) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(154356577406237) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xFCE57B2CU, 0xF2DF1555U, 0x1A0C0CD9U, 0x490109FAU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux48_base.cpp b/libs/random/test/test_ranlux48_base.cpp new file mode 100644 index 0000000000..055baa8f73 --- /dev/null +++ b/libs/random/test/test_ranlux48_base.cpp @@ -0,0 +1,26 @@ +/* test_ranlux48_base.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux48_base.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_RANDOM_URNG boost::random::ranlux48_base + +#define BOOST_RANDOM_SEED_WORDS 24 + +// validation from the C++0x draft (n3126). +#define BOOST_RANDOM_VALIDATION_VALUE UINT64_C(61839128582725) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(15556320400833) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(172853405006548) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xFCE57B2CU, 0xF2DF1555U, 0x1A0C0CD9U, 0x490109FAU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux4_01.cpp b/libs/random/test/test_ranlux4_01.cpp new file mode 100644 index 0000000000..153046bb96 --- /dev/null +++ b/libs/random/test/test_ranlux4_01.cpp @@ -0,0 +1,26 @@ +/* test_ranlux4_01.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux4_01.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux4_01 + +#define BOOST_RANDOM_SEED_WORDS 24 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE 8587295/std::pow(2.0f,24) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 10794046/std::pow(2.0f,24) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 4515722/std::pow(2.0f,24) + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux64_3.cpp b/libs/random/test/test_ranlux64_3.cpp new file mode 100644 index 0000000000..8feda0da65 --- /dev/null +++ b/libs/random/test/test_ranlux64_3.cpp @@ -0,0 +1,27 @@ +/* test_ranlux64_3.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux64_3.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <boost/cstdint.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux64_3 + +#define BOOST_RANDOM_SEED_WORDS 48 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE UINT64_C(141789170949364) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(85538657982635) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(101724473226966) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC35F616BU, 0xDC3C4DF1U, 0xF3F90D0AU, 0x206F9C9EU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux64_3_01.cpp b/libs/random/test/test_ranlux64_3_01.cpp new file mode 100644 index 0000000000..ce16037467 --- /dev/null +++ b/libs/random/test/test_ranlux64_3_01.cpp @@ -0,0 +1,26 @@ +/* test_ranlux64_3_01.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux64_3_01.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux64_3_01 + +#define BOOST_RANDOM_SEED_WORDS 48 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE INT64_C(141789170949364)/std::pow(2.0, 48) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(85538657982635)/std::pow(2.0, 48) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(101724473226966)/std::pow(2.0, 48) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC35F616BU, 0xDC3C4DF1U, 0xF3F90D0AU, 0x206F9C9EU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux64_4.cpp b/libs/random/test/test_ranlux64_4.cpp new file mode 100644 index 0000000000..cd0c51ed8b --- /dev/null +++ b/libs/random/test/test_ranlux64_4.cpp @@ -0,0 +1,27 @@ +/* test_ranlux64_4.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux64_4.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <boost/cstdint.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux64_4 + +#define BOOST_RANDOM_SEED_WORDS 48 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE UINT64_C(199461971133682) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(160535400540538) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(40074210927900) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC35F616BU, 0xDC3C4DF1U, 0xF3F90D0AU, 0x206F9C9EU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_ranlux64_4_01.cpp b/libs/random/test/test_ranlux64_4_01.cpp new file mode 100644 index 0000000000..d40088ef62 --- /dev/null +++ b/libs/random/test/test_ranlux64_4_01.cpp @@ -0,0 +1,26 @@ +/* test_ranlux64_4_01.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_ranlux64_4_01.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/ranlux.hpp> +#include <cmath> + +#define BOOST_RANDOM_URNG boost::random::ranlux64_4_01 + +#define BOOST_RANDOM_SEED_WORDS 48 + +// principal operation validated with CLHEP, values by experiment +#define BOOST_RANDOM_VALIDATION_VALUE INT64_C(199461971133682)/std::pow(2.0, 48) +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE UINT64_C(160535400540538)/std::pow(2.0, 48) +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE UINT64_C(40074210927900)/std::pow(2.0, 48) + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC35F616BU, 0xDC3C4DF1U, 0xF3F90D0AU, 0x206F9C9EU } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_real_distribution.ipp b/libs/random/test/test_real_distribution.ipp new file mode 100644 index 0000000000..acba625a71 --- /dev/null +++ b/libs/random/test/test_real_distribution.ipp @@ -0,0 +1,195 @@ +/* test_real_distribution.ipp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_real_distribution.ipp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#ifndef BOOST_MATH_DISTRIBUTION_INIT +#ifdef BOOST_RANDOM_ARG2_TYPE +#define BOOST_MATH_DISTRIBUTION_INIT (BOOST_RANDOM_ARG1_NAME, BOOST_RANDOM_ARG2_NAME) +#else +#define BOOST_MATH_DISTRIBUTION_INIT (BOOST_RANDOM_ARG1_NAME) +#endif +#endif + +#ifndef BOOST_RANDOM_DISTRIBUTION_INIT +#ifdef BOOST_RANDOM_ARG2_TYPE +#define BOOST_RANDOM_DISTRIBUTION_INIT (BOOST_RANDOM_ARG1_NAME, BOOST_RANDOM_ARG2_NAME) +#else +#define BOOST_RANDOM_DISTRIBUTION_INIT (BOOST_RANDOM_ARG1_NAME) +#endif +#endif + +#ifndef BOOST_RANDOM_P_CUTOFF +#define BOOST_RANDOM_P_CUTOFF 0.99 +#endif + +#include <boost/random/mersenne_twister.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/exception/diagnostic_information.hpp> +#include <boost/preprocessor/stringize.hpp> +#include <boost/range/numeric.hpp> +#include <boost/numeric/conversion/cast.hpp> +#include <iostream> +#include <vector> + +#include "statistic_tests.hpp" +#include "chi_squared_test.hpp" + +bool do_test(BOOST_RANDOM_ARG1_TYPE BOOST_RANDOM_ARG1_NAME, +#ifdef BOOST_RANDOM_ARG2_TYPE + BOOST_RANDOM_ARG2_TYPE BOOST_RANDOM_ARG2_NAME, +#endif + long long max, boost::mt19937& gen) { + std::cout << "running " BOOST_PP_STRINGIZE(BOOST_RANDOM_DISTRIBUTION_NAME) "(" + << BOOST_RANDOM_ARG1_NAME; +#ifdef BOOST_RANDOM_ARG2_NAME + std::cout << ", " << BOOST_RANDOM_ARG2_NAME; +#endif + std::cout << ")" << " " << max << " times: " << std::flush; + + BOOST_MATH_DISTRIBUTION expected BOOST_MATH_DISTRIBUTION_INIT; + + BOOST_RANDOM_DISTRIBUTION dist BOOST_RANDOM_DISTRIBUTION_INIT; + +#ifdef BOOST_RANDOM_DISTRIBUTION_MAX + + BOOST_RANDOM_DISTRIBUTION::result_type max_value = BOOST_RANDOM_DISTRIBUTION_MAX; + + std::vector<double> expected_pdf(max_value+1); + { + for(int i = 0; i <= max_value; ++i) { + expected_pdf[i] = pdf(expected, i); + } + expected_pdf.back() += 1 - boost::accumulate(expected_pdf, 0.0); + } + + std::vector<long long> results(max_value + 1); + for(long long i = 0; i < max; ++i) { + ++results[(std::min)(dist(gen), max_value)]; + } + + long long sum = boost::accumulate(results, 0ll); + if(sum != max) { + std::cout << "*** Failed: incorrect total: " << sum << " ***" << std::endl; + return false; + } + double prob = chi_squared_test(results, expected_pdf, max); + +#else + + kolmogorov_experiment test(boost::numeric_cast<int>(max)); + boost::variate_generator<boost::mt19937&, BOOST_RANDOM_DISTRIBUTION > vgen(gen, dist); + + double prob = test.probability(test.run(vgen, expected)); + +#endif + + bool result = prob < BOOST_RANDOM_P_CUTOFF; + const char* err = result? "" : "*"; + std::cout << std::setprecision(17) << prob << err << std::endl; + + std::cout << std::setprecision(6); + + return result; +} + +template<class Dist1 +#ifdef BOOST_RANDOM_ARG2_NAME + , class Dist2 +#endif +> +bool do_tests(int repeat, Dist1 d1, +#ifdef BOOST_RANDOM_ARG2_NAME + Dist2 d2, +#endif + long long trials) { + boost::mt19937 gen; + int errors = 0; + for(int i = 0; i < repeat; ++i) { + if(!do_test(d1(gen), +#ifdef BOOST_RANDOM_ARG2_NAME + d2(gen), +#endif + trials, gen)) { + ++errors; + } + } + if(errors != 0) { + std::cout << "*** " << errors << " errors detected ***" << std::endl; + } + return errors == 0; +} + +int usage() { + std::cerr << "Usage: test_" BOOST_PP_STRINGIZE(BOOST_RANDOM_DISTRIBUTION_NAME) + " -r <repeat>" + " -" BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG1_NAME) + " <max " BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG1_NAME) ">" +#ifdef BOOST_RANDOM_ARG2_NAME + " -" BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG2_NAME) + " <max " BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG2_NAME) ">" +#endif + " -t <trials>" << std::endl; + return 2; +} + +template<class T> +bool handle_option(int& argc, char**& argv, const char* opt, T& value) { + if(std::strcmp(argv[0], opt) == 0 && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast<T>(argv[0]); + return true; + } else { + return false; + } +} + +int main(int argc, char** argv) { + int repeat = 1; + BOOST_RANDOM_ARG1_TYPE max_arg1 = BOOST_RANDOM_ARG1_DEFAULT; +#ifdef BOOST_RANDOM_ARG2_TYPE + BOOST_RANDOM_ARG2_TYPE max_arg2 = BOOST_RANDOM_ARG2_DEFAULT; +#endif + long long trials = 100000; + + if(argc > 0) { + --argc; + ++argv; + } + while(argc > 0) { + if(argv[0][0] != '-') return usage(); + else if(!handle_option(argc, argv, "-r", repeat) + && !handle_option(argc, argv, "-" BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG1_NAME), max_arg1) +#ifdef BOOST_RANDOM_ARG2_TYPE + && !handle_option(argc, argv, "-" BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG2_NAME), max_arg2) +#endif + && !handle_option(argc, argv, "-t", trials)) { + return usage(); + } + --argc; + ++argv; + } + + try { + if(do_tests(repeat, + BOOST_RANDOM_ARG1_DISTRIBUTION(max_arg1), +#ifdef BOOST_RANDOM_ARG2_TYPE + BOOST_RANDOM_ARG2_DISTRIBUTION(max_arg2), +#endif + trials)) { + return 0; + } else { + return EXIT_FAILURE; + } + } catch(...) { + std::cerr << boost::current_exception_diagnostic_information() << std::endl; + return EXIT_FAILURE; + } +} diff --git a/libs/random/test/test_seed_seq.cpp b/libs/random/test/test_seed_seq.cpp new file mode 100644 index 0000000000..c14593062f --- /dev/null +++ b/libs/random/test/test_seed_seq.cpp @@ -0,0 +1,113 @@ +/* boost test_seed_seq.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_seed_seq.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + */ + +#include <boost/random/seed_seq.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/config.hpp> +#include <vector> + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +using boost::assign::list_of; + +BOOST_AUTO_TEST_CASE(test_seed_seq) { + boost::uint32_t expected_param[4] = { 2, 3, 4, 0xdeadbeaf }; + boost::uint32_t param[4] = { 2, 3, 4, 0xdeadbeaf }; + boost::uint32_t store32[10]; + boost::uint64_t store64[10]; + boost::uint32_t expected[10] = { + 3155793538u, + 2047427591u, + 2886057794u, + 280666868u, + 2184015838u, + 4035763234u, + 808987374u, + 3177165994u, + 2993445429u, + 3110180644u + }; + std::fill_n(&store32[0], 10, 0); + std::fill_n(&store64[0], 10, 0); + boost::random::seed_seq seq; + seq.generate(&store32[0], &store32[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store32[0], &store32[0] + 10, &expected[0], &expected[0] + 10); + seq.generate(&store64[0], &store64[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store64[0], &store64[0] + 10, &expected[0], &expected[0] + 10); + BOOST_CHECK_EQUAL(seq.size(), 0u); + seq.param(¶m[0]); + BOOST_CHECK_EQUAL_COLLECTIONS( + ¶m[0], ¶m[0] + 4, &expected_param[0], &expected_param[0] + 4); + + boost::uint32_t expected_r[10] = { + 2681148375u, + 3302224839u, + 249244011u, + 1549723892u, + 3429166360u, + 2812310274u, + 3902694127u, + 1014283089u, + 1122383019u, + 494552679u + }; + + std::vector<int> data = list_of(2)(3)(4); + + std::fill_n(&store32[0], 10, 0); + std::fill_n(&store64[0], 10, 0); + std::fill_n(¶m[0], 3, 0); + boost::random::seed_seq seq_r(data); + seq_r.generate(&store32[0], &store32[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store32[0], &store32[0] + 10, &expected_r[0], &expected_r[0] + 10); + seq_r.generate(&store64[0], &store64[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store64[0], &store64[0] + 10, &expected_r[0], &expected_r[0] + 10); + BOOST_CHECK_EQUAL(seq_r.size(), 3u); + seq_r.param(¶m[0]); + BOOST_CHECK_EQUAL_COLLECTIONS( + ¶m[0], ¶m[0] + 4, &expected_param[0], &expected_param[0] + 4); + + std::fill_n(&store32[0], 10, 0); + std::fill_n(&store64[0], 10, 0); + std::fill_n(¶m[0], 3, 0); + boost::random::seed_seq seq_it(data.begin(), data.end()); + seq_it.generate(&store32[0], &store32[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store32[0], &store32[0] + 10, &expected_r[0], &expected_r[0] + 10); + seq_it.generate(&store64[0], &store64[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store64[0], &store64[0] + 10, &expected_r[0], &expected_r[0] + 10); + BOOST_CHECK_EQUAL(seq_it.size(), 3u); + seq_it.param(¶m[0]); + BOOST_CHECK_EQUAL_COLLECTIONS( + ¶m[0], ¶m[0] + 4, &expected_param[0], &expected_param[0] + 4); + +#ifndef BOOST_NO_INITIALIZER_LISTS + std::fill_n(&store32[0], 10, 0); + std::fill_n(&store64[0], 10, 0); + std::fill_n(¶m[0], 3, 0); + boost::random::seed_seq seq_il = {2, 3, 4}; + seq_il.generate(&store32[0], &store32[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store32[0], &store32[0] + 10, &expected_r[0], &expected_r[0] + 10); + seq_il.generate(&store64[0], &store64[0] + 10); + BOOST_CHECK_EQUAL_COLLECTIONS( + &store64[0], &store64[0] + 10, &expected_r[0], &expected_r[0] + 10); + BOOST_CHECK_EQUAL(seq_il.size(), 3u); + seq_il.param(¶m[0]); + BOOST_CHECK_EQUAL_COLLECTIONS( + ¶m[0], ¶m[0] + 4, &expected_param[0], &expected_param[0] + 4); +#endif +} diff --git a/libs/random/test/test_student_t.cpp b/libs/random/test/test_student_t.cpp new file mode 100644 index 0000000000..09385257bb --- /dev/null +++ b/libs/random/test/test_student_t.cpp @@ -0,0 +1,24 @@ +/* test_student_t.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_student_t.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/student_t_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/students_t.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::student_t_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME student_t +#define BOOST_MATH_DISTRIBUTION boost::math::students_t +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME n +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_student_t_distribution.cpp b/libs/random/test/test_student_t_distribution.cpp new file mode 100644 index 0000000000..7ab6437d10 --- /dev/null +++ b/libs/random/test/test_student_t_distribution.cpp @@ -0,0 +1,29 @@ +/* test_student_t_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_student_t_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/student_t_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::student_t_distribution<> +#define BOOST_RANDOM_ARG1 n +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 + +#define BOOST_RANDOM_DIST0_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS + +#define BOOST_RANDOM_TEST2_PARAMS (100.0) + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_taus88.cpp b/libs/random/test/test_taus88.cpp new file mode 100644 index 0000000000..b7f3258f82 --- /dev/null +++ b/libs/random/test/test_taus88.cpp @@ -0,0 +1,24 @@ +/* test_taus88.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_taus88.cpp 74867 2011-10-09 23:13:31Z steven_watanabe $ + * + */ + +#include <boost/random/taus88.hpp> + +#define BOOST_RANDOM_URNG boost::random::taus88 + +#define BOOST_RANDOM_SEED_WORDS 3 + +#define BOOST_RANDOM_VALIDATION_VALUE 3535848941U +#define BOOST_RANDOM_SEED_SEQ_VALIDATION_VALUE 2562639222U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3762466828U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x2B55504U, 0x5403F102U, 0xED45297EU, 0x6B84007U } + +#include "test_generator.ipp" diff --git a/libs/random/test/test_triangle.cpp b/libs/random/test/test_triangle.cpp new file mode 100644 index 0000000000..04d0b6dda6 --- /dev/null +++ b/libs/random/test/test_triangle.cpp @@ -0,0 +1,26 @@ +/* test_triangle.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_triangle.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/triangle_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/triangular.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::triangle_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME lognormal +#define BOOST_MATH_DISTRIBUTION boost::math::triangular +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME b +#define BOOST_RANDOM_ARG1_DEFAULT 0.5 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.0001, 0.9999) +#define BOOST_RANDOM_DISTRIBUTION_INIT (0.0, b, 1.0) +#define BOOST_MATH_DISTRIBUTION_INIT (0.0, b, 1.0) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_triangle_distribution.cpp b/libs/random/test/test_triangle_distribution.cpp new file mode 100644 index 0000000000..6f745357c4 --- /dev/null +++ b/libs/random/test/test_triangle_distribution.cpp @@ -0,0 +1,41 @@ +/* test_triangle_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_triangle_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/triangle_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::triangle_distribution<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG3 c +#define BOOST_RANDOM_ARG1_DEFAULT 0.0 +#define BOOST_RANDOM_ARG2_DEFAULT 0.5 +#define BOOST_RANDOM_ARG3_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE -0.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 +#define BOOST_RANDOM_ARG3_VALUE 1.5 + +#define BOOST_RANDOM_DIST0_MIN 0.0 +#define BOOST_RANDOM_DIST0_MAX 1.0 +#define BOOST_RANDOM_DIST1_MIN -0.5 +#define BOOST_RANDOM_DIST1_MAX 1.0 +#define BOOST_RANDOM_DIST2_MIN -0.5 +#define BOOST_RANDOM_DIST2_MAX 1.0 +#define BOOST_RANDOM_DIST3_MIN -0.5 +#define BOOST_RANDOM_DIST3_MAX 1.5 + +#define BOOST_RANDOM_TEST1_PARAMS (-1, -0.5, 0) +#define BOOST_RANDOM_TEST1_MAX 0 + +#define BOOST_RANDOM_TEST2_PARAMS (0, 0.5, 1) +#define BOOST_RANDOM_TEST2_MIN 0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_uniform_int.cpp b/libs/random/test/test_uniform_int.cpp new file mode 100644 index 0000000000..6b270fdce8 --- /dev/null +++ b/libs/random/test/test_uniform_int.cpp @@ -0,0 +1,27 @@ +/* test_uniform_int.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_int.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_int_distribution.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/math/distributions/uniform.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_int_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME uniform_int +#define BOOST_MATH_DISTRIBUTION boost::math::uniform +#define BOOST_RANDOM_ARG1_TYPE int +#define BOOST_RANDOM_ARG1_NAME b +#define BOOST_RANDOM_ARG1_DEFAULT 1000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_int<>(0, n) +#define BOOST_RANDOM_DISTRIBUTION_INIT (0, b) +#define BOOST_MATH_DISTRIBUTION_INIT (0, b+1) +#define BOOST_RANDOM_DISTRIBUTION_MAX b + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_uniform_int.ipp b/libs/random/test/test_uniform_int.ipp new file mode 100644 index 0000000000..bb84c0f6a5 --- /dev/null +++ b/libs/random/test/test_uniform_int.ipp @@ -0,0 +1,149 @@ +/* boost test_uniform_int.ipp + * + * Copyright Jens Maurer 2000 + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_int.ipp 71018 2011-04-05 21:27:52Z steven_watanabe $ + */ + +#include <numeric> +#include <sstream> +#include <vector> +#include <boost/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/limits.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/linear_congruential.hpp> +#include <boost/random/lagged_fibonacci.hpp> +#include <boost/random/variate_generator.hpp> +#include "chi_squared_test.hpp" + +#define BOOST_TEST_MAIN +#include <boost/test/unit_test.hpp> + +template<class Generator> +void check_uniform_int(Generator & gen, int iter) +{ + int range = (gen.max)()-(gen.min)()+1; + std::vector<int> bucket(range); + for(int j = 0; j < iter; j++) { + int result = gen(); + BOOST_CHECK_GE(result, (gen.min)()); + BOOST_CHECK_LE(result, (gen.max)()); + if(result >= (gen.min)() && result <= (gen.max)()) { + bucket[result-(gen.min)()]++; + } + } + int sum = std::accumulate(bucket.begin(), bucket.end(), 0); + std::vector<double> expected(range, 1.0 / range); + BOOST_CHECK_LT(chi_squared_test(bucket, expected, sum), 0.99); +} + +BOOST_AUTO_TEST_CASE(test_uniform_int) +{ + boost::random::mt19937 gen; + typedef BOOST_RANDOM_UNIFORM_INT<int> int_gen; + + // large range => small range (modulo case) + typedef boost::random::variate_generator<boost::random::mt19937&, int_gen> level_one; + + level_one uint12(gen, int_gen(1,2)); + BOOST_CHECK((uint12.distribution().min)() == 1); + BOOST_CHECK((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::random::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); + + // small range => larger range + level_two uint099(uint12, int_gen(0, 99)); + check_uniform_int(uint099, 100000); + + // larger => small range, rejection case + typedef boost::random::variate_generator<level_two&, int_gen> level_three; + level_three uint1_4(uint05, int_gen(1, 4)); + check_uniform_int(uint1_4, 100000); + + typedef BOOST_RANDOM_UNIFORM_INT<boost::uint8_t> int8_gen; + typedef boost::random::variate_generator<boost::random::mt19937&, int8_gen> gen8_t; + + gen8_t gen8_03(gen, int8_gen(0, 3)); + + // use the full range of the type, where the destination + // range is a power of the source range + typedef boost::random::variate_generator<gen8_t, int8_gen> uniform_uint8; + uniform_uint8 uint8_0255(gen8_03, int8_gen(0, 255)); + check_uniform_int(uint8_0255, 100000); + + // use the full range, but a generator whose range is not + // a root of the destination range. + gen8_t gen8_02(gen, int8_gen(0, 2)); + uniform_uint8 uint8_0255_2(gen8_02, int8_gen(0, 255)); + check_uniform_int(uint8_0255_2, 100000); + + // expand the range to a larger type. + typedef boost::random::variate_generator<gen8_t, int_gen> uniform_uint_from8; + uniform_uint_from8 uint0300(gen8_03, int_gen(0, 300)); + check_uniform_int(uint0300, 100000); +} + +#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) + +// testcase by Mario Rutti +class ruetti_gen +{ +public: + ruetti_gen() : state((max)() - 1) {} + 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 BOOST_PREVENT_MACRO_SUBSTITUTION (); } + result_type operator()() { return state--; } +private: + result_type state; +}; + +BOOST_AUTO_TEST_CASE(test_overflow_range) +{ + ruetti_gen gen; + BOOST_RANDOM_DISTRIBUTION dist(0, 10); + for (int i=0;i<10;i++) { + dist(gen); + } +} + +#endif + +BOOST_AUTO_TEST_CASE(test_misc) +{ + // bug report from Ken Mahler: This used to lead to an endless loop. + typedef BOOST_RANDOM_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_RANDOM_DISTRIBUTION > x(mr, BOOST_RANDOM_DISTRIBUTION(0, 8361)); + x(); + + // bug report from Alan Stokes and others: this throws an assertion + boost::variate_generator<boost::minstd_rand, BOOST_RANDOM_DISTRIBUTION > y(mr, BOOST_RANDOM_DISTRIBUTION(1,1)); + y(); + y(); + y(); +} diff --git a/libs/random/test/test_uniform_int_distribution.cpp b/libs/random/test/test_uniform_int_distribution.cpp new file mode 100644 index 0000000000..35a345538a --- /dev/null +++ b/libs/random/test/test_uniform_int_distribution.cpp @@ -0,0 +1,42 @@ +/* test_uniform_int_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_int_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_int_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_int_distribution<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 0 +#define BOOST_RANDOM_ARG2_DEFAULT 0x7fffffff +#define BOOST_RANDOM_ARG1_VALUE 100 +#define BOOST_RANDOM_ARG2_VALUE 250 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX 0x7fffffff +#define BOOST_RANDOM_DIST1_MIN 100 +#define BOOST_RANDOM_DIST1_MAX 0x7fffffff +#define BOOST_RANDOM_DIST2_MIN 100 +#define BOOST_RANDOM_DIST2_MAX 250 + +#define BOOST_RANDOM_TEST1_PARAMS (0, 9) +#define BOOST_RANDOM_TEST1_MIN 0 +#define BOOST_RANDOM_TEST1_MAX 9 + +#define BOOST_RANDOM_TEST2_PARAMS (10, 19) +#define BOOST_RANDOM_TEST2_MIN 10 +#define BOOST_RANDOM_TEST2_MAX 19 + +#include "test_distribution.ipp" + +#define BOOST_RANDOM_UNIFORM_INT boost::random::uniform_int_distribution + +#include "test_uniform_int.ipp" diff --git a/libs/random/test/test_uniform_on_sphere_distribution.cpp b/libs/random/test/test_uniform_on_sphere_distribution.cpp new file mode 100644 index 0000000000..4682de636b --- /dev/null +++ b/libs/random/test/test_uniform_on_sphere_distribution.cpp @@ -0,0 +1,43 @@ +/* test_uniform_on_sphere_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_on_sphere_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_on_sphere.hpp> +#include <boost/assign/list_of.hpp> + +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_on_sphere<> +#define BOOST_RANDOM_ARG1 dim +#define BOOST_RANDOM_ARG1_DEFAULT 2 +#define BOOST_RANDOM_ARG1_VALUE 3 + +std::vector<double> min0 = boost::assign::list_of(-1.0)(0.0); +std::vector<double> max0 = boost::assign::list_of(1.0)(0.0); +std::vector<double> min1 = boost::assign::list_of(-1.0)(0.0)(0.0); +std::vector<double> max1 = boost::assign::list_of(1.0)(0.0)(0.0); + +#define BOOST_RANDOM_DIST0_MIN min0 +#define BOOST_RANDOM_DIST0_MAX max0 +#define BOOST_RANDOM_DIST1_MIN min1 +#define BOOST_RANDOM_DIST1_MAX max1 + +#define BOOST_RANDOM_TEST1_PARAMS (0) +#define BOOST_RANDOM_TEST1_MIN std::vector<double>() +#define BOOST_RANDOM_TEST1_MAX std::vector<double>() +#define BOOST_RANDOM_TEST2_PARAMS +#define BOOST_RANDOM_TEST2_MIN min0 +#define BOOST_RANDOM_TEST2_MAX max0 + +#include <boost/test/test_tools.hpp> + +BOOST_TEST_DONT_PRINT_LOG_VALUE( std::vector<double> ) + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_uniform_real.cpp b/libs/random/test/test_uniform_real.cpp new file mode 100644 index 0000000000..71ac6625aa --- /dev/null +++ b/libs/random/test/test_uniform_real.cpp @@ -0,0 +1,26 @@ +/* test_uniform_real.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_real.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_real_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/uniform.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_real_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME uniform_int +#define BOOST_MATH_DISTRIBUTION boost::math::uniform +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME b +#define BOOST_RANDOM_ARG1_DEFAULT 1000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0, n) +#define BOOST_RANDOM_DISTRIBUTION_INIT (0, b) +#define BOOST_MATH_DISTRIBUTION_INIT (0, b) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_uniform_real_distribution.cpp b/libs/random/test/test_uniform_real_distribution.cpp new file mode 100644 index 0000000000..47312bafac --- /dev/null +++ b/libs/random/test/test_uniform_real_distribution.cpp @@ -0,0 +1,38 @@ +/* test_uniform_real_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_real_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_real_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_real_distribution<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 0.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE -0.5 +#define BOOST_RANDOM_ARG2_VALUE 1.5 + +#define BOOST_RANDOM_DIST0_MIN 0.0 +#define BOOST_RANDOM_DIST0_MAX 1.0 +#define BOOST_RANDOM_DIST1_MIN -0.5 +#define BOOST_RANDOM_DIST1_MAX 1.0 +#define BOOST_RANDOM_DIST2_MIN -0.5 +#define BOOST_RANDOM_DIST2_MAX 1.5 + +#define BOOST_RANDOM_TEST1_PARAMS (-1.0, 0.0) +#define BOOST_RANDOM_TEST1_MIN -1.0 +#define BOOST_RANDOM_TEST1_MAX 0.0 + +#define BOOST_RANDOM_TEST2_PARAMS +#define BOOST_RANDOM_TEST2_MIN 0.0 +#define BOOST_RANDOM_TEST2_MAX 1.0 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_uniform_smallint.cpp b/libs/random/test/test_uniform_smallint.cpp new file mode 100644 index 0000000000..d855f0906c --- /dev/null +++ b/libs/random/test/test_uniform_smallint.cpp @@ -0,0 +1,27 @@ +/* test_uniform_smallint.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_smallint.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_smallint.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/math/distributions/uniform.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_smallint<> +#define BOOST_RANDOM_DISTRIBUTION_NAME uniform_int +#define BOOST_MATH_DISTRIBUTION boost::math::uniform +#define BOOST_RANDOM_ARG1_TYPE int +#define BOOST_RANDOM_ARG1_NAME b +#define BOOST_RANDOM_ARG1_DEFAULT 1000 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_int<>(0, n) +#define BOOST_RANDOM_DISTRIBUTION_INIT (0, b) +#define BOOST_MATH_DISTRIBUTION_INIT (0, b+1) +#define BOOST_RANDOM_DISTRIBUTION_MAX b + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_uniform_smallint_distribution.cpp b/libs/random/test/test_uniform_smallint_distribution.cpp new file mode 100644 index 0000000000..e20cf4ece3 --- /dev/null +++ b/libs/random/test/test_uniform_smallint_distribution.cpp @@ -0,0 +1,38 @@ +/* test_uniform_smallint_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_uniform_smallint_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/uniform_smallint.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_smallint<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 0 +#define BOOST_RANDOM_ARG2_DEFAULT 9 +#define BOOST_RANDOM_ARG1_VALUE 5 +#define BOOST_RANDOM_ARG2_VALUE 250 + +#define BOOST_RANDOM_DIST0_MIN 0 +#define BOOST_RANDOM_DIST0_MAX 9 +#define BOOST_RANDOM_DIST1_MIN 5 +#define BOOST_RANDOM_DIST1_MAX 9 +#define BOOST_RANDOM_DIST2_MIN 5 +#define BOOST_RANDOM_DIST2_MAX 250 + +#define BOOST_RANDOM_TEST1_PARAMS (0, 9) +#define BOOST_RANDOM_TEST1_MIN 0 +#define BOOST_RANDOM_TEST1_MAX 9 + +#define BOOST_RANDOM_TEST2_PARAMS (10, 19) +#define BOOST_RANDOM_TEST2_MIN 10 +#define BOOST_RANDOM_TEST2_MAX 19 + +#include "test_distribution.ipp" diff --git a/libs/random/test/test_weibull.cpp b/libs/random/test/test_weibull.cpp new file mode 100644 index 0000000000..5fbb616dea --- /dev/null +++ b/libs/random/test/test_weibull.cpp @@ -0,0 +1,28 @@ +/* test_weibull.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_weibull.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ + +#include <boost/random/weibull_distribution.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/math/distributions/weibull.hpp> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::weibull_distribution<> +#define BOOST_RANDOM_DISTRIBUTION_NAME weibull +#define BOOST_MATH_DISTRIBUTION boost::math::weibull +#define BOOST_RANDOM_ARG1_TYPE double +#define BOOST_RANDOM_ARG1_NAME a +#define BOOST_RANDOM_ARG1_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG1_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) +#define BOOST_RANDOM_ARG2_TYPE double +#define BOOST_RANDOM_ARG2_NAME b +#define BOOST_RANDOM_ARG2_DEFAULT 1000.0 +#define BOOST_RANDOM_ARG2_DISTRIBUTION(n) boost::uniform_real<>(0.00001, n) + +#include "test_real_distribution.ipp" diff --git a/libs/random/test/test_weibull_distribution.cpp b/libs/random/test/test_weibull_distribution.cpp new file mode 100644 index 0000000000..0465e02ad4 --- /dev/null +++ b/libs/random/test/test_weibull_distribution.cpp @@ -0,0 +1,36 @@ +/* test_weibull_distribution.cpp + * + * Copyright Steven Watanabe 2010 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id: test_weibull_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $ + * + */ +#include <boost/random/weibull_distribution.hpp> +#include <limits> + +#define BOOST_RANDOM_DISTRIBUTION boost::random::weibull_distribution<> +#define BOOST_RANDOM_ARG1 a +#define BOOST_RANDOM_ARG2 b +#define BOOST_RANDOM_ARG1_DEFAULT 1.0 +#define BOOST_RANDOM_ARG2_DEFAULT 1.0 +#define BOOST_RANDOM_ARG1_VALUE 7.5 +#define BOOST_RANDOM_ARG2_VALUE 0.25 + +#define BOOST_RANDOM_DIST0_MIN 0.0 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0.0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<double>::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0.0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits<double>::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS +#define BOOST_RANDOM_TEST1_MIN 0.0 +#define BOOST_RANDOM_TEST1_MAX 100.0 + +#define BOOST_RANDOM_TEST2_PARAMS (1.0, 1000000.0) +#define BOOST_RANDOM_TEST2_MIN 100.0 + +#include "test_distribution.ipp" |