diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 6b8a592..a5db8b7 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -9,7 +9,7 @@ using quickbook ; using doxygen ; -import boostbook ; +using boostbook ; import regex ; import os ; import path ; @@ -19,29 +19,43 @@ doxygen_files = 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 - shuffle_output + seed_seq + shuffle_order + # shuffle_output + student_t_distribution subtract_with_carry + taus88 triangle_distribution uniform_01 - uniform_int + uniform_int_distribution uniform_on_sphere - uniform_real + uniform_real_distribution uniform_smallint variate_generator + weibull_distribution xor_combine ; @@ -58,13 +72,14 @@ local BOOST_ROOT = [ path.relative-to doxygen reference : $(here)/../../../boost/random/$(doxygen_files).hpp - $(here)/../../../boost/nondet_random.hpp $(here)/../../../boost/random.hpp : EXPAND_ONLY_PREDEF=YES "ALIASES= \\ xmlnote=\"@xmlonly @endxmlonly\" \\ endxmlnote=\"@xmlonly @endxmlonly\" \\ + xmlwarning=\"@xmlonly @endxmlonly\" \\ + endxmlwarning=\"@xmlonly @endxmlonly\" \\ blockquote=\"@xmlonly
@endxmlonly\" \\ endblockquote=\"@xmlonly
@endxmlonly\" \\ boost=\"$(BOOST_ROOT)\" \\ @@ -72,25 +87,25 @@ doxygen reference : pseudo_random_number_generator=\"@xmlonly pseudo-random number generator @endxmlonly\" \\ uniform_random_number_generator=\"@xmlonly uniform random number generator @endxmlonly\" \\ nondeterministic_random_number_generator=\"@xmlonly non-deterministic random number generator @endxmlonly\" \\ - number_generator=\"@xmlonly number generator @endxmlonly\" \\ generators=\"@xmlonly generators @endxmlonly\" \\ distributions=\"@xmlonly distributions @endxmlonly\" \\ - additive_combine=\"@xmlonly additive_combine @endxmlonly\" \\ - discard_block=\"@xmlonly discard_block @endxmlonly\" \\ - lagged_fibonacci=\"@xmlonlylagged_fibonacci@endxmlonly\" \\ - linear_congruential=\"@xmlonlylinear_congruential@endxmlonly\" \\ - minstd_rand=\"@xmlonly minstd_rand @endxmlonly\" \\ - minstd_rand0=\"@xmlonly minstd_rand0 @endxmlonly\" \\ - rand48=\"@xmlonly rand48 @endxmlonly\" \\ - mt11213b=\"@xmlonly mt11213b @endxmlonly\" \\ - mt19937=\"@xmlonly mt19937 @endxmlonly\" \\ - ecuyer1988=\"@xmlonly ecuyer1988 @endxmlonly\" \\ - lagged_fibonacci607=\"@xmlonly lagged_fibonacci607 @endxmlonly\" \\ - lagged_fibonacci44497=\"@xmlonly lagged_fibonacci44497 @endxmlonly\" \\ - bernoulli_distribution=\"@xmlonly bernoulli_distribution @endxmlonly\" \\ - cauchy_distribution=\"@xmlonly cauchy_distribution @endxmlonly\" \\ - uniform_01=\"@xmlonlyuniform_01@endxmlonly\" \\ - random_device=\"@xmlonlyrandom_device@endxmlonly\"" + additive_combine_engine=\"@xmlonly additive_combine_engine @endxmlonly\" \\ + discard_block_engine=\"@xmlonly discard_block_engine @endxmlonly\" \\ + lagged_fibonacci_engine=\"@xmlonlylagged_fibonacci_engine@endxmlonly\" \\ + subtract_with_carry_01_engine=\"@xmlonlysubtract_with_carry_01_engine@endxmlonly\" \\ + linear_congruential_engine=\"@xmlonlylinear_congruential_engine@endxmlonly\" \\ + minstd_rand=\"@xmlonly minstd_rand @endxmlonly\" \\ + minstd_rand0=\"@xmlonly minstd_rand0 @endxmlonly\" \\ + rand48=\"@xmlonly rand48 @endxmlonly\" \\ + mt11213b=\"@xmlonly mt11213b @endxmlonly\" \\ + mt19937=\"@xmlonly mt19937 @endxmlonly\" \\ + ecuyer1988=\"@xmlonly ecuyer1988 @endxmlonly\" \\ + lagged_fibonacci607=\"@xmlonly lagged_fibonacci607 @endxmlonly\" \\ + lagged_fibonacci44497=\"@xmlonly lagged_fibonacci44497 @endxmlonly\" \\ + bernoulli_distribution=\"@xmlonly bernoulli_distribution @endxmlonly\" \\ + cauchy_distribution=\"@xmlonly cauchy_distribution @endxmlonly\" \\ + uniform_01=\"@xmlonlyuniform_01@endxmlonly\" \\ + random_device=\"@xmlonlyrandom_device@endxmlonly\"" HIDE_UNDOC_MEMBERS=NO QUIET=YES WARN_IF_UNDOCUMENTED=NO @@ -98,15 +113,47 @@ doxygen reference : ENABLE_PREPROCESSING=YES MACRO_EXPANSION=YES SEARCH_INCLUDES=NO + # Expand macros and clean up a bunch of ugly names "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 friend std::basic_ostream& operator<<(std::basic_ostream& os, const T& t)\" \\ + \"BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,T,t)=template friend std::basic_istream& operator>>(std::basic_istream& 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 explicit Self(T& t)\" \\ + \"BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(Self,T,t)=template 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 void seed(T& t)\"" + \"BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self,T,t)=template void seed(T& t)\" \\ + \"BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(Self,T,t)=template void seed(T& t)\"" "Headers" images/random ; diff --git a/doc/concepts.qbk b/doc/concepts.qbk index f3407d3..d001b0e 100644 --- a/doc/concepts.qbk +++ b/doc/concepts.qbk @@ -31,42 +31,21 @@ random number generators are appropriate: * pseudo-random number generator * quasi-random number generator -All variations have some properties in common, these concepts (in the STL -sense) are called __NumberGenerator and __UniformRandomNumberGenerator. Each -concept will be defined in a subsequent section. +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 -* define a validation interface for the generators +* allow easy integration of third-party random-number generators * provide easy-to-use front-end classes which model popular distributions * provide maximum efficiency -* allow control on quantization effects in front-end processing (not yet done) - -[endsect] - -[section Number Generator] - -A number generator is a /function object/ (std:20.3 [lib.function.objects]) that -takes zero arguments. Each call to `operator()` returns a number. In the -following table, X denotes a number generator class returning objects of type -T, and u is a value of X. - -[table NumberGenerator requirements - [[expression] [return type] [pre/post-condition]] - [[`X::result_type`] [`T`] [`std::numeric_limits::is_specialized` is - `true`, `T` is __LessThanComparable]] - [[`u.operator()()`] [`T`] [-]] -] - -[note The NumberGenerator requirements do not impose any restrictions on the -characteristics of the returned numbers.] [endsect] [section Uniform Random Number Generator] -A uniform random number generator is a __NumberGenerator that provides a +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. @@ -81,18 +60,9 @@ of type T, and v is a const value of X. [table UniformRandomNumberGenerator requirements [[expression] [return type] [pre/post-condition]] - [[`X::has_fixed_range`] [`bool`] [compile-time constant; if `true`, the range - on which the random numbers are uniformly - distributed is known at compile-time and - members `min_value` and `max_value` exist. - Note: This flag may also be `false` due to - compiler limitations]] - [[`X::min_value`] [`T`] [compile-time constant; `min_value` is only defined if - `has_fixed_range` is `true`. If it exists, it is - equal to `v.min()`.]] - [[`X::max_value`] [`T`] [compile-time constant; `max_value` is only defined if - `has_fixed_range` is `true`. If it exists, it is - equal to `v.max()`]] + [[`X::result_type`] [`T`] [`std::numeric_limits::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.]] @@ -158,8 +128,9 @@ to explicitly clear any temporary storage as soon as it is no longer needed.] 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 -Linear congruential] and [classref boost::random::inversive_congruential +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 @@ -186,20 +157,13 @@ a const value of `X`. [[`X()`] [-] [creates a generator in some implementation-defined state. Note: Several generators thusly created may possibly produce dependent or identical sequences of random numbers.]] - [[`explicit X(...)`] [-] [creates a generator with user-provided state; the + [[`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.]] - [[`X::validation(x)`] [`bool`] [compares the pre-computed and hardcoded - 10001th element in the generator's random - number sequence with x. The generator must - have been constructed by its default - constructor and seed must not have been - called for the validation to be - meaningful.]] ] [note The seed member function is similar to the assign member function in @@ -219,7 +183,7 @@ 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 may also model the +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. @@ -247,16 +211,16 @@ 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 NumberGenerator, CopyConstructible, and Assignable) +[table Random distribution requirements (in addition to CopyConstructible, and Assignable) [[expression] [return type] [pre/post-condition] [complexity]] - [[`X::input_type`] [`U`] [-] [compile-time]] + [[`X::result_type`] [`T`] [-] [compile-time]] [[`u.reset()`] [`void`] [subsequent uses of `u` do not depend on values - produced by `e` prior to invoking `reset`.] + 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`]] + [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`. diff --git a/doc/distribution_performance_linux.qbk b/doc/distribution_performance_linux.qbk index 165530b..0d4db87 100644 --- a/doc/distribution_performance_linux.qbk +++ b/doc/distribution_performance_linux.qbk @@ -1,23 +1,24 @@ -[/ - / 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) -] - [table Distributions (Linux) [[\[M rn/sec\]][minstd_rand][kreutzer1986][mt19937][lagged_fibonacci607]] - [[uniform_int][31.25][30.581][11.5607][16.0514]] - [[geometric][5.20833][6.66223][6.68449][6.73854]] - [[binomial][5.01505][21.7865][4.38982][10.9529]] - [[poisson][22.8311][22.1729][20.8768][24.3902]] - [[uniform_real][18.2815][84.0336][67.1141][72.4638]] - [[triangle][13.2802][33.4448][33.67][36.4964]] - [[exponential][6.19195][8.49618][8.2713][8.65052]] - [[normal polar][5.78369][6.56599][6.49773][6.48508]] - [[lognormal][4.13565][4.53515][4.51467][4.57875]] - [[cauchy][6.07533][7.92393][7.77605][8.35422]] - [[gamma][6.07533][7.92393][7.83085][8.34725]] - [[uniform_on_sphere][1.43472][1.62075][1.5625][1.5949]] + [[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/doc/distribution_performance_windows.qbk b/doc/distribution_performance_windows.qbk index 676459b..2a1fce4 100644 --- a/doc/distribution_performance_windows.qbk +++ b/doc/distribution_performance_windows.qbk @@ -1,23 +1,24 @@ -[/ - / 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) -] - [table Distributions (Windows) [[\[M rn/sec\]][minstd_rand][kreutzer1986][mt19937][lagged_fibonacci607]] - [[uniform_int][14.7449][27.465][6.65292][28.5714]] - [[geometric][7.10328][5.53649][3.73622][9.38438]] - [[binomial][6.20155][5.78135][2.65118][4.65463]] - [[poisson][15.9617][8.77886][12.5486][17.9276]] - [[uniform_real][49.6032][27.1223][31.6857][60.35]] - [[triangle][21.3356][11.7][14.2857][22.3015]] - [[exponential][14.3493][6.05473][10.8472][12.982]] - [[normal polar][4.24394][2.75748][7.04871][6.09533]] - [[lognormal][3.30066][1.34822][5.36913][4.0024]] - [[cauchy][11.4286][2.92372][12.0525][7.55629]] - [[gamma][10.5263][3.72523][12.1433][5.87682]] - [[uniform_on_sphere][0.680874][0.38004][1.18737][0.486334]] + [[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/doc/distributions.qbk b/doc/distributions.qbk index ec0462b..e658936 100644 --- a/doc/distributions.qbk +++ b/doc/distributions.qbk @@ -18,24 +18,28 @@ 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 distributions +[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] [discrete uniform distribution on a set of integers; the + [[__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] [continuous uniform distribution on some range [min, max) of + [[__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)]] @@ -43,20 +47,33 @@ statistically to it are not acceptable. experiments] [tossing a coin 20 times and counting how many front sides are shown]] - [[__cauchy_distribution][cauchy distribution][-]] - [[__gamma_distribution][gamma distribution][-]] - [[__poisson_distribution][poisson distribution] - [counting the number of alpha particles emitted - by radioactive matter in a fixed period of time]] [[__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]] - [[__triangle_distribution] [triangle distribution] [-]] + [[__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 @@ -65,6 +82,23 @@ statistically to it are not acceptable. 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 diff --git a/doc/generator_performance_linux.qbk b/doc/generator_performance_linux.qbk index 38176b3..9197b6e 100644 --- a/doc/generator_performance_linux.qbk +++ b/doc/generator_performance_linux.qbk @@ -1,42 +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) -] - [table Basic Generators (Linux) [[generator] [M rn/sec] [time per random number \[nsec\]] [relative speed compared to fastest \[percent\]]] - [[rand48][312.5][3.2][100%]] - [[lrand48 run-time][303.03][3.3][96%]] - [[lrand48 (C library)][67.5676][14.8][21%]] - [[minstd_rand0][96.1538][10.4][30%]] - [[minstd_rand][93.4579][10.7][29%]] - [[ecuyer combined][60.6061][16.5][19%]] - [[kreutzer1986][97.0874][10.3][31%]] - [[taus88][243.902][4.1][78%]] - [[hellekalek1995 (inversive)][2.405][415.8][0%]] - [[mt11213b][138.889][7.2][44%]] - [[mt19937][138.889][7.2][44%]] - [[lagged_fibonacci607][81.9672][12.2][26%]] - [[lagged_fibonacci1279][81.9672][12.2][26%]] - [[lagged_fibonacci2281][81.9672][12.2][26%]] - [[lagged_fibonacci3217][81.3008][12.3][26%]] - [[lagged_fibonacci4423][80.6452][12.4][25%]] - [[lagged_fibonacci9689][80.6452][12.4][25%]] - [[lagged_fibonacci19937][80][12.5][25%]] - [[lagged_fibonacci23209][80.6452][12.4][25%]] - [[lagged_fibonacci44497][79.3651][12.6][25%]] - [[subtract_with_carry][76.9231][13][24%]] - [[subtract_with_carry_01][45.045][22.2][14%]] - [[ranlux3][8.78735][113.8][2%]] - [[ranlux4][5.11771][195.4][1%]] - [[ranlux3_01][5.29381][188.9][1%]] - [[ranlux4_01][3.04599][328.3][0%]] - [[ranlux64_3][8.74126][114.4][2%]] - [[ranlux64_4][5.09684][196.2][1%]] - [[ranlux64_3_01][5.30786][188.4][1%]] - [[ranlux64_4_01][3.02847][330.2][0%]] - [[mt19937ar.c][95.2381][10.5][30%]] + [[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/doc/generator_performance_windows.qbk b/doc/generator_performance_windows.qbk index c4a3362..35d0115 100644 --- a/doc/generator_performance_windows.qbk +++ b/doc/generator_performance_windows.qbk @@ -1,41 +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) -] - [table Basic Generators (Windows) [[generator] [M rn/sec] [time per random number \[nsec\]] [relative speed compared to fastest \[percent\]]] - [[rand48][98.5222][10.15][67%]] - [[lrand48 run-time][17.343][57.66][11%]] - [[minstd_rand0][46.3822][21.56][31%]] - [[minstd_rand][38.5505][25.94][26%]] - [[ecuyer combined][15.8028][63.28][10%]] - [[kreutzer1986][66.6667][15][45%]] - [[taus88][145.56][6.87][100%]] - [[hellekalek1995 (inversive)][4.26658][234.38][2%]] - [[mt11213b][139.082][7.19][95%]] - [[mt19937][142.248][7.03][97%]] - [[lagged_fibonacci607][61.5385][16.25][42%]] - [[lagged_fibonacci1279][58.7199][17.03][40%]] - [[lagged_fibonacci2281][64.0205][15.62][43%]] - [[lagged_fibonacci3217][62.1118][16.1][42%]] - [[lagged_fibonacci4423][63.3714][15.78][43%]] - [[lagged_fibonacci9689][64.6412][15.47][44%]] - [[lagged_fibonacci19937][63.3714][15.78][43%]] - [[lagged_fibonacci23209][64.6412][15.47][44%]] - [[lagged_fibonacci44497][64.0205][15.62][43%]] - [[subtract_with_carry][92.7644][10.78][63%]] - [[subtract_with_carry_01][78.0031][12.82][53%]] - [[ranlux3][9.86193][101.4][6%]] - [[ranlux4][5.80754][172.19][3%]] - [[ranlux3_01][7.15103][139.84][4%]] - [[ranlux4_01][3.8345][260.79][2%]] - [[ranlux64_3][9.10415][109.84][6%]] - [[ranlux64_4][5.05919][197.66][3%]] - [[ranlux64_3_01][6.12445][163.28][4%]] - [[ranlux64_4_01][3.39167][294.84][2%]] - [[mt19937ar.c][125.471][7.97][86%]] + [[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/doc/generators.qbk b/doc/generators.qbk index 553c533..d1326cb 100644 --- a/doc/generators.qbk +++ b/doc/generators.qbk @@ -1,5 +1,5 @@ [/ - / Copyright (c) 2009 Steven Watanabe + / 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 @@ -47,11 +47,13 @@ numbers mean faster random number generation. [[__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]] [-]] @@ -69,6 +71,8 @@ numbers mean faster random number generation. [[__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 diff --git a/doc/performance.qbk b/doc/performance.qbk index 347bb97..151f74a 100644 --- a/doc/performance.qbk +++ b/doc/performance.qbk @@ -12,11 +12,9 @@ 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) Xeon(TM) MP -CPU 3.66GHz, Gentoo Base System release 1.12.11.1, GCC 4.3.2, -glibc 2.9 and on an Intel(R) Core(TM)2 CPU T7600 -@2.33 Ghz with Microsoft Windows XP Professional, Service Pack 2 Build -2600, Microsoft Visual C++ 2008 9.0.21022. +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. diff --git a/doc/performance_data.qbk b/doc/performance_data.qbk index 5b5b96e..c10e42a 100644 --- a/doc/performance_data.qbk +++ b/doc/performance_data.qbk @@ -1,39 +1,34 @@ -[/ - / 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[] 100%] -[template lrand48_run_time_speed[] 96%] -[template lrand48__C_library__speed[] 21%] -[template minstd_rand0_speed[] 30%] -[template minstd_rand_speed[] 29%] -[template ecuyer_combined_speed[] 19%] -[template kreutzer1986_speed[] 31%] -[template taus88_speed[] 78%] -[template hellekalek1995__inversive__speed[] 0%] -[template mt11213b_speed[] 44%] -[template mt19937_speed[] 44%] -[template lagged_fibonacci607_speed[] 26%] -[template lagged_fibonacci1279_speed[] 26%] -[template lagged_fibonacci2281_speed[] 26%] -[template lagged_fibonacci3217_speed[] 26%] -[template lagged_fibonacci4423_speed[] 25%] -[template lagged_fibonacci9689_speed[] 25%] -[template lagged_fibonacci19937_speed[] 25%] -[template lagged_fibonacci23209_speed[] 25%] -[template lagged_fibonacci44497_speed[] 25%] -[template subtract_with_carry_speed[] 24%] -[template subtract_with_carry_01_speed[] 14%] -[template ranlux3_speed[] 2%] -[template ranlux4_speed[] 1%] -[template ranlux3_01_speed[] 1%] -[template ranlux4_01_speed[] 0%] -[template ranlux64_3_speed[] 2%] -[template ranlux64_4_speed[] 1%] -[template ranlux64_3_01_speed[] 1%] -[template ranlux64_4_01_speed[] 0%] -[template mt19937ar_c_speed[] 30%] +[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/doc/random.qbk b/doc/random.qbk index 862012c..3a67ac7 100644 --- a/doc/random.qbk +++ b/doc/random.qbk @@ -1,7 +1,7 @@ [library Boost.Random [quickbook 1.5] [authors [Maurer, Jens]] - [copyright 2000-2005 Jens Maurer, 2009 Steven Watanabe] + [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 @@ -26,52 +26,65 @@ [def __EqualityComparable [@boost:/doc/html/EqualityComparable.html EqualityComparable]] [def __Streamable Streamable] -[def __random_device [classref boost::random_device random_device]] -[def __random_number_generator [classref boost::random_number_generator random_number_generator]] -[def __variate_generator [classref boost::variate_generator variate_generator]] +[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::minstd_rand0 minstd_rand0]] -[def __minstd_rand [classref boost::minstd_rand minstd_rand]] -[def __rand48 [classref boost::rand48 rand48]] -[def __ecuyer1988 [classref boost::ecuyer1988 ecuyer1988]] -[def __kreutzer1986 [classref boost::kreutzer1986 kreutzer1986]] -[def __taus88 [classref boost::taus88 taus88]] -[def __hellekalek1995 [classref boost::hellekalek1995 hellekalek1995]] -[def __mt11213b [classref boost::mt11213b mt11213b]] -[def __mt19937 [classref boost::mt19937 mt19937]] -[def __lagged_fibonacci607 [classref boost::lagged_fibonacci607 lagged_fibonacci607]] -[def __lagged_fibonacci1279 [classref boost::lagged_fibonacci1279 lagged_fibonacci1279]] -[def __lagged_fibonacci2281 [classref boost::lagged_fibonacci2281 lagged_fibonacci2281]] -[def __lagged_fibonacci3217 [classref boost::lagged_fibonacci3217 lagged_fibonacci3217]] -[def __lagged_fibonacci4423 [classref boost::lagged_fibonacci4423 lagged_fibonacci4423]] -[def __lagged_fibonacci9689 [classref boost::lagged_fibonacci9689 lagged_fibonacci9689]] -[def __lagged_fibonacci19937 [classref boost::lagged_fibonacci19937 lagged_fibonacci19937]] -[def __lagged_fibonacci23209 [classref boost::lagged_fibonacci23209 lagged_fibonacci23209]] -[def __lagged_fibonacci44497 [classref boost::lagged_fibonacci44497 lagged_fibonacci44497]] -[def __ranlux3 [classref boost::ranlux3 ranlux3]] -[def __ranlux4 [classref boost::ranlux4 ranlux4]] -[def __ranlux64_3 [classref boost::ranlux64_3 ranlux64_3]] -[def __ranlux64_4 [classref boost::ranlux64_4 ranlux64_4]] -[def __ranlux3_01 [classref boost::ranlux3_01 ranlux3_01]] -[def __ranlux4_01 [classref boost::ranlux4_01 ranlux4_01]] -[def __ranlux64_3_01 [classref boost::ranlux64_3_01 ranlux64_3_01]] -[def __ranlux64_4_01 [classref boost::ranlux64_4_01 ranlux64_4_01]] +[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::uniform_smallint uniform_smallint]] -[def __uniform_int [classref boost::uniform_int uniform_int]] -[def __uniform_01 [classref boost::uniform_01 uniform_01]] -[def __uniform_real [classref boost::uniform_real uniform_real]] -[def __bernoulli_distribution [classref boost::bernoulli_distribution bernoulli_distribution]] -[def __binomial_distribution [classref boost::binomial_distribution binomial_distribution]] -[def __cauchy_distribution [classref boost::cauchy_distribution cauchy_distribution]] -[def __gamma_distribution [classref boost::gamma_distribution gamma_distribution]] -[def __poisson_distribution [classref boost::poisson_distribution poisson_distribution]] -[def __geometric_distribution [classref boost::geometric_distribution geometric_distribution]] -[def __triangle_distribution [classref boost::triangle_distribution triangle_distribution]] -[def __exponential_distribution [classref boost::exponential_distribution exponential_distribution]] -[def __normal_distribution [classref boost::normal_distribution normal_distribution]] -[def __lognormal_distribution [classref boost::lognormal_distribution lognormal_distribution]] -[def __uniform_on_sphere [classref boost::uniform_on_sphere uniform_on_sphere]] +[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] @@ -88,13 +101,12 @@ 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::mt19937]`` rng; // produces randomness out of thin air + ``[classref boost::random::mt19937]`` rng; // produces randomness out of thin air // see pseudo-random number generators - ``[classref boost::uniform_int]<>`` six(1,6); // distribution that maps to 1..6 + ``[classref boost::random::uniform_int_distribution]<>`` six(1,6); + // distribution that maps to 1..6 // see random number distributions - ``[classref boost::variate_generator]``<``[classref boost::mt19937]``&, ``[classref boost::uniform_int]``<> > - die(rng, six); // glues randomness with mapping - int x = die(); // simulate rolling a die + int x = six(rng); // simulate rolling a die [endsect] @@ -124,17 +136,6 @@ For a very quick start, here's an example: [include performance.qbk] [endsect] -[section Rationale] - -The methods for generating and evaluating deterministic and non-deterministic -random numbers differ radically. Furthermore, due to the inherent -deterministic design of present-day computers, it is often difficult to -implement non-deterministic random number generation facilities. Thus, the -random number library is split into separate header files, mirroring the two -different application domains. - -[endsect] - [section History and Acknowledgements] In November 1999, Jeet Sukumaran proposed a framework based on virtual diff --git a/doc/random_number_generator.qbk b/doc/random_number_generator.qbk deleted file mode 100644 index 74b1d2b..0000000 --- a/doc/random_number_generator.qbk +++ /dev/null @@ -1,61 +0,0 @@ -[/ - / 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 Synopsis of miscellaneous decorators in header ] - - namespace boost { - template - class random_number_generator; - } // namespace boost - -[endsect] - -[section Class template random_number_generator] - -[section Synopsis] - - template - class random_number_generator - { - public: - typedef UniformRandomNumberGenerator base_type; - typedef IntType argument_type; - typedef IntType result_type; - random_number_generator(base_type & rng); - result_type operator()(argument_type n); - }; - -[endsect] - -[section Description] - -Instantiations of class template random_number_generator model a -RandomNumberGenerator (std:25.2.11 [lib.alg.random.shuffle]). On each -invocation, it returns a uniformly distributed integer in the range [0..n). - -The template parameter IntType shall denote some integer-like value type. - -[note I consider it unfortunate that the C++ Standard uses the name -RandomNumberGenerator for something rather specific.] - -[endsect] - -[section Members] - - random_number_generator(base_type & rng) - -Effects: Constructs a random_number_generator functor with the given uniform -random number generator as the underlying source of random numbers. - - result_type operator()(argument_type n) - -Returns: The value of uniform_int(rng, 0, n-1)(). - -[endsect] - -[endsect] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 9bed113..d14c340 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -19,3 +19,10 @@ [weighted_die] [endsect] + +[section Generating a random password] + +[import ../example/password.cpp] +[password] + +[endsect] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 851029a..a57fe3f 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -9,3 +9,4 @@ run die.cpp ; run weighted_die.cpp ; +run password.cpp /boost//random ; diff --git a/example/die.cpp b/example/die.cpp index 1df89d3..8ed0b8f 100644 --- a/example/die.cpp +++ b/example/die.cpp @@ -12,11 +12,10 @@ 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. + and __uniform_int_distribution. */ #include -#include -#include +#include /*` We use __mt19937 with the default seed as a source of @@ -25,7 +24,7 @@ change this is to seed with the current time (`std::time(0)` defined in ctime). */ -boost::mt19937 gen; +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 @@ -38,24 +37,17 @@ boost::mt19937 gen; 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 performs this transformation. - [warning Contrary to common C++ usage __uniform_int + __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 can + Given the parameters 1 and 6, __uniform_int_distribution can can produce any of the values 1, 2, 3, 4, 5, or 6.] >>*/ - boost::uniform_int<> dist(1, 6); - /*<< __variate_generator combines a generator with a distribution. - [important We pass [classref boost::mt19937 boost::mt19937&] to - __variate_generator instead of just [classref boost::mt19937] - (note the reference). Without the reference, __variate_generator - would make a copy of the generator and would leave the global - `gen` unchanged. Consequently, `roll_die` would produce *the same value* - every time it was called.] + 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. >>*/ - boost::variate_generator > die(gen, dist); - /*<< A __variate_generator is a function object. >>*/ - return die(); + return dist(gen); } //] diff --git a/example/password.cpp b/example/password.cpp new file mode 100644 index 0000000..19ab308 --- /dev/null +++ b/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 +#include + +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/example/random_demo.cpp b/example/random_demo.cpp index 1ffbc7c..593c757 100644 --- a/example/random_demo.cpp +++ b/example/random_demo.cpp @@ -18,17 +18,7 @@ #include #include #include - -// Sun CC doesn't handle boost::iterator_adaptor yet -#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530) #include -#endif - -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std { - using ::time; -} -#endif // This is a typedef for a random number generator. // Try boost::mt19937 or boost::ecuyer1988 instead of boost::minstd_rand @@ -43,23 +33,18 @@ void experiment(base_generator_type & generator) typedef boost::variate_generator gen_type; gen_type die_gen(generator, distribution_type(1, 6)); -#if !defined(__SUNPRO_CC) || (__SUNPRO_CC > 0x530) // If you want to use an STL iterator interface, use iterator_adaptors.hpp. - // Unfortunately, this doesn't work on SunCC yet. boost::generator_iterator die(&die_gen); for(int i = 0; i < 10; i++) std::cout << *die++ << " "; std::cout << '\n'; -#endif } int main() { // Define a random number generator and initialize it with a reproducible // seed. - // (The seed is unsigned, otherwise the wrong overload may be selected - // when using mt19937 as the base_generator_type.) - base_generator_type generator(42u); + base_generator_type generator(42); std::cout << "10 samples of a uniform distribution in [0..1):\n"; @@ -114,15 +99,12 @@ int main() boost::variate_generator > deg(generator, degen_dist); std::cout << deg() << " " << deg() << " " << deg() << std::endl; -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE { // You can save the generator state for future use. You can read the // state back in at any later time using operator>>. std::ofstream file("rng.saved", std::ofstream::trunc); file << generator; } -#endif - // Some compilers don't pay attention to std:3.6.1/5 and issue a - // warning here if "return 0;" is omitted. + return 0; } diff --git a/example/weighted_die.cpp b/example/weighted_die.cpp index 4a0b5a8..8dd9c2a 100644 --- a/example/weighted_die.cpp +++ b/example/weighted_die.cpp @@ -13,11 +13,7 @@ [@boost://libs/random/example/weighted_die.cpp weighted_die.cpp]. */ #include -#include -#include -#include -#include -#include +#include boost::mt19937 gen; @@ -25,27 +21,27 @@ 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.] */ -static const double probabilities[] = { +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. - Note that the C++0x library contains a `discrete_distribution` - class which would be a better way to do this. */ int roll_weighted_die() { - std::vector cumulative; - std::partial_sum(&probabilities[0], &probabilities[0] + 6, - std::back_inserter(cumulative)); - boost::uniform_real<> dist(0, cumulative.back()); - boost::variate_generator > die(gen, dist); - /*<< Find the position within the sequence and add 1 - (to make sure that the result is in the range [1,6] - instead of [0,5]) + /*<< Add 1 to make sure that the result is in the range [1,6] + instead of [0,5]. >>*/ - return (std::lower_bound(cumulative.begin(), cumulative.end(), die()) - cumulative.begin()) + 1; + return dist(gen) + 1; } //] diff --git a/include/boost/nondet_random.hpp b/include/boost/nondet_random.hpp index 12e1828..1ec2e44 100644 --- a/include/boost/nondet_random.hpp +++ b/include/boost/nondet_random.hpp @@ -17,126 +17,6 @@ #ifndef BOOST_NONDET_RANDOM_HPP #define BOOST_NONDET_RANDOM_HPP -#include // std::abs -#include // std::min -#include -#include -#include // noncopyable -#include // compile-time integral limits -#include - -namespace boost { - -/** - * Class \random_device models a \nondeterministic_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 - * - * @blockquote - * "Randomness Recommendations for Security", D. Eastlake, S. Crocker, - * J. Schiller, Network Working Group, RFC 1750, December 1994 - * @endblockquote - * - * for further discussions. - * - * @xmlnote - * 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. - * @endxmlnote - * - * 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, @c 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. - * - * Implementation Note for Windows - * - * On the Windows operating system, token is interpreted as the name - * of a cryptographic service provider. By default \random_device uses - * MS_DEF_PROV. - * - * 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. - * - * - * - * - *
classtime per invocation [usec]
@xmlonly random_device @endxmlonly 92.0
- * - * The measurement error is estimated at +/- 1 usec. - */ -class random_device : private noncopyable -{ -public: - typedef unsigned int result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = true); - BOOST_STATIC_CONSTANT(result_type, min_value = integer_traits::const_min); - BOOST_STATIC_CONSTANT(result_type, max_value = integer_traits::const_max); - - /** - * Returns: The smallest value that the \random_device can produce. - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value; } - /** - * Returns: The largest value that the \random_device can produce. - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value; } - /** - * Constructs a @c 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. - */ - BOOST_RANDOM_DECL explicit random_device(const std::string& token = default_token); - BOOST_RANDOM_DECL ~random_device(); - /** - * 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. - */ - BOOST_RANDOM_DECL double entropy() const; - /** - * Returns: A random value in the range [min, max] - */ - BOOST_RANDOM_DECL unsigned int operator()(); - -private: - BOOST_RANDOM_DECL static const char * const default_token; - - /* - * std:5.3.5/5 [expr.delete]: "If the object being deleted has incomplete - * class type at the point of deletion and the complete class has a - * non-trivial destructor [...], the behavior is undefined". - * This disallows the use of scoped_ptr<> with pimpl-like classes - * having a non-trivial destructor. - */ - class impl; - impl * pimpl; -}; - - -// TODO: put Schneier's Yarrow-160 algorithm here. - -} // namespace boost +#include #endif /* BOOST_NONDET_RANDOM_HPP */ diff --git a/include/boost/random.hpp b/include/boost/random.hpp index 16423a0..de0a97d 100644 --- a/include/boost/random.hpp +++ b/include/boost/random.hpp @@ -33,52 +33,53 @@ #define BOOST_RANDOM_HPP // generators -#include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include - -namespace boost { - /** - * The specialization taus88 was suggested in - * - * @blockquote - * "Maximally Equidistributed Combined Tausworthe Generators", - * Pierre L'Ecuyer, Mathematics of Computation, Volume 65, - * Number 213, January 1996, Pages 203-213 - * @endblockquote - */ - typedef random::xor_combine, 0, - random::linear_feedback_shift, 0, 0>, 0, - random::linear_feedback_shift, 0, 0> taus88; -} // namespace boost +#include +#include // misc +#include +#include #include +#include // distributions -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #endif // BOOST_RANDOM_HPP diff --git a/include/boost/random/additive_combine.hpp b/include/boost/random/additive_combine.hpp index 42b13f8..d786e18 100644 --- a/include/boost/random/additive_combine.hpp +++ b/include/boost/random/additive_combine.hpp @@ -16,20 +16,23 @@ #ifndef BOOST_RANDOM_ADDITIVE_COMBINE_HPP #define BOOST_RANDOM_ADDITIVE_COMBINE_HPP -#include +#include +#include #include // for std::min and std::max #include #include #include +#include +#include #include namespace boost { namespace random { /** - * An instantiation of class template \additive_combine model a + * An instantiation of class template @c additive_combine_engine models a * \pseudo_random_number_generator. It combines two multiplicative - * \linear_congruential number generators, i.e. those with @c c = 0. + * \linear_congruential_engine number generators, i.e. those with @c c = 0. * It is described in * * @blockquote @@ -38,183 +41,225 @@ namespace random { * @endblockquote * * The template parameters MLCG1 and MLCG2 shall denote two different - * \linear_congruential number generators, each with c = 0. Each invocation - * returns a random number X(n) := (MLCG1(n) - MLCG2(n)) mod (m1 - 1), where - * m1 denotes the modulus of MLCG1. - * - * The template parameter @c val is the validation value checked by validation. + * \linear_congruential_engine number generators, each with c = 0. Each + * invocation returns a random number + * X(n) := (MLCG1(n) - MLCG2(n)) mod (m1 - 1), + * where m1 denotes the modulus of MLCG1. */ -template -class additive_combine +template +class additive_combine_engine { public: - typedef MLCG1 first_base; - typedef MLCG2 second_base; - typedef typename MLCG1::result_type result_type; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION - static const bool has_fixed_range = true; - static const result_type min_value = 1; - static const result_type max_value = MLCG1::max_value-1; -#else - enum { has_fixed_range = false }; -#endif - /** - * Returns: The smallest value that the generator can produce - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 1; } - /** - * Returns: The largest value that the generator can produce - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_mlcg1.max)()-1; } + typedef MLCG1 first_base; + typedef MLCG2 second_base; + typedef typename MLCG1::result_type result_type; - /** - * Constructs an \additive_combine generator using the - * default constructors of the two base generators. - */ - additive_combine() : _mlcg1(), _mlcg2() { } - /** - * Constructs an \additive_combine generator, using aseed as - * the constructor argument for both base generators. - */ - explicit additive_combine(result_type aseed) - : _mlcg1(aseed), _mlcg2(aseed) { } - /** - * Constructs an \additive_combine generator, using - * @c seed1 and @c seed2 as the constructor argument to - * the first and second base generators, respectively. - */ - additive_combine(typename MLCG1::result_type seed1, - typename MLCG2::result_type seed2) - : _mlcg1(seed1), _mlcg2(seed2) { } - /** - * Contructs an \additive_combine generator with - * values from the range defined by the input iterators first - * and last. first will be modified to point to the element - * after the last one used. - * - * Throws: @c std::invalid_argument if the input range is too small. - * - * Exception Safety: Basic - */ - template additive_combine(It& first, It last) - : _mlcg1(first, last), _mlcg2(first, last) { } + // Required by old Boost.Random concept + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + /** + * Returns the smallest value that the generator can produce + */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 1; } + /** + * Returns the largest value that the generator can produce + */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return MLCG1::modulus-1; } - /** - * Seeds an \additive_combine generator using the default - * seeds of the two base generators. - */ - void seed() - { - _mlcg1.seed(); - _mlcg2.seed(); - } + /** + * Constructs an @c additive_combine_engine using the + * default constructors of the two base generators. + */ + additive_combine_engine() : _mlcg1(), _mlcg2() { } + /** + * Constructs an @c additive_combine_engine, using seed as + * the constructor argument for both base generators. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(additive_combine_engine, + result_type, seed_arg) + { + _mlcg1.seed(seed_arg); + _mlcg2.seed(seed_arg); + } + /** + * Constructs an @c additive_combine_engine, using seq as + * the constructor argument for both base generators. + * + * @xmlwarning + * The semantics of this function are liable to change. + * A @c seed_seq is designed to generate all the seeds + * in one shot, but this seeds the two base engines + * independantly and probably ends up giving the same + * sequence to both. + * @endxmlwarning + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(additive_combine_engine, + SeedSeq, seq) + { + _mlcg1.seed(seq); + _mlcg2.seed(seq); + } + /** + * Constructs an @c additive_combine_engine, using + * @c seed1 and @c seed2 as the constructor argument to + * the first and second base generators, respectively. + */ + additive_combine_engine(typename MLCG1::result_type seed1, + typename MLCG2::result_type seed2) + : _mlcg1(seed1), _mlcg2(seed2) { } + /** + * Contructs an @c additive_combine_engine with + * values from the range defined by the input iterators first + * and last. first will be modified to point to the element + * after the last one used. + * + * Throws: @c std::invalid_argument if the input range is too small. + * + * Exception Safety: Basic + */ + template additive_combine_engine(It& first, It last) + : _mlcg1(first, last), _mlcg2(first, last) { } - /** - * Seeds an \additive_combine generator, using @c aseed as the - * seed for both base generators. - */ - void seed(result_type aseed) - { - _mlcg1.seed(aseed); - _mlcg2.seed(aseed); - } + /** + * Seeds an @c additive_combine_engine using the default + * seeds of the two base generators. + */ + void seed() + { + _mlcg1.seed(); + _mlcg2.seed(); + } - /** - * Seeds an \additive_combine generator, using @c seed1 and @c seed2 as - * the seeds to the first and second base generators, respectively. - */ - void seed(typename MLCG1::result_type seed1, - typename MLCG2::result_type seed2) - { - _mlcg1.seed(seed1); - _mlcg2.seed(seed2); - } + /** + * Seeds an @c additive_combine_engine, using @c seed as the + * seed for both base generators. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(additive_combine_engine, + result_type, seed_arg) + { + _mlcg1.seed(seed_arg); + _mlcg2.seed(seed_arg); + } - /** - * Seeds an \additive_combine generator with - * values from the range defined by the input iterators first - * and last. first will be modified to point to the element - * after the last one used. - * - * Throws: @c std::invalid_argument if the input range is too small. - * - * Exception Safety: Basic - */ - template void seed(It& first, It last) - { - _mlcg1.seed(first, last); - _mlcg2.seed(first, last); - } + /** + * Seeds an @c additive_combine_engine, using @c seq to + * seed both base generators. + * + * See the warning on the corresponding constructor. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(additive_combine_engine, + SeedSeq, seq) + { + _mlcg1.seed(seq); + _mlcg2.seed(seq); + } - /** - * Returns: the next value of the generator - */ - result_type operator()() { - result_type z = _mlcg1() - _mlcg2(); - if(z < 1) - z += MLCG1::modulus-1; - return z; - } + /** + * Seeds an @c additive_combine generator, using @c seed1 and @c seed2 as + * the seeds to the first and second base generators, respectively. + */ + void seed(typename MLCG1::result_type seed1, + typename MLCG2::result_type seed2) + { + _mlcg1.seed(seed1); + _mlcg2.seed(seed2); + } - static bool validation(result_type x) { return val == x; } + /** + * Seeds an @c additive_combine_engine with + * values from the range defined by the input iterators first + * and last. first will be modified to point to the element + * after the last one used. + * + * Throws: @c std::invalid_argument if the input range is too small. + * + * Exception Safety: Basic + */ + template void seed(It& first, It last) + { + _mlcg1.seed(first, last); + _mlcg2.seed(first, last); + } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** Returns the next value of the generator. */ + result_type operator()() { + result_type val1 = _mlcg1(); + result_type val2 = _mlcg2(); + if(val2 < val1) return val1 - val2; + else return val1 - val2 + MLCG1::modulus - 1; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - /** - * Writes the state of an \additive_combine generator to a @c - * std::ostream. The textual representation of an \additive_combine - * generator is the textual representation of the first base - * generator followed by the textual representation of the - * second base generator. - */ - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const additive_combine& r) - { os << r._mlcg1 << " " << r._mlcg2; return os; } + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + _mlcg1.discard(z); + _mlcg2.discard(z); + } - /** - * Reads the state of an \additive_combine generator from a - * @c std::istream. - */ - template - friend std::basic_istream& - operator>>(std::basic_istream& is, additive_combine& r) - { is >> r._mlcg1 >> std::ws >> r._mlcg2; return is; } -#endif + /** + * Writes the state of an @c additive_combine_engine to a @c + * std::ostream. The textual representation of an @c + * additive_combine_engine is the textual representation of + * the first base generator followed by the textual representation + * of the second base generator. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, additive_combine_engine, r) + { os << r._mlcg1 << ' ' << r._mlcg2; return os; } - /** - * Returns: true iff the two \additive_combine generators will - * produce the same sequence of values. - */ - friend bool operator==(const additive_combine& x, const additive_combine& y) - { return x._mlcg1 == y._mlcg1 && x._mlcg2 == y._mlcg2; } - /** - * Returns: true iff the two \additive_combine generators will - * produce different sequences of values. - */ - friend bool operator!=(const additive_combine& x, const additive_combine& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const additive_combine& rhs) const - { return _mlcg1 == rhs._mlcg1 && _mlcg2 == rhs._mlcg2; } - bool operator!=(const additive_combine& rhs) const - { return !(*this == rhs); } -#endif + /** + * Reads the state of an @c additive_combine_engine from a + * @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, additive_combine_engine, r) + { is >> r._mlcg1 >> std::ws >> r._mlcg2; return is; } + + /** + * Returns: true iff the two @c additive_combine_engines will + * produce the same sequence of values. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(additive_combine_engine, x, y) + { return x._mlcg1 == y._mlcg1 && x._mlcg2 == y._mlcg2; } + /** + * Returns: true iff the two @c additive_combine_engines will + * produce different sequences of values. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(additive_combine_engine) private: - MLCG1 _mlcg1; - MLCG2 _mlcg2; + MLCG1 _mlcg1; + MLCG2 _mlcg2; }; -} // namespace random +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template +const bool additive_combine_engine::has_fixed_range; +#endif + +/// \cond show_deprecated + +/** Provided for backwards compatibility. */ +template +class additive_combine : public additive_combine_engine +{ + typedef additive_combine_engine base_t; +public: + typedef typename base_t::result_type result_type; + additive_combine() {} + template + additive_combine(T& arg) : base_t(arg) {} + template + additive_combine(const T& arg) : base_t(arg) {} + template + additive_combine(It& first, It last) : base_t(first, last) {} +}; + +/// \endcond /** * The specialization \ecuyer1988 was suggested in @@ -224,10 +269,14 @@ private: * Communications of the ACM, Vol. 31, No. 6, June 1988, pp. 742-749, 774 * @endblockquote */ -typedef random::additive_combine< - random::linear_congruential, - random::linear_congruential, - 2060321752> ecuyer1988; +typedef additive_combine_engine< + linear_congruential_engine, + linear_congruential_engine +> ecuyer1988; + +} // namespace random + +using random::ecuyer1988; } // namespace boost diff --git a/include/boost/random/bernoulli_distribution.hpp b/include/boost/random/bernoulli_distribution.hpp index 86930fb..d66bae4 100644 --- a/include/boost/random/bernoulli_distribution.hpp +++ b/include/boost/random/bernoulli_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/bernoulli_distribution.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -16,11 +17,13 @@ #ifndef BOOST_RANDOM_BERNOULLI_DISTRIBUTION_HPP #define BOOST_RANDOM_BERNOULLI_DISTRIBUTION_HPP -#include -#include +#include +#include #include +#include namespace boost { +namespace random { /** * Instantiations of class template \bernoulli_distribution model a @@ -32,78 +35,163 @@ template class bernoulli_distribution { public: - // In principle, this could work with both integer and floating-point - // types. Generating floating-point random numbers in the first - // place is probably more expensive, so use integer as input. - typedef int input_type; - typedef bool result_type; + // In principle, this could work with both integer and floating-point + // types. Generating floating-point random numbers in the first + // place is probably more expensive, so use integer as input. + typedef int input_type; + typedef bool result_type; - /** - * Constructs a \bernoulli_distribution object. - * p is the parameter of the distribution. - * - * Requires: 0 <= p <= 1 - */ - explicit bernoulli_distribution(const RealType& p_arg = RealType(0.5)) - : _p(p_arg) - { - assert(_p >= 0); - assert(_p <= 1); - } + class param_type + { + public: - // compiler-generated copy ctor and assignment operator are fine + typedef bernoulli_distribution distribution_type; - /** - * Returns: The "p" parameter of the distribution. - */ - RealType p() const { return _p; } - /** - * Effects: Subsequent uses of the distribution do not depend - * on values produced by any engine prior to invoking reset. - */ - void reset() { } + /** + * Constructs the parameters of the distribution. + * + * Requires: 0 <= p <= 1 + */ + explicit param_type(RealType p_arg = RealType(0.5)) + : _p(p_arg) + { + BOOST_ASSERT(_p >= 0); + BOOST_ASSERT(_p <= 1); + } - /** - * Returns: a random variate distributed according to the - * \bernoulli_distribution. - */ - template - result_type operator()(Engine& eng) - { - if(_p == RealType(0)) - return false; - else - return RealType(eng() - (eng.min)()) <= _p * RealType((eng.max)()-(eng.min)()); - } + /** Returns the p parameter of the distribution. */ + RealType p() const { return _p; } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - /** - * Writes the parameters of the distribution to a @c std::ostream. - */ - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const bernoulli_distribution& bd) - { - os << bd._p; - return os; - } + /** Writes the parameters to a std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._p; + return os; + } - /** - * Reads the parameters of the distribution from a @c std::istream. - */ - template - friend std::basic_istream& - operator>>(std::basic_istream& is, bernoulli_distribution& bd) - { - is >> std::ws >> bd._p; - return is; - } -#endif + /** Reads the parameters from a std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._p; + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._p == rhs._p; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _p; + }; + + /** + * Constructs a \bernoulli_distribution object. + * p is the parameter of the distribution. + * + * Requires: 0 <= p <= 1 + */ + explicit bernoulli_distribution(const RealType& p_arg = RealType(0.5)) + : _p(p_arg) + { + BOOST_ASSERT(_p >= 0); + BOOST_ASSERT(_p <= 1); + } + /** + * Constructs \bernoulli_distribution from its parameters + */ + explicit bernoulli_distribution(const param_type& parm) + : _p(parm.p()) {} + + // compiler-generated copy ctor and assignment operator are fine + + /** + * Returns: The "p" parameter of the distribution. + */ + RealType p() const { return _p; } + + /** Returns the smallest value that the distribution can produce. */ + bool min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return false; } + /** Returns the largest value that the distribution can produce. */ + bool max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return true; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_p); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) { _p = parm.p(); } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** + * Returns: a random variate distributed according to the + * \bernoulli_distribution. + */ + template + bool operator()(Engine& eng) const + { + if(_p == RealType(0)) + return false; + else + return RealType(eng() - (eng.min)()) <= _p * RealType((eng.max)()-(eng.min)()); + } + + /** + * Returns: a random variate distributed according to the + * \bernoulli_distribution with parameters specified by param. + */ + template + bool operator()(Engine& eng, const param_type& parm) const + { + return bernoulli_distribution(parm)(eng); + } + + /** + * Writes the parameters of the distribution to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, bernoulli_distribution, bd) + { + os << bd._p; + return os; + } + + /** + * Reads the parameters of the distribution from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, bernoulli_distribution, bd) + { + is >> bd._p; + return is; + } + + /** + * Returns true iff the two distributions will produce identical + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(bernoulli_distribution, lhs, rhs) + { return lhs._p == rhs._p; } + + /** + * Returns true iff the two distributions will produce different + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(bernoulli_distribution) private: - RealType _p; + RealType _p; }; +} // namespace random + +using random::bernoulli_distribution; + } // namespace boost #endif // BOOST_RANDOM_BERNOULLI_DISTRIBUTION_HPP diff --git a/include/boost/random/binomial_distribution.hpp b/include/boost/random/binomial_distribution.hpp index 9634f99..7774581 100644 --- a/include/boost/random/binomial_distribution.hpp +++ b/include/boost/random/binomial_distribution.hpp @@ -1,6 +1,6 @@ /* boost random/binomial_distribution.hpp header file * - * Copyright Jens Maurer 2002 + * 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) @@ -8,104 +8,415 @@ * See http://www.boost.org for most recent version including documentation. * * $Id$ - * */ -#ifndef BOOST_RANDOM_BINOMIAL_DISTRIBUTION_HPP -#define BOOST_RANDOM_BINOMIAL_DISTRIBUTION_HPP +#ifndef BOOST_RANDOM_BINOMIAL_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_BINOMIAL_DISTRIBUTION_HPP_INCLUDED #include -#include +#include +#include + #include -#include +#include + +#include namespace boost { +namespace random { + +namespace detail { + +template +struct binomial_table { + static const RealType table[10]; +}; + +template +const RealType binomial_table::table[10] = { + 0.08106146679532726, + 0.04134069595540929, + 0.02767792568499834, + 0.02079067210376509, + 0.01664469118982119, + 0.01387612882307075, + 0.01189670994589177, + 0.01041126526197209, + 0.009255462182712733, + 0.008330563433362871 +}; + +} /** * The binomial distribution is an integer valued distribution with * two parameters, @c t and @c p. The values of the distribution * are within the range [0,t]. * - * The probability that the distribution produces a value k is - * \f${t \choose k}p^k(1-p)^{t-k}\f$. + * The distribution function is + * \f$\displaystyle P(k) = {t \choose k}p^k(1-p)^{t-k}\f$. + * + * The algorithm used is the BTRD algorithm described in + * + * @blockquote + * "The generation of binomial random variates", Wolfgang Hormann, + * Journal of Statistical Computation and Simulation, Volume 46, + * Issue 1 & 2 April 1993 , pages 101 - 110 + * @endblockquote */ template -class binomial_distribution -{ +class binomial_distribution { public: - typedef typename bernoulli_distribution::input_type input_type; - typedef IntType result_type; + typedef IntType result_type; + typedef RealType input_type; - /** - * Construct an @c binomial_distribution object. @c t and @c p - * are the parameters of the distribution. - * - * Requires: t >=0 && 0 <= p <= 1 - */ - explicit binomial_distribution(IntType t = 1, - const RealType& p = RealType(0.5)) - : _bernoulli(p), _t(t) - { - assert(_t >= 0); - assert(RealType(0) <= p && p <= RealType(1)); - } + class param_type { + public: + typedef binomial_distribution distribution_type; + /** + * Construct a param_type object. @c t and @c p + * are the parameters of the distribution. + * + * Requires: t >=0 && 0 <= p <= 1 + */ + explicit param_type(IntType t_arg = 1, RealType p_arg = RealType (0.5)) + : _t(t_arg), _p(p_arg) + {} + /** Returns the @c t parameter of the distribution. */ + IntType t() const { return _t; } + /** Returns the @c p parameter of the distribution. */ + RealType p() const { return _p; } +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const param_type& parm) + { + os << parm._p << " " << parm._t; + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, param_type& parm) + { + is >> parm._p >> std::ws >> parm._t; + return is; + } +#endif + /** Returns true if the parameters have the same values. */ + friend bool operator==(const param_type& lhs, const param_type& rhs) + { + return lhs._t == rhs._t && lhs._p == rhs._p; + } + /** Returns true if the parameters have different values. */ + friend bool operator!=(const param_type& lhs, const param_type& rhs) + { + return !(lhs == rhs); + } + private: + IntType _t; + RealType _p; + }; + + /** + * Construct a @c binomial_distribution object. @c t and @c p + * are the parameters of the distribution. + * + * Requires: t >=0 && 0 <= p <= 1 + */ + explicit binomial_distribution(IntType t_arg = 1, + RealType p_arg = RealType(0.5)) + : _t(t_arg), _p(p_arg) + { + init(); + } + + /** + * Construct an @c binomial_distribution object from the + * parameters. + */ + explicit binomial_distribution(const param_type& parm) + : _t(parm.t()), _p(parm.p()) + { + init(); + } + + /** + * Returns a random variate distributed according to the + * binomial distribution. + */ + template + IntType operator()(URNG& urng) const + { + if(use_inversion()) { + if(0.5 < _p) { + return _t - invert(_t, 1-_p, urng); + } else { + return invert(_t, _p, urng); + } + } else if(0.5 < _p) { + return _t - generate(urng); + } else { + return generate(urng); + } + } + + /** + * Returns a random variate distributed according to the + * binomial distribution with parameters specified by @c param. + */ + template + IntType operator()(URNG& urng, const param_type& parm) const + { + return binomial_distribution(parm)(urng); + } - // compiler-generated copy ctor and assignment operator are fine + /** Returns the @c t parameter of the distribution. */ + IntType t() const { return _t; } + /** Returns the @c p parameter of the distribution. */ + RealType p() const { return _p; } - /** Returns: the @c t parameter of the distribution */ - IntType t() const { return _t; } - /** Returns: the @c p parameter of the distribution */ - RealType p() const { return _bernoulli.p(); } - /** - * Effects: Subsequent uses of the distribution do not depend - * on values produced by any engine prior to invoking reset. - */ - void reset() { } + /** Returns the smallest value that the distribution can produce. */ + IntType min BOOST_PREVENT_MACRO_SUBSTITUTION() const { return 0; } + /** Returns the largest value that the distribution can produce. */ + IntType max BOOST_PREVENT_MACRO_SUBSTITUTION() const { return _t; } - /** - * Returns: a random variate distributed according to the - * binomial distribution. - */ - template - result_type operator()(Engine& eng) - { - // TODO: This is O(_t), but it should be O(log(_t)) for large _t - result_type n = 0; - for(IntType i = 0; i < _t; ++i) - if(_bernoulli(eng)) - ++n; - return n; - } + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_t, _p); } + /** Sets parameters of the distribution. */ + void param(const param_type& parm) + { + _t = parm.t(); + _p = parm.p(); + init(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - /** - * Writes the parameters of the distribution to a @c std::ostream. - */ - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const binomial_distribution& bd) - { - os << bd._bernoulli << " " << bd._t; - return os; - } - - /** - * Reads the parameters of the distribution from a @c std::istream. - */ - template - friend std::basic_istream& - operator>>(std::basic_istream& is, binomial_distribution& bd) - { - is >> std::ws >> bd._bernoulli >> std::ws >> bd._t; - return is; - } + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const binomial_distribution& bd) + { + os << bd.param(); + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, binomial_distribution& bd) + { + bd.read(is); + return is; + } #endif + /** Returns true if the two distributions will produce the same + sequence of values, given equal generators. */ + friend bool operator==(const binomial_distribution& lhs, + const binomial_distribution& rhs) + { + return lhs._t == rhs._t && lhs._p == rhs._p; + } + /** Returns true if the two distributions could produce different + sequences of values, given equal generators. */ + friend bool operator!=(const binomial_distribution& lhs, + const binomial_distribution& rhs) + { + return !(lhs == rhs); + } + private: - bernoulli_distribution _bernoulli; - IntType _t; + + /// @cond show_private + + template + void read(std::basic_istream& is) { + param_type parm; + if(is >> parm) { + param(parm); + } + } + + bool use_inversion() const + { + // BTRD is safe when np >= 10 + return m < 11; + } + + // computes the correction factor for the Stirling approximation + // for log(k!) + static RealType fc(IntType k) + { + if(k < 10) return detail::binomial_table::table[k]; + else { + RealType ikp1 = RealType(1) / (k + 1); + return (RealType(1)/12 + - (RealType(1)/360 + - (RealType(1)/1260)*(ikp1*ikp1))*(ikp1*ikp1))*ikp1; + } + } + + void init() + { + using std::sqrt; + using std::pow; + + RealType p = (0.5 < _p)? (1 - _p) : _p; + IntType t = _t; + + m = static_cast((t+1)*p); + + if(use_inversion()) { + q_n = pow((1 - p), static_cast(t)); + } else { + btrd.r = p/(1-p); + btrd.nr = (t+1)*btrd.r; + btrd.npq = t*p*(1-p); + RealType sqrt_npq = sqrt(btrd.npq); + btrd.b = 1.15 + 2.53 * sqrt_npq; + btrd.a = -0.0873 + 0.0248*btrd.b + 0.01*p; + btrd.c = t*p + 0.5; + btrd.alpha = (2.83 + 5.1/btrd.b) * sqrt_npq; + btrd.v_r = 0.92 - 4.2/btrd.b; + btrd.u_rv_r = 0.86*btrd.v_r; + } + } + + template + result_type generate(URNG& urng) const + { + using std::floor; + using std::abs; + using std::log; + + while(true) { + RealType u; + RealType v = uniform_01()(urng); + if(v <= btrd.u_rv_r) { + RealType u = v/btrd.v_r - 0.43; + return static_cast(floor( + (2*btrd.a/(0.5 - abs(u)) + btrd.b)*u + btrd.c)); + } + + if(v >= btrd.v_r) { + u = uniform_01()(urng) - 0.5; + } else { + u = v/btrd.v_r - 0.93; + u = ((u < 0)? -0.5 : 0.5) - u; + v = uniform_01()(urng) * btrd.v_r; + } + + RealType us = 0.5 - abs(u); + IntType k = static_cast(floor((2*btrd.a/us + btrd.b)*u + btrd.c)); + if(k < 0 || k > _t) continue; + v = v*btrd.alpha/(btrd.a/(us*us) + btrd.b); + RealType km = abs(k - m); + if(km <= 15) { + RealType f = 1; + if(m < k) { + IntType i = m; + do { + ++i; + f = f*(btrd.nr/i - btrd.r); + } while(i != k); + } else if(m > k) { + IntType i = k; + do { + ++i; + v = v*(btrd.nr/i - btrd.r); + } while(i != m); + } + if(v <= f) return k; + else continue; + } else { + // final acceptance/rejection + v = log(v); + RealType rho = + (km/btrd.npq)*(((km/3. + 0.625)*km + 1./6)/btrd.npq + 0.5); + RealType t = -km*km/(2*btrd.npq); + if(v < t - rho) return k; + if(v > t + rho) continue; + + IntType nm = _t - m + 1; + RealType h = (m + 0.5)*log((m + 1)/(btrd.r*nm)) + + fc(m) + fc(_t - m); + + IntType nk = _t - k + 1; + if(v <= h + (_t+1)*log(static_cast(nm)/nk) + + (k + 0.5)*log(nk*btrd.r/(k+1)) + - fc(k) + - fc(_t - k)) + { + return k; + } else { + continue; + } + } + } + } + + template + IntType invert(IntType t, RealType p, URNG& urng) const + { + RealType q = 1 - p; + RealType s = p / q; + RealType a = (t + 1) * s; + RealType r = q_n; + RealType u = uniform_01()(urng); + IntType x = 0; + while(u > r) { + u = u - r; + ++x; + r = ((a/x) - s) * r; + } + return x; + } + + // parameters + IntType _t; + RealType _p; + + // common data + IntType m; + + union { + // for btrd + struct { + RealType r; + RealType nr; + RealType npq; + RealType b; + RealType a; + RealType c; + RealType alpha; + RealType v_r; + RealType u_rv_r; + } btrd; + // for inversion + RealType q_n; + }; + + /// @endcond }; -} // namespace boost +} -#endif // BOOST_RANDOM_BINOMIAL_DISTRIBUTION_HPP +// backwards compatibility +using random::binomial_distribution; + +} + +#include + +#endif diff --git a/include/boost/random/cauchy_distribution.hpp b/include/boost/random/cauchy_distribution.hpp index 3a7bd0c..998e523 100644 --- a/include/boost/random/cauchy_distribution.hpp +++ b/include/boost/random/cauchy_distribution.hpp @@ -17,105 +17,198 @@ #define BOOST_RANDOM_CAUCHY_DISTRIBUTION_HPP #include -#include +#include +#include #include -#include #include +#include +#include namespace boost { - -#if defined(__GNUC__) && (__GNUC__ < 3) -// Special gcc workaround: gcc 2.95.x ignores using-declarations -// in template classes (confirmed by gcc author Martin v. Loewis) - using std::tan; -#endif +namespace random { // Cauchy distribution: /** * The cauchy distribution is a continuous distribution with two - * parameters, sigma and median. + * parameters, median and sigma. * - * It has \f$p(x) = \frac{\sigma}{\pi(\sigma^2 + (x-m)^2)}\f$ + * It has \f$\displaystyle p(x) = \frac{\sigma}{\pi(\sigma^2 + (x-m)^2)}\f$ */ template class cauchy_distribution { public: - typedef RealType input_type; - typedef RealType result_type; + typedef RealType input_type; + typedef RealType result_type; -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif + class param_type + { + public: - /** - * Constructs a \cauchy_distribution with the paramters @c median - * and @c sigma. - */ - explicit cauchy_distribution(result_type median_arg = result_type(0), - result_type sigma_arg = result_type(1)) - : _median(median_arg), _sigma(sigma_arg) { } + typedef cauchy_distribution distribution_type; - // compiler-generated copy ctor and assignment operator are fine + /** Constructs the parameters of the cauchy distribution. */ + explicit param_type(RealType median_arg = RealType(0.0), + RealType sigma_arg = RealType(1.0)) + : _median(median_arg), _sigma(sigma_arg) {} - /** - * Returns: the "median" parameter of the distribution - */ - result_type median() const { return _median; } - /** - * Returns: the "sigma" parameter of the distribution - */ - result_type sigma() const { return _sigma; } - /** - * Effects: Subsequent uses of the distribution do not depend - * on values produced by any engine prior to invoking reset. - */ - void reset() { } + // backwards compatibility for Boost.Random - /** - * Returns: A random variate distributed according to the - * cauchy distribution. - */ - template - result_type operator()(Engine& eng) - { - // Can we have a boost::mathconst please? - const result_type pi = result_type(3.14159265358979323846); -#ifndef BOOST_NO_STDC_NAMESPACE - using std::tan; -#endif - return _median + _sigma * tan(pi*(eng()-result_type(0.5))); - } + /** Returns the median of the distribution. */ + RealType median() const { return _median; } + /** Returns the sigma parameter of the distribution. */ + RealType sigma() const { return _sigma; } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - /** - * Writes the parameters of the distribution to a @c std::ostream. - */ - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const cauchy_distribution& cd) - { - os << cd._median << " " << cd._sigma; - return os; - } + // The new names in C++0x. - /** - * Reads the parameters of the distribution from a @c std::istream. - */ - template - friend std::basic_istream& - operator>>(std::basic_istream& is, cauchy_distribution& cd) - { - is >> std::ws >> cd._median >> std::ws >> cd._sigma; - return is; - } -#endif + /** Returns the median of the distribution. */ + RealType a() const { return _median; } + /** Returns the sigma parameter of the distribution. */ + RealType b() const { return _sigma; } + + /** Writes the parameters to a std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._median << " " << parm._sigma; + return os; + } + + /** Reads the parameters from a std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._median >> std::ws >> parm._sigma; + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._median == rhs._median && lhs._sigma == rhs._sigma; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _median; + RealType _sigma; + }; + + /** + * Constructs a \cauchy_distribution with the paramters @c median + * and @c sigma. + */ + explicit cauchy_distribution(RealType median_arg = RealType(0.0), + RealType sigma_arg = RealType(1.0)) + : _median(median_arg), _sigma(sigma_arg) { } + + /** + * Constructs a \cauchy_distribution from it's parameters. + */ + explicit cauchy_distribution(const param_type& parm) + : _median(parm.median()), _sigma(parm.sigma()) { } + + // compiler-generated copy ctor and assignment operator are fine + + // backwards compatibility for Boost.Random + + /** Returns: the "median" parameter of the distribution */ + RealType median() const { return _median; } + /** Returns: the "sigma" parameter of the distribution */ + RealType sigma() const { return _sigma; } + + // The new names in C++0x + + /** Returns: the "median" parameter of the distribution */ + RealType a() const { return _median; } + /** Returns: the "sigma" parameter of the distribution */ + RealType b() const { return _sigma; } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return -(std::numeric_limits::infinity)(); } + + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return (std::numeric_limits::infinity)(); } + + param_type param() const { return param_type(_median, _sigma); } + + void param(const param_type& parm) + { + _median = parm.median(); + _sigma = parm.sigma(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** + * Returns: A random variate distributed according to the + * cauchy distribution. + */ + template + result_type operator()(Engine& eng) + { + // Can we have a boost::mathconst please? + const result_type pi = result_type(3.14159265358979323846); + using std::tan; + RealType val = uniform_01()(eng)-result_type(0.5); + return _median + _sigma * tan(pi*val); + } + + /** + * Returns: A random variate distributed according to the + * cauchy distribution with parameters specified by param. + */ + template + result_type operator()(Engine& eng, const param_type& parm) + { + return cauchy_distribution(parm)(eng); + } + + /** + * Writes the distribution to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, cauchy_distribution, cd) + { + os << cd._median << " " << cd._sigma; + return os; + } + + /** + * Reads the distribution from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, cauchy_distribution, cd) + { + is >> cd._median >> std::ws >> cd._sigma; + return is; + } + + /** + * Returns true if the two distributions will produce + * identical sequences of values, given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(cauchy_distribution, lhs, rhs) + { return lhs._median == rhs._median && lhs._sigma == rhs._sigma; } + + /** + * Returns true if the two distributions may produce + * different sequences of values, given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(cauchy_distribution) private: - result_type _median, _sigma; + RealType _median; + RealType _sigma; }; +} // namespace random + +using random::cauchy_distribution; + } // namespace boost #endif // BOOST_RANDOM_CAUCHY_DISTRIBUTION_HPP diff --git a/include/boost/random/chi_squared_distribution.hpp b/include/boost/random/chi_squared_distribution.hpp new file mode 100644 index 0000000..ce63584 --- /dev/null +++ b/include/boost/random/chi_squared_distribution.hpp @@ -0,0 +1,209 @@ +/* boost random/chi_squared_distribution.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_CHI_SQUARED_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_CHI_SQUARED_DISTRIBUTION_HPP_INCLUDED + +#include +#include + +#include +#include + +namespace boost { +namespace random { + +/** + * The chi squared distribution is a real valued distribution with + * one parameter, @c n. The distribution produces values > 0. + * + * The distribution function is + * \f$\displaystyle P(x) = \frac{x^{(n/2)-1}e^{-x/2}}{\Gamma(n/2)2^{n/2}}\f$. + */ +template +class chi_squared_distribution { +public: + typedef RealType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef chi_squared_distribution distribution_type; + /** + * Construct a param_type object. @c n + * is the parameter of the distribution. + * + * Requires: t >=0 && 0 <= p <= 1 + */ + explicit param_type(RealType n_arg = RealType(1)) + : _n(n_arg) + {} + /** Returns the @c n parameter of the distribution. */ + RealType n() const { return _n; } +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const param_type& parm) + { + os << parm._n; + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, param_type& parm) + { + is >> parm._n; + return is; + } +#endif + /** Returns true if the parameters have the same values. */ + friend bool operator==(const param_type& lhs, const param_type& rhs) + { + return lhs._n == rhs._n; + } + /** Returns true if the parameters have different values. */ + friend bool operator!=(const param_type& lhs, const param_type& rhs) + { + return !(lhs == rhs); + } + private: + RealType _n; + }; + + /** + * Construct a @c chi_squared_distribution object. @c n + * is the parameter of the distribution. + * + * Requires: t >=0 && 0 <= p <= 1 + */ + explicit chi_squared_distribution(RealType n_arg = RealType(1)) + : _impl(n_arg / 2) + { + } + + /** + * Construct an @c chi_squared_distribution object from the + * parameters. + */ + explicit chi_squared_distribution(const param_type& parm) + : _impl(parm.n() / 2) + { + } + + /** + * Returns a random variate distributed according to the + * chi squared distribution. + */ + template + RealType operator()(URNG& urng) + { + return 2 * _impl(urng); + } + + /** + * Returns a random variate distributed according to the + * chi squared distribution with parameters specified by @c param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return chi_squared_distribution(parm)(urng); + } + + /** Returns the @c n parameter of the distribution. */ + RealType n() const { return 2 * _impl.alpha(); } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION() const { return 0; } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION() const + { return (std::numeric_limits::infinity)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(n()); } + /** Sets parameters of the distribution. */ + void param(const param_type& parm) + { + typedef gamma_distribution impl_type; + typename impl_type::param_type impl_parm(parm.n() / 2); + _impl.param(impl_parm); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _impl.reset(); } + +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const chi_squared_distribution& c2d) + { + os << c2d.param(); + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, + chi_squared_distribution& c2d) + { + c2d.read(is); + return is; + } +#endif + + /** Returns true if the two distributions will produce the same + sequence of values, given equal generators. */ + friend bool operator==(const chi_squared_distribution& lhs, + const chi_squared_distribution& rhs) + { + return lhs._impl == rhs._impl; + } + /** Returns true if the two distributions could produce different + sequences of values, given equal generators. */ + friend bool operator!=(const chi_squared_distribution& lhs, + const chi_squared_distribution& rhs) + { + return !(lhs == rhs); + } + +private: + + /// @cond show_private + + template + void read(std::basic_istream& is) { + param_type parm; + if(is >> parm) { + param(parm); + } + } + + gamma_distribution _impl; + + /// @endcond +}; + +} + +} + +#endif diff --git a/include/boost/random/detail/const_mod.hpp b/include/boost/random/detail/const_mod.hpp index c669d7f..07f4ea7 100644 --- a/include/boost/random/detail/const_mod.hpp +++ b/include/boost/random/detail/const_mod.hpp @@ -16,113 +16,101 @@ #ifndef BOOST_RANDOM_CONST_MOD_HPP #define BOOST_RANDOM_CONST_MOD_HPP -#include +#include #include -#include #include -#include +#include +#include #include namespace boost { namespace random { -/* - * Some random number generators require modular arithmetic. Put - * everything we need here. - * IntType must be an integral type. - */ - -namespace detail { - - template - struct do_add - { }; - - template<> - struct do_add - { - template - static IntType add(IntType m, IntType x, IntType c) - { - if (x < m - c) - return x + c; - else - return x - (m-c); - } - }; - - template<> - struct do_add - { - template - static IntType add(IntType, IntType, IntType) - { - // difficult - assert(!"const_mod::add with c too large"); - return 0; - } - }; -} // namespace detail - -#if !(defined(__BORLANDC__) && (__BORLANDC__ == 0x560)) - template class const_mod { public: + static IntType apply(IntType x) + { + if(((unsigned_m() - 1) & unsigned_m()) == 0) + return (unsigned_type(x)) & (unsigned_m() - 1); + else { + IntType supress_warnings = (m == 0); + BOOST_ASSERT(supress_warnings == 0); + return x % (m + supress_warnings); + } + } + static IntType add(IntType x, IntType c) { - if(c == 0) + if(((unsigned_m() - 1) & unsigned_m()) == 0) + return (unsigned_type(x) + unsigned_type(c)) & (unsigned_m() - 1); + else if(c == 0) return x; - else if(c <= traits::const_max - m) // i.e. m+c < max - return add_small(x, c); + else if(x < m - c) + return x + c; else - return detail::do_add::add(m, x, c); + return x - (m - c); } static IntType mult(IntType a, IntType x) { - if(a == 1) + if(((unsigned_m() - 1) & unsigned_m()) == 0) + return unsigned_type(a) * unsigned_type(x) & (unsigned_m() - 1); + else if(a == 0) + return 0; + else if(a == 1) return x; else if(m <= traits::const_max/a) // i.e. a*m <= max return mult_small(a, x); else if(traits::is_signed && (m%a < m/a)) return mult_schrage(a, x); - else { - // difficult - assert(!"const_mod::mult with a too large"); - return 0; - } + else + return mult_general(a, x); } static IntType mult_add(IntType a, IntType x, IntType c) { - if(m <= (traits::const_max-c)/a) // i.e. a*m+c <= max - return (a*x+c) % m; - else + if(((unsigned_m() - 1) & unsigned_m()) == 0) + return (unsigned_type(a) * unsigned_type(x) + unsigned_type(c)) & (unsigned_m() - 1); + else if(a == 0) + return c; + else if(m <= (traits::const_max-c)/a) { // i.e. a*m+c <= max + IntType supress_warnings = (m == 0); + BOOST_ASSERT(supress_warnings == 0); + return (a*x+c) % (m + supress_warnings); + } else return add(mult(a, x), c); } + static IntType pow(IntType a, boost::uintmax_t exponent) + { + IntType result = 1; + while(exponent != 0) { + if(exponent % 2 == 1) { + result = mult(result, a); + } + a = mult(a, a); + exponent /= 2; + } + return result; + } + static IntType invert(IntType x) - { return x == 0 ? 0 : invert_euclidian(x); } + { return x == 0 ? 0 : (m == 0? invert_euclidian0(x) : invert_euclidian(x)); } private: typedef integer_traits traits; + typedef typename make_unsigned::type unsigned_type; const_mod(); // don't instantiate - static IntType add_small(IntType x, IntType c) - { - x += c; - if(x >= m) - x -= m; - return x; - } - static IntType mult_small(IntType a, IntType x) { - return a*x % m; + IntType supress_warnings = (m == 0); + BOOST_ASSERT(supress_warnings == 0); + return a*x % (m + supress_warnings); } static IntType mult_schrage(IntType a, IntType value) @@ -130,231 +118,96 @@ private: const IntType q = m / a; const IntType r = m % a; - assert(r < q); // check that overflow cannot happen + BOOST_ASSERT(r < q); // check that overflow cannot happen - value = a*(value%q) - r*(value/q); - // An optimizer bug in the SGI MIPSpro 7.3.1.x compiler requires this - // convoluted formulation of the loop (Synge Todo) - for(;;) { - if (value > 0) - break; - value += m; + return sub(a*(value%q), r*(value/q)); + } + + static IntType mult_general(IntType a, IntType b) + { + IntType suppress_warnings = (m == 0); + BOOST_ASSERT(suppress_warnings == 0); + IntType modulus = m + suppress_warnings; + BOOST_ASSERT(modulus == m); + if(::boost::uintmax_t(modulus) <= + (::std::numeric_limits< ::boost::uintmax_t>::max)() / modulus) + { + return static_cast(boost::uintmax_t(a) * b % modulus); + } else { + return static_cast(detail::mulmod(a, b, modulus)); } - return value; + } + + static IntType sub(IntType a, IntType b) + { + if(a < b) + return m - (b - a); + else + return a - b; + } + + static unsigned_type unsigned_m() + { + if(m == 0) { + return unsigned_type((std::numeric_limits::max)()) + 1; + } else { + return unsigned_type(m); + } } // invert c in the finite field (mod m) (m must be prime) static IntType invert_euclidian(IntType c) { // we are interested in the gcd factor for c, because this is our inverse - BOOST_STATIC_ASSERT(m > 0); -#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) - assert(boost::integer_traits::is_signed); -#elif !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) - BOOST_STATIC_ASSERT(boost::integer_traits::is_signed); -#endif - assert(c > 0); + BOOST_ASSERT(c > 0); IntType l1 = 0; IntType l2 = 1; IntType n = c; IntType p = m; for(;;) { IntType q = p / n; - l1 -= q * l2; // this requires a signed IntType! + l1 += q * l2; p -= q * n; if(p == 0) - return (l2 < 1 ? l2 + m : l2); + return l2; IntType q2 = n / p; - l2 -= q2 * l1; + l2 += q2 * l1; n -= q2 * p; if(n == 0) - return (l1 < 1 ? l1 + m : l1); - } - } -}; - -// The modulus is exactly the word size: rely on machine overflow handling. -// Due to a GCC bug, we cannot partially specialize in the presence of -// template value parameters. -template<> -class const_mod -{ - typedef unsigned int IntType; -public: - static IntType add(IntType x, IntType c) { return x+c; } - static IntType mult(IntType a, IntType x) { return a*x; } - static IntType mult_add(IntType a, IntType x, IntType c) { return a*x+c; } - - // m is not prime, thus invert is not useful -private: // don't instantiate - const_mod(); -}; - -template<> -class const_mod -{ - typedef unsigned long IntType; -public: - static IntType add(IntType x, IntType c) { return x+c; } - static IntType mult(IntType a, IntType x) { return a*x; } - static IntType mult_add(IntType a, IntType x, IntType c) { return a*x+c; } - - // m is not prime, thus invert is not useful -private: // don't instantiate - const_mod(); -}; - -// the modulus is some power of 2: rely partly on machine overflow handling -// we only specialize for rand48 at the moment -#ifndef BOOST_NO_INT64_T -template<> -class const_mod -{ - typedef uint64_t IntType; -public: - static IntType add(IntType x, IntType c) { return c == 0 ? x : mod(x+c); } - static IntType mult(IntType a, IntType x) { return mod(a*x); } - static IntType mult_add(IntType a, IntType x, IntType c) - { return mod(a*x+c); } - static IntType mod(IntType x) { return x &= ((uint64_t(1) << 48)-1); } - - // m is not prime, thus invert is not useful -private: // don't instantiate - const_mod(); -}; -#endif /* !BOOST_NO_INT64_T */ - -#else - -// -// for some reason Borland C++ Builder 6 has problems with -// the full specialisations of const_mod, define a generic version -// instead, the compiler will optimise away the const-if statements: -// - -template -class const_mod -{ -public: - static IntType add(IntType x, IntType c) - { - if(0 == m) - { - return x+c; - } - else - { - if(c == 0) - return x; - else if(c <= traits::const_max - m) // i.e. m+c < max - return add_small(x, c); - else - return detail::do_add::add(m, x, c); + return m - l1; } } - static IntType mult(IntType a, IntType x) - { - if(x == 0) - { - return a*x; - } - else - { - if(a == 1) - return x; - else if(m <= traits::const_max/a) // i.e. a*m <= max - return mult_small(a, x); - else if(traits::is_signed && (m%a < m/a)) - return mult_schrage(a, x); - else { - // difficult - assert(!"const_mod::mult with a too large"); - return 0; - } - } - } - - static IntType mult_add(IntType a, IntType x, IntType c) - { - if(m == 0) - { - return a*x+c; - } - else - { - if(m <= (traits::const_max-c)/a) // i.e. a*m+c <= max - return (a*x+c) % m; - else - return add(mult(a, x), c); - } - } - - static IntType invert(IntType x) - { return x == 0 ? 0 : invert_euclidian(x); } - -private: - typedef integer_traits traits; - - const_mod(); // don't instantiate - - static IntType add_small(IntType x, IntType c) - { - x += c; - if(x >= m) - x -= m; - return x; - } - - static IntType mult_small(IntType a, IntType x) - { - return a*x % m; - } - - static IntType mult_schrage(IntType a, IntType value) - { - const IntType q = m / a; - const IntType r = m % a; - - assert(r < q); // check that overflow cannot happen - - value = a*(value%q) - r*(value/q); - while(value <= 0) - value += m; - return value; - } - - // invert c in the finite field (mod m) (m must be prime) - static IntType invert_euclidian(IntType c) + // invert c in the finite field (mod m) (c must be relatively prime to m) + static IntType invert_euclidian0(IntType c) { // we are interested in the gcd factor for c, because this is our inverse - BOOST_STATIC_ASSERT(m > 0); -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(boost::integer_traits::is_signed); -#endif - assert(c > 0); + BOOST_ASSERT(c > 0); + if(c == 1) return 1; IntType l1 = 0; IntType l2 = 1; IntType n = c; IntType p = m; + IntType max = (std::numeric_limits::max)(); + IntType q = max / n; + BOOST_ASSERT(max % n != n - 1 && "c must be relatively prime to m."); + l1 += q * l2; + p = max - q * n + 1; for(;;) { - IntType q = p / n; - l1 -= q * l2; // this requires a signed IntType! - p -= q * n; if(p == 0) - return (l2 < 1 ? l2 + m : l2); + return l2; IntType q2 = n / p; - l2 -= q2 * l1; + l2 += q2 * l1; n -= q2 * p; if(n == 0) - return (l1 < 1 ? l1 + m : l1); + return m - l1; + q = p / n; + l1 += q * l2; + p -= q * n; } } }; - -#endif - } // namespace random } // namespace boost diff --git a/include/boost/random/detail/generator_seed_seq.hpp b/include/boost/random/detail/generator_seed_seq.hpp new file mode 100644 index 0000000..7e13483 --- /dev/null +++ b/include/boost/random/detail/generator_seed_seq.hpp @@ -0,0 +1,40 @@ +/* boost random/mersenne_twister.hpp header file + * + * Copyright Jens Maurer 2000-2001 + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_DETAIL_GENERATOR_SEED_SEQ_HPP_INCLUDED +#define BOOST_RANDOM_DETAIL_GENERATOR_SEED_SEQ_HPP_INCLUDED + +namespace boost { +namespace random { +namespace detail { + +template +class generator_seed_seq { +public: + generator_seed_seq(Generator& g) : gen(&g) {} + template + void generate(It first, It last) { + for(; first != last; ++first) { + *first = (*gen)(); + } + } +private: + Generator* gen; +}; + +} +} +} + +#endif diff --git a/include/boost/random/detail/integer_log2.hpp b/include/boost/random/detail/integer_log2.hpp new file mode 100644 index 0000000..0ad0c2f --- /dev/null +++ b/include/boost/random/detail/integer_log2.hpp @@ -0,0 +1,70 @@ +/* boost random/detail/integer_log2.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_DETAIL_INTEGER_LOG2_HPP +#define BOOST_RANDOM_DETAIL_INTEGER_LOG2_HPP + +#include +#include +#include + +namespace boost { +namespace random { +namespace detail { + +#if !defined(BOOST_NO_CONSTEXPR) +#define BOOST_RANDOM_DETAIL_CONSTEXPR constexpr +#elif defined(BOOST_MSVC) +#define BOOST_RANDOM_DETAIL_CONSTEXPR __forceinline +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define BOOST_RANDOM_DETAIL_CONSTEXPR __attribute__((const)) __attribute__((always_inline)) +#else +#define BOOST_RANDOM_DETAIL_CONSTEXPR inline +#endif + +template +struct integer_log2_impl +{ + template + BOOST_RANDOM_DETAIL_CONSTEXPR static int apply(T t, int accum) + { + int update = ((t >> Shift) != 0) * Shift; + return integer_log2_impl::apply(t >> update, accum + update); + } +}; + +template<> +struct integer_log2_impl<1> +{ + template + BOOST_RANDOM_DETAIL_CONSTEXPR static int apply(T t, int accum) + { + return int(t >> 1) + accum; + } +}; + +template +BOOST_RANDOM_DETAIL_CONSTEXPR int integer_log2(T t) +{ + return integer_log2_impl< + ::boost::detail::max_pow2_less< + ::std::numeric_limits::digits, 4 + >::value + >::apply(t, 0); +} + +} // namespace detail +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_DETAIL_INTEGER_LOG2_HPP diff --git a/include/boost/random/detail/large_arithmetic.hpp b/include/boost/random/detail/large_arithmetic.hpp new file mode 100644 index 0000000..3113a5e --- /dev/null +++ b/include/boost/random/detail/large_arithmetic.hpp @@ -0,0 +1,122 @@ +/* boost random/detail/large_arithmetic.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP +#define BOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP + +#include +#include +#include +#include + +#include + +namespace boost { +namespace random { +namespace detail { + +struct div_t { + boost::uintmax_t quotient; + boost::uintmax_t remainder; +}; + +inline div_t muldivmod(boost::uintmax_t a, boost::uintmax_t b, boost::uintmax_t m) +{ + static const int bits = + ::std::numeric_limits< ::boost::uintmax_t>::digits / 2; + static const ::boost::uintmax_t mask = (::boost::uintmax_t(1) << bits) - 1; + typedef ::boost::uint_t::fast digit_t; + + int shift = std::numeric_limits< ::boost::uintmax_t>::digits - 1 + - detail::integer_log2(m); + + a <<= shift; + m <<= shift; + + digit_t product[4] = { 0, 0, 0, 0 }; + digit_t a_[2] = { digit_t(a & mask), digit_t((a >> bits) & mask) }; + digit_t b_[2] = { digit_t(b & mask), digit_t((b >> bits) & mask) }; + digit_t m_[2] = { digit_t(m & mask), digit_t((m >> bits) & mask) }; + + // multiply a * b + for(int i = 0; i < 2; ++i) { + digit_t carry = 0; + for(int j = 0; j < 2; ++j) { + ::boost::uint64_t temp = ::boost::uintmax_t(a_[i]) * b_[j] + + carry + product[i + j]; + product[i + j] = digit_t(temp & mask); + carry = digit_t(temp >> bits); + } + if(carry != 0) { + product[i + 2] += carry; + } + } + + digit_t quotient[2]; + + if(m == 0) { + div_t result = { + ((::boost::uintmax_t(product[3]) << bits) | product[2]), + ((::boost::uintmax_t(product[1]) << bits) | product[0]) >> shift, + }; + return result; + } + + // divide product / m + for(int i = 3; i >= 2; --i) { + ::boost::uintmax_t temp = + ::boost::uintmax_t(product[i]) << bits | product[i - 1]; + + digit_t q = digit_t((product[i] == m_[1]) ? mask : temp / m_[1]); + + ::boost::uintmax_t rem = + ((temp - ::boost::uintmax_t(q) * m_[1]) << bits) + product[i - 2]; + + ::boost::uintmax_t diff = m_[0] * ::boost::uintmax_t(q); + + int error = 0; + if(diff > rem) { + if(diff - rem > m) { + error = 2; + } else { + error = 1; + } + } + q -= error; + rem = rem + error * m - diff; + + quotient[i - 2] = q; + product[i] = 0; + product[i-1] = (rem >> bits) & mask; + product[i-2] = rem & mask; + } + + div_t result = { + ((::boost::uintmax_t(quotient[1]) << bits) | quotient[0]), + ((::boost::uintmax_t(product[1]) << bits) | product[0]) >> shift, + }; + return result; +} + +inline boost::uintmax_t muldiv(boost::uintmax_t a, boost::uintmax_t b, boost::uintmax_t m) +{ return detail::muldivmod(a, b, m).quotient; } + +inline boost::uintmax_t mulmod(boost::uintmax_t a, boost::uintmax_t b, boost::uintmax_t m) +{ return detail::muldivmod(a, b, m).remainder; } + +} // namespace detail +} // namespace random +} // namespace boost + +#include + +#endif // BOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP diff --git a/include/boost/random/detail/operators.hpp b/include/boost/random/detail/operators.hpp new file mode 100644 index 0000000..597343c --- /dev/null +++ b/include/boost/random/detail/operators.hpp @@ -0,0 +1,84 @@ +/* boost random/detail/operators.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_DETAIL_OPERATORS_HPP +#define BOOST_RANDOM_DETAIL_OPERATORS_HPP + +#include +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + +#define BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, T, t) \ + template \ + friend std::basic_ostream& \ + operator<<(std::basic_ostream& os, const T& t) { \ + t.print(os, t); \ + return os; \ + } \ + template \ + static std::basic_ostream& \ + print(std::basic_ostream& os, const T& t) + +#define BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, T, t) \ + template \ + friend std::basic_istream& \ + operator>>(std::basic_istream& is, T& t) { \ + t.read(is, t); \ + return is; \ + } \ + template \ + static std::basic_istream& \ + read(std::basic_istream& is, T& t) + +#endif + +#if defined(__BORLANDC__) + +#define BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(T, lhs, rhs) \ + bool operator==(const T& rhs) const \ + { return T::is_equal(*this, rhs); } \ + static bool is_equal(const T& lhs, const T& rhs) + +#define BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(T) \ + bool operator!=(const T& rhs) const \ + { return !T::is_equal(*this, rhs); } + +#endif + +#ifndef BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR +#define BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, T, t) \ + template \ + friend std::basic_ostream& \ + operator<<(std::basic_ostream& os, const T& t) +#endif + +#ifndef BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR +#define BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, T, t) \ + template \ + friend std::basic_istream& \ + operator>>(std::basic_istream& is, T& t) +#endif + +#ifndef BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR +#define BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(T, lhs, rhs) \ + friend bool operator==(const T& lhs, const T& rhs) +#endif + +#ifndef BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR +#define BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(T) \ + friend bool operator!=(const T& lhs, const T& rhs) \ + { return !(lhs == rhs); } +#endif + +#endif diff --git a/include/boost/random/detail/pass_through_engine.hpp b/include/boost/random/detail/pass_through_engine.hpp deleted file mode 100644 index da9626d..0000000 --- a/include/boost/random/detail/pass_through_engine.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* boost random/detail/uniform_int_float.hpp header file - * - * Copyright Jens Maurer 2000-2001 - * Distributed under the Boost Software License, Version 1.0. (See - * accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * See http://www.boost.org for most recent version including documentation. - * - * $Id$ - * - */ - -#ifndef BOOST_RANDOM_DETAIL_PASS_THROUGH_ENGINE_HPP -#define BOOST_RANDOM_DETAIL_PASS_THROUGH_ENGINE_HPP - -#include -#include -#include - -namespace boost { -namespace random { -namespace detail { - -template -class pass_through_engine -{ -private: - typedef ptr_helper helper_type; - -public: - typedef typename helper_type::value_type base_type; - typedef typename base_type::result_type result_type; - - explicit pass_through_engine(UniformRandomNumberGenerator rng) - // make argument an rvalue to avoid matching Generator& constructor - : _rng(static_cast(rng)) - { } - - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (base().min)(); } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (base().max)(); } - base_type& base() { return helper_type::ref(_rng); } - const base_type& base() const { return helper_type::ref(_rng); } - - result_type operator()() { return base()(); } - -private: - UniformRandomNumberGenerator _rng; -}; - -#ifndef BOOST_NO_STD_LOCALE - -template -std::basic_ostream& -operator<<( - std::basic_ostream& os - , const pass_through_engine& ud - ) -{ - return os << ud.base(); -} - -template -std::basic_istream& -operator>>( - std::basic_istream& is - , const pass_through_engine& ud - ) -{ - return is >> ud.base(); -} - -#else // no new streams - -template -inline std::ostream& -operator<<(std::ostream& os, - const pass_through_engine& ud) -{ - return os << ud.base(); -} - -template -inline std::istream& -operator>>(std::istream& is, - const pass_through_engine& ud) -{ - return is >> ud.base(); -} - -#endif - -} // namespace detail -} // namespace random -} // namespace boost - -#include - -#endif // BOOST_RANDOM_DETAIL_PASS_THROUGH_ENGINE_HPP - diff --git a/include/boost/random/detail/seed.hpp b/include/boost/random/detail/seed.hpp index c090b18..55b2fa6 100644 --- a/include/boost/random/detail/seed.hpp +++ b/include/boost/random/detail/seed.hpp @@ -43,12 +43,19 @@ struct disable_constructor {}; template \ void seed(Generator& gen, typename ::boost::random::detail::disable_seed::type* = 0) +#define BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(Self, SeedSeq, seq) \ + template \ + explicit Self(SeedSeq& seq, typename ::boost::random::detail::disable_constructor::type* = 0) + +#define BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(Self, SeedSeq, seq) \ + template \ + void seed(SeedSeq& seq, typename ::boost::random::detail::disable_seed::type* = 0) + #define BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self, T, x) \ explicit Self(const T& x) #define BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(Self, T, x) \ void seed(const T& x) - } } } @@ -76,6 +83,24 @@ struct disable_constructor {}; template\ void boost_random_seed_impl(Generator& gen, ::boost::mpl::false_) +#define BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(Self, SeedSeq, seq) \ + Self(Self& other) { *this = other; } \ + Self(const Self& other) { *this = other; } \ + template \ + explicit Self(SeedSeq& seq) { \ + boost_random_constructor_impl(seq, ::boost::is_arithmetic());\ + } \ + template \ + void boost_random_constructor_impl(SeedSeq& seq, ::boost::mpl::false_) + +#define BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(Self, SeedSeq, seq) \ + template \ + void seed(SeedSeq& seq) { \ + boost_random_seed_impl(seq, ::boost::is_arithmetic()); \ + } \ + template \ + void boost_random_seed_impl(SeedSeq& seq, ::boost::mpl::false_) + #define BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self, T, x) \ explicit Self(const T& x) { boost_random_constructor_impl(x, ::boost::mpl::true_()); }\ void boost_random_constructor_impl(const T& x, ::boost::mpl::true_) diff --git a/include/boost/random/detail/seed_impl.hpp b/include/boost/random/detail/seed_impl.hpp new file mode 100644 index 0000000..31b216f --- /dev/null +++ b/include/boost/random/detail/seed_impl.hpp @@ -0,0 +1,396 @@ +/* boost random/detail/seed.hpp header file + * + * Copyright Steven Watanabe 2009 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_DETAIL_SEED_IMPL_HPP +#define BOOST_RANDOM_DETAIL_SEED_IMPL_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace random { +namespace detail { + +// finds the seed type of an engine, given its +// result_type. If the result_type is integral +// the seed type is the same. If the result_type +// is floating point, the seed type is uint32_t +template +struct seed_type +{ + typedef typename boost::mpl::if_, + T, + boost::uint32_t + >::type type; +}; + +template +struct const_pow_impl +{ + template + static T call(T arg, int n, T result) + { + return const_pow_impl::call(arg * arg, n / 2, + n%2 == 0? result : result * arg); + } +}; + +template<> +struct const_pow_impl<0> +{ + template + static T call(T, int, T result) + { + return result; + } +}; + +// requires N is an upper bound on n +template +inline T const_pow(T arg, int n) { return const_pow_impl::call(arg, n, T(1)); } + +template +inline T pow2(int n) +{ + typedef unsigned int_type; + const int max_bits = std::numeric_limits::digits; + T multiplier = T(int_type(1) << (max_bits - 1)) * 2; + return (int_type(1) << (n % max_bits)) * + const_pow::digits / max_bits>(multiplier, n / max_bits); +} + +template +void generate_from_real(Engine& eng, Iter begin, Iter end) +{ + using std::fmod; + typedef typename Engine::result_type RealType; + const int Bits = Engine::precision(); + int remaining_bits = 0; + boost::uint_least32_t saved_bits = 0; + RealType multiplier = pow2( Bits); + RealType mult32 = RealType(4294967296.0); // 2^32 + while(true) { + RealType val = eng() * multiplier; + int available_bits = Bits; + // Make sure the compiler can optimize this out + // if it isn't possible. + if(Bits < 32 && available_bits < 32 - remaining_bits) { + saved_bits |= boost::uint_least32_t(val) << remaining_bits; + remaining_bits += Bits; + } else { + // If Bits < 32, then remaining_bits != 0, since + // if remaining_bits == 0, available_bits < 32 - 0, + // and we won't get here to begin with. + if(Bits < 32 || remaining_bits != 0) { + boost::uint_least32_t divisor = + (boost::uint_least32_t(1) << (32 - remaining_bits)); + boost::uint_least32_t extra_bits = boost::uint_least32_t(fmod(val, mult32)) & (divisor - 1); + val = val / divisor; + *begin++ = saved_bits | (extra_bits << remaining_bits); + if(begin == end) return; + available_bits -= 32 - remaining_bits; + remaining_bits = 0; + } + // If Bits < 32 we should never enter this loop + if(Bits >= 32) { + for(; available_bits >= 32; available_bits -= 32) { + boost::uint_least32_t word = boost::uint_least32_t(fmod(val, mult32)); + val /= mult32; + *begin++ = word; + if(begin == end) return; + } + } + remaining_bits = available_bits; + saved_bits = static_cast(val); + } + } +} + +template +void generate_from_int(Engine& eng, Iter begin, Iter end) +{ + typedef typename Engine::result_type IntType; + typedef typename boost::make_unsigned::type unsigned_type; + int remaining_bits = 0; + boost::uint_least32_t saved_bits = 0; + unsigned_type range = boost::random::detail::subtract()((eng.max)(), (eng.min)()); + + int bits = + (range == (std::numeric_limits::max)()) ? + std::numeric_limits::digits : + detail::integer_log2(range + 1); + + { + int discarded_bits = detail::integer_log2(bits); + unsigned_type excess = (range + 1) >> (bits - discarded_bits); + if(excess != 0) { + int extra_bits = detail::integer_log2((excess - 1) ^ excess); + bits = bits - discarded_bits + extra_bits; + } + } + + unsigned_type mask = (static_cast(2) << (bits - 1)) - 1; + unsigned_type limit = ((range + 1) & ~mask) - 1; + + while(true) { + unsigned_type val; + do { + val = boost::random::detail::subtract()(eng(), (eng.min)()); + } while(limit != range && val > limit); + val &= mask; + int available_bits = bits; + if(available_bits == 32) { + *begin++ = static_cast(val) & 0xFFFFFFFFu; + if(begin == end) return; + } else if(available_bits % 32 == 0) { + for(int i = 0; i < available_bits / 32; ++i) { + boost::uint_least32_t word = boost::uint_least32_t(val) & 0xFFFFFFFFu; + int supress_warning = (bits >= 32); + BOOST_ASSERT(supress_warning == 1); + val >>= (32 * supress_warning); + *begin++ = word; + if(begin == end) return; + } + } else if(bits < 32 && available_bits < 32 - remaining_bits) { + saved_bits |= boost::uint_least32_t(val) << remaining_bits; + remaining_bits += bits; + } else { + if(bits < 32 || remaining_bits != 0) { + boost::uint_least32_t extra_bits = boost::uint_least32_t(val) & ((boost::uint_least32_t(1) << (32 - remaining_bits)) - 1); + val >>= 32 - remaining_bits; + *begin++ = saved_bits | (extra_bits << remaining_bits); + if(begin == end) return; + available_bits -= 32 - remaining_bits; + remaining_bits = 0; + } + if(bits >= 32) { + for(; available_bits >= 32; available_bits -= 32) { + boost::uint_least32_t word = boost::uint_least32_t(val) & 0xFFFFFFFFu; + int supress_warning = (bits >= 32); + BOOST_ASSERT(supress_warning == 1); + val >>= (32 * supress_warning); + *begin++ = word; + if(begin == end) return; + } + } + remaining_bits = available_bits; + saved_bits = static_cast(val); + } + } +} + +template +void generate_impl(Engine& eng, Iter first, Iter last, boost::mpl::true_) +{ + return detail::generate_from_int(eng, first, last); +} + +template +void generate_impl(Engine& eng, Iter first, Iter last, boost::mpl::false_) +{ + return detail::generate_from_real(eng, first, last); +} + +template +void generate(Engine& eng, Iter first, Iter last) +{ + return detail::generate_impl(eng, first, last, boost::is_integral()); +} + + + +template +IntType seed_one_int(SeedSeq& seq) +{ + static const int log = ::boost::mpl::if_c<(m == 0), + ::boost::mpl::int_<(::std::numeric_limits::digits)>, + ::boost::static_log2 >::type::value; + static const int k = + (log + ((~(static_cast(2) << (log - 1)) & m)? 32 : 31)) / 32; + ::boost::uint_least32_t array[log / 32 + 4]; + seq.generate(&array[0], &array[0] + k + 3); + IntType s = 0; + for(int j = 0; j < k; ++j) { + IntType digit = const_mod::apply(IntType(array[j+3])); + IntType mult = IntType(1) << 32*j; + s = const_mod::mult_add(mult, digit, s); + } + return s; +} + +template +IntType get_one_int(Iter& first, Iter last) +{ + static const int log = ::boost::mpl::if_c<(m == 0), + ::boost::mpl::int_<(::std::numeric_limits::digits)>, + ::boost::static_log2 >::type::value; + static const int k = + (log + ((~(static_cast(2) << (log - 1)) & m)? 32 : 31)) / 32; + IntType s = 0; + for(int j = 0; j < k; ++j) { + if(first == last) { + throw ::std::invalid_argument("Not enough elements in call to seed."); + } + IntType digit = const_mod::apply(IntType(*first++)); + IntType mult = IntType(1) << 32*j; + s = const_mod::mult_add(mult, digit, s); + } + return s; +} + +// TODO: work in-place whenever possible +template +void seed_array_int_impl(SeedSeq& seq, UIntType (&x)[n]) +{ + boost::uint_least32_t storage[((w+31)/32) * n]; + seq.generate(&storage[0], &storage[0] + ((w+31)/32) * n); + for(std::size_t j = 0; j < n; j++) { + UIntType val = 0; + for(std::size_t k = 0; k < (w+31)/32; ++k) { + val += static_cast(storage[(w+31)/32*j + k]) << 32*k; + } + x[j] = val & ::boost::low_bits_mask_t::sig_bits; + } +} + +template +inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::true_) +{ + typedef typename boost::make_unsigned::type unsigned_array[n]; + seed_array_int_impl(seq, reinterpret_cast(x)); +} + +template +inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::false_) +{ + seed_array_int_impl(seq, x); +} + +template +inline void seed_array_int(SeedSeq& seq, IntType (&x)[n]) +{ + seed_array_int_impl(seq, x, boost::is_signed()); +} + +template +void fill_array_int_impl(Iter& first, Iter last, UIntType (&x)[n]) +{ + for(std::size_t j = 0; j < n; j++) { + UIntType val = 0; + for(std::size_t k = 0; k < (w+31)/32; ++k) { + if(first == last) { + throw std::invalid_argument("Not enough elements in call to seed."); + } + val += static_cast(*first++) << 32*k; + } + x[j] = val & ::boost::low_bits_mask_t::sig_bits; + } +} + +template +inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::mpl::true_) +{ + typedef typename boost::make_unsigned::type unsigned_array[n]; + fill_array_int_impl(first, last, reinterpret_cast(x)); +} + +template +inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::mpl::false_) +{ + fill_array_int_impl(first, last, x); +} + +template +inline void fill_array_int(Iter& first, Iter last, IntType (&x)[n]) +{ + fill_array_int_impl(first, last, x, boost::is_signed()); +} + +template +void seed_array_real_impl(const boost::uint_least32_t* storage, RealType (&x)[n]) +{ + boost::uint_least32_t mask = ~((~boost::uint_least32_t(0)) << (w%32)); + RealType two32 = 4294967296.0; + const RealType divisor = RealType(1)/detail::pow2(w); + unsigned int j; + for(j = 0; j < n; ++j) { + RealType val = RealType(0); + RealType mult = divisor; + for(int k = 0; k < w/32; ++k) { + val += *storage++ * mult; + mult *= two32; + } + if(mask != 0) { + val += (*storage++ & mask) * mult; + } + BOOST_ASSERT(val >= 0); + BOOST_ASSERT(val < 1); + x[j] = val; + } +} + +template +void seed_array_real(SeedSeq& seq, RealType (&x)[n]) +{ + using std::pow; + boost::uint_least32_t storage[((w+31)/32) * n]; + seq.generate(&storage[0], &storage[0] + ((w+31)/32) * n); + seed_array_real_impl(storage, x); +} + +template +void fill_array_real(Iter& first, Iter last, RealType (&x)[n]) +{ + boost::uint_least32_t mask = ~((~boost::uint_least32_t(0)) << (w%32)); + RealType two32 = 4294967296.0; + const RealType divisor = RealType(1)/detail::pow2(w); + unsigned int j; + for(j = 0; j < n; ++j) { + RealType val = RealType(0); + RealType mult = divisor; + for(int k = 0; k < w/32; ++k, ++first) { + if(first == last) throw std::invalid_argument("Not enough elements in call to seed."); + val += *first * mult; + mult *= two32; + } + if(mask != 0) { + if(first == last) throw std::invalid_argument("Not enough elements in call to seed."); + val += (*first & mask) * mult; + ++first; + } + BOOST_ASSERT(val >= 0); + BOOST_ASSERT(val < 1); + x[j] = val; + } +} + +} +} +} + +#include + +#endif diff --git a/include/boost/random/detail/uniform_int_float.hpp b/include/boost/random/detail/uniform_int_float.hpp index 0c6e917..f65abd2 100644 --- a/include/boost/random/detail/uniform_int_float.hpp +++ b/include/boost/random/detail/uniform_int_float.hpp @@ -1,6 +1,7 @@ /* boost random/detail/uniform_int_float.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -14,72 +15,59 @@ #ifndef BOOST_RANDOM_DETAIL_UNIFORM_INT_FLOAT_HPP #define BOOST_RANDOM_DETAIL_UNIFORM_INT_FLOAT_HPP +#include #include +#include #include -#include +#include namespace boost { namespace random { namespace detail { -template +template class uniform_int_float { public: - typedef UniformRandomNumberGenerator base_type; - typedef IntType result_type; + typedef URNG base_type; + typedef typename base_type::result_type base_result; - uniform_int_float(base_type rng, IntType min_arg = 0, IntType max_arg = 0xffffffff) - : _rng(rng), _min(min_arg), _max(max_arg) - { - init(); - } + typedef typename boost::uint_t< + (std::numeric_limits::digits < + std::numeric_limits::digits)? + std::numeric_limits::digits : + std::numeric_limits::digits + >::fast result_type; - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } - base_type& base() { return _rng.base(); } - const base_type& base() const { return _rng.base(); } + uniform_int_float(base_type& rng) + : _rng(rng) {} - result_type operator()() - { - return static_cast(_rng() * _range) + _min; - } + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 0; } + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + std::size_t digits = std::numeric_limits::digits; + if(URNG::precision() < digits) digits = URNG::precision(); + return (result_type(2) << (digits - 1)) - 1; + } + base_type& base() { return _rng; } + const base_type& base() const { return _rng; } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const uniform_int_float& ud) - { - os << ud._min << " " << ud._max; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, uniform_int_float& ud) - { - is >> std::ws >> ud._min >> std::ws >> ud._max; - ud.init(); - return is; - } -#endif + result_type operator()() + { + base_result range = static_cast((max)())+1; + return static_cast(_rng() * range); + } private: - void init() - { - _range = static_cast(_max-_min)+1; - } - - typedef typename base_type::result_type base_result; - uniform_01 _rng; - result_type _min, _max; - base_result _range; + base_type& _rng; }; - } // namespace detail } // namespace random } // namespace boost +#include + #endif // BOOST_RANDOM_DETAIL_UNIFORM_INT_FLOAT_HPP diff --git a/include/boost/random/detail/vector_io.hpp b/include/boost/random/detail/vector_io.hpp new file mode 100644 index 0000000..24508c2 --- /dev/null +++ b/include/boost/random/detail/vector_io.hpp @@ -0,0 +1,75 @@ +/* boost random/vector_io.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_DETAIL_VECTOR_IO_HPP +#define BOOST_RANDOM_DETAIL_VECTOR_IO_HPP + +#include +#include +#include + +namespace boost { +namespace random { +namespace detail { + +template +void print_vector(std::basic_ostream& os, + const std::vector& vec) +{ + typename std::vector::const_iterator + iter = vec.begin(), + end = vec.end(); + os << os.widen('['); + if(iter != end) { + os << *iter; + ++iter; + for(; iter != end; ++iter) + { + os << os.widen(' ') << *iter; + } + } + os << os.widen(']'); +} + +template +void read_vector(std::basic_istream& is, std::vector& vec) +{ + CharT ch; + if(!(is >> ch)) { + return; + } + if(ch != is.widen('[')) { + is.putback(ch); + is.setstate(std::ios_base::failbit); + return; + } + T val; + while(is >> std::ws >> val) { + vec.push_back(val); + } + if(is.fail()) { + is.clear(); + if(!(is >> ch)) { + return; + } + if(ch != is.widen(']')) { + is.putback(ch); + is.setstate(std::ios_base::failbit); + } + } +} + +} +} +} + +#endif // BOOST_RANDOM_DETAIL_VECTOR_IO_HPP diff --git a/include/boost/random/discard_block.hpp b/include/boost/random/discard_block.hpp index 6ee3018..0c136e0 100644 --- a/include/boost/random/discard_block.hpp +++ b/include/boost/random/discard_block.hpp @@ -1,6 +1,7 @@ /* boost random/discard_block.hpp header file * * Copyright Jens Maurer 2002 + * 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) @@ -18,113 +19,208 @@ #include #include +#include #include #include #include +#include namespace boost { namespace random { /** - * The class template \discard_block is a model of + * The class template \discard_block_engine is a model of * \pseudo_random_number_generator. It modifies * another generator by discarding parts of its output. - * Out of every block of @c r results, the first @c p + * Out of every block of @c p results, the first @c r * will be returned and the rest discarded. * * Requires: 0 < p <= r */ -template -class discard_block +template +class discard_block_engine { + typedef typename detail::seed_type< + typename UniformRandomNumberGenerator::result_type>::type seed_type; public: - typedef UniformRandomNumberGenerator base_type; - typedef typename base_type::result_type result_type; + typedef UniformRandomNumberGenerator base_type; + typedef typename base_type::result_type result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(unsigned int, total_block = p); - BOOST_STATIC_CONSTANT(unsigned int, returned_block = r); + BOOST_STATIC_CONSTANT(std::size_t, block_size = p); + BOOST_STATIC_CONSTANT(std::size_t, used_block = r); -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(total_block >= returned_block); + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(std::size_t, total_block = p); + BOOST_STATIC_CONSTANT(std::size_t, returned_block = r); + + BOOST_STATIC_ASSERT(total_block >= returned_block); + + /** Uses the default seed for the base generator. */ + discard_block_engine() : _rng(), _n(0) { } + /** Constructs a new \discard_block_engine with a copy of rng. */ + explicit discard_block_engine(const base_type & rng) : _rng(rng), _n(0) { } + +#ifndef BOOST_NO_RVALUE_REFERENCES + /** Constructs a new \discard_block_engine with rng. */ + explicit discard_block_engine(base_type && rng) : _rng(rng), _n(0) { } #endif - discard_block() : _rng(), _n(0) { } - explicit discard_block(const base_type & rng) : _rng(rng), _n(0) { } - template explicit discard_block(T s) : _rng(s), _n(0) {} - template discard_block(It& first, It last) - : _rng(first, last), _n(0) { } - void seed() { _rng.seed(); _n = 0; } - template void seed(T s) { _rng.seed(s); _n = 0; } - template void seed(It& first, It last) - { _n = 0; _rng.seed(first, last); } + /** + * Creates a new \discard_block_engine and seeds the underlying + * generator with @c value + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(discard_block_engine, + seed_type, value) + { _rng.seed(value); _n = 0; } + + /** + * Creates a new \discard_block_engine and seeds the underlying + * generator with @c seq + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(discard_block_engine, SeedSeq, seq) + { _rng.seed(seq); _n = 0; } + + /** + * Creates a new \discard_block_engine and seeds the underlying + * generator with first and last. + */ + template discard_block_engine(It& first, It last) + : _rng(first, last), _n(0) { } + + /** default seeds the underlying generator. */ + void seed() { _rng.seed(); _n = 0; } + /** Seeds the underlying generator with s. */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(discard_block_engine, seed_type, s) + { _rng.seed(s); _n = 0; } + /** Seeds the underlying generator with seq. */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(discard_block_engine, SeedSeq, seq) + { _rng.seed(seq); _n = 0; } + /** Seeds the underlying generator with first and last. */ + template void seed(It& first, It last) + { _rng.seed(first, last); _n = 0; } - const base_type& base() const { return _rng; } + /** Returns the underlying engine. */ + const base_type& base() const { return _rng; } - result_type operator()() - { - if(_n >= returned_block) { - // discard values of random number generator - for( ; _n < total_block; ++_n) - _rng(); - _n = 0; + /** Returns the next value of the generator. */ + result_type operator()() + { + if(_n >= returned_block) { + // discard values of random number generator + _rng.discard(total_block - _n); + _n = 0; + } + ++_n; + return _rng(); } - ++_n; - return _rng(); - } - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_rng.min)(); } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_rng.max)(); } - static bool validation(result_type x) { return true; } // dummy + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + template + void generate(It first, It last) + { detail::generate(*this, first, last); } + + /** + * Returns the smallest value that the generator can produce. + * This is the same as the minimum of the underlying generator. + */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (base_type::min)(); } + /** + * Returns the largest value that the generator can produce. + * This is the same as the maximum of the underlying generator. + */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (base_type::max)(); } + + /** + * INTERNAL ONLY + * Returns the number of random bits. + * This is not part of the standard, and I'm not sure that + * it's the best solution, but something like this is needed + * to implement generate_canonical. For now, mark it as + * an implementation detail. + */ + static std::size_t precision() { return base_type::precision(); } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const discard_block& s) - { - os << s._rng << " " << s._n << " "; - return os; - } + /** Writes a \discard_block_engine to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const discard_block_engine& s) + { + os << s._rng << ' ' << s._n; + return os; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, discard_block& s) - { - is >> s._rng >> std::ws >> s._n >> std::ws; - return is; - } + /** Reads a \discard_block_engine from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, discard_block_engine& s) + { + is >> s._rng >> std::ws >> s._n; + return is; + } #endif - friend bool operator==(const discard_block& x, const discard_block& y) - { return x._rng == y._rng && x._n == y._n; } - friend bool operator!=(const discard_block& x, const discard_block& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const discard_block& rhs) const - { return _rng == rhs._rng && _n == rhs._n; } - bool operator!=(const discard_block& rhs) const - { return !(*this == rhs); } -#endif + /** Returns true if the two generators will produce identical sequences. */ + friend bool operator==(const discard_block_engine& x, + const discard_block_engine& y) + { return x._rng == y._rng && x._n == y._n; } + /** Returns true if the two generators will produce different sequences. */ + friend bool operator!=(const discard_block_engine& x, + const discard_block_engine& y) + { return !(x == y); } private: - base_type _rng; - unsigned int _n; + base_type _rng; + std::size_t _n; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool discard_block::has_fixed_range; -template -const unsigned int discard_block::total_block; -template -const unsigned int discard_block::returned_block; +template +const bool discard_block_engine::has_fixed_range; +template +const std::size_t discard_block_engine::total_block; +template +const std::size_t discard_block_engine::returned_block; +template +const std::size_t discard_block_engine::block_size; +template +const std::size_t discard_block_engine::used_block; #endif +/// \cond \show_deprecated + +template +class discard_block : public discard_block_engine +{ + typedef discard_block_engine base_t; +public: + typedef typename base_t::result_type result_type; + discard_block() {} + template + discard_block(T& arg) : base_t(arg) {} + template + discard_block(const T& arg) : base_t(arg) {} + template + discard_block(It& first, It last) : base_t(first, last) {} + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (this->base().min)(); } + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (this->base().max)(); } +}; + +/// \endcond + } // namespace random } // namespace boost diff --git a/include/boost/random/discrete_distribution.hpp b/include/boost/random/discrete_distribution.hpp new file mode 100644 index 0000000..720ba65 --- /dev/null +++ b/include/boost/random/discrete_distribution.hpp @@ -0,0 +1,453 @@ +/* boost random/discrete_distribution.hpp header file + * + * Copyright Steven Watanabe 2009-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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_NO_INITIALIZER_LISTS +#include +#endif + +#include +#include + +#include + +namespace boost { +namespace random { + +/** + * The class @c discrete_distribution models a \random_distribution. + * It produces integers in the range [0, n) with the probability + * of producing each value is specified by the parameters of the + * distribution. + */ +template +class discrete_distribution { +public: + typedef WeightType input_type; + typedef IntType result_type; + + class param_type { + public: + + typedef discrete_distribution distribution_type; + + /** + * Constructs a @c param_type object, representing a distribution + * with \f$p(0) = 1\f$ and \f$p(k|k>0) = 0\f$. + */ + param_type() : _probabilities(1, static_cast(1)) {} + /** + * If @c first == @c last, equivalent to the default constructor. + * Otherwise, the values of the range represent weights for the + * possible values of the distribution. + */ + template + param_type(Iter first, Iter last) : _probabilities(first, last) + { + normalize(); + } +#ifndef BOOST_NO_INITIALIZER_LISTS + /** + * If wl.size() == 0, equivalent to the default constructor. + * Otherwise, the values of the @c initializer_list represent + * weights for the possible values of the distribution. + */ + param_type(const std::initializer_list& wl) + : _probabilities(wl) + { + normalize(); + } +#endif + /** + * If the range is empty, equivalent to the default constructor. + * Otherwise, the elements of the range represent + * weights for the possible values of the distribution. + */ + template + explicit param_type(const Range& range) + : _probabilities(boost::begin(range), boost::end(range)) + { + normalize(); + } + + /** + * If nw is zero, equivalent to the default constructor. + * Otherwise, the range of the distribution is [0, nw), + * and the weights are found by calling fw with values + * evenly distributed between \f$\mbox{xmin} + \delta/2\f$ and + * \f$\mbox{xmax} - \delta/2\f$, where + * \f$\delta = (\mbox{xmax} - \mbox{xmin})/\mbox{nw}\f$. + */ + template + param_type(std::size_t nw, double xmin, double xmax, Func fw) + { + std::size_t n = (nw == 0) ? 1 : nw; + double delta = (xmax - xmin) / n; + BOOST_ASSERT(delta > 0); + for(std::size_t k = 0; k < n; ++k) { + _probabilities.push_back(fw(xmin + k*delta + delta/2)); + } + normalize(); + } + + /** + * Returns a vector containing the probabilities of each possible + * value of the distribution. + */ + std::vector probabilities() const + { + return _probabilities; + } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + detail::print_vector(os, parm._probabilities); + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + std::vector temp; + detail::read_vector(is, temp); + if(is) { + parm._probabilities.swap(temp); + } + return is; + } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { + return lhs._probabilities == rhs._probabilities; + } + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + private: + /// @cond show_private + friend class discrete_distribution; + explicit param_type(const discrete_distribution& dist) + : _probabilities(dist.probabilities()) + {} + void normalize() + { + WeightType sum = + std::accumulate(_probabilities.begin(), _probabilities.end(), + static_cast(0)); + for(typename std::vector::iterator + iter = _probabilities.begin(), + end = _probabilities.end(); + iter != end; ++iter) + { + *iter /= sum; + } + } + std::vector _probabilities; + /// @endcond + }; + + /** + * Creates a new @c discrete_distribution object that has + * \f$p(0) = 1\f$ and \f$p(i|i>0) = 0\f$. + */ + discrete_distribution() + { + _alias_table.push_back(std::make_pair(static_cast(1), + static_cast(0))); + } + /** + * Constructs a discrete_distribution from an iterator range. + * If @c first == @c last, equivalent to the default constructor. + * Otherwise, the values of the range represent weights for the + * possible values of the distribution. + */ + template + discrete_distribution(Iter first, Iter last) + { + init(first, last); + } +#ifndef BOOST_NO_INITIALIZER_LISTS + /** + * Constructs a @c discrete_distribution from a @c std::initializer_list. + * If the @c initializer_list is empty, equivalent to the default + * constructor. Otherwise, the values of the @c initializer_list + * represent weights for the possible values of the distribution. + * For example, given the distribution + * + * @code + * discrete_distribution<> dist{1, 4, 5}; + * @endcode + * + * The probability of a 0 is 1/10, the probability of a 1 is 2/5, + * the probability of a 2 is 1/2, and no other values are possible. + */ + discrete_distribution(std::initializer_list wl) + { + init(wl.begin(), wl.end()); + } +#endif + /** + * Constructs a discrete_distribution from a Boost.Range range. + * If the range is empty, equivalent to the default constructor. + * Otherwise, the values of the range represent weights for the + * possible values of the distribution. + */ + template + explicit discrete_distribution(const Range& range) + { + init(boost::begin(range), boost::end(range)); + } + /** + * Constructs a discrete_distribution that approximates a function. + * If nw is zero, equivalent to the default constructor. + * Otherwise, the range of the distribution is [0, nw), + * and the weights are found by calling fw with values + * evenly distributed between \f$\mbox{xmin} + \delta/2\f$ and + * \f$\mbox{xmax} - \delta/2\f$, where + * \f$\delta = (\mbox{xmax} - \mbox{xmin})/\mbox{nw}\f$. + */ + template + discrete_distribution(std::size_t nw, double xmin, double xmax, Func fw) + { + std::size_t n = (nw == 0) ? 1 : nw; + double delta = (xmax - xmin) / n; + BOOST_ASSERT(delta > 0); + std::vector weights; + for(std::size_t k = 0; k < n; ++k) { + weights.push_back(fw(xmin + k*delta + delta/2)); + } + init(weights.begin(), weights.end()); + } + /** + * Constructs a discrete_distribution from its parameters. + */ + explicit discrete_distribution(const param_type& parm) + { + param(parm); + } + + /** + * Returns a value distributed according to the parameters of the + * discrete_distribution. + */ + template + IntType operator()(URNG& urng) const + { + BOOST_ASSERT(!_alias_table.empty()); + WeightType test = uniform_01()(urng); + IntType result = uniform_int((min)(), (max)())(urng); + if(test < _alias_table[result].first) { + return result; + } else { + return(_alias_table[result].second); + } + } + + /** + * Returns a value distributed according to the parameters + * specified by param. + */ + template + IntType operator()(URNG& urng, const param_type& parm) const + { + while(true) { + WeightType val = uniform_01()(urng); + WeightType sum = 0; + std::size_t result = 0; + for(typename std::vector::const_iterator + iter = parm._probabilities.begin(), + end = parm._probabilities.end(); + iter != end; ++iter, ++result) + { + sum += *iter; + if(sum > val) { + return result; + } + } + } + } + + /** Returns the smallest value that the distribution can produce. */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } + /** Returns the largest value that the distribution can produce. */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return static_cast(_alias_table.size() - 1); } + + /** + * Returns a vector containing the probabilities of each + * value of the distribution. For example, given + * + * @code + * discrete_distribution<> dist = { 1, 4, 5 }; + * std::vector p = dist.param(); + * @endcode + * + * the vector, p will contain {0.1, 0.4, 0.5}. + */ + std::vector probabilities() const + { + std::vector result(_alias_table.size()); + const WeightType mean = + static_cast(1) / _alias_table.size(); + std::size_t i = 0; + for(typename alias_table_t::const_iterator + iter = _alias_table.begin(), + end = _alias_table.end(); + iter != end; ++iter, ++i) + { + WeightType val = iter->first * mean; + result[i] += val; + result[iter->second] += mean - val; + } + return(result); + } + + /** Returns the parameters of the distribution. */ + param_type param() const + { + return param_type(*this); + } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + init(parm._probabilities.begin(), parm._probabilities.end()); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() {} + + /** Writes a distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, discrete_distribution, dd) + { + os << dd.param(); + return os; + } + + /** Reads a distribution from a @c std::istream */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, discrete_distribution, dd) + { + param_type parm; + if(is >> parm) { + dd.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will return the + * same sequence of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(discrete_distribution, lhs, rhs) + { + return lhs._alias_table == rhs._alias_table; + } + /** + * Returns true if the two distributions may return different + * sequences of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(discrete_distribution) + +private: + + /// @cond show_private + + template + void init(Iter first, Iter last, std::input_iterator_tag) + { + std::vector temp(first, last); + init(temp.begin(), temp.end()); + } + template + void init(Iter first, Iter last, std::forward_iterator_tag) + { + std::vector > below_average; + std::vector > above_average; + std::size_t size = std::distance(first, last); + WeightType weight_sum = + std::accumulate(first, last, static_cast(0)); + WeightType weight_average = weight_sum / size; + std::size_t i = 0; + for(; first != last; ++first, ++i) { + WeightType val = *first / weight_average; + std::pair elem(val, static_cast(i)); + if(val < static_cast(1)) { + below_average.push_back(elem); + } else { + above_average.push_back(elem); + } + } + + _alias_table.resize(size); + typename alias_table_t::iterator + b_iter = below_average.begin(), + b_end = below_average.end(), + a_iter = above_average.begin(), + a_end = above_average.end() + ; + while(b_iter != b_end && a_iter != a_end) { + _alias_table[b_iter->second] = + std::make_pair(b_iter->first, a_iter->second); + a_iter->first -= (static_cast(1) - b_iter->first); + if(a_iter->first < static_cast(1)) { + *b_iter = *a_iter++; + } else { + ++b_iter; + } + } + for(; b_iter != b_end; ++b_iter) { + _alias_table[b_iter->second].first = static_cast(1); + } + for(; a_iter != a_end; ++a_iter) { + _alias_table[a_iter->second].first = static_cast(1); + } + } + template + void init(Iter first, Iter last) + { + if(first == last) { + _alias_table.clear(); + _alias_table.push_back(std::make_pair(static_cast(1), + static_cast(0))); + } else { + typename std::iterator_traits::iterator_category category; + init(first, last, category); + } + } + typedef std::vector > alias_table_t; + alias_table_t _alias_table; + /// @endcond +}; + +} +} + +#include + +#endif diff --git a/include/boost/random/exponential_distribution.hpp b/include/boost/random/exponential_distribution.hpp index a240c8a..53eaa93 100644 --- a/include/boost/random/exponential_distribution.hpp +++ b/include/boost/random/exponential_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/exponential_distribution.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -17,70 +18,165 @@ #define BOOST_RANDOM_EXPONENTIAL_DISTRIBUTION_HPP #include -#include -#include +#include +#include #include -#include #include +#include +#include namespace boost { +namespace random { /** - * The exponential distribution has a single parameter lambda. + * The exponential distribution is a model of \random_distribution with + * a single parameter lambda. * - * It has \f$p(x) = \lambda e^{-\lambda x}\f$ + * It has \f$\displaystyle p(x) = \lambda e^{-\lambda x}\f$ */ template class exponential_distribution { public: - typedef RealType input_type; - typedef RealType result_type; + typedef RealType input_type; + typedef RealType result_type; -#if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) && !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300) - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif + class param_type + { + public: - explicit exponential_distribution(result_type lambda_arg = result_type(1)) - : _lambda(lambda_arg) { assert(_lambda > result_type(0)); } + typedef exponential_distribution distribution_type; - // compiler-generated copy ctor and assignment operator are fine + /** + * Constructs parameters with a given lambda. + * + * Requires: lambda > 0 + */ + param_type(RealType lambda_arg = RealType(1.0)) + : _lambda(lambda_arg) { BOOST_ASSERT(_lambda > RealType(0)); } - result_type lambda() const { return _lambda; } + /** Returns the lambda parameter of the distribution. */ + RealType lambda() const { return _lambda; } - void reset() { } + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._lambda; + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._lambda; + return is; + } - template - result_type operator()(Engine& eng) - { -#ifndef BOOST_NO_STDC_NAMESPACE - using std::log; -#endif - return -result_type(1) / _lambda * log(result_type(1)-eng()); - } + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._lambda == rhs._lambda; } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const exponential_distribution& ed) - { - os << ed._lambda; - return os; - } + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) - template - friend std::basic_istream& - operator>>(std::basic_istream& is, exponential_distribution& ed) - { - is >> std::ws >> ed._lambda; - return is; - } -#endif + private: + RealType _lambda; + }; + + /** + * Constructs an exponential_distribution with a given lambda. + * + * Requires: lambda > 0 + */ + explicit exponential_distribution(RealType lambda_arg = RealType(1.0)) + : _lambda(lambda_arg) { BOOST_ASSERT(_lambda > RealType(0)); } + + /** + * Constructs an exponential_distribution from its parameters + */ + explicit exponential_distribution(const param_type& parm) + : _lambda(parm.lambda()) {} + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns the lambda parameter of the distribution. */ + RealType lambda() const { return _lambda; } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return RealType(0); } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return (std::numeric_limits::infinity)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_lambda); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) { _lambda = parm.lambda(); } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** + * Returns a random variate distributed according to the + * exponential distribution. + */ + template + result_type operator()(Engine& eng) const + { + using std::log; + return -result_type(1) / + _lambda * log(result_type(1)-uniform_01()(eng)); + } + + /** + * Returns a random variate distributed according to the exponential + * distribution with parameters specified by param. + */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { + return exponential_distribution(parm)(eng); + } + + /** Writes the distribution to a std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, exponential_distribution, ed) + { + os << ed._lambda; + return os; + } + + /** Reads the distribution from a std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, exponential_distribution, ed) + { + is >> ed._lambda; + return is; + } + + /** + * Returns true iff the two distributions will produce identical + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(exponential_distribution, lhs, rhs) + { return lhs._lambda == rhs._lambda; } + + /** + * Returns true iff the two distributions will produce different + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(exponential_distribution) private: - result_type _lambda; + result_type _lambda; }; +} // namespace random + +using random::exponential_distribution; + } // namespace boost #endif // BOOST_RANDOM_EXPONENTIAL_DISTRIBUTION_HPP diff --git a/include/boost/random/extreme_value_distribution.hpp b/include/boost/random/extreme_value_distribution.hpp new file mode 100644 index 0000000..419c3da --- /dev/null +++ b/include/boost/random/extreme_value_distribution.hpp @@ -0,0 +1,177 @@ +/* boost random/extreme_value_distribution.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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP +#define BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * The extreme value distribution is a real valued distribution with two + * parameters a and b. + * + * It has \f$\displaystyle p(x) = \frac{1}{b}e^{\frac{a-x}{b} - e^\frac{a-x}{b}}\f$. + */ +template +class extreme_value_distribution { +public: + typedef RealType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef extreme_value_distribution distribution_type; + + /** + * Constructs a @c param_type from the "a" and "b" parameters + * of the distribution. + * + * Requires: b > 0 + */ + explicit param_type(RealType a_arg = 1.0, RealType b_arg = 1.0) + : _a(a_arg), _b(b_arg) + {} + + /** Returns the "a" parameter of the distribtuion. */ + RealType a() const { return _a; } + /** Returns the "b" parameter of the distribution. */ + RealType b() const { return _b; } + + /** Writes a @c param_type to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { os << parm._a << ' ' << parm._b; return os; } + + /** Reads a @c param_type from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { is >> parm._a >> std::ws >> parm._b; return is; } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._a == rhs._a && lhs._b == rhs._b; } + + /** Returns true if the two sets of parameters are the different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _a; + RealType _b; + }; + + /** + * Constructs an @c extreme_value_distribution from its "a" and "b" parameters. + * + * Requires: b > 0 + */ + explicit extreme_value_distribution(RealType a_arg = 1.0, RealType b_arg = 1.0) + : _a(a_arg), _b(b_arg) + {} + /** Constructs an @c extreme_value_distribution from its parameters. */ + explicit extreme_value_distribution(const param_type& parm) + : _a(parm.a()), _b(parm.b()) + {} + + /** + * Returns a random variate distributed according to the + * @c extreme_value_distribution. + */ + template + RealType operator()(URNG& urng) const + { + using std::log; + return _a - log(-log(uniform_01()(urng))) * _b; + } + + /** + * Returns a random variate distributed accordint to the extreme + * value distribution with parameters specified by @c param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return extreme_value_distribution(parm)(urng); + } + + /** Returns the "a" parameter of the distribution. */ + RealType a() const { return _a; } + /** Returns the "b" parameter of the distribution. */ + RealType b() const { return _b; } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return -std::numeric_limits::infinity(); } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return std::numeric_limits::infinity(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_a, _b); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _a = parm.a(); + _b = parm.b(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** Writes an @c extreme_value_distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, extreme_value_distribution, wd) + { + os << wd.param(); + return os; + } + + /** Reads an @c extreme_value_distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, extreme_value_distribution, wd) + { + param_type parm; + if(is >> parm) { + wd.param(parm); + } + return is; + } + + /** + * Returns true if the two instances of @c extreme_value_distribution will + * return identical sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(extreme_value_distribution, lhs, rhs) + { return lhs._a == rhs._a && lhs._b == rhs._b; } + + /** + * Returns true if the two instances of @c extreme_value_distribution will + * return different sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(extreme_value_distribution) + +private: + RealType _a; + RealType _b; +}; + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP diff --git a/include/boost/random/fisher_f_distribution.hpp b/include/boost/random/fisher_f_distribution.hpp new file mode 100644 index 0000000..cdf14da --- /dev/null +++ b/include/boost/random/fisher_f_distribution.hpp @@ -0,0 +1,183 @@ +/* boost random/fisher_f_distribution.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_FISHER_F_DISTRIBUTION_HPP +#define BOOST_RANDOM_FISHER_F_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * The Fisher F distribution is a real valued distribution with two + * parameters m and n. + * + * It has \f$\displaystyle p(x) = + * \frac{\Gamma((m+n)/2)}{\Gamma(m/2)\Gamma(n/2)} + * \left(\frac{m}{n}\right)^{m/2} + * x^{(m/2)-1} \left(1+\frac{mx}{n}\right)^{-(m+n)/2} + * \f$. + */ +template +class fisher_f_distribution { +public: + typedef RealType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef fisher_f_distribution distribution_type; + + /** + * Constructs a @c param_type from the "m" and "n" parameters + * of the distribution. + * + * Requires: m > 0 and n > 0 + */ + explicit param_type(RealType m_arg = RealType(1.0), + RealType n_arg = RealType(1.0)) + : _m(m_arg), _n(n_arg) + {} + + /** Returns the "m" parameter of the distribtuion. */ + RealType m() const { return _m; } + /** Returns the "n" parameter of the distribution. */ + RealType n() const { return _n; } + + /** Writes a @c param_type to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { os << parm._m << ' ' << parm._n; return os; } + + /** Reads a @c param_type from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { is >> parm._m >> std::ws >> parm._n; return is; } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._m == rhs._m && lhs._n == rhs._n; } + + /** Returns true if the two sets of parameters are the different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _m; + RealType _n; + }; + + /** + * Constructs a @c fisher_f_distribution from its "m" and "n" parameters. + * + * Requires: m > 0 and n > 0 + */ + explicit fisher_f_distribution(RealType m_arg = RealType(1.0), + RealType n_arg = RealType(1.0)) + : _impl_m(m_arg), _impl_n(n_arg) + {} + /** Constructs an @c fisher_f_distribution from its parameters. */ + explicit fisher_f_distribution(const param_type& parm) + : _impl_m(parm.m()), _impl_n(parm.n()) + {} + + /** + * Returns a random variate distributed according to the + * F distribution. + */ + template + RealType operator()(URNG& urng) + { + return (_impl_m(urng) * n()) / (_impl_n(urng) * m()); + } + + /** + * Returns a random variate distributed according to the + * F distribution with parameters specified by @c param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return fisher_f_distribution(parm)(urng); + } + + /** Returns the "m" parameter of the distribution. */ + RealType m() const { return _impl_m.n(); } + /** Returns the "n" parameter of the distribution. */ + RealType n() const { return _impl_n.n(); } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return std::numeric_limits::infinity(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(m(), n()); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + typedef chi_squared_distribution impl_type; + typename impl_type::param_type m_param(parm.m()); + _impl_m.param(m_param); + typename impl_type::param_type n_param(parm.n()); + _impl_n.param(n_param); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** Writes an @c fisher_f_distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, fisher_f_distribution, fd) + { + os << fd.param(); + return os; + } + + /** Reads an @c fisher_f_distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, fisher_f_distribution, fd) + { + param_type parm; + if(is >> parm) { + fd.param(parm); + } + return is; + } + + /** + * Returns true if the two instances of @c fisher_f_distribution will + * return identical sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(fisher_f_distribution, lhs, rhs) + { return lhs._impl_m == rhs._impl_m && lhs._impl_n == rhs._impl_n; } + + /** + * Returns true if the two instances of @c fisher_f_distribution will + * return different sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(fisher_f_distribution) + +private: + chi_squared_distribution _impl_m; + chi_squared_distribution _impl_n; +}; + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_EXTREME_VALUE_DISTRIBUTION_HPP diff --git a/include/boost/random/gamma_distribution.hpp b/include/boost/random/gamma_distribution.hpp index a26aece..c9bda4c 100644 --- a/include/boost/random/gamma_distribution.hpp +++ b/include/boost/random/gamma_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/gamma_distribution.hpp header file * * Copyright Jens Maurer 2002 + * 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) @@ -15,129 +16,277 @@ #define BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP #include -#include +#include +#include +#include #include #include #include #include namespace boost { +namespace random { // The algorithm is taken from Knuth /** - * The gamma distribution is a continuous distribution with a single - * parameter alpha. + * The gamma distribution is a continuous distribution with two + * parameters alpha and beta. It produces values > 0. * - * It has \f$p(x) = x^{\alpha-1}\frac{e^{-x}}{\Gamma(\alpha)}\f$. + * It has + * \f$\displaystyle p(x) = x^{\alpha-1}\frac{e^{-x/\beta}}{\beta^\alpha\Gamma(\alpha)}\f$. */ template class gamma_distribution { public: - typedef RealType input_type; - typedef RealType result_type; + typedef RealType input_type; + typedef RealType result_type; -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif + class param_type + { + public: + typedef gamma_distribution distribution_type; - explicit gamma_distribution(const result_type& alpha_arg = result_type(1)) - : _exp(result_type(1)), _alpha(alpha_arg) - { - assert(_alpha > result_type(0)); - init(); - } - - // compiler-generated copy ctor and assignment operator are fine - - RealType alpha() const { return _alpha; } - - void reset() { _exp.reset(); } - - template - result_type operator()(Engine& eng) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::tan; using std::sqrt; using std::exp; using std::log; - using std::pow; -#endif - if(_alpha == result_type(1)) { - return _exp(eng); - } else if(_alpha > result_type(1)) { - // Can we have a boost::mathconst please? - const result_type pi = result_type(3.14159265358979323846); - for(;;) { - result_type y = tan(pi * eng()); - result_type x = sqrt(result_type(2)*_alpha-result_type(1))*y - + _alpha-result_type(1); - if(x <= result_type(0)) - continue; - if(eng() > - (result_type(1)+y*y) * exp((_alpha-result_type(1)) - *log(x/(_alpha-result_type(1))) - - sqrt(result_type(2)*_alpha - -result_type(1))*y)) - continue; - return x; - } - } else /* alpha < 1.0 */ { - for(;;) { - result_type u = eng(); - result_type y = _exp(eng); - result_type x, q; - if(u < _p) { - x = exp(-y/_alpha); - q = _p*exp(-x); - } else { - x = result_type(1)+y; - q = _p + (result_type(1)-_p) * pow(x, _alpha-result_type(1)); + /** + * Constructs a @c param_type object from the "alpha" and "beta" + * parameters. + * + * Requires: alpha > 0 && beta > 0 + */ + param_type(const RealType& alpha_arg = RealType(1.0), + const RealType& beta_arg = RealType(1.0)) + : _alpha(alpha_arg), _beta(beta_arg) + { } - if(u >= q) - continue; - return x; - } - } - } + + /** Returns the "alpha" parameter of the distribution. */ + RealType alpha() const { return _alpha; } + /** Returns the "beta" parameter of the distribution. */ + RealType beta() const { return _beta; } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const gamma_distribution& gd) - { - os << gd._alpha; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, gamma_distribution& gd) - { - is >> std::ws >> gd._alpha; - gd.init(); - return is; - } + /** Writes the parameters to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const param_type& parm) + { + os << parm._alpha << ' ' << parm._beta; + return os; + } + + /** Reads the parameters from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, param_type& parm) + { + is >> parm._alpha >> std::ws >> parm._beta; + return is; + } #endif + /** Returns true if the two sets of parameters are the same. */ + friend bool operator==(const param_type& lhs, const param_type& rhs) + { + return lhs._alpha == rhs._alpha && lhs._beta == rhs._beta; + } + /** Returns true if the two sets fo parameters are different. */ + friend bool operator!=(const param_type& lhs, const param_type& rhs) + { + return !(lhs == rhs); + } + private: + RealType _alpha; + RealType _beta; + }; + +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); +#endif + + /** + * Creates a new gamma_distribution with parameters "alpha" and "beta". + * + * Requires: alpha > 0 && beta > 0 + */ + explicit gamma_distribution(const result_type& alpha_arg = result_type(1.0), + const result_type& beta_arg = result_type(1.0)) + : _exp(result_type(1)), _alpha(alpha_arg), _beta(beta_arg) + { + BOOST_ASSERT(_alpha > result_type(0)); + BOOST_ASSERT(_beta > result_type(0)); + init(); + } + + /** Constructs a @c gamma_distribution from its parameters. */ + explicit gamma_distribution(const param_type& parm) + : _exp(result_type(1)), _alpha(parm.alpha()), _beta(parm.beta()) + { + init(); + } + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns the "alpha" paramter of the distribution. */ + RealType alpha() const { return _alpha; } + /** Returns the "beta" parameter of the distribution. */ + RealType beta() const { return _beta; } + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } + /* Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return (std::numeric_limits::infinity)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_alpha, _beta); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _alpha = parm.alpha(); + _beta = parm.beta(); + init(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _exp.reset(); } + + /** + * Returns a random variate distributed according to + * the gamma distribution. + */ + template + result_type operator()(Engine& eng) + { +#ifndef BOOST_NO_STDC_NAMESPACE + // allow for Koenig lookup + using std::tan; using std::sqrt; using std::exp; using std::log; + using std::pow; +#endif + if(_alpha == result_type(1)) { + return _exp(eng) * _beta; + } else if(_alpha > result_type(1)) { + // Can we have a boost::mathconst please? + const result_type pi = result_type(3.14159265358979323846); + for(;;) { + result_type y = tan(pi * uniform_01()(eng)); + result_type x = sqrt(result_type(2)*_alpha-result_type(1))*y + + _alpha-result_type(1); + if(x <= result_type(0)) + continue; + if(uniform_01()(eng) > + (result_type(1)+y*y) * exp((_alpha-result_type(1)) + *log(x/(_alpha-result_type(1))) + - sqrt(result_type(2)*_alpha + -result_type(1))*y)) + continue; + return x * _beta; + } + } else /* alpha < 1.0 */ { + for(;;) { + result_type u = uniform_01()(eng); + result_type y = _exp(eng); + result_type x, q; + if(u < _p) { + x = exp(-y/_alpha); + q = _p*exp(-x); + } else { + x = result_type(1)+y; + q = _p + (result_type(1)-_p) * pow(x,_alpha-result_type(1)); + } + if(u >= q) + continue; + return x * _beta; + } + } + } + + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return gamma_distribution(parm)(urng); + } + +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes a @c gamma_distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const gamma_distribution& gd) + { + os << gd.param(); + return os; + } + + /** Reads a @c gamma_distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, gamma_distribution& gd) + { + gd.read(is); + return is; + } +#endif + + /** + * Returns true if the two distributions will produce identical + * sequences of random variates given equal generators. + */ + friend bool operator==(const gamma_distribution& lhs, + const gamma_distribution& rhs) + { + return lhs._alpha == rhs._alpha + && lhs._beta == rhs._beta + && lhs._exp == rhs._exp; + } + + /** + * Returns true if the two distributions can produce different + * sequences of random variates, given equal generators. + */ + friend bool operator!=(const gamma_distribution& lhs, + const gamma_distribution& rhs) + { + return !(lhs == rhs); + } + private: - /// \cond hide_private_members - void init() - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::exp; -#endif - _p = exp(result_type(1)) / (_alpha + exp(result_type(1))); - } - /// \endcond + /// \cond hide_private_members - exponential_distribution _exp; - result_type _alpha; - // some data precomputed from the parameters - result_type _p; + template + void read(std::basic_istream& is) + { + param_type parm; + if(is >> parm) { + param(parm); + } + } + + void init() + { +#ifndef BOOST_NO_STDC_NAMESPACE + // allow for Koenig lookup + using std::exp; +#endif + _p = exp(result_type(1)) / (_alpha + exp(result_type(1))); + } + /// \endcond + + exponential_distribution _exp; + result_type _alpha; + result_type _beta; + // some data precomputed from the parameters + result_type _p; }; + +} // namespace random + +using random::gamma_distribution; + } // namespace boost #endif // BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP diff --git a/include/boost/random/generate_canonical.hpp b/include/boost/random/generate_canonical.hpp new file mode 100644 index 0000000..752fc8c --- /dev/null +++ b/include/boost/random/generate_canonical.hpp @@ -0,0 +1,96 @@ +/* boost random/generate_canonical.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_GENERATE_CANONICAL_HPP +#define BOOST_RANDOM_GENERATE_CANONICAL_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { + +namespace detail { + +template +RealType generate_canonical_impl(URNG& g, boost::mpl::true_ /*is_integral*/) +{ + using std::pow; + typedef typename URNG::result_type base_result; + std::size_t digits = std::numeric_limits::digits; + RealType R = RealType((g.max)()) - RealType((g.min)()) + 1; + RealType mult = R; + RealType limit = + pow(RealType(2), + RealType((std::min)(static_cast(bits), digits))); + RealType S = RealType(detail::subtract()(g(), (g.min)())); + while(mult < limit) { + RealType inc = RealType(detail::subtract()(g(), (g.min)())); + S += inc * mult; + mult *= R; + } + return S / mult; +} + +template +RealType generate_canonical_impl(URNG& g, boost::mpl::false_ /*is_integral*/) +{ + using std::pow; + using std::floor; + BOOST_ASSERT((g.min)() == 0); + BOOST_ASSERT((g.max)() == 1); + typedef typename URNG::result_type base_result; + std::size_t digits = std::numeric_limits::digits; + std::size_t engine_bits = g.precision(); + std::size_t b = (std::min)(bits, digits); + RealType R = pow(RealType(2), RealType(engine_bits)); + RealType mult = R; + RealType limit = pow(RealType(2), RealType(b)); + RealType S = RealType(g() - (g.min)()); + while(mult < limit) { + RealType inc(floor((RealType(g()) - RealType((g.min)())) * R)); + S += inc * mult; + mult *= R; + } + return S / mult; +} + +} + +/** + * Returns a value uniformly distributed in the range [0, 1) + * with at least @c bits random bits. + */ +template +RealType generate_canonical(URNG& g) +{ + RealType result = detail::generate_canonical_impl( + g, boost::is_integral()); + BOOST_ASSERT(result >= 0); + BOOST_ASSERT(result <= 1); + if(result == 1) { + result -= std::numeric_limits::epsilon() / 2; + BOOST_ASSERT(result != 1); + } + return result; +} + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_GENERATE_CANONICAL_HPP diff --git a/include/boost/random/geometric_distribution.hpp b/include/boost/random/geometric_distribution.hpp index bb16150..6342ac7 100644 --- a/include/boost/random/geometric_distribution.hpp +++ b/include/boost/random/geometric_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/geometric_distribution.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -17,18 +18,15 @@ #define BOOST_RANDOM_GEOMETRIC_DISTRIBUTION_HPP #include // std::log -#include -#include +#include +#include +#include #include +#include #include namespace boost { - -#if defined(__GNUC__) && (__GNUC__ < 3) -// Special gcc workaround: gcc 2.95.x ignores using-declarations -// in template classes (confirmed by gcc author Martin v. Loewis) - using std::log; -#endif +namespace random { /** * An instantiation of the class template @c geometric_distribution models @@ -36,83 +34,234 @@ namespace boost { * integers which are the number of bernoulli trials * with probability @c p required to get one that fails. * - * For the geometric distribution, \f$p(i) = (1-p) p^{i-1}\f$. + * For the geometric distribution, \f$p(i) = p(1-p)^{i}\f$. + * + * @xmlwarning + * This distribution has been updated to match the C++ standard. + * Its behavior has changed from the original + * boost::geometric_distribution. A backwards compatible + * wrapper is provided in namespace boost. + * @endxmlwarning */ template class geometric_distribution { public: - typedef RealType input_type; - typedef IntType result_type; + typedef RealType input_type; + typedef IntType result_type; - /** - * Contructs a new geometric_distribution with the paramter @c p. - * - * Requires: 0 < p < 1 - */ - explicit geometric_distribution(const RealType& p = RealType(0.5)) - : _p(p) - { - assert(RealType(0) < _p && _p < RealType(1)); - init(); - } + class param_type + { + public: - // compiler-generated copy ctor and assignment operator are fine + typedef geometric_distribution distribution_type; - /** - * Returns: the distribution parameter @c p - */ - RealType p() const { return _p; } - void reset() { } + /** Constructs the parameters with p. */ + explicit param_type(RealType p_arg = RealType(0.5)) + : _p(p_arg) + { + BOOST_ASSERT(RealType(0) < _p && _p < RealType(1)); + } - template - result_type operator()(Engine& eng) - { -#ifndef BOOST_NO_STDC_NAMESPACE - using std::log; - using std::floor; -#endif - return IntType(floor(log(RealType(1)-eng()) / _log_p)) + IntType(1); - } + /** Returns the p parameter of the distribution. */ + RealType p() const { return _p; } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const geometric_distribution& gd) - { - os << gd._p; - return os; - } + /** Writes the parameters to a std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._p; + return os; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, geometric_distribution& gd) - { - is >> std::ws >> gd._p; - gd.init(); - return is; - } -#endif + /** Reads the parameters from a std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + double p_in; + if(is >> p_in) { + if(p_in > RealType(0) && p_in < RealType(1)) { + parm._p = p_in; + } else { + is.setstate(std::ios_base::failbit); + } + } + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._p == rhs._p; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + + private: + RealType _p; + }; + + /** + * Contructs a new geometric_distribution with the paramter @c p. + * + * Requires: 0 < p < 1 + */ + explicit geometric_distribution(const RealType& p = RealType(0.5)) + : _p(p) + { + BOOST_ASSERT(RealType(0) < _p && _p < RealType(1)); + init(); + } + + /** Constructs a new geometric_distribution from its parameters. */ + explicit geometric_distribution(const param_type& parm) + : _p(parm.p()) + { + init(); + } + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns: the distribution parameter @c p */ + RealType p() const { return _p; } + + /** Returns the smallest value that the distribution can produce. */ + IntType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return IntType(1); } + + /** Returns the largest value that the distribution can produce. */ + IntType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return (std::numeric_limits::max)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_p); } + + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _p = parm.p(); + init(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** + * Returns a random variate distributed according to the + * geometric_distribution. + */ + template + result_type operator()(Engine& eng) const + { + using std::log; + using std::floor; + RealType x = RealType(1) - boost::uniform_01()(eng); + return IntType(floor(log(x) / _log_1mp)); + } + + /** + * Returns a random variate distributed according to the + * geometric distribution with parameters specified by param. + */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { return geometric_distribution(parm)(eng); } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, geometric_distribution, gd) + { + os << gd._p; + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, geometric_distribution, gd) + { + param_type parm; + if(is >> parm) { + gd.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will produce identical + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(geometric_distribution, lhs, rhs) + { return lhs._p == rhs._p; } + + /** + * Returns true if the two distributions may produce different + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(geometric_distribution) private: - /// \cond hide_private_functions + /// \cond show_private - void init() - { -#ifndef BOOST_NO_STDC_NAMESPACE - using std::log; -#endif - _log_p = log(_p); - } + void init() + { + using std::log; + _log_1mp = log(1 - _p); + } - /// \endcond + RealType _p; + RealType _log_1mp; - RealType _p; - RealType _log_p; + /// \endcond }; +} // namespace random + +/// \cond show_deprecated + +/** + * Provided for backwards compatibility. This class is + * deprecated. It provides the old behavior of geometric_distribution + * with \f$p(i) = (1-p) p^{i-1}\f$. + */ +template +class geometric_distribution +{ +public: + typedef RealType input_type; + typedef IntType result_type; + + explicit geometric_distribution(RealType p_arg = RealType(0.5)) + : _impl(1 - p_arg) {} + + RealType p() const { return 1 - _impl.p(); } + + void reset() {} + + template + IntType operator()(Engine& eng) const { return _impl(eng) + IntType(1); } + + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, geometric_distribution, gd) + { + os << gd.p(); + return os; + } + + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, geometric_distribution, gd) + { + RealType val; + if(is >> val) { + typename impl_type::param_type impl_param(1 - val); + gd._impl.param(impl_param); + } + return is; + } + +private: + typedef random::geometric_distribution impl_type; + impl_type _impl; +}; + +/// \endcond + } // namespace boost #endif // BOOST_RANDOM_GEOMETRIC_DISTRIBUTION_HPP - diff --git a/include/boost/random/independent_bits.hpp b/include/boost/random/independent_bits.hpp new file mode 100644 index 0000000..5ff52b8 --- /dev/null +++ b/include/boost/random/independent_bits.hpp @@ -0,0 +1,260 @@ +/* boost random/independent_bits.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_INDEPENDENT_BITS_HPP +#define BOOST_RANDOM_INDEPENDENT_BITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * An instantiation of class template @c independent_bits_engine + * model a \pseudo_random_number_generator. It generates random + * numbers distributed between [0, 2^w) by combining one or + * more invocations of the base engine. + * + * Requires: 0 < w <= std::numeric_limits::digits + */ +template +class independent_bits_engine +{ +public: + typedef Engine base_type; + typedef UIntType result_type; + + // Required by old Boost.Random concept + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 0; } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return boost::low_bits_mask_t::sig_bits; } + + /** + * Constructs an @c independent_bits_engine using the + * default constructor of the base generator. + */ + independent_bits_engine() { } + + /** + * Constructs an @c independent_bits_engine, using seed as + * the constructor argument for both base generators. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(independent_bits_engine, + result_type, seed_arg) + { + _base.seed(seed_arg); + } + + /** + * Constructs an @c independent_bits_engine, using seq as + * the constructor argument for the base generator. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(independent_bits_engine, + SeedSeq, seq) + { _base.seed(seq); } + + /** Constructs an @c independent_bits_engine by copying @c base. */ + independent_bits_engine(const base_type& base_arg) : _base(base_arg) {} + + /** + * Contructs an @c independent_bits_engine with + * values from the range defined by the input iterators first + * and last. first will be modified to point to the element + * after the last one used. + * + * Throws: @c std::invalid_argument if the input range is too small. + * + * Exception Safety: Basic + */ + template + independent_bits_engine(It& first, It last) : _base(first, last) { } + + /** + * Seeds an @c independent_bits_engine using the default + * seed of the base generator. + */ + void seed() { _base.seed(); } + + /** + * Seeds an @c independent_bits_engine, using @c seed as the + * seed for the base generator. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(independent_bits_engine, + result_type, seed_arg) + { _base.seed(seed_arg); } + + /** + * Seeds an @c independent_bits_engine, using @c seq to + * seed the base generator. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(independent_bits_engine, + SeedSeq, seq) + { _base.seed(seq); } + + /** + * Seeds an @c independent_bits_engine with + * values from the range defined by the input iterators first + * and last. first will be modified to point to the element + * after the last one used. + * + * Throws: @c std::invalid_argument if the input range is too small. + * + * Exception Safety: Basic + */ + template void seed(It& first, It last) + { _base.seed(first, last); } + + /** Returns the next value of the generator. */ + result_type operator()() + { + // While it may seem wasteful to recalculate this + // every time, both msvc and gcc can propagate + // constants, resolving this at compile time. + base_unsigned range = + detail::subtract()((_base.max)(), (_base.min)()); + std::size_t m = + (range == (std::numeric_limits::max)()) ? + std::numeric_limits::digits : + detail::integer_log2(range + 1); + std::size_t n = (w + m - 1) / m; + std::size_t w0, n0; + base_unsigned y0, y1; + base_unsigned y0_mask, y1_mask; + calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask); + if(base_unsigned(range - y0 + 1) > y0 / n) { + // increment n and try again. + ++n; + calc_params(n, range, w0, n0, y0, y1, y0_mask, y1_mask); + } + + BOOST_ASSERT(n0*w0 + (n - n0)*(w0 + 1) == w); + + result_type S = 0; + for(std::size_t k = 0; k < n0; ++k) { + base_unsigned u; + do { + u = detail::subtract()(_base(), (_base.min)()); + } while(u > base_unsigned(y0 - 1)); + S = (S << w0) + (u & y0_mask); + } + for(std::size_t k = 0; k < (n - n0); ++k) { + base_unsigned u; + do { + u = detail::subtract()(_base(), (_base.min)()); + } while(u > base_unsigned(y1 - 1)); + S = (S << (w0 + 1)) + (u & y1_mask); + } + return S; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } + + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t i = 0; i < z; ++i) { + (*this)(); + } + } + + const base_type& base() const { return _base; } + + /** + * Writes the textual representation if the generator to a @c std::ostream. + * The textual representation of the engine is the textual representation + * of the base engine. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, independent_bits_engine, r) + { + os << r._base; + return os; + } + + /** + * Reads the state of an @c independent_bits_engine from a + * @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, independent_bits_engine, r) + { + is >> r._base; + return is; + } + + /** + * Returns: true iff the two @c independent_bits_engines will + * produce the same sequence of values. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(independent_bits_engine, x, y) + { return x._base == y._base; } + /** + * Returns: true iff the two @c independent_bits_engines will + * produce different sequences of values. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(independent_bits_engine) + +private: + + /// \cond show_private + typedef typename base_type::result_type base_result; + typedef typename make_unsigned::type base_unsigned; + + void calc_params( + std::size_t n, base_unsigned range, + std::size_t& w0, std::size_t& n0, + base_unsigned& y0, base_unsigned& y1, + base_unsigned& y0_mask, base_unsigned& y1_mask) + { + BOOST_ASSERT(w >= n); + w0 = w/n; + n0 = n - w % n; + y0_mask = (base_unsigned(2) << (w0 - 1)) - 1; + y1_mask = (y0_mask << 1) | 1; + y0 = (range + 1) & ~y0_mask; + y1 = (range + 1) & ~y1_mask; + BOOST_ASSERT(y0 != 0 || base_unsigned(range + 1) == 0); + } + /// \endcond + + Engine _base; +}; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template +const bool independent_bits_engine::has_fixed_range; +#endif + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_INDEPENDENT_BITS_HPP diff --git a/include/boost/random/inversive_congruential.hpp b/include/boost/random/inversive_congruential.hpp index ad6fbc8..2329c0d 100644 --- a/include/boost/random/inversive_congruential.hpp +++ b/include/boost/random/inversive_congruential.hpp @@ -16,20 +16,26 @@ #ifndef BOOST_RANDOM_INVERSIVE_CONGRUENTIAL_HPP #define BOOST_RANDOM_INVERSIVE_CONGRUENTIAL_HPP -#include -#include +#include #include +#include #include -#include +#include +#include #include #include +#include +#include +#include + +#include namespace boost { namespace random { // Eichenauer and Lehn 1986 /** - * Instantiations of class template @c inversive_congruential model a + * Instantiations of class template @c inversive_congruential_engine model a * \pseudo_random_number_generator. It uses the inversive congruential * algorithm (ICG) described in * @@ -57,103 +63,185 @@ namespace random { * not optimal for calculating the multiplicative inverse. * @endxmlnote */ -template -class inversive_congruential +template +class inversive_congruential_engine { public: - typedef IntType result_type; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION - static const bool has_fixed_range = true; - static const result_type min_value = (b == 0 ? 1 : 0); - static const result_type max_value = p-1; -#else - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); -#endif - BOOST_STATIC_CONSTANT(result_type, multiplier = a); - BOOST_STATIC_CONSTANT(result_type, increment = b); - BOOST_STATIC_CONSTANT(result_type, modulus = p); + typedef IntType result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return b == 0 ? 1 : 0; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return p-1; } + BOOST_STATIC_CONSTANT(result_type, multiplier = a); + BOOST_STATIC_CONSTANT(result_type, increment = b); + BOOST_STATIC_CONSTANT(result_type, modulus = p); + BOOST_STATIC_CONSTANT(IntType, default_seed = 1); - /** - * Constructs an inversive_congruential generator with - * @c y0 as the initial state. - */ - explicit inversive_congruential(IntType y0 = 1) : value(y0) - { - BOOST_STATIC_ASSERT(b >= 0); - BOOST_STATIC_ASSERT(p > 1); - BOOST_STATIC_ASSERT(a >= 1); - if(b == 0) - assert(y0 > 0); - } - template inversive_congruential(It& first, It last) - { seed(first, last); } + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return b == 0 ? 1 : 0; } + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return p-1; } + + /** + * Constructs an @c inversive_congruential_engine, seeding it with + * the default seed. + */ + inversive_congruential_engine() { seed(); } - /** Changes the current state to y0. */ - void seed(IntType y0 = 1) { value = y0; if(b == 0) assert(y0 > 0); } - template void seed(It& first, It last) - { - if(first == last) - throw std::invalid_argument("inversive_congruential::seed"); - value = *first++; - } - IntType operator()() - { - typedef const_mod do_mod; - value = do_mod::mult_add(a, do_mod::invert(value), b); - return value; - } + /** + * Constructs an @c inversive_congruential_engine, seeding it with @c x0. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(inversive_congruential_engine, + IntType, x0) + { seed(x0); } + + /** + * Constructs an @c inversive_congruential_engine, seeding it with values + * produced by a call to @c seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(inversive_congruential_engine, + SeedSeq, seq) + { seed(seq); } + + /** + * Constructs an @c inversive_congruential_engine, seeds it + * with values taken from the itrator range [first, last), + * and adjusts first to point to the element after the last one + * used. If there are not enough elements, throws @c std::invalid_argument. + * + * first and last must be input iterators. + */ + template inversive_congruential_engine(It& first, It last) + { seed(first, last); } - static bool validation(result_type x) { return val == x; } + /** + * Calls seed(default_seed) + */ + void seed() { seed(default_seed); } + + /** + * If c mod m is zero and x0 mod m is zero, changes the current value of + * the generator to 1. Otherwise, changes it to x0 mod m. If c is zero, + * distinct seeds in the range [1,m) will leave the generator in distinct + * states. If c is not zero, the range is [0,m). + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(inversive_congruential_engine, IntType, x0) + { + // wrap _x if it doesn't fit in the destination + if(modulus == 0) { + _value = x0; + } else { + _value = x0 % modulus; + } + // handle negative seeds + if(_value <= 0 && _value != 0) { + _value += modulus; + } + // adjust to the correct range + if(increment == 0 && _value == 0) { + _value = 1; + } + BOOST_ASSERT(_value >= (min)()); + BOOST_ASSERT(_value <= (max)()); + } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** + * Seeds an @c inversive_congruential_engine using values from a SeedSeq. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(inversive_congruential_engine, SeedSeq, seq) + { seed(detail::seed_one_int(seq)); } + + /** + * seeds an @c inversive_congruential_engine with values taken + * from the itrator range [first, last) and adjusts @c first to + * point to the element after the last one used. If there are + * not enough elements, throws @c std::invalid_argument. + * + * @c first and @c last must be input iterators. + */ + template void seed(It& first, It last) + { seed(detail::get_one_int(first, last)); } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, inversive_congruential x) - { os << x.value; return os; } + /** Returns the next output of the generator. */ + IntType operator()() + { + typedef const_mod do_mod; + _value = do_mod::mult_add(a, do_mod::invert(_value), b); + return _value; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, inversive_congruential& x) - { is >> x.value; return is; } -#endif + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, inversive_congruential_engine, x) + { + os << x._value; + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, inversive_congruential_engine, x) + { + is >> x._value; + return is; + } + + /** + * Returns true if the two generators will produce identical + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(inversive_congruential_engine, x, y) + { return x._value == y._value; } + + /** + * Returns true if the two generators will produce different + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(inversive_congruential_engine) - friend bool operator==(inversive_congruential x, inversive_congruential y) - { return x.value == y.value; } - friend bool operator!=(inversive_congruential x, inversive_congruential y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(inversive_congruential rhs) const - { return value == rhs.value; } - bool operator!=(inversive_congruential rhs) const - { return !(*this == rhs); } -#endif private: - IntType value; + IntType _value; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool inversive_congruential::has_fixed_range; -template -const typename inversive_congruential::result_type inversive_congruential::min_value; -template -const typename inversive_congruential::result_type inversive_congruential::max_value; -template -const typename inversive_congruential::result_type inversive_congruential::multiplier; -template -const typename inversive_congruential::result_type inversive_congruential::increment; -template -const typename inversive_congruential::result_type inversive_congruential::modulus; +template +const bool inversive_congruential_engine::has_fixed_range; +template +const typename inversive_congruential_engine::result_type inversive_congruential_engine::multiplier; +template +const typename inversive_congruential_engine::result_type inversive_congruential_engine::increment; +template +const typename inversive_congruential_engine::result_type inversive_congruential_engine::modulus; +template +const typename inversive_congruential_engine::result_type inversive_congruential_engine::default_seed; #endif -} // namespace random +/// \cond show_deprecated + +// provided for backwards compatibility +template +class inversive_congruential : public inversive_congruential_engine +{ + typedef inversive_congruential_engine base_type; +public: + inversive_congruential(IntType x0 = 1) : base_type(x0) {} + template + inversive_congruential(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond /** * The specialization hellekalek1995 was suggested in @@ -165,9 +253,15 @@ const typename inversive_congruential::result_type invers * (editors), 1995, pp. 255-262. ftp://random.mat.sbg.ac.at/pub/data/wsc95.ps * @endblockquote */ -typedef random::inversive_congruential hellekalek1995; +typedef inversive_congruential_engine hellekalek1995; + +} // namespace random + +using random::hellekalek1995; } // namespace boost +#include + #endif // BOOST_RANDOM_INVERSIVE_CONGRUENTIAL_HPP diff --git a/include/boost/random/lagged_fibonacci.hpp b/include/boost/random/lagged_fibonacci.hpp index cbb2d47..87e9076 100644 --- a/include/boost/random/lagged_fibonacci.hpp +++ b/include/boost/random/lagged_fibonacci.hpp @@ -16,289 +16,223 @@ #ifndef BOOST_RANDOM_LAGGED_FIBONACCI_HPP #define BOOST_RANDOM_LAGGED_FIBONACCI_HPP -#include -#include +#include +#include #include // std::max #include #include // std::pow #include #include #include -#include +#include #include #include #include #include -#include +#include +#include namespace boost { namespace random { -#if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300 -# define BOOST_RANDOM_EXTRACT_LF -#endif - -#if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3) -# define BOOST_RANDOM_EXTRACT_LF -#endif - -# ifdef BOOST_RANDOM_EXTRACT_LF -namespace detail -{ - template - IStream& - extract_lagged_fibonacci_01( - IStream& is - , F const& f - , unsigned int& i - , RealType* x - , RealType modulus) - { - is >> i >> std::ws; - for(unsigned int i = 0; i < f.long_lag; ++i) - { - RealType value; - is >> value >> std::ws; - x[i] = value / modulus; - } - return is; - } - - template - IStream& - extract_lagged_fibonacci( - IStream& is - , F const& f - , unsigned int& i - , UIntType* x) - { - is >> i >> std::ws; - for(unsigned int i = 0; i < f.long_lag; ++i) - is >> x[i] >> std::ws; - return is; - } -} -# endif - /** - * Instantiations of class template \lagged_fibonacci model a + * Instantiations of class template \lagged_fibonacci_engine model a * \pseudo_random_number_generator. It uses a lagged Fibonacci * algorithm with two lags @c p and @c q: * x(i) = x(i-p) + x(i-q) (mod 2w) with p > q. */ -template -class lagged_fibonacci +template +class lagged_fibonacci_engine { public: - typedef UIntType result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, word_size = w); - BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); - BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); + typedef UIntType result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(int, word_size = w); + BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); + BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); - /** - * Returns: the smallest value that the generator can produce - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } - /** - * Returns: the largest value that the generator can produce - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return wordmask; } + BOOST_STATIC_CONSTANT(UIntType, default_seed = 331u); - /** - * Creates a new @c lagged_fibonacci generator and calls @c seed() - */ - lagged_fibonacci() { init_wordmask(); seed(); } - /** - * Creates a new @c lagged_fibonacci generator and calls @c seed(value) - */ - explicit lagged_fibonacci(uint32_t value) { init_wordmask(); seed(value); } - /** - * Creates a new @c lagged_fibonacci generator and calls @c seed(first, last) - */ - template lagged_fibonacci(It& first, It last) - { init_wordmask(); seed(first, last); } - // compiler-generated copy ctor and assignment operator are fine + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return low_bits_mask_t::sig_bits; } -private: - /// \cond hide_private_members - void init_wordmask() - { - wordmask = 0; - for(int j = 0; j < w; ++j) - wordmask |= (1u << j); - } - /// \endcond + /** Creates a new @c lagged_fibonacci_engine and calls @c seed(). */ + lagged_fibonacci_engine() { seed(); } -public: - /** - * Sets the state of the generator to values produced by - * a \minstd_rand generator. - */ - void seed(uint32_t value = 331u) - { - minstd_rand0 gen(value); - for(unsigned int j = 0; j < long_lag; ++j) - x[j] = gen() & wordmask; - i = long_lag; - } + /** Creates a new @c lagged_fibonacci_engine and calls @c seed(value). */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_engine, + UIntType, value) + { seed(value); } - /** - * Sets the state of the generator to values from the iterator - * range [first, last). If there are not enough elements in the - * range [first, last) throws @c std::invalid_argument. - */ - template - void seed(It& first, It last) - { - // word size could be smaller than the seed values - unsigned int j; - for(j = 0; j < long_lag && first != last; ++j, ++first) - x[j] = *first & wordmask; - i = long_lag; - if(first == last && j < long_lag) - throw std::invalid_argument("lagged_fibonacci::seed"); - } + /** Creates a new @c lagged_fibonacci_engine and calls @c seed(seq). */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_engine, + SeedSeq, seq) + { seed(seq); } - /** - * Returns: the next value of the generator - */ - result_type operator()() - { - if(i >= long_lag) - fill(); - return x[i++]; - } + /** + * Creates a new @c lagged_fibonacci_engine and calls @c seed(first, last). + */ + template lagged_fibonacci_engine(It& first, It last) + { seed(first, last); } - static bool validation(result_type x) - { - return x == val; - } + // compiler-generated copy ctor and assignment operator are fine + + /** Calls @c seed(default_seed). */ + void seed() { seed(default_seed); } + + /** + * Sets the state of the generator to values produced by + * a \minstd_rand0 generator. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_engine, + UIntType, value) + { + minstd_rand0 intgen(static_cast(value)); + detail::generator_seed_seq gen(intgen); + seed(gen); + } + + /** + * Sets the state of the generator using values produced by seq. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_engine, SeedSeq, seq) + { + detail::seed_array_int(seq, x); + i = long_lag; + } + + /** + * Sets the state of the generator to values from the iterator + * range [first, last). If there are not enough elements in the + * range [first, last) throws @c std::invalid_argument. + */ + template + void seed(It& first, It last) + { + detail::fill_array_int(first, last, x); + i = long_lag; + } + + /** Returns the next value of the generator. */ + result_type operator()() + { + if(i >= long_lag) + fill(); + return x[i++]; + } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const lagged_fibonacci& f) - { - os << f.i << " "; - for(unsigned int i = 0; i < f.long_lag; ++i) - os << f.x[i] << " "; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, lagged_fibonacci& f) - { -# ifdef BOOST_RANDOM_EXTRACT_LF - return detail::extract_lagged_fibonacci(is, f, f.i, f.x); -# else - is >> f.i >> std::ws; - for(unsigned int i = 0; i < f.long_lag; ++i) - is >> f.x[i] >> std::ws; - return is; -# endif - } -#endif - - friend bool operator==(const lagged_fibonacci& x, const lagged_fibonacci& y) - { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } - friend bool operator!=(const lagged_fibonacci& x, - const lagged_fibonacci& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const lagged_fibonacci& rhs) const - { return i == rhs.i && std::equal(x, x+long_lag, rhs.x); } - bool operator!=(const lagged_fibonacci& rhs) const - { return !(*this == rhs); } -#endif + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_engine, f) + { + os << f.i; + for(unsigned int i = 0; i < f.long_lag; ++i) + os << ' ' << f.x[i]; + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_engine, f) + { + is >> f.i >> std::ws; + for(unsigned int i = 0; i < f.long_lag; ++i) + is >> f.x[i] >> std::ws; + return is; + } + + /** + * Returns true if the two generators will produce identical + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_engine, x, y) + { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } + + /** + * Returns true if the two generators will produce different + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_engine) private: - /// \cond hide_private_members - void fill(); - /// \endcond + /// \cond show_private + void fill(); + /// \endcond - UIntType wordmask; - unsigned int i; - UIntType x[long_lag]; + unsigned int i; + UIntType x[long_lag]; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool lagged_fibonacci::has_fixed_range; -template -const unsigned int lagged_fibonacci::long_lag; -template -const unsigned int lagged_fibonacci::short_lag; +template +const bool lagged_fibonacci_engine::has_fixed_range; +template +const unsigned int lagged_fibonacci_engine::long_lag; +template +const unsigned int lagged_fibonacci_engine::short_lag; +template +const UIntType lagged_fibonacci_engine::default_seed; #endif -/// \cond hide_private_members +/// \cond show_private -template -void lagged_fibonacci::fill() +template +void lagged_fibonacci_engine::fill() { - // two loops to avoid costly modulo operations - { // extra scope for MSVC brokenness w.r.t. for scope - for(unsigned int j = 0; j < short_lag; ++j) - x[j] = (x[j] + x[j+(long_lag-short_lag)]) & wordmask; - } - for(unsigned int j = short_lag; j < long_lag; ++j) - x[j] = (x[j] + x[j-short_lag]) & wordmask; - i = 0; + // two loops to avoid costly modulo operations + { // extra scope for MSVC brokenness w.r.t. for scope + for(unsigned int j = 0; j < short_lag; ++j) + x[j] = (x[j] + x[j+(long_lag-short_lag)]) & low_bits_mask_t::sig_bits; + } + for(unsigned int j = short_lag; j < long_lag; ++j) + x[j] = (x[j] + x[j-short_lag]) & low_bits_mask_t::sig_bits; + i = 0; } +/// \endcond +/// \cond show_deprecated + +// provided for backwards compatibility +template +class lagged_fibonacci : public lagged_fibonacci_engine +{ + typedef lagged_fibonacci_engine base_type; +public: + lagged_fibonacci() {} + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci, UIntType, val) + { this->seed(val); } + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci, SeedSeq, seq) + { this->seed(seq); } + template + lagged_fibonacci(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond // lagged Fibonacci generator for the range [0..1) // contributed by Matthias Troyer // for p=55, q=24 originally by G. J. Mitchell and D. P. Moore 1958 -template -struct fibonacci_validation -{ - BOOST_STATIC_CONSTANT(bool, is_specialized = false); - static T value() { return 0; } - static T tolerance() { return 0; } -}; - -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION -// A definition is required even for integral static constants -template -const bool fibonacci_validation::is_specialized; -#endif - -#define BOOST_RANDOM_FIBONACCI_VAL(T,P,Q,V,E) \ -template<> \ -struct fibonacci_validation \ -{ \ - BOOST_STATIC_CONSTANT(bool, is_specialized = true); \ - static T value() { return V; } \ - static T tolerance() \ -{ return (std::max)(E, static_cast(5*std::numeric_limits::epsilon())); } \ -}; -// (The extra static_cast in the std::max call above is actually -// unnecessary except for HP aCC 1.30, which claims that -// numeric_limits::epsilon() doesn't actually return a double.) - -BOOST_RANDOM_FIBONACCI_VAL(double, 607, 273, 0.4293817707235914, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 1279, 418, 0.9421630240437659, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 2281, 1252, 0.1768114046909004, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 3217, 576, 0.1956232694868209, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 4423, 2098, 0.9499762202147172, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 9689, 5502, 0.05737836943695162, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 19937, 9842, 0.5076528587449834, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 23209, 13470, 0.5414473810619185, 1e-14) -BOOST_RANDOM_FIBONACCI_VAL(double, 44497,21034, 0.254135073399297, 1e-14) - -#undef BOOST_RANDOM_FIBONACCI_VAL - -/// \endcond - /** * Instantiations of class template @c lagged_fibonacci_01 model a * \pseudo_random_number_generator. It uses a lagged Fibonacci @@ -322,216 +256,215 @@ BOOST_RANDOM_FIBONACCI_VAL(double, 44497,21034, 0.254135073399297, 1e-14) * 4856 bytes and \lagged_fibonacci44497 requires about 350 KBytes. */ template -class lagged_fibonacci_01 +class lagged_fibonacci_01_engine { public: - typedef RealType result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, word_size = w); - BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); - BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); + typedef RealType result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(int, word_size = w); + BOOST_STATIC_CONSTANT(unsigned int, long_lag = p); + BOOST_STATIC_CONSTANT(unsigned int, short_lag = q); - /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(). */ - lagged_fibonacci_01() { init_modulus(); seed(); } - /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(value). */ - BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, uint32_t, value) - { init_modulus(); seed(value); } - /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(gen). */ - BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(lagged_fibonacci_01, Generator, gen) - { init_modulus(); seed(gen); } - template lagged_fibonacci_01(It& first, It last) - { init_modulus(); seed(first, last); } - // compiler-generated copy ctor and assignment operator are fine + BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 331u); -private: - /// \cond hide_private_members - void init_modulus() - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::pow; -#endif - _modulus = pow(RealType(2), word_size); - } - /// \endcond + /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(). */ + lagged_fibonacci_01_engine() { seed(); } + /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(value). */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01_engine, uint32_t, value) + { seed(value); } + /** Constructs a @c lagged_fibonacci_01 generator and calls @c seed(gen). */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01_engine, SeedSeq, seq) + { seed(seq); } + template lagged_fibonacci_01_engine(It& first, It last) + { seed(first, last); } -public: - /** Calls seed(331u). */ - void seed() { seed(331u); } - /** - * Constructs a \minstd_rand0 generator with the constructor parameter - * value and calls seed with it. Distinct seeds in the range - * [1, 2147483647) will produce generators with different states. Other - * seeds will be equivalent to some seed within this range. See - * \linear_congruential for details. - */ - BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01, uint32_t, value) - { - minstd_rand0 intgen(value); - seed(intgen); - } + // compiler-generated copy ctor and assignment operator are fine - /** - * Sets the state of this @c lagged_fibonacci_01 to the values returned - * by p invocations of \uniform_01\()(gen). - * - * Complexity: Exactly p invocations of gen. - */ - BOOST_RANDOM_DETAIL_GENERATOR_SEED(lagged_fibonacci, Generator, gen) - { - // use pass-by-reference, but wrap argument in pass_through_engine - typedef detail::pass_through_engine ref_gen; - uniform_01 gen01 = - uniform_01(ref_gen(gen)); - // I could have used std::generate_n, but it takes "gen" by value - for(unsigned int j = 0; j < long_lag; ++j) - x[j] = gen01(); - i = long_lag; - } + /** Calls seed(default_seed). */ + void seed() { seed(default_seed); } - template - void seed(It& first, It last) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::fmod; - using std::pow; -#endif - unsigned long mask = ~((~0u) << (w%32)); // now lowest w bits set - RealType two32 = pow(RealType(2), 32); - unsigned int j; - for(j = 0; j < long_lag && first != last; ++j) { - x[j] = RealType(0); - for(int k = 0; k < w/32 && first != last; ++k, ++first) - x[j] += *first / pow(two32,k+1); - if(first != last && mask != 0) { - x[j] += fmod((*first & mask) / _modulus, RealType(1)); - ++first; - } - } - i = long_lag; - if(first == last && j < long_lag) - throw std::invalid_argument("lagged_fibonacci_01::seed"); - } - - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } - - result_type operator()() - { - if(i >= long_lag) - fill(); - return x[i++]; - } - - static bool validation(result_type x) - { - result_type v = fibonacci_validation::value(); - result_type epsilon = fibonacci_validation::tolerance(); - // std::abs is a source of trouble: sometimes, it's not overloaded - // for double, plus the usual namespace std noncompliance -> avoid it - // using std::abs; - // return abs(x - v) < 5 * epsilon - return x > v - epsilon && x < v + epsilon; - } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const lagged_fibonacci_01&f) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::pow; -#endif - os << f.i << " "; - std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); - for(unsigned int i = 0; i < f.long_lag; ++i) - os << f.x[i] * f._modulus << " "; - os.flags(oldflags); - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, lagged_fibonacci_01& f) + /** + * Constructs a \minstd_rand0 generator with the constructor parameter + * value and calls seed with it. Distinct seeds in the range + * [1, 2147483647) will produce generators with different states. Other + * seeds will be equivalent to some seed within this range. See + * \linear_congruential_engine for details. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01_engine, boost::uint32_t, value) { -# ifdef BOOST_RANDOM_EXTRACT_LF - return detail::extract_lagged_fibonacci_01(is, f, f.i, f.x, f._modulus); -# else - is >> f.i >> std::ws; + minstd_rand0 intgen(value); + detail::generator_seed_seq gen(intgen); + seed(gen); + } + + /** + * Seeds this @c lagged_fibonacci_01_engine using values produced by + * @c seq.generate. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(lagged_fibonacci_01_engine, SeedSeq, seq) + { + detail::seed_array_real(seq, x); + i = long_lag; + } + + /** + * Seeds this @c lagged_fibonacci_01_engine using values from the + * iterator range [first, last). If there are not enough elements + * in the range, throws @c std::invalid_argument. + */ + template + void seed(It& first, It last) + { + detail::fill_array_real(first, last, x); + i = long_lag; + } + + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(0); } + /** Returns the upper bound of the generators outputs. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return result_type(1); } + + /** + * INTERNAL ONLY + * Returns the number of random bits. + * This is not part of the standard, and I'm not sure that + * it's the best solution, but something like this is needed + * to implement generate_canonical. For now, mark it as + * an implementation detail. + */ + static std::size_t precision() { return w; } + + /** Returns the next value of the generator. */ + result_type operator()() + { + if(i >= long_lag) + fill(); + return x[i++]; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { return detail::generate_from_real(*this, first, last); } + + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lagged_fibonacci_01_engine, f) + { + // allow for Koenig lookup + using std::pow; + os << f.i; + std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); + for(unsigned int i = 0; i < f.long_lag; ++i) + os << ' ' << f.x[i] * f.modulus(); + os.flags(oldflags); + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lagged_fibonacci_01_engine, f) + { + is >> f.i; for(unsigned int i = 0; i < f.long_lag; ++i) { - typename lagged_fibonacci_01::result_type value; - is >> value >> std::ws; - f.x[i] = value / f._modulus; + typename lagged_fibonacci_01_engine::result_type value; + is >> std::ws >> value; + f.x[i] = value / f.modulus(); } return is; -# endif } -#endif - - friend bool operator==(const lagged_fibonacci_01& x, - const lagged_fibonacci_01& y) - { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } - friend bool operator!=(const lagged_fibonacci_01& x, - const lagged_fibonacci_01& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const lagged_fibonacci_01& rhs) const - { return i == rhs.i && std::equal(x, x+long_lag, rhs.x); } - bool operator!=(const lagged_fibonacci_01& rhs) const - { return !(*this == rhs); } -#endif + + /** + * Returns true if the two generators will produce identical + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lagged_fibonacci_01_engine, x, y) + { return x.i == y.i && std::equal(x.x, x.x+long_lag, y.x); } + + /** + * Returns true if the two generators will produce different + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lagged_fibonacci_01_engine) private: - /// \cond hide_private_members - void fill(); - /// \endcond - unsigned int i; - RealType x[long_lag]; - RealType _modulus; + /// \cond show_private + void fill(); + static RealType modulus() + { + using std::pow; + return pow(RealType(2), word_size); + } + /// \endcond + unsigned int i; + RealType x[long_lag]; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants template -const bool lagged_fibonacci_01::has_fixed_range; +const bool lagged_fibonacci_01_engine::has_fixed_range; template -const unsigned int lagged_fibonacci_01::long_lag; +const unsigned int lagged_fibonacci_01_engine::long_lag; template -const unsigned int lagged_fibonacci_01::short_lag; +const unsigned int lagged_fibonacci_01_engine::short_lag; template -const int lagged_fibonacci_01::word_size; - +const int lagged_fibonacci_01_engine::word_size; +template +const boost::uint32_t lagged_fibonacci_01_engine::default_seed; #endif -/// \cond hide_private_members +/// \cond show_private template -void lagged_fibonacci_01::fill() +void lagged_fibonacci_01_engine::fill() { - // two loops to avoid costly modulo operations - { // extra scope for MSVC brokenness w.r.t. for scope - for(unsigned int j = 0; j < short_lag; ++j) { - RealType t = x[j] + x[j+(long_lag-short_lag)]; - if(t >= RealType(1)) - t -= RealType(1); - x[j] = t; - } - } - for(unsigned int j = short_lag; j < long_lag; ++j) { - RealType t = x[j] + x[j-short_lag]; - if(t >= RealType(1)) - t -= RealType(1); - x[j] = t; - } - i = 0; + // two loops to avoid costly modulo operations + { // extra scope for MSVC brokenness w.r.t. for scope + for(unsigned int j = 0; j < short_lag; ++j) { + RealType t = x[j] + x[j+(long_lag-short_lag)]; + if(t >= RealType(1)) + t -= RealType(1); + x[j] = t; + } + } + for(unsigned int j = short_lag; j < long_lag; ++j) { + RealType t = x[j] + x[j-short_lag]; + if(t >= RealType(1)) + t -= RealType(1); + x[j] = t; + } + i = 0; } /// \endcond -} // namespace random +/// \cond show_deprecated + +// provided for backwards compatibility +template +class lagged_fibonacci_01 : public lagged_fibonacci_01_engine +{ + typedef lagged_fibonacci_01_engine base_type; +public: + lagged_fibonacci_01() {} + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, boost::uint32_t, val) + { this->seed(val); } + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(lagged_fibonacci_01, SeedSeq, seq) + { this->seed(seq); } + template + lagged_fibonacci_01(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond #ifdef BOOST_RANDOM_DOXYGEN namespace detail { @@ -558,47 +491,36 @@ struct lagged_fibonacci_doc {}; } #endif -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci607; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci1279; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci2281; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci3217; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci4423; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci9689; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci19937; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci23209; -/** - * @copydoc boost::detail::lagged_fibonacci_doc - */ -typedef random::lagged_fibonacci_01 lagged_fibonacci44497; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci607; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci1279; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci2281; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci3217; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci4423; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci9689; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci19937; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci23209; +/** @copydoc boost::random::detail::lagged_fibonacci_doc */ +typedef lagged_fibonacci_01_engine lagged_fibonacci44497; +} // namespace random -// It is possible to partially specialize uniform_01<> on lagged_fibonacci_01<> -// to help the compiler generate efficient code. For GCC, this seems useless, -// because GCC optimizes (x-0)/(1-0) to (x-0). This is good enough for now. +using random::lagged_fibonacci607; +using random::lagged_fibonacci1279; +using random::lagged_fibonacci2281; +using random::lagged_fibonacci3217; +using random::lagged_fibonacci4423; +using random::lagged_fibonacci9689; +using random::lagged_fibonacci19937; +using random::lagged_fibonacci23209; +using random::lagged_fibonacci44497; } // namespace boost diff --git a/include/boost/random/linear_congruential.hpp b/include/boost/random/linear_congruential.hpp index 90f6e61..de3a1d0 100644 --- a/include/boost/random/linear_congruential.hpp +++ b/include/boost/random/linear_congruential.hpp @@ -17,13 +17,19 @@ #define BOOST_RANDOM_LINEAR_CONGRUENTIAL_HPP #include -#include #include +#include #include +#include #include #include +#include +#include +#include #include #include +#include +#include #include #include @@ -32,13 +38,15 @@ namespace boost { namespace random { /** - * Instantiations of class template linear_congruential model a + * Instantiations of class template linear_congruential_engine model a * \pseudo_random_number_generator. Linear congruential pseudo-random * number generators are described in: * + * @blockquote * "Mathematical methods in large-scale computing units", D. H. Lehmer, * Proc. 2nd Symposium on Large-Scale Digital Calculating Machines, * Harvard University Press, 1951, pp. 141-146 + * @endblockquote * * Let x(n) denote the sequence of numbers returned by some pseudo-random * number generator. Then for the linear congruential generator, @@ -51,208 +59,250 @@ namespace random { * the parameters. User code should use one of the sensibly parameterized * generators such as minstd_rand instead. */ -template -class linear_congruential +template +class linear_congruential_engine { public: - typedef IntType result_type; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION - static const bool has_fixed_range = true; - static const result_type min_value = ( c == 0 ? 1 : 0 ); - static const result_type max_value = m-1; -#else - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); -#endif - BOOST_STATIC_CONSTANT(IntType, multiplier = a); - BOOST_STATIC_CONSTANT(IntType, increment = c); - BOOST_STATIC_CONSTANT(IntType, modulus = m); + typedef IntType result_type; - // MSVC 6 and possibly others crash when encountering complicated integral - // constant expressions. Avoid the check for now. - // BOOST_STATIC_ASSERT(m == 0 || a < m); - // BOOST_STATIC_ASSERT(m == 0 || c < m); + // Required for old Boost.Random concept + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - /** - * Constructs a linear_congruential generator, seeding it with @c x0. - */ - explicit linear_congruential(IntType x0 = 1) - { - seed(x0); - - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_CONSTANT(IntType, multiplier = a); + BOOST_STATIC_CONSTANT(IntType, increment = c); + BOOST_STATIC_CONSTANT(IntType, modulus = m); + BOOST_STATIC_CONSTANT(IntType, default_seed = 1); + BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); + BOOST_STATIC_ASSERT(m == 0 || a < m); + BOOST_STATIC_ASSERT(m == 0 || c < m); + + /** + * Constructs a @c linear_congruential_engine, using the default seed + */ + linear_congruential_engine() { seed(); } + + /** + * Constructs a @c linear_congruential_engine, seeding it with @c x0. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(linear_congruential_engine, + IntType, x0) + { seed(x0); } + + /** + * Constructs a @c linear_congruential_engine, seeding it with values + * produced by a call to @c seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(linear_congruential_engine, + SeedSeq, seq) + { seed(seq); } + + /** + * Constructs a @c linear_congruential_engine and seeds it + * with values taken from the itrator range [first, last) + * and adjusts first to point to the element after the last one + * used. If there are not enough elements, throws @c std::invalid_argument. + * + * first and last must be input iterators. + */ + template + linear_congruential_engine(It& first, It last) + { + seed(first, last); + } + + // compiler-generated copy constructor and assignment operator are fine + + /** + * Calls seed(default_seed) + */ + void seed() { seed(default_seed); } + + /** + * If c mod m is zero and x0 mod m is zero, changes the current value of + * the generator to 1. Otherwise, changes it to x0 mod m. If c is zero, + * distinct seeds in the range [1,m) will leave the generator in distinct + * states. If c is not zero, the range is [0,m). + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(linear_congruential_engine, IntType, x0) + { + // wrap _x if it doesn't fit in the destination + if(modulus == 0) { + _x = x0; + } else { + _x = x0 % modulus; + } + // handle negative seeds + if(_x <= 0 && _x != 0) { + _x += modulus; + } + // adjust to the correct range + if(increment == 0 && _x == 0) { + _x = 1; + } + BOOST_ASSERT(_x >= (min)()); + BOOST_ASSERT(_x <= (max)()); + } + + /** + * Seeds a @c linear_congruential_engine using values from a SeedSeq. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(linear_congruential_engine, SeedSeq, seq) + { seed(detail::seed_one_int(seq)); } + + /** + * seeds a @c linear_congruential_engine with values taken + * from the itrator range [first, last) and adjusts @c first to + * point to the element after the last one used. If there are + * not enough elements, throws @c std::invalid_argument. + * + * @c first and @c last must be input iterators. + */ + template + void seed(It& first, It last) + { seed(detail::get_one_int(first, last)); } + + /** + * Returns the smallest value that the @c linear_congruential_engine + * can produce. + */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return c == 0 ? 1 : 0; } + /** + * Returns the largest value that the @c linear_congruential_engine + * can produce. + */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return modulus-1; } + + /** Returns the next value of the @c linear_congruential_engine. */ + IntType operator()() + { + _x = const_mod::mult_add(a, _x, c); + return _x; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } + + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + typedef const_mod mod_type; + IntType b_inv = mod_type::invert(a-1); + IntType b_gcd = mod_type::mult(a-1, b_inv); + if(b_gcd == 1) { + IntType a_z = mod_type::pow(a, z); + _x = mod_type::mult_add(a_z, _x, + mod_type::mult(mod_type::mult(c, b_inv), a_z - 1)); + } else { + // compute (a^z - 1)*c % (b_gcd * m) / (b / b_gcd) * inv(b / b_gcd) + // we're storing the intermediate result / b_gcd + IntType a_zm1_over_gcd = 0; + IntType a_km1_over_gcd = (a - 1) / b_gcd; + boost::uintmax_t exponent = z; + while(exponent != 0) { + if(exponent % 2 == 1) { + a_zm1_over_gcd = + mod_type::mult_add( + b_gcd, + mod_type::mult(a_zm1_over_gcd, a_km1_over_gcd), + mod_type::add(a_zm1_over_gcd, a_km1_over_gcd)); + } + a_km1_over_gcd = mod_type::mult_add( + b_gcd, + mod_type::mult(a_km1_over_gcd, a_km1_over_gcd), + mod_type::add(a_km1_over_gcd, a_km1_over_gcd)); + exponent /= 2; + } + + IntType a_z = mod_type::mult_add(b_gcd, a_zm1_over_gcd, 1); + IntType num = mod_type::mult(c, a_zm1_over_gcd); + b_inv = mod_type::invert((a-1)/b_gcd); + _x = mod_type::mult_add(a_z, _x, mod_type::mult(b_inv, num)); + } + } + + friend bool operator==(const linear_congruential_engine& x, + const linear_congruential_engine& y) + { return x._x == y._x; } + friend bool operator!=(const linear_congruential_engine& x, + const linear_congruential_engine& y) + { return !(x == y); } + +#if !defined(BOOST_RANDOM_NO_STREAM_OPERATORS) + /** Writes a @c linear_congruential_engine to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const linear_congruential_engine& lcg) + { + return os << lcg._x; + } + + /** Reads a @c linear_congruential_engine from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, + linear_congruential_engine& lcg) + { + lcg.read(is); + return is; + } #endif - } - /** - * Constructs a @c linear_congruential generator and seeds it - * with values taken from the itrator range [first, last) - * and adjusts first to point to the element after the last one - * used. If there are not enough elements, throws @c std::invalid_argument. - * - * first and last must be input iterators. - */ - template - linear_congruential(It& first, It last) - { - seed(first, last); - } - - // compiler-generated copy constructor and assignment operator are fine - - /** - * If c mod m is zero and x0 mod m is zero, changes the current value of - * the generator to 1. Otherwise, changes it to x0 mod m. If c is zero, - * distinct seeds in the range [1,m) will leave the generator in distinct - * states. If c is not zero, the range is [0,m). - */ - void seed(IntType x0 = 1) - { - // wrap _x if it doesn't fit in the destination - if(modulus == 0) { - _x = x0; - } else { - _x = x0 % modulus; - } - // handle negative seeds - if(_x <= 0 && _x != 0) { - _x += modulus; - } - // adjust to the correct range - if(increment == 0 && _x == 0) { - _x = 1; - } - assert(_x >= (min)()); - assert(_x <= (max)()); - } - - /** - * seeds a @c linear_congruential generator with values taken - * from the itrator range [first, last) and adjusts @c first to - * point to the element after the last one used. If there are - * not enough elements, throws @c std::invalid_argument. - * - * @c first and @c last must be input iterators. - */ - template - void seed(It& first, It last) - { - if(first == last) - throw std::invalid_argument("linear_congruential::seed"); - seed(*first++); - } - - /** - * Returns the smallest value that the @c linear_congruential generator - * can produce. - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return c == 0 ? 1 : 0; } - /** - * Returns the largest value that the @c linear_congruential generator - * can produce. - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return modulus-1; } - - /** Returns the next value of the @c linear_congruential generator. */ - IntType operator()() - { - _x = const_mod::mult_add(a, _x, c); - return _x; - } - - static bool validation(IntType x) { return val == x; } - -#ifdef BOOST_NO_OPERATORS_IN_NAMESPACE - - // Use a member function; Streamable concept not supported. - bool operator==(const linear_congruential& rhs) const - { return _x == rhs._x; } - bool operator!=(const linear_congruential& rhs) const - { return !(*this == rhs); } - -#else - friend bool operator==(const linear_congruential& x, - const linear_congruential& y) - { return x._x == y._x; } - friend bool operator!=(const linear_congruential& x, - const linear_congruential& y) - { return !(x == y); } - -#if !defined(BOOST_RANDOM_NO_STREAM_OPERATORS) && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, - const linear_congruential& lcg) - { - return os << lcg._x; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, - linear_congruential& lcg) - { - return is >> lcg._x; - } - private: -#endif -#endif - IntType _x; + /// \cond show_private + + template + void read(std::basic_istream& is) { + IntType x; + if(is >> x) { + if(x >= (min)() && x <= (max)()) { + _x = x; + } else { + is.setstate(std::ios_base::failbit); + } + } + } + + /// \endcond + + IntType _x; }; -// probably needs the "no native streams" caveat for STLPort -#if !defined(__SGI_STL_PORT) && BOOST_WORKAROUND(__GNUC__, == 2) -template -std::ostream& -operator<<(std::ostream& os, - const linear_congruential& lcg) -{ - return os << lcg._x; -} - -template -std::istream& -operator>>(std::istream& is, - linear_congruential& lcg) -{ - return is >> lcg._x; -} -#elif defined(BOOST_RANDOM_NO_STREAM_OPERATORS) || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - const linear_congruential& lcg) -{ - return os << lcg._x; -} - -template -std::basic_istream& -operator>>(std::basic_istream& is, - linear_congruential& lcg) -{ - return is >> lcg._x; -} -#endif - #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool linear_congruential::has_fixed_range; -template -const typename linear_congruential::result_type linear_congruential::min_value; -template -const typename linear_congruential::result_type linear_congruential::max_value; -template -const IntType linear_congruential::modulus; +template +const bool linear_congruential_engine::has_fixed_range; +template +const IntType linear_congruential_engine::multiplier; +template +const IntType linear_congruential_engine::increment; +template +const IntType linear_congruential_engine::modulus; +template +const IntType linear_congruential_engine::default_seed; #endif -} // namespace random +/// \cond show_deprecated + +// provided for backwards compatibility +template +class linear_congruential : public linear_congruential_engine +{ + typedef linear_congruential_engine base_type; +public: + linear_congruential(IntType x0 = 1) : base_type(x0) {} + template + linear_congruential(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond -// validation values from the publications /** * The specialization \minstd_rand0 was originally suggested in * @@ -270,8 +320,7 @@ const IntType linear_congruential::modulus; * the ACM, Vol. 31, No. 10, October 1988, pp. 1192-1201 * @endblockquote */ -typedef random::linear_congruential minstd_rand0; +typedef linear_congruential_engine minstd_rand0; /** The specialization \minstd_rand was suggested in * @@ -281,12 +330,12 @@ typedef random::linear_congruential minstd_rand; +typedef linear_congruential_engine minstd_rand; #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -/** Class @c rand48 models a \pseudo_random_number_generator. It uses +/** + * Class @c rand48 models a \pseudo_random_number_generator. It uses * the linear congruential algorithm with the parameters a = 0x5DEECE66D, * c = 0xB, m = 2**48. It delivers identical results to the @c lrand48() * function available on some systems (assuming lcong48 has not been called). @@ -298,104 +347,118 @@ typedef random::linear_congruential::const_max; -#else - enum { has_fixed_range = false }; -#endif - /** - * Returns the smallest value that the generator can produce - */ - int32_t min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } - /** - * Returns the largest value that the generator can produce - */ - int32_t max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } + typedef boost::uint32_t result_type; + + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + /** + * Returns the smallest value that the generator can produce + */ + static uint32_t min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + /** + * Returns the largest value that the generator can produce + */ + static uint32_t max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 0x7FFFFFFF; } -#ifdef BOOST_RANDOM_DOXYGEN - /** - * If T is an integral type smaller than int46_t, constructs - * a \rand48 generator with x(0) := (x0 << 16) | 0x330e. Otherwise - * constructs a \rand48 generator with x(0) = x0. - */ - template explicit rand48(T x0 = 1); -#else - rand48() : lcf(cnv(static_cast(1))) {} - template explicit rand48(T x0) : lcf(cnv(x0)) { } -#endif - template rand48(It& first, It last) : lcf(first, last) { } + /** Seeds the generator with the default seed. */ + rand48() : lcf(cnv(static_cast(1))) {} + /** + * Constructs a \rand48 generator with x(0) := (x0 << 16) | 0x330e. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(rand48, result_type, x0) + { seed(x0); } + /** + * Seeds the generator with values produced by @c seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(rand48, SeedSeq, seq) + { seed(seq); } + /** + * Seeds the generator using values from an iterator range, + * and updates first to point one past the last value consumed. + */ + template rand48(It& first, It last) : lcf(first, last) { } - // compiler-generated copy ctor and assignment operator are fine + // compiler-generated copy ctor and assignment operator are fine -#ifdef BOOST_RANDOM_DOXYGEN - /** - * If T is an integral type smaller than int46_t, changes - * the current value x(n) of the generator to (x0 << 16) | 0x330e. - * Otherwise changes the current value x(n) to x0. - */ - template void seed(T x0 = 1); -#else - void seed() { seed(static_cast(1)); } - template void seed(T x0) { lcf.seed(cnv(x0)); } -#endif - template void seed(It& first, It last) { lcf.seed(first,last); } + /** Seeds the generator with the default seed. */ + void seed() { seed(static_cast(1)); } + /** + * Changes the current value x(n) of the generator to (x0 << 16) | 0x330e. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(rand48, result_type, x0) + { lcf.seed(cnv(x0)); } + /** + * Seeds the generator using values from an iterator range, + * and updates first to point one past the last value consumed. + */ + template void seed(It& first, It last) { lcf.seed(first,last); } + /** + * Seeds the generator with values produced by @c seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(rand48, SeedSeq, seq) + { lcf.seed(seq); } - /** - * Returns the next value of the generator. - */ - int32_t operator()() { return static_cast(lcf() >> 17); } - // by experiment from lrand48() - static bool validation(int32_t x) { return x == 1993516219; } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** Returns the next value of the generator. */ + uint32_t operator()() { return static_cast(lcf() >> 17); } + + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) { lcf.discard(z); } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { + for(; first != last; ++first) { + *first = (*this)(); + } + } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const rand48& r) - { os << r.lcf; return os; } + /** Writes a @c rand48 to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const rand48& r) + { os << r.lcf; return os; } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, rand48& r) - { is >> r.lcf; return is; } + /** Reads a @c rand48 from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, rand48& r) + { is >> r.lcf; return is; } #endif - friend bool operator==(const rand48& x, const rand48& y) - { return x.lcf == y.lcf; } - friend bool operator!=(const rand48& x, const rand48& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const rand48& rhs) const - { return lcf == rhs.lcf; } - bool operator!=(const rand48& rhs) const - { return !(*this == rhs); } -#endif + /** + * Returns true if the two generators will produce identical + * sequences of values. + */ + friend bool operator==(const rand48& x, const rand48& y) + { return x.lcf == y.lcf; } + /** + * Returns true if the two generators will produce different + * sequences of values. + */ + friend bool operator!=(const rand48& x, const rand48& y) + { return !(x == y); } private: - /// \cond hide_private_members - random::linear_congruential lcf; - template - static uint64_t cnv(T x) - { - if(sizeof(T) < sizeof(uint64_t)) { - return (static_cast(x) << 16) | 0x330e; - } else { - return(static_cast(x)); - } - } - static uint64_t cnv(float x) { return(static_cast(x)); } - static uint64_t cnv(double x) { return(static_cast(x)); } - static uint64_t cnv(long double x) { return(static_cast(x)); } - /// \endcond + /// \cond show_private + typedef random::linear_congruential_engine lcf_t; + lcf_t lcf; + + static boost::uint64_t cnv(boost::uint32_t x) + { return (static_cast(x) << 16) | 0x330e; } + /// \endcond }; #endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */ +} // namespace random + +using random::minstd_rand0; +using random::minstd_rand; +using random::rand48; + } // namespace boost #include diff --git a/include/boost/random/linear_feedback_shift.hpp b/include/boost/random/linear_feedback_shift.hpp index a7ec9f6..a695dfd 100644 --- a/include/boost/random/linear_feedback_shift.hpp +++ b/include/boost/random/linear_feedback_shift.hpp @@ -1,6 +1,7 @@ -/* boost random/tausworthe.hpp header file +/* boost random/linear_feedback_shift.hpp header file * * Copyright Jens Maurer 2002 + * 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) @@ -14,19 +15,22 @@ #ifndef BOOST_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP #define BOOST_RANDOM_LINEAR_FEEDBACK_SHIFT_HPP -#include -#include +#include #include #include +#include #include -#include +#include #include +#include +#include +#include namespace boost { namespace random { /** - * Instatiation of @c linear_feedback_shift model a + * Instatiations of @c linear_feedback_shift model a * \pseudo_random_number_generator. It was originally * proposed in * @@ -35,125 +39,178 @@ namespace random { * Tausworthe, R. C.(1965), Mathematics of Computation 19, 201-209. * @endblockquote */ -template -class linear_feedback_shift +template +class linear_feedback_shift_engine { public: - typedef UIntType result_type; - // avoid the warning trouble when using (1< 0); - // BOOST_STATIC_ASSERT(q > 0); - // BOOST_STATIC_ASSERT(k < w); - // BOOST_STATIC_ASSERT(0 < 2*q && 2*q < k); - // BOOST_STATIC_ASSERT(0 < s && s <= k-q); + BOOST_STATIC_ASSERT(w > 0); + BOOST_STATIC_ASSERT(q > 0); + BOOST_STATIC_ASSERT(k < w); + BOOST_STATIC_ASSERT(0 < 2*q && 2*q < k); + BOOST_STATIC_ASSERT(0 < s && s <= k-q); - explicit linear_feedback_shift(UIntType s0 = 341) : wordmask(0) - { - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); - BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); -#endif + /** Constructs a @c linear_feedback_shift_engine, using the default seed. */ + linear_feedback_shift_engine() { seed(); } + + /** Constructs a @c linear_feedback_shift_engine, seeding it with s0. */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(linear_feedback_shift_engine, + UIntType, s0) + { seed(s0); } + + /** Constructs a @c linear_feedback_shift_engine, seeding it with seq. */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(linear_feedback_shift_engine, + SeedSeq, seq) + { seed(seq); } + + /** + * Constructs a @c linear_feedback_shift_engine, seeding it with + * values from the range [first, last). + */ + template linear_feedback_shift_engine(It& first, It last) + { seed(first, last); } + + /** Seeds a @c linear_feedback_shift_engine with the default seed. */ + void seed() { seed(default_seed); } + + /** Seeds a @c linear_feedback_shift_engine with @c s0. */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(linear_feedback_shift_engine, + UIntType, s0) + { + value = s0 & wordmask(); + if(value < (1 << (w-k))) { + value += 1 << (w-k); + } + } + + /** + * Seeds a @c linear_feedback_shift_engine with values + * produced by @c seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(linear_feedback_shift_engine, + SeedSeq, seq) + { seed(detail::seed_one_int(seq)); } + + /** + * Seeds a @c linear_feedback_shift_engine with values + * from the range [first, last). + */ + template void seed(It& first, It last) + { + seed(detail::get_one_int(first, last)); + } - // avoid "left shift count >= with of type" warning - for(int i = 0; i < w; ++i) - wordmask |= (1u << i); - seed(s0); - } + /** Returns the next value of the generator. */ + result_type operator()() + { + const UIntType b = (((value << q) ^ value) & wordmask()) >> (k-s); + const UIntType mask = (wordmask() << (w-k)) & wordmask(); + value = ((value & mask) << s) ^ b; + return value; + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } - template linear_feedback_shift(It& first, It last) : wordmask(0) - { - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); - BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); -#endif + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, linear_feedback_shift_engine, x) + { + os << x.value; + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, linear_feedback_shift_engine, x) + { + is >> x.value; + return is; + } - // avoid "left shift count >= with of type" warning - for(int i = 0; i < w; ++i) - wordmask |= (1u << i); - seed(first, last); - } - - void seed(UIntType s0 = 341) { - if(s0 < (1 << (w-k))) { - s0 += 1 << (w-k); - } - value = s0; - } - template void seed(It& first, It last) - { - if(first == last) - throw std::invalid_argument("linear_feedback_shift::seed"); - value = *first++; - assert(value >= (1 << (w-k))); - } - - result_type operator()() - { - const UIntType b = (((value << q) ^ value) & wordmask) >> (k-s); - const UIntType mask = ( (~static_cast(0)) << (w-k) ) & wordmask; - value = ((value & mask) << s) ^ b; - return value; - } - static bool validation(result_type x) { return val == x; } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, linear_feedback_shift x) - { os << x.value; return os; } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, linear_feedback_shift& x) - { is >> x.value; return is; } -#endif - - friend bool operator==(linear_feedback_shift x, linear_feedback_shift y) - { return x.value == y.value; } - friend bool operator!=(linear_feedback_shift x, linear_feedback_shift y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(linear_feedback_shift rhs) const - { return value == rhs.value; } - bool operator!=(linear_feedback_shift rhs) const - { return !(*this == rhs); } -#endif + /** + * Returns true if the two generators will produce identical + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(linear_feedback_shift_engine, x, y) + { return x.value == y.value; } + + /** + * Returns true if the two generators will produce different + * sequences of outputs. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(linear_feedback_shift_engine) private: - UIntType wordmask; // avoid "left shift count >= width of type" warnings - UIntType value; + /// \cond show_private + static UIntType wordmask() { return boost::low_bits_mask_t::sig_bits; } + /// \endcond + UIntType value; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool linear_feedback_shift::has_fixed_range; -template -const int linear_feedback_shift::word_size; -template -const int linear_feedback_shift::exponent1; -template -const int linear_feedback_shift::exponent2; -template -const int linear_feedback_shift::step_size; +template +const bool linear_feedback_shift_engine::has_fixed_range; +template +const int linear_feedback_shift_engine::word_size; +template +const int linear_feedback_shift_engine::exponent1; +template +const int linear_feedback_shift_engine::exponent2; +template +const int linear_feedback_shift_engine::step_size; +template +const UIntType linear_feedback_shift_engine::default_seed; #endif +/// \cond show_deprecated + +/** Provided for backwards compatibility. */ +template +class linear_feedback_shift : + public linear_feedback_shift_engine +{ + typedef linear_feedback_shift_engine base_type; +public: + linear_feedback_shift() {} + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(linear_feedback_shift, + SeedSeq, seq) + { seed(seq); } + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(linear_feedback_shift, + UIntType, val) + { seed(val); } + template + linear_feedback_shift(It& first, It last) : base_type(first, last) {} +}; + +/// \endcond + } // namespace random } // namespace boost diff --git a/include/boost/random/lognormal_distribution.hpp b/include/boost/random/lognormal_distribution.hpp index 9703d46..7ed1e13 100644 --- a/include/boost/random/lognormal_distribution.hpp +++ b/include/boost/random/lognormal_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/lognormal_distribution.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -18,112 +19,236 @@ #include // std::exp, std::sqrt #include -#include +#include +#include #include -#include #include +#include #include -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std { - using ::log; - using ::sqrt; -} -#endif - namespace boost { - -#if defined(__GNUC__) && (__GNUC__ < 3) -// Special gcc workaround: gcc 2.95.x ignores using-declarations -// in template classes (confirmed by gcc author Martin v. Loewis) - using std::sqrt; - using std::exp; -#endif +namespace random { /** * Instantiations of class template lognormal_distribution model a * \random_distribution. Such a distribution produces random numbers - * with \f$p(x) = \frac{1}{x \sigma_N \sqrt{2\pi}} e^{\frac{-\left(\log(x)-\mu_N\right)^2}{2\sigma_N^2}}\f$ - * for x > 0, where \f$\mu_N = \log\left(\frac{\mu^2}{\sqrt{\sigma^2 + \mu^2}}\right)\f$ and - * \f$\sigma_N = \sqrt{\log\left(1 + \frac{\sigma^2}{\mu^2}\right)}\f$. + * with \f$\displaystyle p(x) = \frac{1}{x s \sqrt{2\pi}} e^{\frac{-\left(\log(x)-m\right)^2}{2s^2}}\f$ + * for x > 0. + * + * @xmlwarning + * This distribution has been updated to match the C++ standard. + * Its behavior has changed from the original + * boost::lognormal_distribution. A backwards compatible + * version is provided in namespace boost. + * @endxmlwarning */ template class lognormal_distribution { public: - typedef typename normal_distribution::input_type input_type; - typedef RealType result_type; + typedef typename normal_distribution::input_type input_type; + typedef RealType result_type; -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif + class param_type + { + public: - /** - * Constructs a lognormal_distribution. @c mean and @c sigma are the - * mean and standard deviation of the lognormal distribution. - */ - explicit lognormal_distribution(result_type mean_arg = result_type(1), - result_type sigma_arg = result_type(1)) - : _mean(mean_arg), _sigma(sigma_arg) - { - assert(_mean > result_type(0)); - init(); - } + typedef lognormal_distribution distribution_type; - // compiler-generated copy ctor and assignment operator are fine + /** Constructs the parameters of a lognormal_distribution. */ + explicit param_type(RealType m_arg = RealType(0.0), + RealType s_arg = RealType(1.0)) + : _m(m_arg), _s(s_arg) {} - RealType mean() const { return _mean; } - RealType sigma() const { return _sigma; } - void reset() { _normal.reset(); } + /** Returns the "m" parameter of the distribution. */ + RealType m() const { return _m; } - template - result_type operator()(Engine& eng) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::exp; -#endif - return exp(_normal(eng) * _nsigma + _nmean); - } + /** Returns the "s" parameter of the distribution. */ + RealType s() const { return _s; } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const lognormal_distribution& ld) - { - os << ld._normal << " " << ld._mean << " " << ld._sigma; - return os; - } + /** Writes the parameters to a std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._m << " " << parm._s; + return os; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, lognormal_distribution& ld) - { - is >> std::ws >> ld._normal >> std::ws >> ld._mean >> std::ws >> ld._sigma; - ld.init(); - return is; - } -#endif + /** Reads the parameters from a std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._m >> std::ws >> parm._s; + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._m == rhs._m && lhs._s == rhs._s; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _m; + RealType _s; + }; + + /** + * Constructs a lognormal_distribution. @c m and @c s are the + * parameters of the distribution. + */ + explicit lognormal_distribution(RealType m_arg = RealType(0.0), + RealType s_arg = RealType(1.0)) + : _normal(m_arg, s_arg) {} + + /** + * Constructs a lognormal_distribution from its parameters. + */ + explicit lognormal_distribution(const param_type& parm) + : _normal(parm.m(), parm.s()) {} + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns the m parameter of the distribution. */ + RealType m() const { return _normal.mean(); } + /** Returns the s parameter of the distribution. */ + RealType s() const { return _normal.sigma(); } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return RealType(0); } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return (std::numeric_limits::infinity)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(m(), s()); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + typedef normal_distribution normal_type; + typename normal_type::param_type normal_param(parm.m(), parm.s()); + _normal.param(normal_param); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _normal.reset(); } + + /** + * Returns a random variate distributed according to the + * lognormal distribution. + */ + template + result_type operator()(Engine& eng) + { + using std::exp; + return exp(_normal(eng)); + } + + /** + * Returns a random variate distributed according to the + * lognormal distribution with parameters specified by param. + */ + template + result_type operator()(Engine& eng, const param_type& parm) + { return lognormal_distribution(parm)(eng); } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lognormal_distribution, ld) + { + os << ld._normal; + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lognormal_distribution, ld) + { + is >> ld._normal; + return is; + } + + /** + * Returns true if the two distributions will produce identical + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(lognormal_distribution, lhs, rhs) + { return lhs._normal == rhs._normal; } + + /** + * Returns true if the two distributions may produce different + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(lognormal_distribution) private: - - /// \cond hide_private_members - void init() - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::exp; using std::log; using std::sqrt; -#endif - _nmean = log(_mean*_mean/sqrt(_sigma*_sigma + _mean*_mean)); - _nsigma = sqrt(log(_sigma*_sigma/_mean/_mean+result_type(1))); - } - /// \endcond - - RealType _mean, _sigma; - RealType _nmean, _nsigma; - normal_distribution _normal; + normal_distribution _normal; }; +} // namespace random + +/// \cond show_deprecated + +/** + * Provided for backwards compatibility. This class is + * deprecated. It provides the old behavior of lognormal_distribution with + * \f$\displaystyle p(x) = \frac{1}{x \sigma_N \sqrt{2\pi}} e^{\frac{-\left(\log(x)-\mu_N\right)^2}{2\sigma_N^2}}\f$ + * for x > 0, where \f$\displaystyle \mu_N = \log\left(\frac{\mu^2}{\sqrt{\sigma^2 + \mu^2}}\right)\f$ and + * \f$\displaystyle \sigma_N = \sqrt{\log\left(1 + \frac{\sigma^2}{\mu^2}\right)}\f$. + */ +template +class lognormal_distribution +{ +public: + typedef typename normal_distribution::input_type input_type; + typedef RealType result_type; + + lognormal_distribution(RealType mean_arg = RealType(1.0), + RealType sigma_arg = RealType(1.0)) + : _mean(mean_arg), _sigma(sigma_arg) + { + init(); + } + RealType mean() const { return _mean; } + RealType sigma() const { return _sigma; } + void reset() { _normal.reset(); } + template + RealType operator()(Engine& eng) + { + using std::exp; + return exp(_normal(eng) * _nsigma + _nmean); + } + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, lognormal_distribution, ld) + { + os << ld._normal << " " << ld._mean << " " << ld._sigma; + return os; + } + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, lognormal_distribution, ld) + { + is >> ld._normal >> std::ws >> ld._mean >> std::ws >> ld._sigma; + ld.init(); + return is; + } +private: + /// \cond show_private + void init() + { + using std::log; + using std::sqrt; + _nmean = log(_mean*_mean/sqrt(_sigma*_sigma + _mean*_mean)); + _nsigma = sqrt(log(_sigma*_sigma/_mean/_mean+result_type(1))); + } + RealType _mean; + RealType _sigma; + RealType _nmean; + RealType _nsigma; + normal_distribution _normal; + /// \endcond +}; + +/// \endcond + } // namespace boost #endif // BOOST_RANDOM_LOGNORMAL_DISTRIBUTION_HPP diff --git a/include/boost/random/mersenne_twister.hpp b/include/boost/random/mersenne_twister.hpp index 4215353..ca13bdf 100644 --- a/include/boost/random/mersenne_twister.hpp +++ b/include/boost/random/mersenne_twister.hpp @@ -1,6 +1,7 @@ /* boost random/mersenne_twister.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -16,25 +17,23 @@ #ifndef BOOST_RANDOM_MERSENNE_TWISTER_HPP #define BOOST_RANDOM_MERSENNE_TWISTER_HPP -#include -#include // std::copy +#include +#include #include #include -#include -#include -#include #include -#include -#include +#include #include #include #include +#include +#include namespace boost { namespace random { /** - * Instantiations of class template mersenne_twister model a + * Instantiations of class template mersenne_twister_engine model a * \pseudo_random_number_generator. It uses the algorithm described in * * @blockquote @@ -61,307 +60,486 @@ namespace random { * its state array. For example, \mt11213b requires about 1408 bytes and * \mt19937 requires about 2496 bytes. */ -template -class mersenne_twister +template +class mersenne_twister_engine { public: - typedef UIntType result_type; - BOOST_STATIC_CONSTANT(int, word_size = w); - BOOST_STATIC_CONSTANT(int, state_size = n); - BOOST_STATIC_CONSTANT(int, shift_size = m); - BOOST_STATIC_CONSTANT(int, mask_bits = r); - BOOST_STATIC_CONSTANT(UIntType, parameter_a = a); - BOOST_STATIC_CONSTANT(int, output_u = u); - BOOST_STATIC_CONSTANT(int, output_s = s); - BOOST_STATIC_CONSTANT(UIntType, output_b = b); - BOOST_STATIC_CONSTANT(int, output_t = t); - BOOST_STATIC_CONSTANT(UIntType, output_c = c); - BOOST_STATIC_CONSTANT(int, output_l = l); - - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + typedef UIntType result_type; + BOOST_STATIC_CONSTANT(std::size_t, word_size = w); + BOOST_STATIC_CONSTANT(std::size_t, state_size = n); + BOOST_STATIC_CONSTANT(std::size_t, shift_size = m); + BOOST_STATIC_CONSTANT(std::size_t, mask_bits = r); + BOOST_STATIC_CONSTANT(UIntType, xor_mask = a); + BOOST_STATIC_CONSTANT(std::size_t, tempering_u = u); + BOOST_STATIC_CONSTANT(UIntType, tempering_d = d); + BOOST_STATIC_CONSTANT(std::size_t, tempering_s = s); + BOOST_STATIC_CONSTANT(UIntType, tempering_b = b); + BOOST_STATIC_CONSTANT(std::size_t, tempering_t = t); + BOOST_STATIC_CONSTANT(UIntType, tempering_c = c); + BOOST_STATIC_CONSTANT(std::size_t, tempering_l = l); + BOOST_STATIC_CONSTANT(UIntType, initialization_multiplier = f); + BOOST_STATIC_CONSTANT(UIntType, default_seed = 5489u); - /** - * Constructs a @c mersenne_twister and calls @c seed(). - */ - mersenne_twister() { seed(); } + // backwards compatibility + BOOST_STATIC_CONSTANT(UIntType, parameter_a = a); + BOOST_STATIC_CONSTANT(std::size_t, output_u = u); + BOOST_STATIC_CONSTANT(std::size_t, output_s = s); + BOOST_STATIC_CONSTANT(UIntType, output_b = b); + BOOST_STATIC_CONSTANT(std::size_t, output_t = t); + BOOST_STATIC_CONSTANT(UIntType, output_c = c); + BOOST_STATIC_CONSTANT(std::size_t, output_l = l); + + // old Boost.Random concept requirements + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - /** - * Constructs a @c mersenne_twister and calls @c seed(value). - */ - BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(mersenne_twister, UIntType, value) - { seed(value); } - template mersenne_twister(It& first, It last) { seed(first,last); } - /** - * Constructs a mersenne_twister and calls @c seed(gen). - * - * @xmlnote - * The copy constructor will always be preferred over - * the templated constructor. - * @endxmlnote - */ - BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(mersenne_twister, Generator, gen) - { seed(gen); } + /** + * Constructs a @c mersenne_twister_engine and calls @c seed(). + */ + mersenne_twister_engine() { seed(); } - // compiler-generated copy ctor and assignment operator are fine + /** + * Constructs a @c mersenne_twister_engine and calls @c seed(value). + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(mersenne_twister_engine, + UIntType, value) + { seed(value); } + template mersenne_twister_engine(It& first, It last) + { seed(first,last); } - /** Calls @c seed(result_type(5489)). */ - void seed() { seed(UIntType(5489)); } + /** + * Constructs a mersenne_twister_engine and calls @c seed(gen). + * + * @xmlnote + * The copy constructor will always be preferred over + * the templated constructor. + * @endxmlnote + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(mersenne_twister_engine, + SeedSeq, seq) + { seed(seq); } - /** - * Sets the state x(0) to v mod 2w. Then, iteratively, - * sets x(i) to (i + 1812433253 * (x(i-1) xor (x(i-1) rshift w-2))) mod 2w - * for i = 1 .. n-1. x(n) is the first value to be returned by operator(). - */ - BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister, UIntType, value) - { - // New seeding algorithm from - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html - // In the previous versions, MSBs of the seed affected only MSBs of the - // state x[]. - const UIntType mask = ~0u; - x[0] = value & mask; - for (i = 1; i < n; i++) { - // See Knuth "The Art of Computer Programming" Vol. 2, 3rd ed., page 106 - x[i] = (1812433253UL * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask; + // compiler-generated copy ctor and assignment operator are fine + + /** Calls @c seed(default_seed). */ + void seed() { seed(default_seed); } + + /** + * Sets the state x(0) to v mod 2w. Then, iteratively, + * sets x(i) to + * (i + f * (x(i-1) xor (x(i-1) rshift w-2))) mod 2w + * for i = 1 .. n-1. x(n) is the first value to be returned by operator(). + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister_engine, UIntType, value) + { + // New seeding algorithm from + // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html + // In the previous versions, MSBs of the seed affected only MSBs of the + // state x[]. + const UIntType mask = (max)(); + x[0] = value & mask; + for (i = 1; i < n; i++) { + // See Knuth "The Art of Computer Programming" + // Vol. 2, 3rd ed., page 106 + x[i] = (f * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask; + } } - } + + /** + * Seeds a mersenne_twister_engine using values produced by seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(mersenne_twister_engine, SeeqSeq, seq) + { + detail::seed_array_int(seq, x); + i = n; - /** - * Sets the state of this mersenne_twister to the values - * returned by n invocations of gen. - * - * Complexity: Exactly n invocations of gen. - */ - BOOST_RANDOM_DETAIL_GENERATOR_SEED(mersenne_twister, Generator, gen) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); -#endif - // I could have used std::generate_n, but it takes "gen" by value - for(int j = 0; j < n; j++) - x[j] = gen(); - i = n; - } + // fix up the state if it's all zeroes. + if((x[0] & (~static_cast(0) << r)) == 0) { + for(std::size_t j = 1; i < n; ++j) { + if(x[j] != 0) return; + } + x[0] = static_cast(1) << (w-1); + } + } - template - void seed(It& first, It last) - { - int j; - for(j = 0; j < n && first != last; ++j, ++first) - x[j] = *first; - i = n; - if(first == last && j < n) - throw std::invalid_argument("mersenne_twister::seed"); - } + /** Sets the state of the generator using values from an iterator range. */ + template + void seed(It& first, It last) + { + detail::fill_array_int(first, last, x); + i = n; + + // fix up the state if it's all zeroes. + if((x[0] & (~static_cast(0) << r)) == 0) { + for(std::size_t j = 1; i < n; ++j) { + if(x[j] != 0) return; + } + x[0] = static_cast(1) << (w-1); + } + } - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const - { - // avoid "left shift count >= with of type" warning - result_type res = 0; - for(int j = 0; j < w; ++j) - res |= (1u << j); - return res; - } + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 0; } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return boost::low_bits_mask_t::sig_bits; } + + /** Produces the next value of the generator. */ + result_type operator()(); - result_type operator()(); - static bool validation(result_type v) { return val == v; } + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** + * Advances the state of the generator by @c z steps. Equivalent to + * + * @code + * for(unsigned long long i = 0; i < z; ++i) { + * gen(); + * } + * @endcode + */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const mersenne_twister& mt) - { - for(int j = 0; j < mt.state_size; ++j) - os << mt.compute(j) << " "; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, mersenne_twister& mt) - { - for(int j = 0; j < mt.state_size; ++j) - is >> mt.x[j] >> std::ws; - // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template - // value parameter "n" available from the class template scope, so use - // the static constant with the same value - mt.i = mt.state_size; - return is; - } + /** Writes a mersenne_twister_engine to a @c std::ostream */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const mersenne_twister_engine& mt) + { + mt.print(os); + return os; + } + + /** Reads a mersenne_twister_engine from a @c std::istream */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, + mersenne_twister_engine& mt) + { + for(std::size_t j = 0; j < mt.state_size; ++j) + is >> mt.x[j] >> std::ws; + // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template + // value parameter "n" available from the class template scope, so use + // the static constant with the same value + mt.i = mt.state_size; + return is; + } #endif - friend bool operator==(const mersenne_twister& x, const mersenne_twister& y) - { - for(int j = 0; j < state_size; ++j) - if(x.compute(j) != y.compute(j)) - return false; - return true; - } - - friend bool operator!=(const mersenne_twister& x, const mersenne_twister& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const mersenne_twister& rhs) const - { - for(int j = 0; j < state_size; ++j) - if(compute(j) != rhs.compute(j)) - return false; - return true; - } - - bool operator!=(const mersenne_twister& rhs) const - { return !(*this == rhs); } -#endif + /** + * Returns true if the two generators are in the same state, + * and will thus produce identical sequences. + */ + friend bool operator==(const mersenne_twister_engine& x, + const mersenne_twister_engine& y) + { + if(x.i < y.i) return x.equal_imp(y); + else return y.equal_imp(x); + } + + /** + * Returns true if the two generators are in different states. + */ + friend bool operator!=(const mersenne_twister_engine& x, + const mersenne_twister_engine& y) + { return !(x == y); } private: - /// \cond hide_private_members - // returns x(i-n+index), where index is in 0..n-1 - UIntType compute(unsigned int index) const - { - // equivalent to (i-n+index) % 2n, but doesn't produce negative numbers - return x[ (i + n + index) % (2*n) ]; - } - void twist(int block); - /// \endcond + /// \cond show_private - // state representation: next output is o(x(i)) - // x[0] ... x[k] x[k+1] ... x[n-1] x[n] ... x[2*n-1] represents - // x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) x(i-k-n) ... x[i(i-k-1)] - // The goal is to always have x(i-n) ... x(i-1) available for - // operator== and save/restore. + void twist(); - UIntType x[2*n]; - int i; + /** + * Does the work of operator==. This is in a member function + * for portability. Some compilers, such as msvc 7.1 and + * Sun CC 5.10 can't access template parameters or static + * members of the class from inline friend functions. + * + * requires i <= other.i + */ + bool equal_imp(const mersenne_twister_engine& other) const + { + UIntType back[n]; + std::size_t offset = other.i - i; + for(std::size_t j = 0; j + offset < n; ++j) + if(x[j] != other.x[j+offset]) + return false; + rewind(&back[n-1], offset); + for(std::size_t j = 0; j < offset; ++j) + if(back[j + n - offset] != other.x[j]) + return false; + return true; + } + + /** + * Does the work of operator<<. This is in a member function + * for portability. + */ + template + void print(std::basic_ostream& os) const + { + UIntType data[n]; + for(std::size_t j = 0; j < i; ++j) { + data[j + n - i] = x[j]; + } + if(i != n) { + rewind(&data[n - i - 1], n - i); + } + os << data[0]; + for(std::size_t j = 1; j < n; ++j) { + os << ' ' << data[j]; + } + } + + /** + * Copies z elements of the state preceding x[0] into + * the array whose last element is last. + */ + void rewind(UIntType* last, std::size_t z) const + { + const UIntType upper_mask = (~static_cast(0)) << r; + const UIntType lower_mask = ~upper_mask; + UIntType y0 = x[m-1] ^ x[n-1]; + if(y0 & (static_cast(1) << (w-1))) { + y0 = ((y0 ^ a) << 1) | 1; + } else { + y0 = y0 << 1; + } + for(std::size_t sz = 0; sz < z; ++sz) { + UIntType y1 = + rewind_find(last, sz, m-1) ^ rewind_find(last, sz, n-1); + if(y1 & (static_cast(1) << (w-1))) { + y1 = ((y1 ^ a) << 1) | 1; + } else { + y1 = y1 << 1; + } + *(last - sz) = (y0 & upper_mask) | (y1 & lower_mask); + y0 = y1; + } + } + + /** + * Given a pointer to the last element of the rewind array, + * and the current size of the rewind array, finds an element + * relative to the next available slot in the rewind array. + */ + UIntType + rewind_find(UIntType* last, std::size_t size, std::size_t j) const + { + std::size_t index = (j + n - size + n - 1) % n; + if(index < n - size) { + return x[index]; + } else { + return *(last - (n - 1 - index)); + } + } + + /// \endcond + + // state representation: next output is o(x(i)) + // x[0] ... x[k] x[k+1] ... x[n-1] represents + // x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) + + UIntType x[n]; + std::size_t i; }; +/// \cond show_private + #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool mersenne_twister::has_fixed_range; -template -const int mersenne_twister::state_size; -template -const int mersenne_twister::shift_size; -template -const int mersenne_twister::mask_bits; -template -const UIntType mersenne_twister::parameter_a; -template -const int mersenne_twister::output_u; -template -const int mersenne_twister::output_s; -template -const UIntType mersenne_twister::output_b; -template -const int mersenne_twister::output_t; -template -const UIntType mersenne_twister::output_c; -template -const int mersenne_twister::output_l; +#define BOOST_RANDOM_MT_DEFINE_CONSTANT(type, name) \ +template \ +const type mersenne_twister_engine::name +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, word_size); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, state_size); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, shift_size); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, mask_bits); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, xor_mask); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, tempering_u); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, tempering_d); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, tempering_s); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, tempering_b); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, tempering_t); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, tempering_c); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, tempering_l); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, initialization_multiplier); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, default_seed); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, parameter_a); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, output_u ); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, output_s); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, output_b); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, output_t); +BOOST_RANDOM_MT_DEFINE_CONSTANT(UIntType, output_c); +BOOST_RANDOM_MT_DEFINE_CONSTANT(std::size_t, output_l); +BOOST_RANDOM_MT_DEFINE_CONSTANT(bool, has_fixed_range); +#undef BOOST_RANDOM_MT_DEFINE_CONSTANT #endif -/// \cond hide_private_members -template -void mersenne_twister::twist(int block) +template +void +mersenne_twister_engine::twist() { - const UIntType upper_mask = (~0u) << r; - const UIntType lower_mask = ~upper_mask; + const UIntType upper_mask = (~static_cast(0)) << r; + const UIntType lower_mask = ~upper_mask; + + const std::size_t unroll_factor = 6; + const std::size_t unroll_extra1 = (n-m) % unroll_factor; + const std::size_t unroll_extra2 = (m-1) % unroll_factor; - if(block == 0) { - for(int j = n; j < 2*n; j++) { - UIntType y = (x[j-n] & upper_mask) | (x[j-(n-1)] & lower_mask); - x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0); - } - } else if (block == 1) { // split loop to avoid costly modulo operations { // extra scope for MSVC brokenness w.r.t. for scope - for(int j = 0; j < n-m; j++) { - UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask); - x[j] = x[j+n+m] ^ (y >> 1) ^ (y&1 ? a : 0); - } + for(std::size_t j = 0; j < n-m-unroll_extra1; j++) { + UIntType y = (x[j] & upper_mask) | (x[j+1] & lower_mask); + x[j] = x[j+m] ^ (y >> 1) ^ ((x[j+1]&1) * a); + } } - - for(int j = n-m; j < n-1; j++) { - UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask); - x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0); + { + for(std::size_t j = n-m-unroll_extra1; j < n-m; j++) { + UIntType y = (x[j] & upper_mask) | (x[j+1] & lower_mask); + x[j] = x[j+m] ^ (y >> 1) ^ ((x[j+1]&1) * a); + } + } + { + for(std::size_t j = n-m; j < n-1-unroll_extra2; j++) { + UIntType y = (x[j] & upper_mask) | (x[j+1] & lower_mask); + x[j] = x[j-(n-m)] ^ (y >> 1) ^ ((x[j+1]&1) * a); + } + } + { + for(std::size_t j = n-1-unroll_extra2; j < n-1; j++) { + UIntType y = (x[j] & upper_mask) | (x[j+1] & lower_mask); + x[j] = x[j-(n-m)] ^ (y >> 1) ^ ((x[j+1]&1) * a); + } } // last iteration - UIntType y = (x[2*n-1] & upper_mask) | (x[0] & lower_mask); - x[n-1] = x[m-1] ^ (y >> 1) ^ (y&1 ? a : 0); + UIntType y = (x[n-1] & upper_mask) | (x[0] & lower_mask); + x[n-1] = x[m-1] ^ (y >> 1) ^ ((x[0]&1) * a); i = 0; - } } /// \endcond -template -inline typename mersenne_twister::result_type -mersenne_twister::operator()() +template +inline typename +mersenne_twister_engine::result_type +mersenne_twister_engine::operator()() { - if(i == n) - twist(0); - else if(i >= 2*n) - twist(1); - // Step 4 - UIntType z = x[i]; - ++i; - z ^= (z >> u); - z ^= ((z << s) & b); - z ^= ((z << t) & c); - z ^= (z >> l); - return z; + if(i == n) + twist(); + // Step 4 + UIntType z = x[i]; + ++i; + z ^= ((z >> u) & d); + z ^= ((z << s) & b); + z ^= ((z << t) & c); + z ^= (z >> l); + return z; } +/** + * The specializations \mt11213b and \mt19937 are from + * + * @blockquote + * "Mersenne Twister: A 623-dimensionally equidistributed + * uniform pseudo-random number generator", Makoto Matsumoto + * and Takuji Nishimura, ACM Transactions on Modeling and + * Computer Simulation: Special Issue on Uniform Random Number + * Generation, Vol. 8, No. 1, January 1998, pp. 3-30. + * @endblockquote + */ +typedef mersenne_twister_engine mt11213b; + +/** + * The specializations \mt11213b and \mt19937 are from + * + * @blockquote + * "Mersenne Twister: A 623-dimensionally equidistributed + * uniform pseudo-random number generator", Makoto Matsumoto + * and Takuji Nishimura, ACM Transactions on Modeling and + * Computer Simulation: Special Issue on Uniform Random Number + * Generation, Vol. 8, No. 1, January 1998, pp. 3-30. + * @endblockquote + */ +typedef mersenne_twister_engine mt19937; + +#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) +typedef mersenne_twister_engine mt19937_64; +#endif + +/// \cond show_deprecated + +template +class mersenne_twister : + public mersenne_twister_engine +{ + typedef mersenne_twister_engine base_type; +public: + mersenne_twister() {} + BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(mersenne_twister, Gen, gen) + { seed(gen); } + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(mersenne_twister, UIntType, val) + { seed(val); } + template + mersenne_twister(It& first, It last) : base_type(first, last) {} + void seed() { base_type::seed(); } + BOOST_RANDOM_DETAIL_GENERATOR_SEED(mersenne_twister, Gen, gen) + { + detail::generator_seed_seq seq(gen); + base_type::seed(seq); + } + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister, UIntType, val) + { base_type::seed(val); } + template + void seed(It& first, It last) { base_type::seed(first, last); } +}; + +/// \endcond + } // namespace random -/** - * The specializations \mt11213b and \mt19937 are from - * - * @blockquote - * "Mersenne Twister: A 623-dimensionally equidistributed - * uniform pseudo-random number generator", Makoto Matsumoto - * and Takuji Nishimura, ACM Transactions on Modeling and - * Computer Simulation: Special Issue on Uniform Random Number - * Generation, Vol. 8, No. 1, January 1998, pp. 3-30. - * @endblockquote - */ -typedef random::mersenne_twister mt11213b; - -/** - * The specializations \mt11213b and \mt19937 are from - * - * @blockquote - * "Mersenne Twister: A 623-dimensionally equidistributed - * uniform pseudo-random number generator", Makoto Matsumoto - * and Takuji Nishimura, ACM Transactions on Modeling and - * Computer Simulation: Special Issue on Uniform Random Number - * Generation, Vol. 8, No. 1, January 1998, pp. 3-30. - * @endblockquote - */ -typedef random::mersenne_twister mt19937; +using random::mt11213b; +using random::mt19937; +using random::mt19937_64; } // namespace boost +BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt11213b) BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937) +BOOST_RANDOM_PTR_HELPER_SPEC(boost::mt19937_64) #endif // BOOST_RANDOM_MERSENNE_TWISTER_HPP diff --git a/include/boost/random/negative_binomial_distribution.hpp b/include/boost/random/negative_binomial_distribution.hpp new file mode 100644 index 0000000..cbe26fa --- /dev/null +++ b/include/boost/random/negative_binomial_distribution.hpp @@ -0,0 +1,220 @@ +/* boost random/negative_binomial_distribution.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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_NEGATIVE_BINOMIAL_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_NEGATIVE_BINOMIAL_DISTRIBUTION_HPP_INCLUDED + +#include + +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * The negative binomial distribution is an integer valued + * distribution with two parameters, @c k and @c p. The + * distribution produces non-negative values. + * + * The distribution function is + * \f$\displaystyle P(i) = {k+i-1\choose i}p^k(1-p)^i\f$. + * + * This implementation uses a gamma-poisson mixture. + */ +template +class negative_binomial_distribution { +public: + typedef IntType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef negative_binomial_distribution distribution_type; + /** + * Construct a param_type object. @c k and @c p + * are the parameters of the distribution. + * + * Requires: k >=0 && 0 <= p <= 1 + */ + explicit param_type(IntType k_arg = 1, RealType p_arg = RealType (0.5)) + : _k(k_arg), _p(p_arg) + {} + /** Returns the @c k parameter of the distribution. */ + IntType k() const { return _k; } + /** Returns the @c p parameter of the distribution. */ + RealType p() const { return _p; } +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const param_type& parm) + { + os << parm._p << " " << parm._k; + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, param_type& parm) + { + is >> parm._p >> std::ws >> parm._k; + return is; + } +#endif + /** Returns true if the parameters have the same values. */ + friend bool operator==(const param_type& lhs, const param_type& rhs) + { + return lhs._k == rhs._k && lhs._p == rhs._p; + } + /** Returns true if the parameters have different values. */ + friend bool operator!=(const param_type& lhs, const param_type& rhs) + { + return !(lhs == rhs); + } + private: + IntType _k; + RealType _p; + }; + + /** + * Construct a @c negative_binomial_distribution object. @c k and @c p + * are the parameters of the distribution. + * + * Requires: k >=0 && 0 <= p <= 1 + */ + explicit negative_binomial_distribution(IntType k_arg = 1, + RealType p_arg = RealType(0.5)) + : _k(k_arg), _p(p_arg) + {} + + /** + * Construct an @c negative_binomial_distribution object from the + * parameters. + */ + explicit negative_binomial_distribution(const param_type& parm) + : _k(parm.k()), _p(parm.p()) + {} + + /** + * Returns a random variate distributed according to the + * negative binomial distribution. + */ + template + IntType operator()(URNG& urng) const + { + gamma_distribution gamma(_k, (1-_p)/_p); + poisson_distribution poisson(gamma(urng)); + return poisson(urng); + } + + /** + * Returns a random variate distributed according to the negative + * binomial distribution with parameters specified by @c param. + */ + template + IntType operator()(URNG& urng, const param_type& parm) const + { + return negative_binomial_distribution(parm)(urng); + } + + /** Returns the @c k parameter of the distribution. */ + IntType k() const { return _k; } + /** Returns the @c p parameter of the distribution. */ + RealType p() const { return _p; } + + /** Returns the smallest value that the distribution can produce. */ + IntType min BOOST_PREVENT_MACRO_SUBSTITUTION() const { return 0; } + /** Returns the largest value that the distribution can produce. */ + IntType max BOOST_PREVENT_MACRO_SUBSTITUTION() const + { return (std::numeric_limits::max)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_k, _p); } + /** Sets parameters of the distribution. */ + void param(const param_type& parm) + { + _k = parm.k(); + _p = parm.p(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const negative_binomial_distribution& bd) + { + os << bd.param(); + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, + negative_binomial_distribution& bd) + { + bd.read(is); + return is; + } +#endif + + /** Returns true if the two distributions will produce the same + sequence of values, given equal generators. */ + friend bool operator==(const negative_binomial_distribution& lhs, + const negative_binomial_distribution& rhs) + { + return lhs._k == rhs._k && lhs._p == rhs._p; + } + /** Returns true if the two distributions could produce different + sequences of values, given equal generators. */ + friend bool operator!=(const negative_binomial_distribution& lhs, + const negative_binomial_distribution& rhs) + { + return !(lhs == rhs); + } + +private: + + /// @cond \show_private + + template + void read(std::basic_istream& is) { + param_type parm; + if(is >> parm) { + param(parm); + } + } + + // parameters + IntType _k; + RealType _p; + + /// @endcond +}; + +} + +} + +#endif diff --git a/include/boost/random/normal_distribution.hpp b/include/boost/random/normal_distribution.hpp index 342fc7a..4d0c07e 100644 --- a/include/boost/random/normal_distribution.hpp +++ b/include/boost/random/normal_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/normal_distribution.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -17,115 +18,206 @@ #define BOOST_RANDOM_NORMAL_DISTRIBUTION_HPP #include -#include -#include +#include +#include +#include #include #include #include +#include +#include namespace boost { +namespace random { + +// deterministic Box-Muller method, uses trigonometric functions /** * Instantiations of class template normal_distribution model a * \random_distribution. Such a distribution produces random numbers * @c x distributed with probability density function - * \f$p(x) = \frac{1}{\sqrt{2\pi\sigma}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}\f$, + * \f$\displaystyle p(x) = + * \frac{1}{\sqrt{2\pi\sigma}} e^{-\frac{(x-\mu)^2}{2\sigma^2}} + * \f$, * where mean and sigma are the parameters of the distribution. */ -// deterministic Box-Muller method, uses trigonometric functions template class normal_distribution { public: - typedef RealType input_type; - typedef RealType result_type; + typedef RealType input_type; + typedef RealType result_type; -#if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) && !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300) - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif + class param_type { + public: + typedef normal_distribution distribution_type; - /** - * Constructs a normal_distribution object. @c mean and @c sigma are - * the parameters for the distribution. - * - * Requires: sigma > 0 - */ - explicit normal_distribution(const result_type& mean_arg = result_type(0), - const result_type& sigma_arg = result_type(1)) - : _mean(mean_arg), _sigma(sigma_arg), _valid(false) - { - assert(_sigma >= result_type(0)); - } + /** + * Constructs a @c param_type with a given mean and + * standard deviation. + * + * Requires: sigma >= 0 + */ + explicit param_type(RealType mean_arg = RealType(0.0), + RealType sigma_arg = RealType(1.0)) + : _mean(mean_arg), + _sigma(sigma_arg) + {} - // compiler-generated copy constructor is NOT fine, need to purge cache - normal_distribution(const normal_distribution& other) - : _mean(other._mean), _sigma(other._sigma), _valid(false) - { - } + /** Returns the mean of the distribution. */ + RealType mean() const { return _mean; } - // compiler-generated copy ctor and assignment operator are fine + /** Returns the standand deviation of the distribution. */ + RealType sigma() const { return _sigma; } - /** - * Returns: The "mean" parameter of the distribution. - */ - RealType mean() const { return _mean; } - /** - * Returns: The "sigma" parameter of the distribution. - */ - RealType sigma() const { return _sigma; } + /** Writes a @c param_type to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { os << parm._mean << " " << parm._sigma ; return os; } - void reset() { _valid = false; } + /** Reads a @c param_type from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { is >> parm._mean >> std::ws >> parm._sigma; return is; } - template - result_type operator()(Engine& eng) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::sqrt; using std::log; using std::sin; using std::cos; -#endif - if(!_valid) { - _r1 = eng(); - _r2 = eng(); - _cached_rho = sqrt(-result_type(2) * log(result_type(1)-_r2)); - _valid = true; - } else { - _valid = false; + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._mean == rhs._mean && lhs._sigma == rhs._sigma; } + + /** Returns true if the two sets of parameters are the different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _mean; + RealType _sigma; + }; + + /** + * Constructs a @c normal_distribution object. @c mean and @c sigma are + * the parameters for the distribution. + * + * Requires: sigma >= 0 + */ + explicit normal_distribution(const RealType& mean_arg = RealType(0.0), + const RealType& sigma_arg = RealType(1.0)) + : _mean(mean_arg), _sigma(sigma_arg), + _r1(0), _r2(0), _cached_rho(0), _valid(false) + { + BOOST_ASSERT(_sigma >= RealType(0)); } - // Can we have a boost::mathconst please? - const result_type pi = result_type(3.14159265358979323846); - - return _cached_rho * (_valid ? - cos(result_type(2)*pi*_r1) : - sin(result_type(2)*pi*_r1)) - * _sigma + _mean; - } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const normal_distribution& nd) - { - os << nd._mean << " " << nd._sigma << " " - << nd._valid << " " << nd._cached_rho << " " << nd._r1; - return os; - } + /** + * Constructs a @c normal_distribution object from its parameters. + */ + explicit normal_distribution(const param_type& parm) + : _mean(parm.mean()), _sigma(parm.sigma()), + _r1(0), _r2(0), _cached_rho(0), _valid(false) + {} + + /** Returns the mean of the distribution. */ + RealType mean() const { return _mean; } + /** Returns the standard deviation of the distribution. */ + RealType sigma() const { return _sigma; } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return -std::numeric_limits::infinity(); } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return std::numeric_limits::infinity(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_mean, _sigma); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _mean = parm.mean(); + _sigma = parm.sigma(); + _valid = false; + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _valid = false; } + + /** Returns a normal variate. */ + template + result_type operator()(Engine& eng) + { + using std::sqrt; + using std::log; + using std::sin; + using std::cos; + + if(!_valid) { + _r1 = boost::uniform_01()(eng); + _r2 = boost::uniform_01()(eng); + _cached_rho = sqrt(-result_type(2) * log(result_type(1)-_r2)); + _valid = true; + } else { + _valid = false; + } + // Can we have a boost::mathconst please? + const result_type pi = result_type(3.14159265358979323846); + + return _cached_rho * (_valid ? + cos(result_type(2)*pi*_r1) : + sin(result_type(2)*pi*_r1)) + * _sigma + _mean; + } + + /** Returns a normal variate with parameters specified by @c param. */ + template + result_type operator()(URNG& urng, const param_type& parm) + { + return normal_distribution(parm)(urng); + } + + /** Writes a @c normal_distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, normal_distribution, nd) + { + os << nd._mean << " " << nd._sigma << " " + << nd._valid << " " << nd._cached_rho << " " << nd._r1; + return os; + } + + /** Reads a @c normal_distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, normal_distribution, nd) + { + is >> std::ws >> nd._mean >> std::ws >> nd._sigma + >> std::ws >> nd._valid >> std::ws >> nd._cached_rho + >> std::ws >> nd._r1; + return is; + } + + /** + * Returns true if the two instances of @c normal_distribution will + * return identical sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(normal_distribution, lhs, rhs) + { + return lhs._mean == rhs._mean && lhs._sigma == rhs._sigma + && lhs._valid == rhs._valid + && (!lhs._valid || (lhs._r1 == rhs._r1 && lhs._r2 == rhs._r2)); + } + + /** + * Returns true if the two instances of @c normal_distribution will + * return different sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(normal_distribution) - template - friend std::basic_istream& - operator>>(std::basic_istream& is, normal_distribution& nd) - { - is >> std::ws >> nd._mean >> std::ws >> nd._sigma - >> std::ws >> nd._valid >> std::ws >> nd._cached_rho - >> std::ws >> nd._r1; - return is; - } -#endif private: - result_type _mean, _sigma; - result_type _r1, _r2, _cached_rho; - bool _valid; + RealType _mean, _sigma; + RealType _r1, _r2, _cached_rho; + bool _valid; + }; +} // namespace random + +using random::normal_distribution; + } // namespace boost #endif // BOOST_RANDOM_NORMAL_DISTRIBUTION_HPP diff --git a/include/boost/random/piecewise_constant_distribution.hpp b/include/boost/random/piecewise_constant_distribution.hpp new file mode 100644 index 0000000..e466f53 --- /dev/null +++ b/include/boost/random/piecewise_constant_distribution.hpp @@ -0,0 +1,466 @@ +/* boost random/piecewise_constant_distribution.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_NO_INITIALIZER_LISTS +#include +#endif + +#include +#include + +namespace boost { +namespace random { + +/** + * The class @c piecewise_constant_distribution models a \random_distribution. + */ +template +class piecewise_constant_distribution { +public: + typedef std::size_t input_type; + typedef RealType result_type; + + class param_type { + public: + + typedef piecewise_constant_distribution distribution_type; + + /** + * Constructs a @c param_type object, representing a distribution + * that produces values uniformly distributed in the range [0, 1). + */ + param_type() + { + _weights.push_back(WeightType(1)); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + /** + * Constructs a @c param_type object from two iterator ranges + * containing the interval boundaries and the interval weights. + * If there are less than two boundaries, then this is equivalent to + * the default constructor and creates a single interval, [0, 1). + * + * The values of the interval boundaries must be strictly + * increasing, and the number of weights must be one less than + * the number of interval boundaries. If there are extra + * weights, they are ignored. + */ + template + param_type(IntervalIter intervals_first, IntervalIter intervals_last, + WeightIter weight_first) + : _intervals(intervals_first, intervals_last) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.push_back(WeightType(1)); + } else { + _weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + _weights.push_back(*weight_first++); + } + } + } +#ifndef BOOST_NO_INITIALIZER_LISTS + /** + * Constructs a @c param_type object from an + * initializer_list containing the interval boundaries + * and a unary function specifying the weights. Each + * weight is determined by calling the function at the + * midpoint of the corresponding interval. + * + * If the initializer_list contains less than two elements, + * this is equivalent to the default constructor and the + * distribution will produce values uniformly distributed + * in the range [0, 1). + */ + template + param_type(const std::initializer_list& il, F f) + : _intervals(il.begin(), il.end()) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.push_back(WeightType(1)); + } else { + _weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2; + _weights.push_back(f(midpoint)); + } + } + } +#endif + /** + * Constructs a @c param_type object from Boost.Range + * ranges holding the interval boundaries and the weights. If + * there are less than two interval boundaries, this is equivalent + * to the default constructor and the distribution will produce + * values uniformly distributed in the range [0, 1). The + * number of weights must be one less than the number of + * interval boundaries. + */ + template + param_type(const IntervalRange& intervals_arg, + const WeightRange& weights_arg) + : _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)), + _weights(boost::begin(weights_arg), boost::end(weights_arg)) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.push_back(WeightType(1)); + } + } + + /** + * Constructs the parameters for a distribution that approximates a + * function. The range of the distribution is [xmin, xmax). This + * range is divided into nw equally sized intervals and the weights + * are found by calling the unary function f on the midpoints of the + * intervals. + */ + template + param_type(std::size_t nw, RealType xmin, RealType xmax, F f) + { + std::size_t n = (nw == 0) ? 1 : nw; + double delta = (xmax - xmin) / n; + BOOST_ASSERT(delta > 0); + for(std::size_t k = 0; k < n; ++k) { + _weights.push_back(f(xmin + k*delta + delta/2)); + _intervals.push_back(xmin + k*delta); + } + _intervals.push_back(xmax); + } + + /** Returns a vector containing the interval boundaries. */ + std::vector intervals() const { return _intervals; } + + /** + * Returns a vector containing the probability densities + * over all the intervals of the distribution. + */ + std::vector densities() const + { + RealType sum = std::accumulate(_weights.begin(), _weights.end(), + static_cast(0)); + std::vector result; + result.reserve(_weights.size()); + for(std::size_t i = 0; i < _weights.size(); ++i) { + RealType width = _intervals[i + 1] - _intervals[i]; + result.push_back(_weights[i] / (sum * width)); + } + return result; + } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + detail::print_vector(os, parm._intervals); + detail::print_vector(os, parm._weights); + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + std::vector new_intervals; + std::vector new_weights; + detail::read_vector(is, new_intervals); + detail::read_vector(is, new_weights); + if(is) { + parm._intervals.swap(new_intervals); + parm._weights.swap(new_weights); + } + return is; + } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { + return lhs._intervals == rhs._intervals + && lhs._weights == rhs._weights; + } + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + + friend class piecewise_constant_distribution; + + std::vector _intervals; + std::vector _weights; + }; + + /** + * Creates a new @c piecewise_constant_distribution with + * a single interval, [0, 1). + */ + piecewise_constant_distribution() + { + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + /** + * Constructs a piecewise_constant_distribution from two iterator ranges + * containing the interval boundaries and the interval weights. + * If there are less than two boundaries, then this is equivalent to + * the default constructor and creates a single interval, [0, 1). + * + * The values of the interval boundaries must be strictly + * increasing, and the number of weights must be one less than + * the number of interval boundaries. If there are extra + * weights, they are ignored. + * + * For example, + * + * @code + * double intervals[] = { 0.0, 1.0, 4.0 }; + * double weights[] = { 1.0, 1.0 }; + * piecewise_constant_distribution<> dist( + * &intervals[0], &intervals[0] + 3, &weights[0]); + * @endcode + * + * The distribution has a 50% chance of producing a + * value between 0 and 1 and a 50% chance of producing + * a value between 1 and 4. + */ + template + piecewise_constant_distribution(IntervalIter first_interval, + IntervalIter last_interval, + WeightIter first_weight) + : _intervals(first_interval, last_interval) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } else { + std::vector actual_weights; + actual_weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + actual_weights.push_back(*first_weight++); + } + typedef discrete_distribution bins_type; + typename bins_type::param_type bins_param(actual_weights); + _bins.param(bins_param); + } + } +#ifndef BOOST_NO_INITIALIZER_LISTS + /** + * Constructs a piecewise_constant_distribution from an + * initializer_list containing the interval boundaries + * and a unary function specifying the weights. Each + * weight is determined by calling the function at the + * midpoint of the corresponding interval. + * + * If the initializer_list contains less than two elements, + * this is equivalent to the default constructor and the + * distribution will produce values uniformly distributed + * in the range [0, 1). + */ + template + piecewise_constant_distribution(std::initializer_list il, F f) + : _intervals(il.begin(), il.end()) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } else { + std::vector actual_weights; + actual_weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2; + actual_weights.push_back(f(midpoint)); + } + typedef discrete_distribution bins_type; + typename bins_type::param_type bins_param(actual_weights); + _bins.param(bins_param); + } + } +#endif + /** + * Constructs a piecewise_constant_distribution from Boost.Range + * ranges holding the interval boundaries and the weights. If + * there are less than two interval boundaries, this is equivalent + * to the default constructor and the distribution will produce + * values uniformly distributed in the range [0, 1). The + * number of weights must be one less than the number of + * interval boundaries. + */ + template + piecewise_constant_distribution(const IntervalsRange& intervals_arg, + const WeightsRange& weights_arg) + : _bins(weights_arg), + _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + } + /** + * Constructs a piecewise_constant_distribution that approximates a + * function. The range of the distribution is [xmin, xmax). This + * range is divided into nw equally sized intervals and the weights + * are found by calling the unary function f on the midpoints of the + * intervals. + */ + template + piecewise_constant_distribution(std::size_t nw, + RealType xmin, + RealType xmax, + F f) + : _bins(nw, xmin, xmax, f) + { + if(nw == 0) { nw = 1; } + RealType delta = (xmax - xmin) / nw; + _intervals.reserve(nw + 1); + for(std::size_t i = 0; i < nw; ++i) { + _intervals.push_back(xmin + i * delta); + } + _intervals.push_back(xmax); + } + /** + * Constructs a piecewise_constant_distribution from its parameters. + */ + explicit piecewise_constant_distribution(const param_type& parm) + : _bins(parm._weights), + _intervals(parm._intervals) + { + } + + /** + * Returns a value distributed according to the parameters of the + * piecewist_constant_distribution. + */ + template + RealType operator()(URNG& urng) const + { + std::size_t i = _bins(urng); + return uniform_real(_intervals[i], _intervals[i+1])(urng); + } + + /** + * Returns a value distributed according to the parameters + * specified by param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return piecewise_constant_distribution(parm)(urng); + } + + /** Returns the smallest value that the distribution can produce. */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return _intervals.front(); } + /** Returns the largest value that the distribution can produce. */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return _intervals.back(); } + + /** + * Returns a vector containing the probability density + * over each interval. + */ + std::vector densities() const + { + std::vector result(_bins.probabilities()); + for(std::size_t i = 0; i < result.size(); ++i) { + result[i] /= (_intervals[i+1] - _intervals[i]); + } + return(result); + } + /** Returns a vector containing the interval boundaries. */ + std::vector intervals() const { return _intervals; } + + /** Returns the parameters of the distribution. */ + param_type param() const + { + return param_type(_intervals, _bins.probabilities()); + } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + std::vector new_intervals(parm._intervals); + typedef discrete_distribution bins_type; + typename bins_type::param_type bins_param(parm._weights); + _bins.param(bins_param); + _intervals.swap(new_intervals); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _bins.reset(); } + + /** Writes a distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR( + os, piecewise_constant_distribution, pcd) + { + os << pcd.param(); + return os; + } + + /** Reads a distribution from a @c std::istream */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR( + is, piecewise_constant_distribution, pcd) + { + param_type parm; + if(is >> parm) { + pcd.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will return the + * same sequence of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR( + piecewise_constant_distribution, lhs, rhs) + { + return lhs._bins == rhs._bins && lhs._intervals == rhs._intervals; + } + /** + * Returns true if the two distributions may return different + * sequences of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(piecewise_constant_distribution) + +private: + discrete_distribution _bins; + std::vector _intervals; +}; + +} +} + +#endif diff --git a/include/boost/random/piecewise_linear_distribution.hpp b/include/boost/random/piecewise_linear_distribution.hpp new file mode 100644 index 0000000..67f8424 --- /dev/null +++ b/include/boost/random/piecewise_linear_distribution.hpp @@ -0,0 +1,530 @@ +/* boost random/piecewise_linear_distribution.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_PIECEWISE_LINEAR_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_PIECEWISE_LINEAR_DISTRIBUTION_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_NO_INITIALIZER_LISTS +#include +#endif + +#include +#include + +namespace boost { +namespace random { + +/** + * The class @c piecewise_linear_distribution models a \random_distribution. + */ +template +class piecewise_linear_distribution { +public: + typedef std::size_t input_type; + typedef RealType result_type; + + class param_type { + public: + + typedef piecewise_linear_distribution distribution_type; + + /** + * Constructs a @c param_type object, representing a distribution + * that produces values uniformly distributed in the range [0, 1). + */ + param_type() + { + _weights.push_back(RealType(1)); + _weights.push_back(RealType(1)); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + /** + * Constructs a @c param_type object from two iterator ranges + * containing the interval boundaries and weights at the boundaries. + * If there are fewer than two boundaries, then this is equivalent to + * the default constructor and the distribution will produce values + * uniformly distributed in the range [0, 1). + * + * The values of the interval boundaries must be strictly + * increasing, and the number of weights must be the same as + * the number of interval boundaries. If there are extra + * weights, they are ignored. + */ + template + param_type(IntervalIter intervals_first, IntervalIter intervals_last, + WeightIter weight_first) + : _intervals(intervals_first, intervals_last) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _weights.push_back(RealType(1)); + _weights.push_back(RealType(1)); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } else { + _weights.reserve(_intervals.size()); + for(std::size_t i = 0; i < _intervals.size(); ++i) { + _weights.push_back(*weight_first++); + } + } + } +#ifndef BOOST_NO_INITIALIZER_LISTS + /** + * Constructs a @c param_type object from an initializer_list + * containing the interval boundaries and a unary function + * specifying the weights at the boundaries. Each weight is + * determined by calling the function at the corresponding point. + * + * If the initializer_list contains fewer than two elements, + * this is equivalent to the default constructor and the + * distribution will produce values uniformly distributed + * in the range [0, 1). + */ + template + param_type(const std::initializer_list& il, F f) + : _intervals(il.begin(), il.end()) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _weights.push_back(RealType(1)); + _weights.push_back(RealType(1)); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } else { + _weights.reserve(_intervals.size()); + for(typename std::vector::const_iterator + iter = _intervals.begin(), end = _intervals.end(); + iter != end; ++iter) + { + _weights.push_back(f(*iter)); + } + } + } +#endif + /** + * Constructs a @c param_type object from Boost.Range ranges holding + * the interval boundaries and the weights at the boundaries. If + * there are fewer than two interval boundaries, this is equivalent + * to the default constructor and the distribution will produce + * values uniformly distributed in the range [0, 1). The + * number of weights must be equal to the number of + * interval boundaries. + */ + template + param_type(const IntervalRange& intervals_arg, + const WeightRange& weights_arg) + : _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)), + _weights(boost::begin(weights_arg), boost::end(weights_arg)) + { + if(_intervals.size() < 2) { + _weights.clear(); + _weights.push_back(RealType(1)); + _weights.push_back(RealType(1)); + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + } + + /** + * Constructs the parameters for a distribution that approximates a + * function. The range of the distribution is [xmin, xmax). This + * range is divided into nw equally sized intervals and the weights + * are found by calling the unary function f on the boundaries of the + * intervals. + */ + template + param_type(std::size_t nw, RealType xmin, RealType xmax, F f) + { + std::size_t n = (nw == 0) ? 1 : nw; + double delta = (xmax - xmin) / n; + BOOST_ASSERT(delta > 0); + for(std::size_t k = 0; k < n; ++k) { + _weights.push_back(f(xmin + k*delta)); + _intervals.push_back(xmin + k*delta); + } + _weights.push_back(f(xmax)); + _intervals.push_back(xmax); + } + + /** Returns a vector containing the interval boundaries. */ + std::vector intervals() const { return _intervals; } + + /** + * Returns a vector containing the probability densities + * at all the interval boundaries. + */ + std::vector densities() const + { + RealType sum = static_cast(0); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + RealType width = _intervals[i + 1] - _intervals[i]; + sum += (_weights[i] + _weights[i + 1]) * width / 2; + } + std::vector result; + result.reserve(_weights.size()); + for(typename std::vector::const_iterator + iter = _weights.begin(), end = _weights.end(); + iter != end; ++iter) + { + result.push_back(*iter / sum); + } + return result; + } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + detail::print_vector(os, parm._intervals); + detail::print_vector(os, parm._weights); + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + std::vector new_intervals; + std::vector new_weights; + detail::read_vector(is, new_intervals); + detail::read_vector(is, new_weights); + if(is) { + parm._intervals.swap(new_intervals); + parm._weights.swap(new_weights); + } + return is; + } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { + return lhs._intervals == rhs._intervals + && lhs._weights == rhs._weights; + } + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + friend class piecewise_linear_distribution; + + std::vector _intervals; + std::vector _weights; + }; + + /** + * Creates a new @c piecewise_linear_distribution that + * produces values uniformly distributed in the range [0, 1). + */ + piecewise_linear_distribution() + { + default_init(); + } + /** + * Constructs a piecewise_linear_distribution from two iterator ranges + * containing the interval boundaries and the weights at the boundaries. + * If there are fewer than two boundaries, then this is equivalent to + * the default constructor and creates a distribution that + * produces values uniformly distributed in the range [0, 1). + * + * The values of the interval boundaries must be strictly + * increasing, and the number of weights must be equal to + * the number of interval boundaries. If there are extra + * weights, they are ignored. + * + * For example, + * + * @code + * double intervals[] = { 0.0, 1.0, 2.0 }; + * double weights[] = { 0.0, 1.0, 0.0 }; + * piecewise_constant_distribution<> dist( + * &intervals[0], &intervals[0] + 3, &weights[0]); + * @endcode + * + * produces a triangle distribution. + */ + template + piecewise_linear_distribution(IntervalIter first_interval, + IntervalIter last_interval, + WeightIter first_weight) + : _intervals(first_interval, last_interval) + { + if(_intervals.size() < 2) { + default_init(); + } else { + _weights.reserve(_intervals.size()); + for(std::size_t i = 0; i < _intervals.size(); ++i) { + _weights.push_back(*first_weight++); + } + init(); + } + } +#ifndef BOOST_NO_INITIALIZER_LISTS + /** + * Constructs a piecewise_linear_distribution from an + * initializer_list containing the interval boundaries + * and a unary function specifying the weights. Each + * weight is determined by calling the function at the + * corresponding interval boundary. + * + * If the initializer_list contains fewer than two elements, + * this is equivalent to the default constructor and the + * distribution will produce values uniformly distributed + * in the range [0, 1). + */ + template + piecewise_linear_distribution(std::initializer_list il, F f) + : _intervals(il.begin(), il.end()) + { + if(_intervals.size() < 2) { + default_init(); + } else { + _weights.reserve(_intervals.size()); + for(typename std::vector::const_iterator + iter = _intervals.begin(), end = _intervals.end(); + iter != end; ++iter) + { + _weights.push_back(f(*iter)); + } + init(); + } + } +#endif + /** + * Constructs a piecewise_linear_distribution from Boost.Range + * ranges holding the interval boundaries and the weights. If + * there are fewer than two interval boundaries, this is equivalent + * to the default constructor and the distribution will produce + * values uniformly distributed in the range [0, 1). The + * number of weights must be equal to the number of + * interval boundaries. + */ + template + piecewise_linear_distribution(const IntervalsRange& intervals_arg, + const WeightsRange& weights_arg) + : _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)), + _weights(boost::begin(weights_arg), boost::end(weights_arg)) + { + if(_intervals.size() < 2) { + default_init(); + } else { + init(); + } + } + /** + * Constructs a piecewise_linear_distribution that approximates a + * function. The range of the distribution is [xmin, xmax). This + * range is divided into nw equally sized intervals and the weights + * are found by calling the unary function f on the interval boundaries. + */ + template + piecewise_linear_distribution(std::size_t nw, + RealType xmin, + RealType xmax, + F f) + { + if(nw == 0) { nw = 1; } + RealType delta = (xmax - xmin) / nw; + _intervals.reserve(nw + 1); + for(std::size_t i = 0; i < nw; ++i) { + RealType x = xmin + i * delta; + _intervals.push_back(x); + _weights.push_back(f(x)); + } + _intervals.push_back(xmax); + _weights.push_back(f(xmax)); + init(); + } + /** + * Constructs a piecewise_linear_distribution from its parameters. + */ + explicit piecewise_linear_distribution(const param_type& parm) + : _intervals(parm._intervals), + _weights(parm._weights) + { + init(); + } + + /** + * Returns a value distributed according to the parameters of the + * piecewise_linear_distribution. + */ + template + RealType operator()(URNG& urng) const + { + std::size_t i = _bins(urng); + bool is_in_rectangle = (i % 2 == 0); + i = i / 2; + uniform_real dist(_intervals[i], _intervals[i+1]); + if(is_in_rectangle) { + return dist(urng); + } else if(_weights[i] < _weights[i+1]) { + return (std::max)(dist(urng), dist(urng)); + } else { + return (std::min)(dist(urng), dist(urng)); + } + } + + /** + * Returns a value distributed according to the parameters + * specified by param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return piecewise_linear_distribution(parm)(urng); + } + + /** Returns the smallest value that the distribution can produce. */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return _intervals.front(); } + /** Returns the largest value that the distribution can produce. */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return _intervals.back(); } + + /** + * Returns a vector containing the probability densities + * at the interval boundaries. + */ + std::vector densities() const + { + RealType sum = static_cast(0); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + RealType width = _intervals[i + 1] - _intervals[i]; + sum += (_weights[i] + _weights[i + 1]) * width / 2; + } + std::vector result; + result.reserve(_weights.size()); + for(typename std::vector::const_iterator + iter = _weights.begin(), end = _weights.end(); + iter != end; ++iter) + { + result.push_back(*iter / sum); + } + return result; + } + /** Returns a vector containing the interval boundaries. */ + std::vector intervals() const { return _intervals; } + + /** Returns the parameters of the distribution. */ + param_type param() const + { + return param_type(_intervals, _weights); + } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + std::vector new_intervals(parm._intervals); + std::vector new_weights(parm._weights); + init(new_intervals, new_weights); + _intervals.swap(new_intervals); + _weights.swap(new_weights); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _bins.reset(); } + + /** Writes a distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR( + os, piecewise_linear_distribution, pld) + { + os << pld.param(); + return os; + } + + /** Reads a distribution from a @c std::istream */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR( + is, piecewise_linear_distribution, pld) + { + param_type parm; + if(is >> parm) { + pld.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will return the + * same sequence of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR( + piecewise_linear_distribution, lhs, rhs) + { + return lhs._intervals == rhs._intervals && lhs._weights == rhs._weights; + } + /** + * Returns true if the two distributions may return different + * sequences of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(piecewise_linear_distribution) + +private: + + /// @cond \show_private + + void init(const std::vector& intervals_arg, + const std::vector& weights_arg) + { + std::vector bin_weights; + bin_weights.reserve((intervals_arg.size() - 1) * 2); + for(std::size_t i = 0; i < intervals_arg.size() - 1; ++i) { + RealType width = intervals_arg[i + 1] - intervals_arg[i]; + RealType w1 = weights_arg[i]; + RealType w2 = weights_arg[i + 1]; + bin_weights.push_back((std::min)(w1, w2) * width); + bin_weights.push_back(std::abs(w1 - w2) * width / 2); + } + typedef discrete_distribution bins_type; + typename bins_type::param_type bins_param(bin_weights); + _bins.param(bins_param); + } + + void init() + { + init(_intervals, _weights); + } + + void default_init() + { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.clear(); + _weights.push_back(RealType(1)); + _weights.push_back(RealType(1)); + init(); + } + + discrete_distribution _bins; + std::vector _intervals; + std::vector _weights; + + /// @endcond +}; + +} +} + +#endif diff --git a/include/boost/random/poisson_distribution.hpp b/include/boost/random/poisson_distribution.hpp index 0b3e421..759f206 100644 --- a/include/boost/random/poisson_distribution.hpp +++ b/include/boost/random/poisson_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/poisson_distribution.hpp header file * * Copyright Jens Maurer 2002 + * 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) @@ -15,102 +16,345 @@ #define BOOST_RANDOM_POISSON_DISTRIBUTION_HPP #include -#include -#include +#include +#include +#include #include -#include +#include #include -namespace boost { +#include -// Knuth +namespace boost { +namespace random { + +namespace detail { + +template +struct poisson_table { + static RealType value[10]; +}; + +template +RealType poisson_table::value[10] = { + 0.0, + 0.0, + 0.69314718055994529, + 1.7917594692280550, + 3.1780538303479458, + 4.7874917427820458, + 6.5792512120101012, + 8.5251613610654147, + 10.604602902745251, + 12.801827480081469 +}; + +} /** * An instantiation of the class template @c poisson_distribution is a * model of \random_distribution. The poisson distribution has * \f$p(i) = \frac{e^{-\lambda}\lambda^i}{i!}\f$ + * + * This implementation is based on the PTRD algorithm described + * + * @blockquote + * "The transformed rejection method for generating Poisson random variables", + * Wolfgang Hormann, Insurance: Mathematics and Economics + * Volume 12, Issue 1, February 1993, Pages 39-45 + * @endblockquote */ template -class poisson_distribution -{ +class poisson_distribution { public: - typedef RealType input_type; - typedef IntType result_type; + typedef IntType result_type; + typedef RealType input_type; - /** - * Constructs a @c poisson_distribution with the parameter @c mean. - * - * Requires: mean > 0 - */ - explicit poisson_distribution(const RealType& mean_arg = RealType(1)) - : _mean(mean_arg) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); + class param_type { + public: + typedef poisson_distribution distribution_type; + /** + * Construct a param_type object with the parameter "mean" + * + * Requires: mean > 0 + */ + explicit param_type(RealType mean_arg = RealType(1)) + : _mean(mean_arg) + { + BOOST_ASSERT(_mean > 0); + } + /* Returns the "mean" parameter of the distribution. */ + RealType mean() const { return _mean; } +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const param_type& parm) + { + os << parm._mean; + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, param_type& parm) + { + is >> parm._mean; + return is; + } #endif - - assert(_mean > RealType(0)); - init(); - } - - // compiler-generated copy ctor and assignment operator are fine - - /** - * Returns: the "mean" parameter of the distribution. - */ - RealType mean() const { return _mean; } - void reset() { } - - template - result_type operator()(Engine& eng) - { - // TODO: This is O(_mean), but it should be O(log(_mean)) for large _mean - RealType product = RealType(1); - for(result_type m = 0; ; ++m) { - product *= eng(); - if(product <= _exp_mean) - return m; + /** Returns true if the parameters have the same values. */ + friend bool operator==(const param_type& lhs, const param_type& rhs) + { + return lhs._mean == rhs._mean; + } + /** Returns true if the parameters have different values. */ + friend bool operator!=(const param_type& lhs, const param_type& rhs) + { + return !(lhs == rhs); + } + private: + RealType _mean; + }; + + /** + * Constructs a @c poisson_distribution with the parameter @c mean. + * + * Requires: mean > 0 + */ + explicit poisson_distribution(RealType mean_arg = RealType(1)) + : _mean(mean_arg) + { + BOOST_ASSERT(_mean > 0); + init(); } - } + + /** + * Construct an @c poisson_distribution object from the + * parameters. + */ + explicit poisson_distribution(const param_type& parm) + : _mean(parm.mean()) + { + init(); + } + + /** + * Returns a random variate distributed according to the + * poisson distribution. + */ + template + IntType operator()(URNG& urng) const + { + if(use_inversion()) { + return invert(urng); + } else { + return generate(urng); + } + } + + /** + * Returns a random variate distributed according to the + * poisson distribution with parameters specified by param. + */ + template + IntType operator()(URNG& urng, const param_type& parm) const + { + return poisson_distribution(parm)(urng); + } + + /** Returns the "mean" parameter of the distribution. */ + RealType mean() const { return _mean; } + + /** Returns the smallest value that the distribution can produce. */ + IntType min BOOST_PREVENT_MACRO_SUBSTITUTION() const { return 0; } + /** Returns the largest value that the distribution can produce. */ + IntType max BOOST_PREVENT_MACRO_SUBSTITUTION() const + { return (std::numeric_limits::max)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_mean); } + /** Sets parameters of the distribution. */ + void param(const param_type& parm) + { + _mean = parm.mean(); + init(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const poisson_distribution& pd) - { - os << pd._mean; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, poisson_distribution& pd) - { - is >> std::ws >> pd._mean; - pd.init(); - return is; - } + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const poisson_distribution& pd) + { + os << pd.param(); + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, poisson_distribution& pd) + { + pd.read(is); + return is; + } #endif + + /** Returns true if the two distributions will produce the same + sequence of values, given equal generators. */ + friend bool operator==(const poisson_distribution& lhs, + const poisson_distribution& rhs) + { + return lhs._mean == rhs._mean; + } + /** Returns true if the two distributions could produce different + sequences of values, given equal generators. */ + friend bool operator!=(const poisson_distribution& lhs, + const poisson_distribution& rhs) + { + return !(lhs == rhs); + } private: - /// \cond hide_private_members - void init() - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::exp; -#endif - _exp_mean = exp(-_mean); - } - /// \endcond - RealType _mean; - // some precomputed data from the parameters - RealType _exp_mean; + /// @cond show_private + + template + void read(std::basic_istream& is) { + param_type parm; + if(is >> parm) { + param(parm); + } + } + + bool use_inversion() const + { + return _mean < 10; + } + + static RealType log_factorial(IntType k) + { + BOOST_ASSERT(k >= 0); + BOOST_ASSERT(k < 10); + return detail::poisson_table::value[k]; + } + + void init() + { + using std::sqrt; + using std::exp; + + if(use_inversion()) { + _exp_mean = exp(-_mean); + } else { + _ptrd.smu = sqrt(_mean); + _ptrd.b = 0.931 + 2.53 * _ptrd.smu; + _ptrd.a = -0.059 + 0.02483 * _ptrd.b; + _ptrd.inv_alpha = 1.1239 + 1.1328 / (_ptrd.b - 3.4); + _ptrd.v_r = 0.9277 - 3.6224 / (_ptrd.b - 2); + } + } + + template + IntType generate(URNG& urng) const + { + using std::floor; + using std::abs; + using std::log; + + while(true) { + RealType u; + RealType v = uniform_01()(urng); + if(v <= 0.86 * _ptrd.v_r) { + u = v / _ptrd.v_r - 0.43; + return static_cast(floor( + (2*_ptrd.a/(0.5-abs(u)) + _ptrd.b)*u + _mean + 0.445)); + } + + if(v >= _ptrd.v_r) { + u = uniform_01()(urng) - 0.5; + } else { + u = v/_ptrd.v_r - 0.93; + u = ((u < 0)? -0.5 : 0.5) - u; + v = uniform_01()(urng) * _ptrd.v_r; + } + + RealType us = 0.5 - abs(u); + if(us < 0.013 && v > us) { + continue; + } + + RealType k = floor((2*_ptrd.a/us + _ptrd.b)*u+_mean+0.445); + v = v*_ptrd.inv_alpha/(_ptrd.a/(us*us) + _ptrd.b); + + RealType log_sqrt_2pi = 0.91893853320467267; + + if(k >= 10) { + if(log(v*_ptrd.smu) <= (k + 0.5)*log(_mean/k) + - _mean + - log_sqrt_2pi + + k + - (1/12. - (1/360. - 1/(1260.*k*k))/(k*k))/k) { + return static_cast(k); + } + } else if(k >= 0) { + if(log(v) <= k*log(_mean) + - _mean + - log_factorial(static_cast(k))) { + return static_cast(k); + } + } + } + } + + template + IntType invert(URNG& urng) const + { + RealType p = _exp_mean; + IntType x = 0; + RealType u = uniform_01()(urng); + while(u > p) { + u = u - p; + ++x; + p = _mean * p / x; + } + return x; + } + + RealType _mean; + + union { + // for ptrd + struct { + RealType v_r; + RealType a; + RealType b; + RealType smu; + RealType inv_alpha; + } _ptrd; + // for inversion + RealType _exp_mean; + }; + + /// @endcond }; +} // namespace random + +using random::poisson_distribution; + } // namespace boost +#include + #endif // BOOST_RANDOM_POISSON_DISTRIBUTION_HPP diff --git a/include/boost/random/random_device.hpp b/include/boost/random/random_device.hpp new file mode 100644 index 0000000..b18d38a --- /dev/null +++ b/include/boost/random/random_device.hpp @@ -0,0 +1,142 @@ +/* boost random/random_device.hpp header file + * + * 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$ + * + * Revision history + * 2000-02-18 Portability fixes (thanks to Beman Dawes) + */ + +// See http://www.boost.org/libs/random for documentation. + + +#ifndef BOOST_RANDOM_RANDOM_DEVICE_HPP +#define BOOST_RANDOM_RANDOM_DEVICE_HPP + +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * Class \random_device models a \nondeterministic_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 + * + * @blockquote + * "Randomness Recommendations for Security", D. Eastlake, S. Crocker, + * J. Schiller, Network Working Group, RFC 1750, December 1994 + * @endblockquote + * + * for further discussions. + * + * @xmlnote + * 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. + * @endxmlnote + * + * 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, @c 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. + * + * Implementation Note for Windows + * + * On the Windows operating system, token is interpreted as the name + * of a cryptographic service provider. By default \random_device uses + * MS_DEF_PROV. + * + * Performance + * + * The test program + * nondet_random_speed.cpp measures the execution times of the + * random_device.hpp implementation of the above algorithms in a tight + * loop. 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. + * + * + * + * + * + *
Platformtime per invocation [microseconds]
Windows 2.9
Linux 1.7
+ * + * The measurement error is estimated at +/- 1 usec. + */ +class random_device : private noncopyable +{ +public: + typedef unsigned int result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + + /** Returns the smallest value that the \random_device can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } + /** Returns the largest value that the \random_device can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return ~0u; } + + /** Constructs a @c random_device, optionally using the default device. */ + BOOST_RANDOM_DECL random_device(); + /** + * Constructs a @c 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. + */ + BOOST_RANDOM_DECL explicit random_device(const std::string& token); + + BOOST_RANDOM_DECL ~random_device(); + + /** + * 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. + */ + BOOST_RANDOM_DECL double entropy() const; + /** Returns a random value in the range [min, max]. */ + BOOST_RANDOM_DECL unsigned int operator()(); + + /** Fills a range with random 32-bit values. */ + template + void generate(Iter begin, Iter end) + { + for(; begin != end; ++begin) { + *begin = (*this)(); + } + } + +private: + class impl; + impl * pimpl; +}; + +} // namespace random + +using random::random_device; + +} // namespace boost + +#endif /* BOOST_RANDOM_RANDOM_DEVICE_HPP */ diff --git a/include/boost/random/random_number_generator.hpp b/include/boost/random/random_number_generator.hpp index 58853fc..ac975e3 100644 --- a/include/boost/random/random_number_generator.hpp +++ b/include/boost/random/random_number_generator.hpp @@ -16,13 +16,13 @@ #ifndef BOOST_RANDOM_RANDOM_NUMBER_GENERATOR_HPP #define BOOST_RANDOM_RANDOM_NUMBER_GENERATOR_HPP -#include -#include -#include -#include -#include +#include +#include + +#include namespace boost { +namespace random { /** * Instantiations of class template random_number_generator model a @@ -32,40 +32,42 @@ namespace boost { * * The template parameter IntType shall denote some integer-like value type. */ -template +template class random_number_generator { public: - typedef UniformRandomNumberGenerator base_type; - typedef IntType argument_type; - typedef IntType result_type; - /** - * Constructs a random_number_generator functor with the given - * \uniform_random_number_generator as the underlying source of - * random numbers. - */ - random_number_generator(base_type& rng) : _rng(rng) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); -#endif - } - // compiler-generated copy ctor is fine - // assignment is disallowed because there is a reference member + typedef URNG base_type; + typedef IntType argument_type; + typedef IntType result_type; + /** + * Constructs a random_number_generator functor with the given + * \uniform_random_number_generator as the underlying source of + * random numbers. + */ + random_number_generator(base_type& rng) : _rng(rng) {} - /** - * Returns a value in the range [0, n) - */ - result_type operator()(argument_type n) - { - typedef uniform_int dist_type; - return variate_generator(_rng, dist_type(0, n-1))(); - } + // compiler-generated copy ctor is fine + // assignment is disallowed because there is a reference member + + /** + * Returns a value in the range [0, n) + */ + result_type operator()(argument_type n) + { + BOOST_ASSERT(n > 0); + return uniform_int_distribution(0, n-1)(_rng); + } private: - base_type& _rng; + base_type& _rng; }; +} // namespace random + +using random::random_number_generator; + } // namespace boost +#include + #endif // BOOST_RANDOM_RANDOM_NUMBER_GENERATOR_HPP diff --git a/include/boost/random/ranlux.hpp b/include/boost/random/ranlux.hpp index 960bc41..5a14f95 100644 --- a/include/boost/random/ranlux.hpp +++ b/include/boost/random/ranlux.hpp @@ -23,12 +23,7 @@ namespace boost { namespace random { - typedef subtract_with_carry ranlux_base; - typedef subtract_with_carry_01 ranlux_base_01; - typedef subtract_with_carry_01 ranlux64_base_01; -} -namespace random { namespace detail { /** * The ranlux family of generators are described in @@ -49,33 +44,56 @@ namespace detail { */ class ranlux_documentation {}; } -} + +typedef subtract_with_carry_engine ranlux_base; +typedef subtract_with_carry_01_engine ranlux_base_01; +typedef subtract_with_carry_01_engine ranlux64_base_01; + /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux3; +typedef discard_block_engine ranlux3; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux4; +typedef discard_block_engine ranlux4; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux3_01; +typedef discard_block_engine ranlux3_01; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux4_01; +typedef discard_block_engine ranlux4_01; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux64_3_01; +typedef discard_block_engine ranlux64_3_01; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux64_4_01; +typedef discard_block_engine ranlux64_4_01; #if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -namespace random { - typedef random::subtract_with_carry ranlux64_base; -} +typedef subtract_with_carry_engine ranlux64_base; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux64_3; +typedef discard_block_engine ranlux64_3; /** @copydoc boost::random::detail::ranlux_documentation */ -typedef random::discard_block ranlux64_4; +typedef discard_block_engine ranlux64_4; #endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */ + +typedef subtract_with_carry_engine ranlux24_base; +typedef subtract_with_carry_engine ranlux48_base; + +typedef discard_block_engine ranlux24; +#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) +typedef discard_block_engine ranlux48; +#endif +} + +using random::ranlux3; +using random::ranlux4; +using random::ranlux3_01; +using random::ranlux4_01; +using random::ranlux64_3_01; +using random::ranlux64_4_01; +#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) +using random::ranlux64_3; +using random::ranlux64_4; +#endif + } // namespace boost #endif // BOOST_RANDOM_LINEAR_CONGRUENTIAL_HPP diff --git a/include/boost/random/seed_seq.hpp b/include/boost/random/seed_seq.hpp new file mode 100644 index 0000000..a541a53 --- /dev/null +++ b/include/boost/random/seed_seq.hpp @@ -0,0 +1,118 @@ +/* boost random/seed_seq.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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_SEED_SEQ_HPP +#define BOOST_RANDOM_SEED_SEQ_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_NO_INITIALIZER_LISTS +#include +#endif + +namespace boost { +namespace random { + +/** + * The class @c seed_seq stores a sequence of 32-bit words + * for seeding a \pseudo_random_number_generator. These + * words will be combined to fill the entire state of the + * generator. + */ +class seed_seq { +public: + typedef boost::uint_least32_t result_type; + + /** Initializes a seed_seq to hold an empty sequence. */ + seed_seq() {} +#ifndef BOOST_NO_INITIALIZER_LISTS + /** Initializes the sequence from an initializer_list. */ + template + seed_seq(const std::initializer_list& il) : v(il.begin(), il.end()) {} +#endif + /** Initializes the sequence from an iterator range. */ + template + seed_seq(Iter first, Iter last) : v(first, last) {} + /** Initializes the sequence from Boost.Range range. */ + template + explicit seed_seq(const Range& range) + : v(boost::begin(range), boost::end(range)) {} + + /** + * Fills a range with 32-bit values based on the stored sequence. + * + * Requires: Iter must be a Random Access Iterator whose value type + * is an unsigned integral type at least 32 bits wide. + */ + template + void generate(Iter first, Iter last) const + { + typedef typename std::iterator_traits::value_type value_type; + std::fill(first, last, static_cast(0x8b8b8b8bu)); + std::size_t s = v.size(); + std::size_t n = last - first; + std::size_t t = + (n >= 623) ? 11 : + (n >= 68) ? 7 : + (n >= 39) ? 5 : + (n >= 7) ? 3 : + (n - 1)/2; + std::size_t p = (n - t) / 2; + std::size_t q = p + t; + std::size_t m = (std::max)(s+1, n); + value_type mask = 0xffffffffu; + for(std::size_t k = 0; k < m; ++k) { + value_type r1 = + *(first + k%n) ^ *(first + (k+p)%n) ^ *(first + (k+n-1)%n); + r1 = r1 ^ (r1 >> 27); + r1 = (r1 * 1664525u) & mask; + value_type r2 = r1 + + ((k == 0) ? s : + (k <= s) ? k % n + v[k - 1] : + (k % n)); + *(first + (k+p)%n) = (*(first + (k+p)%n) + r1) & mask; + *(first + (k+q)%n) = (*(first + (k+q)%n) + r2) & mask; + *(first + k%n) = r2; + } + for(std::size_t k = m; k < m + n; ++k) { + value_type r3 = + (*(first + k%n) + *(first + (k+p)%n) + *(first + (k+n-1)%n)) + & mask; + r3 = r3 ^ (r3 >> 27); + r3 = (r3 * 1566083941u) & mask; + value_type r4 = r3 - k%m; + *(first + (k+p)%n) ^= r4; + *(first + (k+q)%n) ^= r3; + *(first + k%n) = r4; + } + } + /** Returns the size of the sequence. */ + std::size_t size() const { return v.size(); } + /** Writes the stored sequence to iter. */ + template + void param(Iter out) { std::copy(v.begin(), v.end(), out); } +private: + std::vector v; +}; + +} +} + +#endif diff --git a/include/boost/random/shuffle_order.hpp b/include/boost/random/shuffle_order.hpp new file mode 100644 index 0000000..ec1a293 --- /dev/null +++ b/include/boost/random/shuffle_order.hpp @@ -0,0 +1,269 @@ +/* boost random/shuffle_order.hpp header file + * + * Copyright Jens Maurer 2000-2001 + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_SHUFFLE_ORDER_HPP +#define BOOST_RANDOM_SHUFFLE_ORDER_HPP + +#include +#include // std::copy +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace random { + +/** + * Instatiations of class template @c shuffle_order_engine model a + * \pseudo_random_number_generator. It mixes the output + * of some (usually \linear_congruential_engine) + * \uniform_random_number_generator to get better statistical properties. + * The algorithm is described in + * + * @blockquote + * "Improving a poor random number generator", Carter Bays + * and S.D. Durham, ACM Transactions on Mathematical Software, + * Vol 2, No. 1, March 1976, pp. 59-64. + * http://doi.acm.org/10.1145/355666.355670 + * @endblockquote + * + * The output of the base generator is buffered in an array of + * length k. Every output X(n) has a second role: It gives an + * index into the array where X(n+1) will be retrieved. Used + * array elements are replaced with fresh output from the base + * generator. + * + * Template parameters are the base generator and the array + * length k, which should be around 100. + */ +template +class shuffle_order_engine +{ +public: + typedef UniformRandomNumberGenerator base_type; + typedef typename base_type::result_type result_type; + + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(std::size_t, buffer_size = k); + BOOST_STATIC_CONSTANT(std::size_t, table_size = k); + + BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); + BOOST_STATIC_ASSERT(k > 0); + + /** + * Constructs a @c shuffle_order_engine by invoking the + * default constructor of the base generator. + * + * Complexity: Exactly k+1 invocations of the base generator. + */ + shuffle_order_engine() : _rng() { init(); } + /** + * Constructs a @c shuffle_output_engine by invoking the one-argument + * constructor of the base generator with the parameter seed. + * + * Complexity: Exactly k+1 invocations of the base generator. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(shuffle_order_engine, + result_type, s) + { _rng.seed(s); init(); } + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(shuffle_order_engine, SeedSeq, seq) + { _rng.seed(seq); init(); } + /** + * Constructs a @c shuffle_output_engine by using a copy + * of the provided generator. + * + * Precondition: The template argument UniformRandomNumberGenerator + * shall denote a CopyConstructible type. + * + * Complexity: Exactly k+1 invocations of the base generator. + */ + explicit shuffle_order_engine(const base_type & rng) : _rng(rng) { init(); } + +#ifndef BOOST_NO_RVALUE_REFERENCES + explicit shuffle_order_engine(base_type&& rng) : _rng(rng) { init(); } +#endif + + template shuffle_order_engine(It& first, It last) + : _rng(first, last) { init(); } + void seed() { _rng.seed(); init(); } + /** + * Invokes the one-argument seed method of the base generator + * with the parameter seed and re-initializes the internal buffer array. + * + * Complexity: Exactly k+1 invocations of the base generator. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(shuffle_order_engine, + result_type, seed_arg) + { _rng.seed(seed_arg); init(); } + /** + * Invokes the one-argument seed method of the base generator + * with the parameter seq and re-initializes the internal buffer array. + * + * Complexity: Exactly k+1 invocations of the base generator. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(shuffle_order_engine, SeedSeq, seq) + { _rng.seed(seq); init(); } + template void seed(It& first, It last) + { _rng.seed(first, last); init(); } + + const base_type& base() const { return _rng; } + + result_type operator()() { + // calculating the range every time may seem wasteful. However, this + // makes the information locally available for the optimizer. + typedef typename make_unsigned::type base_unsigned; + const base_unsigned brange = + detail::subtract()((max)(), (min)()); + const base_unsigned off = + detail::subtract()(y, (min)()); + + base_unsigned j; + if(k == 1) { + j = 0; + } else if(brange < (std::numeric_limits::max)() / k) { + // try to do it in the native type if we know that it won't + // overflow + j = k * off / (brange + 1); + } else if(brange < (std::numeric_limits::max)() / k) { + // Otherwise try to use uint64_t + j = static_cast( + static_cast(off) * k / + (static_cast(brange) + 1)); + } else { + boost::uintmax_t divisor = + static_cast(brange) + 1; + j = static_cast(detail::muldiv(off, k, divisor)); + } + // assert(0 <= j && j < k); + y = v[j]; + v[j] = _rng(); + return y; + } + + /** Advances the generator by z steps. */ + void discard(boost::uintmax_t z) + { + for(boost::uintmax_t j = 0; j < z; ++j) { + (*this)(); + } + } + + /** Fills a range with pseudo-random values. */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } + + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (base_type::min)(); } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (base_type::max)(); } + + /** Writes a @c shuffle_order_engine to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, shuffle_order_engine, s) + { + os << s._rng; + for(std::size_t i = 0; i < k; ++i) + os << ' ' << s.v[i]; + os << ' ' << s.y; + return os; + } + + /** Reads a @c shuffle_order_engine from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, shuffle_order_engine, s) + { + is >> s._rng; + for(std::size_t i = 0; i < k; ++i) + is >> std::ws >> s.v[i]; + is >> std::ws >> s.y; + return is; + } + + /** Returns true if the two generators will produce identical sequences. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(shuffle_order_engine, x, y) + { return x._rng == y._rng && x.y == y.y && std::equal(x.v, x.v+k, y.v); } + /** Returns true if the two generators will produce different sequences. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(shuffle_order_engine) + +private: + + /// \cond show_private + + void init() + { + // we cannot use std::generate, because it uses pass-by-value for _rng + for(result_type * p = v; p != v+k; ++p) + *p = _rng(); + y = _rng(); + } + + /// \endcond + + base_type _rng; + result_type v[k]; + result_type y; +}; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +// A definition is required even for integral static constants +template +const bool shuffle_order_engine::has_fixed_range; +template +const std::size_t shuffle_order_engine::table_size; +template +const std::size_t shuffle_order_engine::buffer_size; +#endif + +/** + * According to Harry Erwin (private e-mail), the specialization + * @c kreutzer1986 was suggested in: + * + * @blockquote + * "System Simulation: Programming Styles and Languages (International + * Computer Science Series)", Wolfgang Kreutzer, Addison-Wesley, December 1986. + * @endblockquote + */ +typedef shuffle_order_engine< + linear_congruential_engine, + 97> kreutzer1986; + +/** + * The specialization @c knuth_b is specified by the C++ standard. + * It is described in + * + * @blockquote + * "The Art of Computer Programming, Second Edition, Volume 2, + * Seminumerical Algorithms", Donald Knuth, Addison-Wesley, 1981. + * @endblockquote + */ +typedef shuffle_order_engine knuth_b; + +} // namespace random + +using random::kreutzer1986; + +} // namespace boost + +#include + +#endif // BOOST_RANDOM_SHUFFLE_OUTPUT_HPP diff --git a/include/boost/random/shuffle_output.hpp b/include/boost/random/shuffle_output.hpp index 79c5aa2..b47d9f3 100644 --- a/include/boost/random/shuffle_output.hpp +++ b/include/boost/random/shuffle_output.hpp @@ -16,219 +16,36 @@ #ifndef BOOST_RANDOM_SHUFFLE_OUTPUT_HPP #define BOOST_RANDOM_SHUFFLE_OUTPUT_HPP -#include -#include // std::copy -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace random { -/** - * Instatiations of class template shuffle_output model a - * \pseudo_random_number_generator. It mixes the output - * of some (usually \linear_congruential) \uniform_random_number_generator - * to get better statistical properties. - * The algorithm is described in - * - * @blockquote - * "Improving a poor random number generator", Carter Bays - * and S.D. Durham, ACM Transactions on Mathematical Software, - * Vol 2, No. 1, March 1976, pp. 59-64. - * http://doi.acm.org/10.1145/355666.355670 - * @endblockquote - * - * The output of the base generator is buffered in an array of - * length k. Every output X(n) has a second role: It gives an - * index into the array where X(n+1) will be retrieved. Used - * array elements are replaced with fresh output from the base - * generator. - * - * Template parameters are the base generator and the array - * length k, which should be around 100. The template parameter - * val is the validation value checked by validation. - */ -template -class shuffle_output +/// \cond + +template +class shuffle_output : public shuffle_order_engine { + typedef shuffle_order_engine base_t; + typedef typename base_t::result_type result_type; public: - typedef UniformRandomNumberGenerator base_type; - typedef typename base_type::result_type result_type; - - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, buffer_size = k); - - /** - * Constructs a @c shuffle_output generator by invoking the - * default constructor of the base generator. - * - * Complexity: Exactly k+1 invocations of the base generator. - */ - shuffle_output() : _rng() { init(); } -#if defined(BOOST_MSVC) && _MSC_VER < 1300 - // MSVC does not implicitly generate the copy constructor here - shuffle_output(const shuffle_output & x) - : _rng(x._rng), y(x.y) { std::copy(x.v, x.v+k, v); } -#endif - /** - * Constructs a shuffle_output generator by invoking the one-argument - * constructor of the base generator with the parameter seed. - * - * Complexity: Exactly k+1 invocations of the base generator. - */ - template - explicit shuffle_output(T s) : _rng(s) { init(); } - /** - * Constructs a shuffle_output generator by using a copy - * of the provided generator. - * - * Precondition: The template argument UniformRandomNumberGenerator - * shall denote a CopyConstructible type. - * - * Complexity: Exactly k+1 invocations of the base generator. - */ - explicit shuffle_output(const base_type & rng) : _rng(rng) { init(); } - template shuffle_output(It& first, It last) - : _rng(first, last) { init(); } - void seed() { _rng.seed(); init(); } - /** - * Invokes the one-argument seed method of the base generator - * with the parameter seed and re-initializes the internal buffer array. - * - * Complexity: Exactly k+1 invocations of the base generator. - */ - template - void seed(T s) { _rng.seed(s); init(); } - template void seed(It& first, It last) - { - _rng.seed(first, last); - init(); - } - - const base_type& base() const { return _rng; } - - result_type operator()() { - // calculating the range every time may seem wasteful. However, this - // makes the information locally available for the optimizer. - result_type range = (max)()-(min)()+1; - int j = k*(y-(min)())/range; - // assert(0 <= j && j < k); - y = v[j]; - v[j] = _rng(); - return y; - } - - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_rng.min)(); } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_rng.max)(); } - static bool validation(result_type x) { return val == x; } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const shuffle_output& s) - { - os << s._rng << " " << s.y << " "; - for(int i = 0; i < s.buffer_size; ++i) - os << s.v[i] << " "; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, shuffle_output& s) - { - is >> s._rng >> std::ws >> s.y >> std::ws; - for(int i = 0; i < s.buffer_size; ++i) - is >> s.v[i] >> std::ws; - return is; - } -#endif - - friend bool operator==(const shuffle_output& x, const shuffle_output& y) - { return x._rng == y._rng && x.y == y.y && std::equal(x.v, x.v+k, y.v); } - friend bool operator!=(const shuffle_output& x, const shuffle_output& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const shuffle_output& rhs) const - { return _rng == rhs._rng && y == rhs.y && std::equal(v, v+k, rhs.v); } - bool operator!=(const shuffle_output& rhs) const - { return !(*this == rhs); } -#endif -private: - void init() - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); -#endif - result_type range = (max)()-(min)(); - assert(range > 0); // otherwise there would be little choice - if(static_cast(k * range) < - static_cast(range)) // not a sufficient condition - // likely overflow with bucket number computation - assert(!"overflow will occur"); - - // we cannot use std::generate, because it uses pass-by-value for _rng - for(result_type * p = v; p != v+k; ++p) - *p = _rng(); - y = _rng(); - } - - base_type _rng; - result_type v[k]; - result_type y; + shuffle_output() {} + template + shuffle_output(T& arg) : base_t(arg) {} + template + shuffle_output(const T& arg) : base_t(arg) {} + template + shuffle_output(It& first, It last) : base_t(first, last) {} + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (this->base().min)(); } + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return (this->base().max)(); } }; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION -// A definition is required even for integral static constants -template -const bool shuffle_output::has_fixed_range; +/// \endcond -template -const int shuffle_output::buffer_size; -#endif - -} // namespace random - -// validation by experiment from Harry Erwin's generator.h (private e-mail) -/** - * According to Harry Erwin (private e-mail), the specialization - * @c kreutzer1986 was suggested in: - * - * @blockquote - * "System Simulation: Programming Styles and Languages (International - * Computer Science Series)", Wolfgang Kreutzer, Addison-Wesley, December 1986. - * @endblockquote - */ -typedef random::shuffle_output< - random::linear_congruential, - 97, 139726> kreutzer1986; - - -} // namespace boost +} +} #endif // BOOST_RANDOM_SHUFFLE_OUTPUT_HPP diff --git a/include/boost/random/student_t_distribution.hpp b/include/boost/random/student_t_distribution.hpp new file mode 100644 index 0000000..e28b0e3 --- /dev/null +++ b/include/boost/random/student_t_distribution.hpp @@ -0,0 +1,180 @@ +/* boost random/student_t_distribution.hpp header file + * + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_STUDENT_T_DISTRIBUTION_HPP +#define BOOST_RANDOM_STUDENT_T_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * The Student t distribution is a real valued distribution with one + * parameter n, the number of degrees of freedom. + * + * It has \f$\displaystyle p(x) = + * \frac{1}{\sqrt{n\pi}} + * \frac{\Gamma((n+1)/2)}{\Gamma(n/2)} + * \left(1+\frac{x^2}{n}\right)^{-(n+1)/2} + * \f$. + */ +template +class student_t_distribution { +public: + typedef RealType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef student_t_distribution distribution_type; + + /** + * Constructs a @c param_type with "n" degrees of freedom. + * + * Requires: n > 0 + */ + explicit param_type(RealType n_arg = RealType(1.0)) + : _n(n_arg) + {} + + /** Returns the number of degrees of freedom of the distribution. */ + RealType n() const { return _n; } + + /** Writes a @c param_type to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { os << parm._n; return os; } + + /** Reads a @c param_type from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { is >> parm._n; return is; } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._n == rhs._n; } + + /** Returns true if the two sets of parameters are the different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _n; + }; + + /** + * Constructs an @c student_t_distribution with "n" degrees of freedom. + * + * Requires: n > 0 + */ + explicit student_t_distribution(RealType n_arg = RealType(1.0)) + : _normal(), _chi_squared(n_arg) + {} + /** Constructs an @c student_t_distribution from its parameters. */ + explicit student_t_distribution(const param_type& parm) + : _normal(), _chi_squared(parm.n()) + {} + + /** + * Returns a random variate distributed according to the + * Student t distribution. + */ + template + RealType operator()(URNG& urng) + { + using std::sqrt; + return _normal(urng) / sqrt(_chi_squared(urng) / n()); + } + + /** + * Returns a random variate distributed accordint to the Student + * t distribution with parameters specified by @c param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return student_t_distribution(parm)(urng); + } + + /** Returns the number of degrees of freedom. */ + RealType n() const { return _chi_squared.n(); } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return -std::numeric_limits::infinity(); } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return std::numeric_limits::infinity(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(n()); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + typedef chi_squared_distribution chi_squared_type; + typename chi_squared_type::param_type chi_squared_param(parm.n()); + _chi_squared.param(chi_squared_param); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() + { + _normal.reset(); + _chi_squared.reset(); + } + + /** Writes a @c student_t_distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, student_t_distribution, td) + { + os << td.param(); + return os; + } + + /** Reads a @c student_t_distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, student_t_distribution, td) + { + param_type parm; + if(is >> parm) { + td.param(parm); + } + return is; + } + + /** + * Returns true if the two instances of @c student_t_distribution will + * return identical sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(student_t_distribution, lhs, rhs) + { return lhs._normal == rhs._normal && lhs._chi_squared == rhs._chi_squared; } + + /** + * Returns true if the two instances of @c student_t_distribution will + * return different sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(student_t_distribution) + +private: + normal_distribution _normal; + chi_squared_distribution _chi_squared; +}; + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_STUDENT_T_DISTRIBUTION_HPP diff --git a/include/boost/random/subtract_with_carry.hpp b/include/boost/random/subtract_with_carry.hpp index ec1dccc..eed4b0a 100644 --- a/include/boost/random/subtract_with_carry.hpp +++ b/include/boost/random/subtract_with_carry.hpp @@ -16,56 +16,88 @@ #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP -#include +#include // std::pow #include #include // std::equal #include -#include // std::pow #include #include #include #include +#include +#include #include #include #include +#include +#include +#include #include namespace boost { namespace random { -#if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300 -# define BOOST_RANDOM_EXTRACT_SWC_01 -#endif - -#if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3) -# define BOOST_RANDOM_EXTRACT_SWC_01 -#endif - -# ifdef BOOST_RANDOM_EXTRACT_SWC_01 -namespace detail +namespace detail { + +struct subtract_with_carry_discard { - template - void extract_subtract_with_carry_01( - IStream& is - , SubtractWithCarry& f - , RealType& carry - , RealType* x - , RealType modulus) - { - RealType value; - for(unsigned int j = 0; j < f.long_lag; ++j) { - is >> value >> std::ws; - x[j] = value / modulus; + template + static void apply(Engine& eng, boost::uintmax_t z) + { + typedef typename Engine::result_type IntType; + const std::size_t short_lag = Engine::short_lag; + const std::size_t long_lag = Engine::long_lag; + std::size_t k = eng.k; + IntType carry = eng.carry; + if(k != 0) { + // increment k until it becomes 0. + if(k < short_lag) { + std::size_t limit = (short_lag - k) < z? + short_lag : (k + static_cast(z)); + for(std::size_t j = k; j < limit; ++j) { + carry = eng.do_update(j, j + long_lag - short_lag, carry); + } + } + std::size_t limit = (long_lag - k) < z? + long_lag : (k + static_cast(z)); + std::size_t start = (k < short_lag ? short_lag : k); + for(std::size_t j = start; j < limit; ++j) { + carry = eng.do_update(j, j - short_lag, carry); + } + } + + k = ((z % long_lag) + k) % long_lag; + + if(k < z) { + // main loop: update full blocks from k = 0 to long_lag + for(std::size_t i = 0; i < (z - k) / long_lag; ++i) { + for(std::size_t j = 0; j < short_lag; ++j) { + carry = eng.do_update(j, j + long_lag - short_lag, carry); + } + for(std::size_t j = short_lag; j < long_lag; ++j) { + carry = eng.do_update(j, j - short_lag, carry); + } + } + + // Update the last partial block + std::size_t limit = short_lag < k? short_lag : k; + for(std::size_t j = 0; j < limit; ++j) { + carry = eng.do_update(j, j + long_lag - short_lag, carry); + } + for(std::size_t j = short_lag; j < k; ++j) { + carry = eng.do_update(j, j - short_lag, carry); + } + } + eng.carry = carry; + eng.k = k; } - is >> value >> std::ws; - carry = value / modulus; - } +}; + } -# endif /** - * Instantiations of @c subtract_with_carry model a + * Instantiations of @c subtract_with_carry_engine model a * \pseudo_random_number_generator. The algorithm is * described in * @@ -75,388 +107,497 @@ namespace detail * Volume 1, Number 3 (1991), 462-480. * @endblockquote */ -template -class subtract_with_carry +template +class subtract_with_carry_engine { public: - typedef IntType result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = true); - BOOST_STATIC_CONSTANT(result_type, min_value = 0); - BOOST_STATIC_CONSTANT(result_type, max_value = m-1); - BOOST_STATIC_CONSTANT(result_type, modulus = m); - BOOST_STATIC_CONSTANT(unsigned int, long_lag = r); - BOOST_STATIC_CONSTANT(unsigned int, short_lag = s); + typedef IntType result_type; + BOOST_STATIC_CONSTANT(std::size_t, word_size = w); + BOOST_STATIC_CONSTANT(std::size_t, long_lag = r); + BOOST_STATIC_CONSTANT(std::size_t, short_lag = s); + BOOST_STATIC_CONSTANT(uint32_t, default_seed = 19780503u); - subtract_with_carry() { - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(std::numeric_limits::is_signed); + // Required by the old Boost.Random concepts + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + // Backwards compatibility + BOOST_STATIC_CONSTANT(result_type, modulus = (result_type(1) << w)); + BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); -#endif - seed(); - } - BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry, uint32_t, value) - { seed(value); } - BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Generator, gen) - { seed(gen); } - template subtract_with_carry(It& first, It last) { seed(first,last); } - // compiler-generated copy ctor and assignment operator are fine + /** + * Constructs a new @c subtract_with_carry_engine and seeds + * it with the default seed. + */ + subtract_with_carry_engine() { seed(); } + /** + * Constructs a new @c subtract_with_carry_engine and seeds + * it with @c value. + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_engine, + IntType, value) + { seed(value); } + /** + * Constructs a new @c subtract_with_carry_engine and seeds + * it with values produced by @c seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_engine, + SeedSeq, seq) + { seed(seq); } + /** + * Constructs a new @c subtract_with_carry_engine and seeds + * it with values from a range. first is updated to point + * one past the last value consumed. If there are not + * enough elements in the range to fill the entire state of + * the generator, throws @c std::invalid_argument. + */ + template subtract_with_carry_engine(It& first, It last) + { seed(first,last); } - void seed() { seed(19780503u); } - BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, uint32_t, value) - { - random::linear_congruential intgen(value); - seed(intgen); - } + // compiler-generated copy ctor and assignment operator are fine - // For GCC, moving this function out-of-line prevents inlining, which may - // reduce overall object code size. However, MSVC does not grok - // out-of-line template member functions. - BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Generator, gen) - { - // I could have used std::generate_n, but it takes "gen" by value - for(unsigned int j = 0; j < long_lag; ++j) - x[j] = gen() % modulus; - carry = (x[long_lag-1] == 0); - k = 0; - } - - template - void seed(It& first, It last) - { - unsigned int j; - for(j = 0; j < long_lag && first != last; ++j, ++first) - x[j] = *first % modulus; - if(first == last && j < long_lag) - throw std::invalid_argument("subtract_with_carry::seed"); - carry = (x[long_lag-1] == 0); - k = 0; - } - - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value; } - - result_type operator()() - { - int short_index = k - short_lag; - if(short_index < 0) - short_index += long_lag; - IntType delta; - if (x[short_index] >= x[k] + carry) { - // x(n) >= 0 - delta = x[short_index] - (x[k] + carry); - carry = 0; - } else { - // x(n) < 0 - delta = modulus - x[k] - carry + x[short_index]; - carry = 1; + /** Seeds the generator with the default seed. */ + void seed() { seed(default_seed); } + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_engine, + IntType, value) + { + typedef linear_congruential_engine gen_t; + gen_t intgen(static_cast(value)); + detail::generator_seed_seq gen(intgen); + seed(gen); } - x[k] = delta; - ++k; - if(k >= long_lag) - k = 0; - return delta; - } -public: - static bool validation(result_type x) { return x == val; } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** Seeds the generator with values produced by @c seq.generate(). */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry, SeedSeq, seq) + { + detail::seed_array_int(seq, x); + carry = (x[long_lag-1] == 0); + k = 0; + } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, - const subtract_with_carry& f) - { - for(unsigned int j = 0; j < f.long_lag; ++j) - os << f.compute(j) << " "; - os << f.carry << " "; - return os; - } + /** + * Seeds the generator with values from a range. Updates @c first to + * point one past the last consumed value. If the range does not + * contain enough elements to fill the entire state of the generator, + * throws @c std::invalid_argument. + */ + template + void seed(It& first, It last) + { + detail::fill_array_int(first, last, x); + carry = (x[long_lag-1] == 0); + k = 0; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, subtract_with_carry& f) - { - for(unsigned int j = 0; j < f.long_lag; ++j) - is >> f.x[j] >> std::ws; - is >> f.carry >> std::ws; - f.k = 0; - return is; - } -#endif + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 0; } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return boost::low_bits_mask_t::sig_bits; } - friend bool operator==(const subtract_with_carry& x, const subtract_with_carry& y) - { - for(unsigned int j = 0; j < r; ++j) - if(x.compute(j) != y.compute(j)) - return false; - return true; - } + /** Returns the next value of the generator. */ + result_type operator()() + { + std::size_t short_index = + (k < short_lag)? + (k + long_lag - short_lag) : + (k - short_lag); + carry = do_update(k, short_index, carry); + IntType result = x[k]; + ++k; + if(k >= long_lag) + k = 0; + return result; + } - friend bool operator!=(const subtract_with_carry& x, const subtract_with_carry& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const subtract_with_carry& rhs) const - { - for(unsigned int j = 0; j < r; ++j) - if(compute(j) != rhs.compute(j)) - return false; - return true; - } + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + detail::subtract_with_carry_discard::apply(*this, z); + } - bool operator!=(const subtract_with_carry& rhs) const - { return !(*this == rhs); } -#endif + /** Fills a range with random values. */ + template + void generate(It first, It last) + { detail::generate_from_int(*this, first, last); } + + /** Writes a @c subtract_with_carry_engine to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_engine, f) + { + for(unsigned int j = 0; j < f.long_lag; ++j) + os << f.compute(j) << ' '; + os << f.carry; + return os; + } + + /** Reads a @c subtract_with_carry_engine from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_engine, f) + { + for(unsigned int j = 0; j < f.long_lag; ++j) + is >> f.x[j] >> std::ws; + is >> f.carry; + f.k = 0; + return is; + } + + /** + * Returns true if the two generators will produce identical + * sequences of values. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_engine, x, y) + { + for(unsigned int j = 0; j < r; ++j) + if(x.compute(j) != y.compute(j)) + return false; + return true; + } + + /** + * Returns true if the two generators will produce different + * sequences of values. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_engine) private: - /// \cond hide_private_members - // returns x(i-r+index), where index is in 0..r-1 - IntType compute(unsigned int index) const - { - return x[(k+index) % long_lag]; - } - /// \endcond + /// \cond show_private + // returns x(i-r+index), where index is in 0..r-1 + IntType compute(unsigned int index) const + { + return x[(k+index) % long_lag]; + } - // state representation; next output (state) is x(i) - // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents - // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1) - // speed: base: 20-25 nsec - // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec - // This state representation makes operator== and save/restore more - // difficult, because we've already computed "too much" and thus - // have to undo some steps to get at x(i-r) etc. + friend struct detail::subtract_with_carry_discard; - // state representation: next output (state) is x(i) - // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents - // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1) - // speed: base 28 nsec - // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec - IntType x[long_lag]; - unsigned int k; - int carry; + IntType do_update(std::size_t current, std::size_t short_index, IntType carry) + { + IntType delta; + IntType temp = x[current] + carry; + if (x[short_index] >= temp) { + // x(n) >= 0 + delta = x[short_index] - temp; + carry = 0; + } else { + // x(n) < 0 + delta = modulus - temp + x[short_index]; + carry = 1; + } + x[current] = delta; + return carry; + } + /// \endcond + + // state representation; next output (state) is x(i) + // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents + // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1) + // speed: base: 20-25 nsec + // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec + // This state representation makes operator== and save/restore more + // difficult, because we've already computed "too much" and thus + // have to undo some steps to get at x(i-r) etc. + + // state representation: next output (state) is x(i) + // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents + // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1) + // speed: base 28 nsec + // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec + IntType x[long_lag]; + std::size_t k; + IntType carry; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool subtract_with_carry::has_fixed_range; -template -const IntType subtract_with_carry::min_value; -template -const IntType subtract_with_carry::max_value; -template -const IntType subtract_with_carry::modulus; -template -const unsigned int subtract_with_carry::long_lag; -template -const unsigned int subtract_with_carry::short_lag; +template +const bool subtract_with_carry_engine::has_fixed_range; +template +const IntType subtract_with_carry_engine::modulus; +template +const std::size_t subtract_with_carry_engine::word_size; +template +const std::size_t subtract_with_carry_engine::long_lag; +template +const std::size_t subtract_with_carry_engine::short_lag; +template +const uint32_t subtract_with_carry_engine::default_seed; #endif // use a floating-point representation to produce values in [0..1) -/** @copydoc boost::random::subtract_with_carry */ -template -class subtract_with_carry_01 +/** + * Instantiations of \subtract_with_carry_01_engine model a + * \pseudo_random_number_generator. The algorithm is + * described in + * + * @blockquote + * "A New Class of Random Number Generators", George + * Marsaglia and Arif Zaman, Annals of Applied Probability, + * Volume 1, Number 3 (1991), 462-480. + * @endblockquote + */ +template +class subtract_with_carry_01_engine { public: - typedef RealType result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, word_size = w); - BOOST_STATIC_CONSTANT(unsigned int, long_lag = r); - BOOST_STATIC_CONSTANT(unsigned int, short_lag = s); + typedef RealType result_type; + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(std::size_t, word_size = w); + BOOST_STATIC_CONSTANT(std::size_t, long_lag = r); + BOOST_STATIC_CONSTANT(std::size_t, short_lag = s); + BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 19780503u); -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif + BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); - subtract_with_carry_01() { init_modulus(); seed(); } - explicit subtract_with_carry_01(uint32_t value) - { init_modulus(); seed(value); } - template subtract_with_carry_01(It& first, It last) - { init_modulus(); seed(first,last); } + /** Creates a new \subtract_with_carry_01_engine using the default seed. */ + subtract_with_carry_01_engine() { init_modulus(); seed(); } + /** Creates a new subtract_with_carry_01_engine and seeds it with value. */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01_engine, + boost::uint32_t, value) + { init_modulus(); seed(value); } + /** + * Creates a new \subtract_with_carry_01_engine and seeds with with values + * produced by seq.generate(). + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_01_engine, + SeedSeq, seq) + { init_modulus(); seed(seq); } + /** + * Creates a new \subtract_with_carry_01_engine and seeds it with values + * from a range. Advances first to point one past the last consumed + * value. If the range does not contain enough elements to fill the + * entire state, throws @c std::invalid_argument. + */ + template subtract_with_carry_01_engine(It& first, It last) + { init_modulus(); seed(first,last); } private: - /// \cond hide_private_members - void init_modulus() - { + /// \cond show_private + void init_modulus() + { #ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::pow; + // allow for Koenig lookup + using std::pow; #endif - _modulus = pow(RealType(2), word_size); - } - /// \endcond hide_private_members + _modulus = pow(RealType(2), RealType(word_size)); + } + /// \endcond public: - // compiler-generated copy ctor and assignment operator are fine + // compiler-generated copy ctor and assignment operator are fine - void seed(uint32_t value = 19780503u) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::fmod; -#endif - random::linear_congruential gen(value); - unsigned long array[(w+31)/32 * long_lag]; - for(unsigned int j = 0; j < sizeof(array)/sizeof(unsigned long); ++j) - array[j] = gen(); - unsigned long * start = array; - seed(start, array + sizeof(array)/sizeof(unsigned long)); - } + /** Seeds the generator with the default seed. */ + void seed() { seed(default_seed); } - template - void seed(It& first, It last) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::fmod; - using std::pow; -#endif - unsigned long mask = ~((~0u) << (w%32)); // now lowest (w%32) bits set - RealType two32 = pow(RealType(2), 32); - unsigned int j; - for(j = 0; j < long_lag && first != last; ++j) { - x[j] = RealType(0); - for(int i = 0; i < w/32 && first != last; ++i, ++first) - x[j] += *first / pow(two32,i+1); - if(first != last && mask != 0) { - x[j] += fmod((*first & mask) / _modulus, RealType(1)); - ++first; - } + /** Seeds the generator with @c value. */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01_engine, + boost::uint32_t, value) + { + typedef linear_congruential_engine gen_t; + gen_t intgen(value); + detail::generator_seed_seq gen(intgen); + seed(gen); } - if(first == last && j < long_lag) - throw std::invalid_argument("subtract_with_carry_01::seed"); - carry = (x[long_lag-1] ? 0 : 1 / _modulus); - k = 0; - } - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } - - result_type operator()() - { - int short_index = k - short_lag; - if(short_index < 0) - short_index += long_lag; - RealType delta = x[short_index] - x[k] - carry; - if(delta < 0) { - delta += RealType(1); - carry = RealType(1)/_modulus; - } else { - carry = 0; + /** Seeds the generator with values produced by @c seq.generate(). */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry_01_engine, + SeedSeq, seq) + { + detail::seed_array_real(seq, x); + carry = (x[long_lag-1] ? 0 : 1 / _modulus); + k = 0; } - x[k] = delta; - ++k; - if(k >= long_lag) - k = 0; - return delta; - } - static bool validation(result_type x) - { return x == val/pow(RealType(2), word_size); } - -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, - const subtract_with_carry_01& f) - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::pow; -#endif - std::ios_base::fmtflags oldflags = os.flags(os.dec | os.fixed | os.left); - for(unsigned int j = 0; j < f.long_lag; ++j) - os << (f.compute(j) * f._modulus) << " "; - os << (f.carry * f._modulus); - os.flags(oldflags); - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, subtract_with_carry_01& f) - { -# ifdef BOOST_RANDOM_EXTRACT_SWC_01 - detail::extract_subtract_with_carry_01(is, f, f.carry, f.x, f._modulus); -# else - // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template type - // parameter "RealType" available from the class template scope, so use - // the member typedef - typename subtract_with_carry_01::result_type value; - for(unsigned int j = 0; j < long_lag; ++j) { - is >> value >> std::ws; - f.x[j] = value / f._modulus; + /** + * Seeds the generator with values from a range. Updates first to + * point one past the last consumed element. If there are not + * enough elements in the range to fill the entire state, throws + * @c std::invalid_argument. + */ + template + void seed(It& first, It last) + { + detail::fill_array_real(first, last, x); + carry = (x[long_lag-1] ? 0 : 1 / _modulus); + k = 0; } - is >> value >> std::ws; - f.carry = value / f._modulus; -# endif - f.k = 0; - return is; - } -#endif - friend bool operator==(const subtract_with_carry_01& x, - const subtract_with_carry_01& y) - { - for(unsigned int j = 0; j < r; ++j) - if(x.compute(j) != y.compute(j)) - return false; - return true; - } + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return result_type(0); } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return result_type(1); } - friend bool operator!=(const subtract_with_carry_01& x, - const subtract_with_carry_01& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const subtract_with_carry_01& rhs) const - { - for(unsigned int j = 0; j < r; ++j) - if(compute(j) != rhs.compute(j)) - return false; - return true; - } + /** + * INTERNAL ONLY + * Returns the number of random bits. + * This is not part of the standard, and I'm not sure that + * it's the best solution, but something like this is needed + * to implement generate_canonical. For now, mark it as + * an implementation detail. + */ + static std::size_t precision() { return w; } - bool operator!=(const subtract_with_carry_01& rhs) const - { return !(*this == rhs); } -#endif + /** Returns the next value of the generator. */ + result_type operator()() + { + std::size_t short_index = + (k < short_lag) ? + (k + long_lag - short_lag) : + (k - short_lag); + carry = do_update(k, short_index, carry); + RealType result = x[k]; + ++k; + if(k >= long_lag) + k = 0; + return result; + } + + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { detail::subtract_with_carry_discard::apply(*this, z); } + + /** Fills a range with random values. */ + template + void generate(Iter first, Iter last) + { detail::generate_from_real(*this, first, last); } + + /** Writes a \subtract_with_carry_01_engine to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_01_engine, f) + { + std::ios_base::fmtflags oldflags = + os.flags(os.dec | os.fixed | os.left); + for(unsigned int j = 0; j < f.long_lag; ++j) + os << (f.compute(j) * f._modulus) << ' '; + os << (f.carry * f._modulus); + os.flags(oldflags); + return os; + } + + /** Reads a \subtract_with_carry_01_engine from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_01_engine, f) + { + RealType value; + for(unsigned int j = 0; j < long_lag; ++j) { + is >> value >> std::ws; + f.x[j] = value / f._modulus; + } + is >> value; + f.carry = value / f._modulus; + f.k = 0; + return is; + } + + /** Returns true if the two generators will produce identical sequences. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_01_engine, x, y) + { + for(unsigned int j = 0; j < r; ++j) + if(x.compute(j) != y.compute(j)) + return false; + return true; + } + + /** Returns true if the two generators will produce different sequences. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_01_engine) private: - /// \cond hide_private_members - RealType compute(unsigned int index) const; - /// \endcond - unsigned int k; - RealType carry; - RealType x[long_lag]; - RealType _modulus; + /// \cond show_private + RealType compute(unsigned int index) const + { + return x[(k+index) % long_lag]; + } + + friend struct detail::subtract_with_carry_discard; + + RealType do_update(std::size_t current, std::size_t short_index, RealType carry) + { + RealType delta = x[short_index] - x[current] - carry; + if(delta < 0) { + delta += RealType(1); + carry = RealType(1)/_modulus; + } else { + carry = 0; + } + x[current] = delta; + return carry; + } + /// \endcond + std::size_t k; + RealType carry; + RealType x[long_lag]; + RealType _modulus; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool subtract_with_carry_01::has_fixed_range; -template -const int subtract_with_carry_01::word_size; -template -const unsigned int subtract_with_carry_01::long_lag; -template -const unsigned int subtract_with_carry_01::short_lag; +template +const bool subtract_with_carry_01_engine::has_fixed_range; +template +const std::size_t subtract_with_carry_01_engine::word_size; +template +const std::size_t subtract_with_carry_01_engine::long_lag; +template +const std::size_t subtract_with_carry_01_engine::short_lag; +template +const uint32_t subtract_with_carry_01_engine::default_seed; #endif -/// \cond hide_private_members -template -RealType subtract_with_carry_01::compute(unsigned int index) const + +/// \cond show_deprecated + +template +class subtract_with_carry : + public subtract_with_carry_engine::value, s, r> { - return x[(k+index) % long_lag]; -} + typedef subtract_with_carry_engine::value, s, r> base_type; +public: + subtract_with_carry() {} + BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Gen, gen) + { seed(gen); } + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry, + IntType, val) + { seed(val); } + template + subtract_with_carry(It& first, It last) : base_type(first, last) {} + void seed() { base_type::seed(); } + BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Gen, gen) + { + detail::generator_seed_seq seq(gen); + base_type::seed(seq); + } + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, IntType, val) + { base_type::seed(val); } + template + void seed(It& first, It last) { base_type::seed(first, last); } +}; + +template +class subtract_with_carry_01 : + public subtract_with_carry_01_engine +{ + typedef subtract_with_carry_01_engine base_type; +public: + subtract_with_carry_01() {} + BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry_01, Gen, gen) + { seed(gen); } + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01, + uint32_t, val) + { seed(val); } + template + subtract_with_carry_01(It& first, It last) : base_type(first, last) {} + void seed() { base_type::seed(); } + BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry_01, Gen, gen) + { + detail::generator_seed_seq seq(gen); + base_type::seed(seq); + } + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01, uint32_t, val) + { base_type::seed(val); } + template + void seed(It& first, It last) { base_type::seed(first, last); } +}; + /// \endcond } // namespace random diff --git a/include/boost/random/taus88.hpp b/include/boost/random/taus88.hpp new file mode 100644 index 0000000..68214f3 --- /dev/null +++ b/include/boost/random/taus88.hpp @@ -0,0 +1,45 @@ +/* boost random/taus88.hpp header file + * + * Copyright Jens Maurer 2000-2001 + * 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) + * + * See http://www.boost.org/libs/random for documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_TAUS88_HPP +#define BOOST_RANDOM_TAUS88_HPP + +#include +#include + +namespace boost { +namespace random { + +/** + * The specialization taus88 was suggested in + * + * @blockquote + * "Maximally Equidistributed Combined Tausworthe Generators", + * Pierre L'Ecuyer, Mathematics of Computation, Volume 65, + * Number 213, January 1996, Pages 203-213 + * @endblockquote + */ +typedef xor_combine_engine< + xor_combine_engine< + linear_feedback_shift_engine, 0, + linear_feedback_shift_engine, 0>, 0, + linear_feedback_shift_engine, 0> taus88; + +} // namespace random + +using random::taus88; + +} // namespace boost + +#endif // BOOST_RANDOM_TAUS88_HPP diff --git a/include/boost/random/triangle_distribution.hpp b/include/boost/random/triangle_distribution.hpp index 23a4cb7..5ac6604 100644 --- a/include/boost/random/triangle_distribution.hpp +++ b/include/boost/random/triangle_distribution.hpp @@ -1,6 +1,7 @@ /* boost random/triangle_distribution.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -17,11 +18,16 @@ #define BOOST_RANDOM_TRIANGLE_DISTRIBUTION_HPP #include -#include +#include +#include +#include +#include #include +#include #include namespace boost { +namespace random { /** * Instantiations of @c triangle_distribution model a \random_distribution. @@ -33,86 +39,194 @@ template class triangle_distribution { public: - typedef RealType input_type; - typedef RealType result_type; + typedef RealType input_type; + typedef RealType result_type; - /** - * Constructs a @c triangle_distribution with the parameters - * @c a, @c b, and @c c. - * - * Preconditions: a <= b <= c. - */ - explicit triangle_distribution(result_type a_arg = result_type(0), - result_type b_arg = result_type(0.5), - result_type c_arg = result_type(1)) - : _a(a_arg), _b(b_arg), _c(c_arg) - { - assert(_a <= _b && _b <= _c); - init(); - } + class param_type + { + public: - // compiler-generated copy ctor and assignment operator are fine + typedef triangle_distribution distribution_type; - /** Returns the @c a parameter of the distribution */ - result_type a() const { return _a; } - /** Returns the @c b parameter of the distribution */ - result_type b() const { return _b; } - /** Returns the @c c parameter of the distribution */ - result_type c() const { return _c; } + /** Constructs the parameters of a @c triangle_distribution. */ + explicit param_type(RealType a_arg = RealType(0.0), + RealType b_arg = RealType(0.5), + RealType c_arg = RealType(1.0)) + : _a(a_arg), _b(b_arg), _c(c_arg) + { + BOOST_ASSERT(_a <= _b && _b <= _c); + } - void reset() { } + /** Returns the minimum value of the distribution. */ + RealType a() const { return _a; } + /** Returns the mode of the distribution. */ + RealType b() const { return _b; } + /** Returns the maximum value of the distribution. */ + RealType c() const { return _c; } - template - result_type operator()(Engine& eng) - { -#ifndef BOOST_NO_STDC_NAMESPACE - using std::sqrt; -#endif - result_type u = eng(); - if( u <= q1 ) - return _a + p1*sqrt(u); - else - return _c - d3*sqrt(d2*u-d1); - } + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._a << " " << parm._b << " " << parm._c; + return os; + } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const triangle_distribution& td) - { - os << td._a << " " << td._b << " " << td._c; - return os; - } + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + double a_in, b_in, c_in; + if(is >> a_in >> std::ws >> b_in >> std::ws >> c_in) { + if(a_in <= b_in && b_in <= c_in) { + parm._a = a_in; + parm._b = b_in; + parm._c = c_in; + } else { + is.setstate(std::ios_base::failbit); + } + } + return is; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, triangle_distribution& td) - { - is >> std::ws >> td._a >> std::ws >> td._b >> std::ws >> td._c; - td.init(); - return is; - } -#endif + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._a == rhs._a && lhs._b == rhs._b && lhs._c == rhs._c; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _a; + RealType _b; + RealType _c; + }; + + /** + * Constructs a @c triangle_distribution with the parameters + * @c a, @c b, and @c c. + * + * Preconditions: a <= b <= c. + */ + explicit triangle_distribution(RealType a_arg = RealType(0.0), + RealType b_arg = RealType(0.5), + RealType c_arg = RealType(1.0)) + : _a(a_arg), _b(b_arg), _c(c_arg) + { + BOOST_ASSERT(_a <= _b && _b <= _c); + init(); + } + + /** Constructs a @c triangle_distribution from its parameters. */ + explicit triangle_distribution(const param_type& parm) + : _a(parm.a()), _b(parm.b()), _c(parm.c()) + { + init(); + } + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns the @c a parameter of the distribution */ + result_type a() const { return _a; } + /** Returns the @c b parameter of the distribution */ + result_type b() const { return _b; } + /** Returns the @c c parameter of the distribution */ + result_type c() const { return _c; } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _a; } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _c; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_a, _b, _c); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _a = parm.a(); + _b = parm.b(); + _c = parm.c(); + init(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** + * Returns a random variate distributed according to the + * triangle distribution. + */ + template + result_type operator()(Engine& eng) + { + using std::sqrt; + result_type u = uniform_01<>()(eng); + if( u <= q1 ) + return _a + p1*sqrt(u); + else + return _c - d3*sqrt(d2*u-d1); + } + + /** + * Returns a random variate distributed according to the + * triangle distribution with parameters specified by param. + */ + template + result_type operator()(Engine& eng, const param_type& parm) + { return triangle_distribution(parm)(eng); } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, triangle_distribution, td) + { + os << td.param(); + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, triangle_distribution, td) + { + param_type parm; + if(is >> parm) { + td.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will produce identical + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(triangle_distribution, lhs, rhs) + { return lhs._a == rhs._a && lhs._b == rhs._b && lhs._c == rhs._c; } + + /** + * Returns true if the two distributions may produce different + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(triangle_distribution) private: - /// \cond hide_private_members - void init() - { -#ifndef BOOST_NO_STDC_NAMESPACE - using std::sqrt; -#endif - d1 = _b - _a; - d2 = _c - _a; - d3 = sqrt(_c - _b); - q1 = d1 / d2; - p1 = sqrt(d1 * d2); - } - /// \endcond + /// \cond show_private + void init() + { + using std::sqrt; + d1 = _b - _a; + d2 = _c - _a; + d3 = sqrt(_c - _b); + q1 = d1 / d2; + p1 = sqrt(d1 * d2); + } + /// \endcond - result_type _a, _b, _c; - result_type d1, d2, d3, q1, p1; + RealType _a, _b, _c; + RealType d1, d2, d3, q1, p1; }; +} // namespace random + +using random::triangle_distribution; + } // namespace boost #endif // BOOST_RANDOM_TRIANGLE_DISTRIBUTION_HPP diff --git a/include/boost/random/uniform_01.hpp b/include/boost/random/uniform_01.hpp index ec1accc..b7de7e9 100644 --- a/include/boost/random/uniform_01.hpp +++ b/include/boost/random/uniform_01.hpp @@ -21,11 +21,12 @@ #include #include #include -#include +#include #include namespace boost { +namespace random { #ifdef BOOST_RANDOM_DOXYGEN @@ -121,7 +122,6 @@ template class backward_compatible_uniform_01 { typedef boost::random::detail::ptr_helper traits; - typedef boost::random::detail::pass_through_engine internal_engine_type; public: typedef UniformRandomNumberGenerator base_type; typedef RealType result_type; @@ -135,7 +135,7 @@ public: explicit backward_compatible_uniform_01(typename traits::rvalue_type rng) : _rng(rng), _factor(result_type(1) / - (result_type((_rng.max)()-(_rng.min)()) + + (result_type((base().max)()-(base().min)()) + result_type(std::numeric_limits::is_integer ? 1 : 0))) { } @@ -143,13 +143,13 @@ public: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } - typename traits::value_type& base() { return _rng.base(); } - const typename traits::value_type& base() const { return _rng.base(); } + typename traits::value_type& base() { return traits::ref(_rng); } + const typename traits::value_type& base() const { return traits::ref(_rng); } void reset() { } result_type operator()() { for (;;) { - result_type result = result_type(_rng() - (_rng.min)()) * _factor; + result_type result = result_type(base()() - (base().min)()) * _factor; if (result < result_type(1)) return result; } @@ -174,8 +174,8 @@ public: #endif private: - typedef typename internal_engine_type::result_type base_result; - internal_engine_type _rng; + typedef typename traits::value_type::result_type base_result; + UniformRandomNumberGenerator _rng; result_type _factor; }; @@ -266,6 +266,10 @@ public: #endif +} // namespace random + +using random::uniform_01; + } // namespace boost #include diff --git a/include/boost/random/uniform_int.hpp b/include/boost/random/uniform_int.hpp index 2eff53b..4362652 100644 --- a/include/boost/random/uniform_int.hpp +++ b/include/boost/random/uniform_int.hpp @@ -17,15 +17,8 @@ #ifndef BOOST_RANDOM_UNIFORM_INT_HPP #define BOOST_RANDOM_UNIFORM_INT_HPP -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include namespace boost { @@ -35,264 +28,70 @@ namespace boost { * distributed in the set of integer numbers {min, min+1, min+2, ..., max}. * * The template parameter IntType shall denote an integer-like value type. + * + * This class is deprecated. Please use @c uniform_int_distribution in + * new code. */ template -class uniform_int +class uniform_int : public random::uniform_int_distribution { + typedef random::uniform_int_distribution base_type; public: - typedef IntType input_type; - typedef IntType result_type; - /// \cond hide_private_members - typedef typename make_unsigned::type range_type; - /// \endcond + class param_type : public base_type::param_type + { + public: + typedef uniform_int distribution_type; + /** + * Constructs the parameters of a uniform_int distribution. + * + * Requires: min <= max + */ + explicit param_type(IntType min_arg = 0, IntType max_arg = 9) + : base_type::param_type(min_arg, max_arg) + {} + }; - /** - * Constructs a uniform_int object. @c min and @c max are - * the parameters of the distribution. - * - * Requires: min <= max - */ - explicit uniform_int(IntType min_arg = 0, IntType max_arg = 9) - : _min(min_arg), _max(max_arg) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); -#endif - assert(min_arg <= max_arg); - init(); - } + /** + * Constructs a uniform_int object. @c min and @c max are + * the parameters of the distribution. + * + * Requires: min <= max + */ + explicit uniform_int(IntType min_arg = 0, IntType max_arg = 9) + : base_type(min_arg, max_arg) + {} - /** - * Returns: The "min" parameter of the distribution - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } - /** - * Returns: The "max" parameter of the distribution - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } - void reset() { } - - // can't have member function templates out-of-line due to MSVC bugs - template - result_type operator()(Engine& eng) - { - return generate(eng, _min, _max, _range); - } + /** Constructs a uniform_int distribution from its parameters. */ + explicit uniform_int(const param_type& parm) + : base_type(parm) + {} - template - result_type operator()(Engine& eng, result_type n) - { - assert(n > 0); + /** Returns the parameters of the distribution */ + param_type param() const { return param_type(this->a(), this->b()); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) { this->base_type::param(parm); } - if (n == 1) - { - return 0; - } + // Codergear seems to have trouble with a using declaration here - return generate(eng, 0, n - 1, n - 1); - } - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const uniform_int& ud) - { - os << ud._min << " " << ud._max; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, uniform_int& ud) - { - is >> std::ws >> ud._min >> std::ws >> ud._max; - ud.init(); - return is; - } -#endif - -private: - -#ifdef BOOST_MSVC -#pragma warning(push) -// disable division by zero warning, since we can't -// actually divide by zero. -#pragma warning(disable:4723) -#endif - - /// \cond hide_private_members - template - static result_type generate(Engine& eng, result_type min_value, result_type /*max_value*/, range_type range) - { - typedef typename Engine::result_type base_result; - // ranges are always unsigned - typedef typename make_unsigned::type base_unsigned; - const base_result bmin = (eng.min)(); - const base_unsigned brange = - random::detail::subtract()((eng.max)(), (eng.min)()); - - if(range == 0) { - return min_value; - } else if(brange == range) { - // this will probably never happen in real life - // basically nothing to do; just take care we don't overflow / underflow - base_unsigned v = random::detail::subtract()(eng(), bmin); - return random::detail::add()(v, min_value); - } else if(brange < range) { - // use rejection method to handle things like 0..3 --> 0..4 - for(;;) { - // concatenate several invocations of the base RNG - // take extra care to avoid overflows - - // limit == floor((range+1)/(brange+1)) - // Therefore limit*(brange+1) <= range+1 - range_type limit; - if(range == (std::numeric_limits::max)()) { - limit = range/(range_type(brange)+1); - if(range % (range_type(brange)+1) == range_type(brange)) - ++limit; - } else { - limit = (range+1)/(range_type(brange)+1); - } - - // We consider "result" as expressed to base (brange+1): - // For every power of (brange+1), we determine a random factor - range_type result = range_type(0); - range_type mult = range_type(1); - - // loop invariants: - // result < mult - // mult <= range - while(mult <= limit) { - // Postcondition: result <= range, thus no overflow - // - // limit*(brange+1)<=range+1 def. of limit (1) - // eng()-bmin<=brange eng() post. (2) - // and mult<=limit. loop condition (3) - // Therefore mult*(eng()-bmin+1)<=range+1 by (1),(2),(3) (4) - // Therefore mult*(eng()-bmin)+mult<=range+1 rearranging (4) (5) - // result(random::detail::subtract()(eng(), bmin) * mult); - - // equivalent to (mult * (brange+1)) == range+1, but avoids overflow. - if(mult * range_type(brange) == range - mult + 1) { - // The destination range is an integer power of - // the generator's range. - return(result); - } - - // Postcondition: mult <= range - // - // limit*(brange+1)<=range+1 def. of limit (1) - // mult<=limit loop condition (2) - // Therefore mult*(brange+1)<=range+1 by (1), (2) (3) - // mult*(brange+1)!=range+1 preceding if (4) - // Therefore mult*(brange+1) limit loop condition (1) - // Suppose range/mult >= brange+1 Assumption (2) - // range >= mult*(brange+1) by (2) (3) - // range+1 > mult*(brange+1) by (3) (4) - // range+1 > (limit+1)*(brange+1) by (1), (4) (5) - // (range+1)/(brange+1) > limit+1 by (5) (6) - // limit < floor((range+1)/(brange+1)) by (6) (7) - // limit==floor((range+1)/(brange+1)) def. of limit (8) - // not (2) reductio (9) - // - // loop postcondition: (range/mult)*mult+(mult-1) >= range - // - // (range/mult)*mult + range%mult == range identity (1) - // range%mult < mult def. of % (2) - // (range/mult)*mult+mult > range by (1), (2) (3) - // (range/mult)*mult+(mult-1) >= range by (3) (4) - // - // Note that the maximum value of result at this point is (mult-1), - // so after this final step, we generate numbers that can be - // at least as large as range. We have to really careful to avoid - // overflow in this final addition and in the rejection. Anything - // that overflows is larger than range and can thus be rejected. - - // range/mult < brange+1 -> no endless loop - range_type result_increment = uniform_int(0, range/mult)(eng); - if((std::numeric_limits::max)() / mult < result_increment) { - // The multiplcation would overflow. Reject immediately. - continue; - } - result_increment *= mult; - // unsigned integers are guaranteed to wrap on overflow. - result += result_increment; - if(result < result_increment) { - // The addition overflowed. Reject. - continue; - } - if(result > range) { - // Too big. Reject. - continue; - } - return random::detail::add()(result, min_value); - } - } else { // brange > range - base_unsigned bucket_size; - // it's safe to add 1 to range, as long as we cast it first, - // because we know that it is less than brange. However, - // we do need to be careful not to cause overflow by adding 1 - // to brange. - if(brange == (std::numeric_limits::max)()) { - bucket_size = brange / (static_cast(range)+1); - if(brange % (static_cast(range)+1) == static_cast(range)) { - ++bucket_size; - } - } else { - bucket_size = (brange+1) / (static_cast(range)+1); - } - for(;;) { - base_unsigned result = - random::detail::subtract()(eng(), bmin); - result /= bucket_size; - // result and range are non-negative, and result is possibly larger - // than range, so the cast is safe - if(result <= static_cast(range)) - return random::detail::add()(result, min_value); - } + template + IntType operator()(Engine& eng) const + { + return static_cast(*this)(eng); } - } -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif + template + IntType operator()(Engine& eng, const param_type& parm) const + { + return static_cast(*this)(eng, parm); + } - void init() - { - _range = random::detail::subtract()(_max, _min); - } - - /// \endcond - - // The result_type may be signed or unsigned, but the _range is always - // unsigned. - result_type _min, _max; - range_type _range; + template + IntType operator()(Engine& eng, IntType n) const + { + BOOST_ASSERT(n > 0); + return static_cast(*this)(eng, param_type(0, n - 1)); + } }; } // namespace boost diff --git a/include/boost/random/uniform_int_distribution.hpp b/include/boost/random/uniform_int_distribution.hpp new file mode 100644 index 0000000..a175025 --- /dev/null +++ b/include/boost/random/uniform_int_distribution.hpp @@ -0,0 +1,400 @@ +/* boost random/uniform_int_distribution.hpp header file + * + * Copyright Jens Maurer 2000-2001 + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + * Revision history + * 2001-04-08 added min +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { +namespace detail { + + +#ifdef BOOST_MSVC +#pragma warning(push) +// disable division by zero warning, since we can't +// actually divide by zero. +#pragma warning(disable:4723) +#endif + +template +T generate_uniform_int( + Engine& eng, T min_value, T max_value, + boost::mpl::true_ /** is_integral */) +{ + typedef T result_type; + typedef typename make_unsigned::type range_type; + typedef typename Engine::result_type base_result; + // ranges are always unsigned + typedef typename make_unsigned::type base_unsigned; + const range_type range = random::detail::subtract()(max_value, min_value); + const base_result bmin = (eng.min)(); + const base_unsigned brange = + random::detail::subtract()((eng.max)(), (eng.min)()); + + if(range == 0) { + return min_value; + } else if(brange == range) { + // this will probably never happen in real life + // basically nothing to do; just take care we don't overflow / underflow + base_unsigned v = random::detail::subtract()(eng(), bmin); + return random::detail::add()(v, min_value); + } else if(brange < range) { + // use rejection method to handle things like 0..3 --> 0..4 + for(;;) { + // concatenate several invocations of the base RNG + // take extra care to avoid overflows + + // limit == floor((range+1)/(brange+1)) + // Therefore limit*(brange+1) <= range+1 + range_type limit; + if(range == (std::numeric_limits::max)()) { + limit = range/(range_type(brange)+1); + if(range % (range_type(brange)+1) == range_type(brange)) + ++limit; + } else { + limit = (range+1)/(range_type(brange)+1); + } + + // We consider "result" as expressed to base (brange+1): + // For every power of (brange+1), we determine a random factor + range_type result = range_type(0); + range_type mult = range_type(1); + + // loop invariants: + // result < mult + // mult <= range + while(mult <= limit) { + // Postcondition: result <= range, thus no overflow + // + // limit*(brange+1)<=range+1 def. of limit (1) + // eng()-bmin<=brange eng() post. (2) + // and mult<=limit. loop condition (3) + // Therefore mult*(eng()-bmin+1)<=range+1 by (1),(2),(3) (4) + // Therefore mult*(eng()-bmin)+mult<=range+1 rearranging (4) (5) + // result(random::detail::subtract()(eng(), bmin) * mult); + + // equivalent to (mult * (brange+1)) == range+1, but avoids overflow. + if(mult * range_type(brange) == range - mult + 1) { + // The destination range is an integer power of + // the generator's range. + return(result); + } + + // Postcondition: mult <= range + // + // limit*(brange+1)<=range+1 def. of limit (1) + // mult<=limit loop condition (2) + // Therefore mult*(brange+1)<=range+1 by (1), (2) (3) + // mult*(brange+1)!=range+1 preceding if (4) + // Therefore mult*(brange+1) limit loop condition (1) + // Suppose range/mult >= brange+1 Assumption (2) + // range >= mult*(brange+1) by (2) (3) + // range+1 > mult*(brange+1) by (3) (4) + // range+1 > (limit+1)*(brange+1) by (1), (4) (5) + // (range+1)/(brange+1) > limit+1 by (5) (6) + // limit < floor((range+1)/(brange+1)) by (6) (7) + // limit==floor((range+1)/(brange+1)) def. of limit (8) + // not (2) reductio (9) + // + // loop postcondition: (range/mult)*mult+(mult-1) >= range + // + // (range/mult)*mult + range%mult == range identity (1) + // range%mult < mult def. of % (2) + // (range/mult)*mult+mult > range by (1), (2) (3) + // (range/mult)*mult+(mult-1) >= range by (3) (4) + // + // Note that the maximum value of result at this point is (mult-1), + // so after this final step, we generate numbers that can be + // at least as large as range. We have to really careful to avoid + // overflow in this final addition and in the rejection. Anything + // that overflows is larger than range and can thus be rejected. + + // range/mult < brange+1 -> no endless loop + range_type result_increment = + generate_uniform_int( + eng, + static_cast(0), + static_cast(range/mult), + boost::mpl::true_()); + if((std::numeric_limits::max)() / mult < result_increment) { + // The multiplcation would overflow. Reject immediately. + continue; + } + result_increment *= mult; + // unsigned integers are guaranteed to wrap on overflow. + result += result_increment; + if(result < result_increment) { + // The addition overflowed. Reject. + continue; + } + if(result > range) { + // Too big. Reject. + continue; + } + return random::detail::add()(result, min_value); + } + } else { // brange > range + base_unsigned bucket_size; + // it's safe to add 1 to range, as long as we cast it first, + // because we know that it is less than brange. However, + // we do need to be careful not to cause overflow by adding 1 + // to brange. + if(brange == (std::numeric_limits::max)()) { + bucket_size = brange / (static_cast(range)+1); + if(brange % (static_cast(range)+1) == static_cast(range)) { + ++bucket_size; + } + } else { + bucket_size = (brange+1) / (static_cast(range)+1); + } + for(;;) { + base_unsigned result = + random::detail::subtract()(eng(), bmin); + result /= bucket_size; + // result and range are non-negative, and result is possibly larger + // than range, so the cast is safe + if(result <= static_cast(range)) + return random::detail::add()(result, min_value); + } + } +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +inline T generate_uniform_int( + Engine& eng, T min_value, T max_value, + boost::mpl::false_ /** is_integral */) +{ + uniform_int_float wrapper(eng); + return generate_uniform_int(wrapper, min_value, max_value, boost::mpl::true_()); +} + +template +inline T generate_uniform_int(Engine& eng, T min_value, T max_value) +{ + typedef typename Engine::result_type base_result; + return generate_uniform_int(eng, min_value, max_value, + boost::is_integral()); +} + +} + +/** + * The class template uniform_int_distribution models a \random_distribution. + * On each invocation, it returns a random integer value uniformly + * distributed in the set of integers {min, min+1, min+2, ..., max}. + * + * The template parameter IntType shall denote an integer-like value type. + */ +template +class uniform_int_distribution +{ +public: + typedef IntType input_type; + typedef IntType result_type; + + class param_type + { + public: + + typedef uniform_int_distribution distribution_type; + + /** + * Constructs the parameters of a uniform_int_distribution. + * + * Requires min <= max + */ + explicit param_type( + IntType min_arg = 0, + IntType max_arg = (std::numeric_limits::max)()) + : _min(min_arg), _max(max_arg) + { + BOOST_ASSERT(_min <= _max); + } + + /** Returns the minimum value of the distribution. */ + IntType a() const { return _min; } + /** Returns the maximum value of the distribution. */ + IntType b() const { return _max; } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._min << " " << parm._max; + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + IntType min_in, max_in; + if(is >> min_in >> std::ws >> max_in) { + if(min_in <= max_in) { + parm._min = min_in; + parm._max = max_in; + } else { + is.setstate(std::ios_base::failbit); + } + } + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._min == rhs._min && lhs._max == rhs._max; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + + IntType _min; + IntType _max; + }; + + /** + * Constructs a uniform_int_distribution. @c min and @c max are + * the parameters of the distribution. + * + * Requires: min <= max + */ + explicit uniform_int_distribution( + IntType min_arg = 0, + IntType max_arg = (std::numeric_limits::max)()) + : _min(min_arg), _max(max_arg) + { + BOOST_ASSERT(min_arg <= max_arg); + } + /** Constructs a uniform_int_distribution from its parameters. */ + explicit uniform_int_distribution(const param_type& parm) + : _min(parm.a()), _max(parm.b()) {} + + /** Returns the minimum value of the distribution */ + IntType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } + /** Returns the maximum value of the distribution */ + IntType max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } + + /** Returns the minimum value of the distribution */ + IntType a() const { return _min; } + /** Returns the maximum value of the distribution */ + IntType b() const { return _max; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_min, _max); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _min = parm.a(); + _max = parm.b(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** Returns an integer uniformly distributed in the range [min, max]. */ + template + result_type operator()(Engine& eng) const + { return detail::generate_uniform_int(eng, _min, _max); } + + /** + * Returns an integer uniformly distributed in the range + * [param.a(), param.b()]. + */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { return detail::generate_uniform_int(eng, parm.a(), parm.b()); } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_int_distribution, ud) + { + os << ud.param(); + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_int_distribution, ud) + { + param_type parm; + if(is >> parm) { + ud.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will produce identical sequences + * of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_int_distribution, lhs, rhs) + { return lhs._min == rhs._min && lhs._max == rhs._max; } + + /** + * Returns true if the two distributions may produce different sequences + * of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_int_distribution) + +private: + IntType _min; + IntType _max; +}; + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_UNIFORM_INT_HPP diff --git a/include/boost/random/uniform_on_sphere.hpp b/include/boost/random/uniform_on_sphere.hpp index 899f336..e73d8ff 100644 --- a/include/boost/random/uniform_on_sphere.hpp +++ b/include/boost/random/uniform_on_sphere.hpp @@ -1,6 +1,7 @@ /* boost random/uniform_on_sphere.hpp header file * * Copyright Jens Maurer 2000-2001 + * 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) @@ -19,10 +20,13 @@ #include #include // std::transform #include // std::bind2nd, std::divides +#include #include +#include #include namespace boost { +namespace random { /** * Instantiations of class template uniform_on_sphere model a @@ -30,72 +34,196 @@ namespace boost { * numbers uniformly distributed on the unit sphere of arbitrary * dimension @c dim. The @c Cont template parameter must be a STL-like * container type with begin and end operations returning non-const - * ForwardIterators of type @c Cont::iterator. Each invocation of the - * @c UniformRandomNumberGenerator shall result in a floating-point - * value in the range [0,1). + * ForwardIterators of type @c Cont::iterator. */ template > class uniform_on_sphere { public: - typedef RealType input_type; - typedef Cont result_type; + typedef RealType input_type; + typedef Cont result_type; - /** - * Constructs a @c uniform_on_sphere distribution. - * @c dim is the dimension of the sphere. - */ - explicit uniform_on_sphere(int dim = 2) : _container(dim), _dim(dim) { } + class param_type + { + public: - // compiler-generated copy ctor and assignment operator are fine + typedef uniform_on_sphere distribution_type; - void reset() { _normal.reset(); } + /** + * Constructs the parameters of a uniform_on_sphere + * distribution, given the dimension of the sphere. + */ + explicit param_type(int dim_arg = 2) : _dim(dim_arg) + { + BOOST_ASSERT(_dim >= 0); + } - template - const result_type & operator()(Engine& eng) - { - RealType sqsum = 0; - for(typename Cont::iterator it = _container.begin(); - it != _container.end(); - ++it) { - RealType val = _normal(eng); - *it = val; - sqsum += val * val; + /** Returns the dimension of the sphere. */ + int dim() const { return _dim; } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._dim; + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._dim; + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._dim == rhs._dim; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + int _dim; + }; + + /** + * Constructs a @c uniform_on_sphere distribution. + * @c dim is the dimension of the sphere. + * + * Requires: dim >= 0 + */ + explicit uniform_on_sphere(int dim_arg = 2) + : _container(dim_arg), _dim(dim_arg) { } + + /** + * Constructs a @c uniform_on_sphere distribution from its parameters. + */ + explicit uniform_on_sphere(const param_type& parm) + : _container(parm.dim()), _dim(parm.dim()) { } + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns the dimension of the sphere. */ + int dim() const { return _dim; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_dim); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _dim = parm.dim(); + _container.resize(_dim); } -#ifndef BOOST_NO_STDC_NAMESPACE - using std::sqrt; -#endif - // for all i: result[i] /= sqrt(sqsum) - std::transform(_container.begin(), _container.end(), _container.begin(), - std::bind2nd(std::divides(), sqrt(sqsum))); - return _container; - } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const uniform_on_sphere& sd) - { - os << sd._dim; - return os; - } + /** + * Returns the smallest value that the distribution can produce. + * Note that this is required to approximate the standard library's + * requirements. The behavior is defined according to lexicographical + * comparison so that for a container type of std::vector, + * dist.min() <= x <= dist.max() where x is any value produced + * by the distribution. + */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { + result_type result(_dim); + if(_dim != 0) { + result.front() = RealType(-1.0); + } + return result; + } + /** + * Returns the largest value that the distribution can produce. + * Note that this is required to approximate the standard library's + * requirements. The behavior is defined according to lexicographical + * comparison so that for a container type of std::vector, + * dist.min() <= x <= dist.max() where x is any value produced + * by the distribution. + */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { + result_type result(_dim); + if(_dim != 0) { + result.front() = RealType(1.0); + } + return result; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, uniform_on_sphere& sd) - { - is >> std::ws >> sd._dim; - sd._container.resize(sd._dim); - return is; - } -#endif + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _normal.reset(); } + + /** + * Returns a point uniformly distributed over the surface of + * a sphere of dimension dim(). + */ + template + const result_type & operator()(Engine& eng) + { + RealType sqsum = 0; + for(typename Cont::iterator it = _container.begin(); + it != _container.end(); + ++it) { + RealType val = _normal(eng); + *it = val; + sqsum += val * val; + } + using std::sqrt; + // for all i: result[i] /= sqrt(sqsum) + std::transform(_container.begin(), _container.end(), _container.begin(), + std::bind2nd(std::divides(), sqrt(sqsum))); + return _container; + } + + /** + * Returns a point uniformly distributed over the surface of + * a sphere of dimension param.dim(). + */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { + return uniform_on_sphere(parm)(eng); + } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_on_sphere, sd) + { + os << sd._dim; + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_on_sphere, sd) + { + is >> sd._dim; + sd._container.resize(sd._dim); + return is; + } + + /** + * Returns true if the two distributions will produce identical + * sequences of values, given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_on_sphere, lhs, rhs) + { return lhs._dim == rhs._dim && lhs._normal == rhs._normal; } + + /** + * Returns true if the two distributions may produce different + * sequences of values, given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_on_sphere) private: - normal_distribution _normal; - result_type _container; - int _dim; + normal_distribution _normal; + result_type _container; + int _dim; }; +} // namespace random + +using random::uniform_on_sphere; + } // namespace boost #endif // BOOST_RANDOM_UNIFORM_ON_SPHERE_HPP diff --git a/include/boost/random/uniform_real.hpp b/include/boost/random/uniform_real.hpp index 6857ad5..4c1dd35 100644 --- a/include/boost/random/uniform_real.hpp +++ b/include/boost/random/uniform_real.hpp @@ -17,90 +17,64 @@ #ifndef BOOST_RANDOM_UNIFORM_REAL_HPP #define BOOST_RANDOM_UNIFORM_REAL_HPP -#include -#include +#include #include #include -#include -#include +#include namespace boost { /** * The distribution function uniform_real models a random distribution. * On each invocation, it returns a random floating-point value uniformly - * distributed in the range [min..max). The value is computed using - * std::numeric_limits::digits random binary digits, i.e. - * the mantissa of the floating-point value is completely filled with - * random bits. + * distributed in the range [min..max). * - * Note: The current implementation is buggy, because it may not fill - * all of the mantissa with random bits. + * This class is deprecated. Please use @c uniform_real_distribution in + * new code. */ template -class uniform_real +class uniform_real : public random::uniform_real_distribution { + typedef random::uniform_real_distribution base_type; public: - typedef RealType input_type; - typedef RealType result_type; - /** - * Constructs a uniform_real object. @c min and @c max are the - * parameters of the distribution. - * - * Requires: min <= max - */ - explicit uniform_real(RealType min_arg = RealType(0), - RealType max_arg = RealType(1)) - : _min(min_arg), _max(max_arg) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); -#endif - assert(min_arg <= max_arg); - } + class param_type : public base_type::param_type + { + public: + typedef uniform_real distribution_type; + /** + * Constructs the parameters of a uniform_real distribution. + * + * Requires: min <= max + */ + explicit param_type(RealType min_arg = RealType(0.0), + RealType max_arg = RealType(1.0)) + : base_type::param_type(min_arg, max_arg) + {} + }; - // compiler-generated copy ctor and assignment operator are fine + /** + * Constructs a uniform_real object. @c min and @c max are the + * parameters of the distribution. + * + * Requires: min <= max + */ + explicit uniform_real(RealType min_arg = RealType(0.0), + RealType max_arg = RealType(1.0)) + : base_type(min_arg, max_arg) + { + BOOST_ASSERT(min_arg <= max_arg); + } - /** - * Returns: The "min" parameter of the distribution - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } - /** - * Returns: The "max" parameter of the distribution - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } - void reset() { } + /** Constructs a uniform_real distribution from its parameters. */ + explicit uniform_real(const param_type& parm) + : base_type(parm) + {} - template - result_type operator()(Engine& eng) { - result_type numerator = static_cast(eng() - eng.min BOOST_PREVENT_MACRO_SUBSTITUTION()); - result_type divisor = static_cast(eng.max BOOST_PREVENT_MACRO_SUBSTITUTION() - eng.min BOOST_PREVENT_MACRO_SUBSTITUTION()); - assert(divisor > 0); - assert(numerator >= 0 && numerator <= divisor); - return numerator / divisor * (_max - _min) + _min; - } - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const uniform_real& ud) - { - os << ud._min << " " << ud._max; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, uniform_real& ud) - { - is >> std::ws >> ud._min >> std::ws >> ud._max; - return is; - } -#endif - -private: - RealType _min, _max; + /** Returns the parameters of the distribution */ + param_type param() const { return param_type(this->a(), this->b()); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) { this->base_type::param(parm); } }; } // namespace boost diff --git a/include/boost/random/uniform_real_distribution.hpp b/include/boost/random/uniform_real_distribution.hpp new file mode 100644 index 0000000..464696c --- /dev/null +++ b/include/boost/random/uniform_real_distribution.hpp @@ -0,0 +1,239 @@ +/* boost random/uniform_real_distribution.hpp header file + * + * Copyright Jens Maurer 2000-2001 + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + * + */ + +#ifndef BOOST_RANDOM_UNIFORM_REAL_DISTRIBUTION_HPP +#define BOOST_RANDOM_UNIFORM_REAL_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { +namespace detail { + +template +T generate_uniform_real( + Engine& eng, T min_value, T max_value, + boost::mpl::false_ /** is_integral */) +{ + for(;;) { + typedef T result_type; + typedef typename Engine::result_type base_result; + result_type numerator = static_cast(eng() - (eng.min)()); + result_type divisor = static_cast((eng.max)() - (eng.min)()); + BOOST_ASSERT(divisor > 0); + BOOST_ASSERT(numerator >= 0 && numerator <= divisor); + T result = numerator / divisor * (max_value - min_value) + min_value; + if(result < max_value) return result; + } +} + +template +T generate_uniform_real( + Engine& eng, T min_value, T max_value, + boost::mpl::true_ /** is_integral */) +{ + for(;;) { + typedef T result_type; + typedef typename Engine::result_type base_result; + result_type numerator = static_cast(subtract()(eng(), (eng.min)())); + result_type divisor = static_cast(subtract()((eng.max)(), (eng.min)())) + 1; + BOOST_ASSERT(divisor > 0); + BOOST_ASSERT(numerator >= 0 && numerator <= divisor); + T result = numerator / divisor * (max_value - min_value) + min_value; + if(result < max_value) return result; + } +} + +template +inline T generate_uniform_real(Engine& eng, T min_value, T max_value) +{ + typedef typename Engine::result_type base_result; + return generate_uniform_real(eng, min_value, max_value, + boost::is_integral()); +} + +} + +/** + * The class template uniform_real_distribution models a \random_distribution. + * On each invocation, it returns a random floating-point value uniformly + * distributed in the range [min..max). + */ +template +class uniform_real_distribution +{ +public: + typedef RealType input_type; + typedef RealType result_type; + + class param_type + { + public: + + typedef uniform_real_distribution distribution_type; + + /** + * Constructs the parameters of a uniform_real_distribution. + * + * Requires min <= max + */ + explicit param_type(RealType min_arg = RealType(0.0), + RealType max_arg = RealType(1.0)) + : _min(min_arg), _max(max_arg) + { + BOOST_ASSERT(_min <= _max); + } + + /** Returns the minimum value of the distribution. */ + RealType a() const { return _min; } + /** Returns the maximum value of the distribution. */ + RealType b() const { return _max; } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._min << " " << parm._max; + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + RealType min_in, max_in; + if(is >> min_in >> std::ws >> max_in) { + if(min_in <= max_in) { + parm._min = min_in; + parm._max = max_in; + } else { + is.setstate(std::ios_base::failbit); + } + } + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._min == rhs._min && lhs._max == rhs._max; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + + RealType _min; + RealType _max; + }; + + /** + * Constructs a uniform_real_distribution. @c min and @c max are + * the parameters of the distribution. + * + * Requires: min <= max + */ + explicit uniform_real_distribution( + RealType min_arg = RealType(0.0), + RealType max_arg = RealType(1.0)) + : _min(min_arg), _max(max_arg) + { + BOOST_ASSERT(min_arg <= max_arg); + } + /** Constructs a uniform_real_distribution from its parameters. */ + explicit uniform_real_distribution(const param_type& parm) + : _min(parm.a()), _max(parm.b()) {} + + /** Returns the minimum value of the distribution */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } + /** Returns the maximum value of the distribution */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } + + /** Returns the minimum value of the distribution */ + RealType a() const { return _min; } + /** Returns the maximum value of the distribution */ + RealType b() const { return _max; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_min, _max); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _min = parm.a(); + _max = parm.b(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** Returns a value uniformly distributed in the range [min, max). */ + template + result_type operator()(Engine& eng) const + { return detail::generate_uniform_real(eng, _min, _max); } + + /** + * Returns a value uniformly distributed in the range + * [param.a(), param.b()). + */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { return detail::generate_uniform_real(eng, parm.a(), parm.b()); } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_real_distribution, ud) + { + os << ud.param(); + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_real_distribution, ud) + { + param_type parm; + if(is >> parm) { + ud.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will produce identical sequences + * of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_real_distribution, lhs, rhs) + { return lhs._min == rhs._min && lhs._max == rhs._max; } + + /** + * Returns true if the two distributions may produce different sequences + * of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_real_distribution) + +private: + RealType _min; + RealType _max; +}; + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_UNIFORM_INT_HPP diff --git a/include/boost/random/uniform_smallint.hpp b/include/boost/random/uniform_smallint.hpp index b28d54f..4f5f437 100644 --- a/include/boost/random/uniform_smallint.hpp +++ b/include/boost/random/uniform_smallint.hpp @@ -17,16 +17,20 @@ #ifndef BOOST_RANDOM_UNIFORM_SMALLINT_HPP #define BOOST_RANDOM_UNIFORM_SMALLINT_HPP -#include -#include +#include +#include +#include #include #include -#include +#include #include +#include +#include #include #include namespace boost { +namespace random { // uniform integer distribution on a small range [min, max] @@ -38,121 +42,247 @@ namespace boost { * underlying source of random numbers and thus makes no attempt to limit * quantization errors. * - * Let rout=(max-min+1) the desired range of integer numbers, and - * let rbase be the range of the underlying source of random + * Let \f$r_{\mathtt{out}} = (\mbox{max}-\mbox{min}+1)\f$ the desired range of + * integer numbers, and + * let \f$r_{\mathtt{base}}\f$ be the range of the underlying source of random * numbers. Then, for the uniform distribution, the theoretical probability - * for any number i in the range rout will be pout(i) = - * 1/rout. Likewise, assume a uniform distribution on rbase for - * the underlying source of random numbers, i.e. pbase(i) = - * 1/rbase. Let pout_s(i) denote the random + * for any number i in the range \f$r_{\mathtt{out}}\f$ will be + * \f$\displaystyle p_{\mathtt{out}}(i) = \frac{1}{r_{\mathtt{out}}}\f$. + * Likewise, assume a uniform distribution on \f$r_{\mathtt{base}}\f$ for + * the underlying source of random numbers, i.e. + * \f$\displaystyle p_{\mathtt{base}}(i) = \frac{1}{r_{\mathtt{base}}}\f$. + * Let \f$p_{\mathtt{out\_s}}(i)\f$ denote the random * distribution generated by @c uniform_smallint. Then the sum over all - * i in rout of (pout_s(i)/pout(i) - 1)2 - * shall not exceed rout/rbase2 - * (rbase mod rout)(rout - - * rbase mod rout). + * i in \f$r_{\mathtt{out}}\f$ of + * \f$\displaystyle + * \left(\frac{p_{\mathtt{out\_s}}(i)}{p_{\mathtt{out}}(i)} - 1\right)^2\f$ + * shall not exceed + * \f$\displaystyle \frac{r_{\mathtt{out}}}{r_{\mathtt{base}}^2} + * (r_{\mathtt{base}} \mbox{ mod } r_{\mathtt{out}}) + * (r_{\mathtt{out}} - r_{\mathtt{base}} \mbox{ mod } r_{\mathtt{out}})\f$. * * The template parameter IntType shall denote an integer-like value type. * - * Note: The property above is the square sum of the relative differences + * @xmlnote + * The property above is the square sum of the relative differences * in probabilities between the desired uniform distribution - * pout(i) and the generated distribution pout_s(i). + * \f$p_{\mathtt{out}}(i)\f$ and the generated distribution + * \f$p_{\mathtt{out\_s}}(i)\f$. * The property can be fulfilled with the calculation - * (base_rng mod rout), as follows: Let r = rbase mod - * rout. The base distribution on rbase is folded onto the - * range rout. The numbers i < r have assigned (rbase - * div rout)+1 numbers of the base distribution, the rest has - * only (rbase div rout). Therefore, - * pout_s(i) = ((rbase div rout)+1) / - * rbase for i < r and pout_s(i) = (rbase - * div rout)/rbase otherwise. Substituting this in the + * \f$(\mbox{base\_rng} \mbox{ mod } r_{\mathtt{out}})\f$, as follows: + * Let \f$r = r_{\mathtt{base}} \mbox{ mod } r_{\mathtt{out}}\f$. + * The base distribution on \f$r_{\mathtt{base}}\f$ is folded onto the + * range \f$r_{\mathtt{out}}\f$. The numbers i < r have assigned + * \f$\displaystyle + * \left\lfloor\frac{r_{\mathtt{base}}}{r_{\mathtt{out}}}\right\rfloor+1\f$ + * numbers of the base distribution, the rest has only \f$\displaystyle + * \left\lfloor\frac{r_{\mathtt{base}}}{r_{\mathtt{out}}}\right\rfloor\f$. + * Therefore, + * \f$\displaystyle p_{\mathtt{out\_s}}(i) = + * \left(\left\lfloor\frac{r_{\mathtt{base}}} + * {r_{\mathtt{out}}}\right\rfloor+1\right) / + * r_{\mathtt{base}}\f$ for i < r and \f$\displaystyle p_{\mathtt{out\_s}}(i) = + * \left\lfloor\frac{r_{\mathtt{base}}} + * {r_{\mathtt{out}}}\right\rfloor/r_{\mathtt{base}}\f$ otherwise. + * Substituting this in the * above sum formula leads to the desired result. + * @endxmlnote * - * Note: The upper bound for (rbase mod rout) - * (rout - rbase mod rout) is - * rout2/4. Regarding the upper bound for the - * square sum of the relative quantization error of - * rout3/(4*rbase2), it - * seems wise to either choose rbase so that rbase > - * 10*rout2 or ensure that rbase is - * divisible by rout. + * Note: The upper bound for + * \f$(r_{\mathtt{base}} \mbox{ mod } r_{\mathtt{out}}) + * (r_{\mathtt{out}} - r_{\mathtt{base}} \mbox{ mod } r_{\mathtt{out}})\f$ is + * \f$\displaystyle \frac{r_{\mathtt{out}}^2}{4}\f$. Regarding the upper bound + * for the square sum of the relative quantization error of + * \f$\displaystyle \frac{r_\mathtt{out}^3}{4r_{\mathtt{base}}^2}\f$, it + * seems wise to either choose \f$r_{\mathtt{base}}\f$ so that + * \f$r_{\mathtt{base}} > 10r_{\mathtt{out}}^2\f$ or ensure that + * \f$r_{\mathtt{base}}\f$ is + * divisible by \f$r_{\mathtt{out}}\f$. */ template class uniform_smallint { public: - typedef IntType input_type; - typedef IntType result_type; + typedef IntType input_type; + typedef IntType result_type; - /** - * Constructs a @c uniform_smallint. @c min and @c max are the - * lower and upper bounds of the output range, respectively. - */ - explicit uniform_smallint(IntType min_arg = 0, IntType max_arg = 9) - : _min(min_arg), _max(max_arg) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); -#endif - } + class param_type + { + public: - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } - void reset() { } + typedef uniform_smallint distribution_type; - template - result_type operator()(Engine& eng) - { - typedef typename Engine::result_type base_result; - base_result _range = static_cast(_max-_min)+1; - base_result _factor = 1; + /** constructs the parameters of a @c uniform_smallint distribution. */ + param_type(IntType min_arg = 0, IntType max_arg = 9) + : _min(min_arg), _max(max_arg) + { + BOOST_ASSERT(_min <= _max); + } + + /** Returns the minimum value. */ + IntType a() const { return _min; } + /** Returns the maximum value. */ + IntType b() const { return _max; } + + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._min << " " << parm._max; + return os; + } - // LCGs get bad when only taking the low bits. - // (probably put this logic into a partial template specialization) - // Check how many low bits we can ignore before we get too much - // quantization error. - base_result r_base = (eng.max)() - (eng.min)(); - if(r_base == (std::numeric_limits::max)()) { - _factor = 2; - r_base /= 2; - } - r_base += 1; - if(r_base % _range == 0) { - // No quantization effects, good - _factor = r_base / _range; - } else { - // carefully avoid overflow; pessimizing here - for( ; r_base/_range/32 >= _range; _factor *= 2) - r_base /= 2; + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._min >> std::ws >> parm._max; + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._min == rhs._min && lhs._max == rhs._max; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + IntType _min; + IntType _max; + }; + + /** + * Constructs a @c uniform_smallint. @c min and @c max are the + * lower and upper bounds of the output range, respectively. + */ + explicit uniform_smallint(IntType min_arg = 0, IntType max_arg = 9) + : _min(min_arg), _max(max_arg) {} + + /** + * Constructs a @c uniform_smallint from its parameters. + */ + explicit uniform_smallint(const param_type& parm) + : _min(parm.a()), _max(parm.b()) {} + + /** Returns the minimum value of the distribution. */ + result_type a() const { return _min; } + /** Returns the maximum value of the distribution. */ + result_type b() const { return _max; } + /** Returns the minimum value of the distribution. */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _min; } + /** Returns the maximum value of the distribution. */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return _max; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_min, _max); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _min = parm.a(); + _max = parm.b(); } - return static_cast(((eng() - (eng.min)()) / _factor) % _range + _min); - } + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const uniform_smallint& ud) - { - os << ud._min << " " << ud._max; - return os; - } + /** Returns a value uniformly distributed in the range [min(), max()]. */ + template + result_type operator()(Engine& eng) const + { + typedef typename Engine::result_type base_result; + return generate(eng, boost::is_integral()); + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, uniform_smallint& ud) - { - is >> std::ws >> ud._min >> std::ws >> ud._max; - return is; - } -#endif + /** Returns a value uniformly distributed in the range [param.a(), param.b()]. */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { return uniform_smallint(parm)(eng); } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_smallint, ud) + { + os << ud._min << " " << ud._max; + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_smallint, ud) + { + is >> ud._min >> std::ws >> ud._max; + return is; + } + + /** + * Returns true if the two distributions will produce identical + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_smallint, lhs, rhs) + { return lhs._min == rhs._min && lhs._max == rhs._max; } + + /** + * Returns true if the two distributions may produce different + * sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_smallint) private: + + // \cond show_private + template + result_type generate(Engine& eng, boost::mpl::true_) const + { + // equivalent to (eng() - eng.min()) % (_max - _min + 1) + _min, + // but guarantees no overflow. + typedef typename Engine::result_type base_result; + typedef typename boost::make_unsigned::type base_unsigned; + typedef typename boost::make_unsigned::type range_type; + range_type range = random::detail::subtract()(_max, _min); + base_unsigned base_range = + random::detail::subtract()((eng.max)(), (eng.min)()); + base_unsigned val = + random::detail::subtract()(eng(), (eng.min)()); + if(range >= base_range) { + return boost::random::detail::add()( + static_cast(val), _min); + } else { + base_unsigned modulus = static_cast(range) + 1; + return boost::random::detail::add()( + static_cast(val % modulus), _min); + } + } + + template + result_type generate(Engine& eng, boost::mpl::false_) const + { + typedef typename Engine::result_type base_result; + typedef typename boost::make_unsigned::type range_type; + range_type range = random::detail::subtract()(_max, _min); + base_result val = boost::uniform_01()(eng); + // what is the worst that can possibly happen here? + // base_result may not be able to represent all the values in [0, range] + // exactly. If this happens, it will cause round off error and we + // won't be able to produce all the values in the range. We don't + // care about this because the user has already told us not to by + // using uniform_smallint. However, we do need to be careful + // to clamp the result, or floating point rounding can produce + // an out of range result. + range_type offset = static_cast(val * (static_cast(range) + 1)); + if(offset > range) return _max; + return boost::random::detail::add()(offset , _min); + } + // \endcond - result_type _min; - result_type _max; + result_type _min; + result_type _max; }; +} // namespace random + +using random::uniform_smallint; + } // namespace boost #endif // BOOST_RANDOM_UNIFORM_SMALLINT_HPP diff --git a/include/boost/random/variate_generator.hpp b/include/boost/random/variate_generator.hpp index 5a8dc9d..6d5aac4 100644 --- a/include/boost/random/variate_generator.hpp +++ b/include/boost/random/variate_generator.hpp @@ -1,6 +1,7 @@ /* boost random/variate_generator.hpp header file * * Copyright Jens Maurer 2002 + * 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) @@ -14,21 +15,8 @@ #ifndef BOOST_RANDOM_RANDOM_GENERATOR_HPP #define BOOST_RANDOM_RANDOM_GENERATOR_HPP -#include - -// implementation details -#include -#include -#include -#include #include -// Borland C++ 5.6.0 has problems using its numeric_limits traits as -// template parameters -#if BOOST_WORKAROUND(__BORLANDC__, <= 0x564) -#include -#endif - #include namespace boost { @@ -36,54 +24,6 @@ namespace boost { /// \cond hide_private_members namespace random { -namespace detail { - -template -struct engine_helper; - -// for consistency, always have two levels of decorations -template<> -struct engine_helper -{ - template - struct impl - { - typedef pass_through_engine type; - }; -}; - -template<> -struct engine_helper -{ - template - struct impl - { - typedef uniform_01 type; - }; -}; - -template<> -struct engine_helper -{ - template - struct impl - { - typedef uniform_01 type; - }; -}; - -template<> -struct engine_helper -{ - template - struct impl - { - typedef uniform_int_float type; - }; -}; - -} // namespace detail -} // namespace random ///\endcond @@ -93,9 +33,6 @@ struct engine_helper * Boost.Random provides a vast choice of \generators as well * as \distributions. * - * Instantations of class template @c variate_generator model - * a \number_generator. - * * The argument for the template parameter Engine shall be of * the form U, U&, or U*, where U models a * \uniform_random_number_generator. Then, the member @@ -114,107 +51,72 @@ template class variate_generator { private: - typedef random::detail::pass_through_engine decorated_engine; - + typedef boost::random::detail::ptr_helper helper_type; public: - typedef typename decorated_engine::base_type engine_value_type; - typedef Engine engine_type; - typedef Distribution distribution_type; - typedef typename Distribution::result_type result_type; + typedef typename helper_type::value_type engine_value_type; + typedef Engine engine_type; + typedef Distribution distribution_type; + typedef typename Distribution::result_type result_type; - /** - * Constructs a @c variate_generator object with the associated - * \uniform_random_number_generator eng and the associated - * \random_distribution d. - * - * Throws: If and what the copy constructor of Engine or - * Distribution throws. - */ - variate_generator(Engine e, Distribution d) - : _eng(decorated_engine(e)), _dist(d) { } + /** + * Constructs a @c variate_generator object with the associated + * \uniform_random_number_generator eng and the associated + * \random_distribution d. + * + * Throws: If and what the copy constructor of Engine or + * Distribution throws. + */ + variate_generator(Engine e, Distribution d) + : _eng(e), _dist(d) { } - /** - * Returns: distribution()(e) - * - * Notes: The sequence of numbers produced by the - * \uniform_random_number_generator e, se, is - * obtained from the sequence of numbers produced by the - * associated \uniform_random_number_generator eng, seng, - * as follows: Consider the values of @c numeric_limits::is_integer - * for @c T both @c Distribution::input_type and - * @c engine_value_type::result_type. If the values for both types are - * true, then se is identical to seng. Otherwise, if the - * values for both types are false, then the numbers in seng - * are divided by engine().max()-engine().min() to obtain the numbers - * in se. Otherwise, if the value for - * @c engine_value_type::result_type is true and the value for - * @c Distribution::input_type is false, then the numbers in seng - * are divided by engine().max()-engine().min()+1 to obtain the numbers in - * se. Otherwise, the mapping from seng to - * se is implementation-defined. In all cases, an - * implicit conversion from @c engine_value_type::result_type to - * @c Distribution::input_type is performed. If such a conversion does - * not exist, the program is ill-formed. - */ - result_type operator()() { return _dist(_eng); } - /** - * Returns: distribution()(e, value). - * For the semantics of e, see the description of operator()(). - */ - template - result_type operator()(T value) { return _dist(_eng, value); } + /** Returns: distribution()(engine()) */ + result_type operator()() { return _dist(engine()); } + /** + * Returns: distribution()(engine(), value). + */ + template + result_type operator()(const T& value) { return _dist(engine(), value); } - /** - * Returns: A reference to the associated uniform random number generator. - */ - engine_value_type& engine() { return _eng.base().base(); } - /** - * Returns: A reference to the associated uniform random number generator. - */ - const engine_value_type& engine() const { return _eng.base().base(); } + /** + * Returns: A reference to the associated uniform random number generator. + */ + engine_value_type& engine() { return helper_type::ref(_eng); } + /** + * Returns: A reference to the associated uniform random number generator. + */ + const engine_value_type& engine() const { return helper_type::ref(_eng); } - /** - * Returns: A reference to the associated random distribution. - */ - distribution_type& distribution() { return _dist; } - /** - * Returns: A reference to the associated random distribution. - */ - const distribution_type& distribution() const { return _dist; } + /** Returns: A reference to the associated \random_distribution. */ + distribution_type& distribution() { return _dist; } + /** + * Returns: A reference to the associated random distribution. + */ + const distribution_type& distribution() const { return _dist; } - /** - * Precondition: distribution().min() is well-formed - * - * Returns: distribution().min() - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (distribution().min)(); } - /** - * Precondition: distribution().max() is well-formed - * - * Returns: distribution().max() - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (distribution().max)(); } + /** + * Precondition: distribution().min() is well-formed + * + * Returns: distribution().min() + */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (distribution().min)(); } + /** + * Precondition: distribution().max() is well-formed + * + * Returns: distribution().max() + */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (distribution().max)(); } private: -#if BOOST_WORKAROUND(__BORLANDC__, <= 0x564) - typedef typename random::detail::engine_helper< - ::boost::is_integral::value, - ::boost::is_integral::value - >::BOOST_NESTED_TEMPLATE impl::type internal_engine_type; -#else - enum { - have_int = std::numeric_limits::is_integer, - want_int = std::numeric_limits::is_integer - }; - typedef typename random::detail::engine_helper::BOOST_NESTED_TEMPLATE impl::type internal_engine_type; -#endif - - internal_engine_type _eng; - distribution_type _dist; + Engine _eng; + distribution_type _dist; }; +} // namespace random + +using random::variate_generator; + } // namespace boost -#include +#include #endif // BOOST_RANDOM_RANDOM_GENERATOR_HPP diff --git a/include/boost/random/weibull_distribution.hpp b/include/boost/random/weibull_distribution.hpp new file mode 100644 index 0000000..55e3c04 --- /dev/null +++ b/include/boost/random/weibull_distribution.hpp @@ -0,0 +1,177 @@ +/* boost random/weibull_distribution.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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_WEIBULL_DISTRIBUTION_HPP +#define BOOST_RANDOM_WEIBULL_DISTRIBUTION_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace random { + +/** + * The Weibull distribution is a real valued distribution with two + * parameters a and b, producing values >= 0. + * + * It has \f$\displaystyle p(x) = \frac{a}{b}\left(\frac{x}{b}\right)^{a-1}e^{-\left(\frac{x}{b}\right)^a}\f$. + */ +template +class weibull_distribution { +public: + typedef RealType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef weibull_distribution distribution_type; + + /** + * Constructs a @c param_type from the "a" and "b" parameters + * of the distribution. + * + * Requires: a > 0 && b > 0 + */ + explicit param_type(RealType a_arg = 1.0, RealType b_arg = 1.0) + : _a(a_arg), _b(b_arg) + {} + + /** Returns the "a" parameter of the distribtuion. */ + RealType a() const { return _a; } + /** Returns the "b" parameter of the distribution. */ + RealType b() const { return _b; } + + /** Writes a @c param_type to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { os << parm._a << ' ' << parm._b; return os; } + + /** Reads a @c param_type from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { is >> parm._a >> std::ws >> parm._b; return is; } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._a == rhs._a && lhs._b == rhs._b; } + + /** Returns true if the two sets of parameters are the different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + RealType _a; + RealType _b; + }; + + /** + * Constructs a @c weibull_distribution from its "a" and "b" parameters. + * + * Requires: a > 0 && b > 0 + */ + explicit weibull_distribution(RealType a_arg = 1.0, RealType b_arg = 1.0) + : _a(a_arg), _b(b_arg) + {} + /** Constructs a @c weibull_distribution from its parameters. */ + explicit weibull_distribution(const param_type& parm) + : _a(parm.a()), _b(parm.b()) + {} + + /** + * Returns a random variate distributed according to the + * @c weibull_distribution. + */ + template + RealType operator()(URNG& urng) const + { + using std::pow; + using std::log; + return _b*pow(-log(1 - uniform_01()(urng)), 1/_a); + } + + /** + * Returns a random variate distributed accordint to the Weibull + * distribution with parameters specified by @c param. + */ + template + RealType operator()(URNG& urng, const param_type& parm) const + { + return weibull_distribution(parm)(urng); + } + + /** Returns the "a" parameter of the distribution. */ + RealType a() const { return _a; } + /** Returns the "b" parameter of the distribution. */ + RealType b() const { return _b; } + + /** Returns the smallest value that the distribution can produce. */ + RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; } + /** Returns the largest value that the distribution can produce. */ + RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return std::numeric_limits::infinity(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_a, _b); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _a = parm.a(); + _b = parm.b(); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } + + /** Writes a @c weibull_distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, weibull_distribution, wd) + { + os << wd.param(); + return os; + } + + /** Reads a @c weibull_distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, weibull_distribution, wd) + { + param_type parm; + if(is >> parm) { + wd.param(parm); + } + return is; + } + + /** + * Returns true if the two instances of @c weibull_distribution will + * return identical sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(weibull_distribution, lhs, rhs) + { return lhs._a == rhs._a && lhs._b == rhs._b; } + + /** + * Returns true if the two instances of @c weibull_distribution will + * return different sequences of values given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(weibull_distribution) + +private: + RealType _a; + RealType _b; +}; + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_WEIBULL_DISTRIBUTION_HPP diff --git a/include/boost/random/xor_combine.hpp b/include/boost/random/xor_combine.hpp index 59e9a79..1e164ed 100644 --- a/include/boost/random/xor_combine.hpp +++ b/include/boost/random/xor_combine.hpp @@ -14,169 +14,192 @@ #ifndef BOOST_RANDOM_XOR_COMBINE_HPP #define BOOST_RANDOM_XOR_COMBINE_HPP -#include +#include +#include #include #include // for std::min and std::max #include #include -#include #include // uint32_t #include - +#include +#include namespace boost { namespace random { -/// \cond hide_private_members -#ifndef BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS - #define BOOST_RANDOM_VAL_TYPE typename URNG1::result_type -#else - #define BOOST_RANDOM_VAL_TYPE uint32_t -#endif -/// \endcond - /** - * Instantiations of @c xor_combine model a \pseudo_random_number_generator. - * To produce its output it invokes each of the base generators, shifts - * their results and xors them together. + * Instantiations of @c xor_combine_engine model a + * \pseudo_random_number_generator. To produce its output it + * invokes each of the base generators, shifts their results + * and xors them together. */ -template -class xor_combine +template +class xor_combine_engine { public: - typedef URNG1 base1_type; - typedef URNG2 base2_type; - typedef typename base1_type::result_type result_type; + typedef URNG1 base1_type; + typedef URNG2 base2_type; + typedef typename base1_type::result_type result_type; - BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); - BOOST_STATIC_CONSTANT(int, shift1 = s1); - BOOST_STATIC_CONSTANT(int, shift2 = s2); + BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); + BOOST_STATIC_CONSTANT(int, shift1 = s1); + BOOST_STATIC_CONSTANT(int, shift2 = s2); - /** - * Constructors a @c xor_combine by default constructing - * both base generators. - */ - xor_combine() : _rng1(), _rng2() - { } - /** - * Constructs a @c xor_combine by copying two base generators. - */ - xor_combine(const base1_type & rng1, const base2_type & rng2) - : _rng1(rng1), _rng2(rng2) { } - /** - * Constructs a @c xor_combine, seeding both base generators - * with @c v. - */ - xor_combine(const result_type & v) - : _rng1(v), _rng2(v) { } - /** - * Constructs a @c xor_combine, seeding both base generators - * with values from the iterator range [first, last) and changes - * first to point to the element after the last one used. If there - * are not enough elements in the range to seed both generators, - * throws @c std::invalid_argument. - */ - template xor_combine(It& first, It last) - : _rng1(first, last), _rng2( /* advanced by other call */ first, last) { } - /** - * Calls @c seed() for both base generators. - */ - void seed() { _rng1.seed(); _rng2.seed(); } - /** - * @c seeds both base generators with @c v. - */ - void seed(const result_type & v) { _rng1.seed(v); _rng2.seed(v); } - /** - * seeds both base generators with values from the iterator - * range [first, last) and changes first to point to the element - * after the last one used. If there are not enough elements in - * the range to seed both generators, throws @c std::invalid_argument. - */ - template void seed(It& first, It last) - { - _rng1.seed(first, last); - _rng2.seed(first, last); - } + /** + * Constructors a @c xor_combine_engine by default constructing + * both base generators. + */ + xor_combine_engine() : _rng1(), _rng2() { } - /** Returns the first base generator. */ - const base1_type& base1() { return _rng1; } - /** Returns the second base generator. */ - const base2_type& base2() { return _rng2; } + /** Constructs a @c xor_combine by copying two base generators. */ + xor_combine_engine(const base1_type & rng1, const base2_type & rng2) + : _rng1(rng1), _rng2(rng2) { } - /** Returns the next value of the generator. */ - result_type operator()() - { - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope -#if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) && !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300) - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); - BOOST_STATIC_ASSERT(std::numeric_limits::digits >= std::numeric_limits::digits); -#endif - return (_rng1() << s1) ^ (_rng2() << s2); - } + /** + * Constructs a @c xor_combine_engine, seeding both base generators + * with @c v. + * + * @xmlwarning + * The exact algorithm used by this function may change in the future. + * @endxmlwarning + */ + BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(xor_combine_engine, + result_type, v) + { seed(v); } - /** - * Returns the smallest value that the generator can produce. - */ - result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::min BOOST_PREVENT_MACRO_SUBSTITUTION((_rng1.min)(), (_rng2.min)()); } - /** - * Returns the largest value that the generator can produce. - */ - result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::max BOOST_PREVENT_MACRO_SUBSTITUTION((_rng1.min)(), (_rng2.max)()); } - static bool validation(result_type x) { return val == x; } + /** + * Constructs a @c xor_combine_engine, seeding both base generators + * with values produced by @c seq. + */ + BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(xor_combine_engine, + SeedSeq, seq) + { seed(seq); } -#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE + /** + * Constructs a @c xor_combine_engine, seeding both base generators + * with values from the iterator range [first, last) and changes + * first to point to the element after the last one used. If there + * are not enough elements in the range to seed both generators, + * throws @c std::invalid_argument. + */ + template xor_combine_engine(It& first, It last) + : _rng1(first, last), _rng2( /* advanced by other call */ first, last) { } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const xor_combine& s) - { - os << s._rng1 << " " << s._rng2 << " "; - return os; - } + /** Calls @c seed() for both base generators. */ + void seed() { _rng1.seed(); _rng2.seed(); } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, xor_combine& s) - { - is >> s._rng1 >> std::ws >> s._rng2 >> std::ws; - return is; - } -#endif + /** @c seeds both base generators with @c v. */ + BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(xor_combine_engine, result_type, v) + { _rng1.seed(v); _rng2.seed(v); } - friend bool operator==(const xor_combine& x, const xor_combine& y) - { return x._rng1 == y._rng1 && x._rng2 == y._rng2; } - friend bool operator!=(const xor_combine& x, const xor_combine& y) - { return !(x == y); } -#else - // Use a member function; Streamable concept not supported. - bool operator==(const xor_combine& rhs) const - { return _rng1 == rhs._rng1 && _rng2 == rhs._rng2; } - bool operator!=(const xor_combine& rhs) const - { return !(*this == rhs); } -#endif + /** @c seeds both base generators with values produced by @c seq. */ + BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(xor_combine_engine, SeedSeq, seq) + { _rng1.seed(seq); _rng2.seed(seq); } + + /** + * seeds both base generators with values from the iterator + * range [first, last) and changes first to point to the element + * after the last one used. If there are not enough elements in + * the range to seed both generators, throws @c std::invalid_argument. + */ + template void seed(It& first, It last) + { + _rng1.seed(first, last); + _rng2.seed(first, last); + } + + /** Returns the first base generator. */ + const base1_type& base1() const { return _rng1; } + + /** Returns the second base generator. */ + const base2_type& base2() const { return _rng2; } + + /** Returns the next value of the generator. */ + result_type operator()() + { + return (_rng1() << s1) ^ (_rng2() << s2); + } + + /** Fills a range with random values */ + template + void generate(Iter first, Iter last) + { detail::generate_from_int(*this, first, last); } + + /** Advances the state of the generator by @c z. */ + void discard(boost::uintmax_t z) + { + _rng1.discard(z); + _rng2.discard(z); + } + + /** Returns the smallest value that the generator can produce. */ + static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::min)((URNG1::min)(), (URNG2::min)()); } + /** Returns the largest value that the generator can produce. */ + static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::max)((URNG1::min)(), (URNG2::max)()); } + + /** + * Writes the textual representation of the generator to a @c std::ostream. + */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, xor_combine_engine, s) + { + os << s._rng1 << ' ' << s._rng2; + return os; + } + + /** + * Reads the textual representation of the generator from a @c std::istream. + */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, xor_combine_engine, s) + { + is >> s._rng1 >> std::ws >> s._rng2; + return is; + } + + /** Returns true if the two generators will produce identical sequences. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(xor_combine_engine, x, y) + { return x._rng1 == y._rng1 && x._rng2 == y._rng2; } + + /** Returns true if the two generators will produce different sequences. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(xor_combine_engine) private: - base1_type _rng1; - base2_type _rng2; + base1_type _rng1; + base2_type _rng2; }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION // A definition is required even for integral static constants -template -const bool xor_combine::has_fixed_range; -template -const int xor_combine::shift1; -template -const int xor_combine::shift2; +template +const bool xor_combine_engine::has_fixed_range; +template +const int xor_combine_engine::shift1; +template +const int xor_combine_engine::shift2; #endif -#undef BOOST_RANDOM_VAL_TYPE +/// \cond show_private + +/** Provided for backwards compatibility. */ +template +class xor_combine : public xor_combine_engine +{ + typedef xor_combine_engine base_type; +public: + typedef typename base_type::result_type result_type; + xor_combine() {} + xor_combine(result_type val) : base_type(val) {} + template + xor_combine(It& first, It last) : base_type(first, last) {} + xor_combine(const URNG1 & rng1, const URNG2 & rng2) + : base_type(rng1, rng2) { } + + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::min)((this->base1().min)(), (this->base2().min)()); } + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (std::max)((this->base1().min)(), (this->base2().max)()); } +}; + +/// \endcond } // namespace random } // namespace boost diff --git a/performance/Jamfile.v2 b/performance/Jamfile.v2 new file mode 100644 index 0000000..4315385 --- /dev/null +++ b/performance/Jamfile.v2 @@ -0,0 +1,18 @@ +mt19937ar-files = [ glob mt19937ar.c ] ; + +if $(mt19937ar-files) +{ + alias mt19937ar : $(mt19937ar-files) : : HAVE_MT19937AR_C ; +} +else +{ + alias mt19937ar ; +} + +exe random_speed.exe : random_speed.cpp mt19937ar : release ; +exe generate_table.exe : generate_table.cpp /boost//regex : static ; +exe nondet_random_speed.exe : nondet_random_speed.cpp /boost//random : release static ; + +install random_speed : random_speed.exe : EXE . ; +install nondet_random_speed : nondet_random_speed.exe : EXE . ; +install generate_table : generate_table.exe : EXE . ; diff --git a/performance/generate_table.cpp b/performance/generate_table.cpp index a72fbef..c899d08 100644 --- a/performance/generate_table.cpp +++ b/performance/generate_table.cpp @@ -43,7 +43,19 @@ typedef boost::multi_index_container< > > unique_list; -int main() { +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 > generator_info; std::string line; while(std::getline(std::cin, line)) { @@ -63,8 +75,8 @@ int main() { 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.qbk"); - generator_performance << "[table Basic Generators\n"; + 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"; @@ -96,9 +108,9 @@ int main() { } } while(std::getline(std::cin, line)); - std::ofstream distribution_performance("distribution_performance.qbk"); + std::ofstream distribution_performance(("distribution_performance_" + suffix + ".qbk").c_str()); - distribution_performance << "[table Distributions\n"; + 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; diff --git a/performance/nondet_random_speed.cpp b/performance/nondet_random_speed.cpp index 4482934..bf45a08 100644 --- a/performance/nondet_random_speed.cpp +++ b/performance/nondet_random_speed.cpp @@ -12,10 +12,10 @@ #include #include #include -#include +#include -// set to your CPU frequency in MHz -static const double cpu_frequency = 200 * 1e6; +// 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) { @@ -53,12 +53,8 @@ int main(int argc, char*argv[]) int iter = std::atoi(argv[1]); -#ifdef __linux__ - boost::random_device dev; + boost::random::random_device dev; timing(dev, iter, "random_device"); -#else -#error The non-deterministic random device is currently available on Linux only. -#endif return 0; } diff --git a/performance/random_speed.cpp b/performance/random_speed.cpp index fb6e433..aac9ab5 100644 --- a/performance/random_speed.cpp +++ b/performance/random_speed.cpp @@ -21,16 +21,16 @@ */ // define if your C library supports the non-standard drand48 family -#define HAVE_DRAND48 +//#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 +// #define HAVE_MT19937AR_C -// set to your CPU frequency in MHz -static const double cpu_frequency = 3.66 * 1e9; +// set to your CPU frequency +static const double cpu_frequency = 1.87 * 1e9; /* * End of Configuration Section @@ -244,98 +244,71 @@ void distrib(int iter, const std::string & name, const Gen &) { Gen gen; - timing(make_gen(gen, boost::uniform_int<>(-2, 4)), + timing(make_gen(gen, boost::random::uniform_int_distribution<>(-2, 4)), iter, name + " uniform_int"); - timing(make_gen(gen, boost::geometric_distribution<>(0.5)), + 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::binomial_distribution(4, 0.8)), + timing(make_gen(gen, boost::random::binomial_distribution(4, 0.8)), iter, name + " binomial"); - timing(make_gen(gen, boost::poisson_distribution<>(1)), + timing(make_gen(gen, boost::random::negative_binomial_distribution(4, 0.8)), + iter, name + " negative_binomial"); + + timing(make_gen(gen, boost::random::poisson_distribution<>(1)), iter, name + " poisson"); - timing(make_gen(gen, boost::uniform_real<>(-5.3, 4.8)), + timing(make_gen(gen, boost::random::uniform_real_distribution<>(-5.3, 4.8)), iter, name + " uniform_real"); - timing(make_gen(gen, boost::triangle_distribution<>(1, 2, 7)), + 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::exponential_distribution<>(3)), + timing(make_gen(gen, boost::random::exponential_distribution<>(3)), iter, name + " exponential"); - timing(make_gen(gen, boost::normal_distribution<>()), + timing(make_gen(gen, boost::random::normal_distribution<>()), iter, name + " normal polar"); - timing(make_gen(gen, boost::lognormal_distribution<>()), + timing(make_gen(gen, boost::random::lognormal_distribution<>()), iter, name + " lognormal"); - timing(make_gen(gen, boost::cauchy_distribution<>()), + 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::cauchy_distribution<>()), + 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_sphere(make_gen(gen, boost::uniform_on_sphere<>(3)), + 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"); } - -template -inline boost::shared_ptr > -make_dynamic(URNG & rng, const Dist& d) -{ - typedef DynamicRandomGenerator type; - return boost::shared_ptr(new type(rng, d)); -} - -template -void distrib_runtime(int iter, const std::string & n, const Gen &) -{ - std::string name = n + " virtual function "; - Gen gen; - - GenericRandomGenerator g_int; - - g_int.set(make_dynamic(gen, boost::uniform_int<>(-2,4))); - timing(g_int, iter, name + "uniform_int"); - - g_int.set(make_dynamic(gen, boost::geometric_distribution<>(0.5))); - timing(g_int, iter, name + "geometric"); - - g_int.set(make_dynamic(gen, boost::binomial_distribution<>(4, 0.8))); - timing(g_int, iter, name + "binomial"); - - g_int.set(make_dynamic(gen, boost::poisson_distribution<>(1))); - timing(g_int, iter, name + "poisson"); - - GenericRandomGenerator g; - - g.set(make_dynamic(gen, boost::uniform_real<>(-5.3, 4.8))); - timing(g, iter, name + "uniform_real"); - - g.set(make_dynamic(gen, boost::triangle_distribution<>(1, 2, 7))); - timing(g, iter, name + "triangle"); - - g.set(make_dynamic(gen, boost::exponential_distribution<>(3))); - timing(g, iter, name + "exponential"); - - g.set(make_dynamic(gen, boost::normal_distribution<>())); - timing(g, iter, name + "normal polar"); - - g.set(make_dynamic(gen, boost::lognormal_distribution<>())); - timing(g, iter, name + "lognormal"); - - g.set(make_dynamic(gen, boost::cauchy_distribution<>())); - timing(g, iter, name + "cauchy"); - - g.set(make_dynamic(gen, boost::gamma_distribution<>(0.4))); - timing(g, iter, name + "gamma"); -} - - int main(int argc, char*argv[]) { if(argc != 2) { @@ -370,11 +343,15 @@ int main(int argc, char*argv[]) 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()); @@ -396,6 +373,8 @@ int main(int argc, char*argv[]) 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()); @@ -409,7 +388,6 @@ int main(int argc, char*argv[]) #endif distrib(iter, "counting", counting()); - distrib_runtime(iter, "counting", counting()); distrib(iter, "minstd_rand", boost::minstd_rand()); @@ -418,6 +396,4 @@ int main(int argc, char*argv[]) distrib(iter, "mt19937", boost::mt19937()); distrib(iter, "lagged_fibonacci607", boost::lagged_fibonacci607()); - - distrib_runtime(iter, "mt19937", boost::mt19937()); } diff --git a/src/random_device.cpp b/src/random_device.cpp index 8e31bdf..ad35c0b 100644 --- a/src/random_device.cpp +++ b/src/random_device.cpp @@ -1,7 +1,7 @@ /* boost random_device.cpp implementation * * Copyright Jens Maurer 2000 - * Copyright Steven Watanabe 2010 + * 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) @@ -12,16 +12,15 @@ #define BOOST_RANDOM_SOURCE -#include +#include +#include +#include +#include #include -#include - -#if defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) +#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_device::has_fixed_range; -const boost::random_device::result_type boost::random_device::min_value; -const boost::random_device::result_type boost::random_device::max_value; +const bool boost::random::random_device::has_fixed_range; #endif @@ -56,9 +55,13 @@ CryptEnumProvidersA( #endif -BOOST_RANDOM_DECL const char * const boost::random_device::default_token = MS_DEF_PROV_A; +namespace { -class boost::random_device::impl +const char * const default_token = MS_DEF_PROV_A; + +} + +class boost::random::random_device::impl { public: impl(const std::string & token) : provider(token) { @@ -120,9 +123,11 @@ private: #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 boost::random_device::default_token = "/dev/urandom"; +const char * const default_token = "/dev/urandom"; +} /* * This uses the POSIX interface for unbuffered reading. @@ -153,7 +158,7 @@ extern int close(int __fd); #include // std::invalid_argument -class boost::random_device::impl +class boost::random::random_device::impl { public: impl(const std::string & token) : path(token) { @@ -188,16 +193,16 @@ private: #endif // BOOST_WINDOWS -BOOST_RANDOM_DECL boost::random_device::random_device(const std::string& token) +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)) -{ - assert((std::numeric_limits::max)() == max_value); -} +{} BOOST_RANDOM_DECL boost::random_device::~random_device() { - // the complete class impl is now visible, so we're safe - // (see comment in random.hpp) delete pimpl; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9af497f..8cdae2b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,5 +1,5 @@ # Copyright 2003 Jens Maurer -# Copyright 2009-2010 Steven Watanabe +# 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) @@ -8,38 +8,111 @@ # bring in rules for testing import testing ; -project /boost/random/test ; +project /boost/random/test : requirements msvc:_SCL_SECURE_NO_WARNINGS ; -run random_test.cpp ; +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 validate.cpp ; run test_random_device.cpp /boost//random : : : static : test_random_device ; run test_random_device.cpp /boost//random : : : shared : test_random_device_dll ; -local all-urngs = - rand48 - minstd_rand0 - minstd_rand - ecuyer1988 - kreutzer1986 - hellekalek1995 - mt11213b - mt19937 - lagged_fibonacci - lagged_fibonacci607 - ranlux3 - ranlux4 - ranlux3_01 - ranlux4_01 - ranlux64_3_01 - ranlux64_4_01 - taus88 -; +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 ; -for urng in $(all-urngs) -{ - run instantiate.cpp : : : BOOST_RANDOM_URNG_TEST=$(urng) : test_$(urng) ; -} +# 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 ; @@ -47,7 +120,7 @@ for urng in $(all-urngs) # run statistic_tests.cpp ; exe statistic_tests.exe : statistic_tests.cpp ; -explicit statistics_tests ; +explicit statistic_tests.exe ; install statistic_tests : statistic_tests.exe : EXE . ; explicit statistic_tests ; diff --git a/test/chi_squared_test.hpp b/test/chi_squared_test.hpp new file mode 100644 index 0000000..42737ef --- /dev/null +++ b/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$ + * + */ + +#ifndef BOOST_RANDOM_TEST_CHI_SQUARED_TEST_HPP_INCLUDED +#define BOOST_RANDOM_TEST_CHI_SQUARED_TEST_HPP_INCLUDED + +#include + +#include +#include + +// This only works for discrete distributions with fixed +// upper and lower bounds. + +template +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 +double chi_squared_test(const std::vector& results, const std::vector& probabilities, IntType iterations) { + chi_squared_collector calc; + for(std::size_t i = 0; i < results.size(); ++i) { + calc(results[i], iterations * probabilities[i]); + } + return calc.cdf(); +} + +#endif diff --git a/test/concepts.hpp b/test/concepts.hpp new file mode 100644 index 0000000..52852e4 --- /dev/null +++ b/test/concepts.hpp @@ -0,0 +1,221 @@ +/* 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$ + * + */ + +#ifndef BOOST_RANDOM_TEST_CONCEPTS_HPP +#define BOOST_RANDOM_TEST_CONCEPTS_HPP + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +#include + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4510) +#pragma warning(disable:4610) +#endif + +namespace boost { +namespace random { +namespace test { + +template > +struct seed_seq_archetype : Base +{ + template + BOOST_CONCEPT_REQUIRES( + ((Mutable_RandomAccessIterator)) + ((UnsignedInteger::value_type>)), + (void)) + generate(Iter, Iter) {} +}; + +template > +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 +struct SeedSeq +{ +public: + BOOST_CONCEPT_USAGE(SeedSeq) + { + q.generate(rb, re); + } +private: + SSeq q; + mutable_random_access_iterator_archetype rb, re; +}; + +template +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 +void same_type(T const&, T const&) {} + +template +struct RandomNumberEngine : + DefaultConstructible, + CopyConstructible, + Assignable, + EqualityComparable, + Streamable +{ +public: + typedef typename E::result_type result_type; + + // relaxed from the standard + BOOST_MPL_ASSERT((boost::is_arithmetic)); + + // backwards compatibility check + BOOST_STATIC_ASSERT(!E::has_fixed_range); + + // a generator can be used to seed another generator (extension) + BOOST_CONCEPT_ASSERT((SeedSeq)); + + BOOST_CONCEPT_USAGE(RandomNumberEngine) + { + same_type(e(), result_type()); + same_type((E::min)(), result_type()); + same_type((E::max)(), result_type()); + + check_extra(boost::is_integral()); + + (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::type s; + unsigned long long z; + + void check_extra(boost::mpl::true_ /*is_integral*/) {} + + void check_extra(boost::mpl::false_ /*is_integral*/) + { + // This is an undocumented extension, but we still need + // to check for it. + same_type(E::precision(), std::size_t(0)); + } + + input_iterator_archetype sb, se; +}; + +template +struct RandomNumberDistribution : + DefaultConstructible, + CopyConstructible, + Assignable, + EqualityComparable, + Streamable +{ +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

)); + BOOST_CONCEPT_ASSERT((CopyConstructible

)); + BOOST_CONCEPT_ASSERT((Assignable

)); + BOOST_CONCEPT_ASSERT((EqualityComparable

)); + BOOST_CONCEPT_ASSERT((Streamable

)); + + BOOST_MPL_ASSERT((boost::is_same)); + + 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/test/instantiate.cpp b/test/instantiate.cpp deleted file mode 100644 index 1ba024f..0000000 --- a/test/instantiate.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* boost validate.cpp - * - * 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$ - */ - -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::abs; using ::fabs; using ::pow; } -#endif - - -/* - * General portability note: - * MSVC mis-compiles explicit function template instantiations. - * For example, f() and f() are both compiled to call f(). - * 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. - */ - -/* - * Check function signatures - */ - -#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x570) ) -#pragma warn -par -#endif -template -void instantiate_dist(URNG& urng, const char * name, const Dist& dist) -{ - std::cout << "Testing " << name << std::endl; - // this makes a copy of urng - boost::variate_generator gen(urng, dist); - - // this keeps a reference to urng - boost::variate_generator genref(urng, dist); - - BOOST_CHECK(gen.engine() == genref.engine()); - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - // and here is a pointer to (a copy of) the urng - URNG copy = urng; - boost::variate_generator genptr(©, dist); -#endif - - for(int i = 0; i < 1000; ++i) { - (void) gen(); - (void) genref(); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - (void) genptr(); -#endif - } - // If the values are not exactly equal, we cannot - // rely on them being close... - typename Dist::result_type g = gen(); - BOOST_CHECK_EQUAL(g, genref()); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - BOOST_CHECK_EQUAL(g, genptr()); -#endif - - (void) gen.engine(); - gen.distribution().reset(); - - Dist d = dist; // copy ctor - d = dist; // copy assignment - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - { - std::ostringstream file; - file << urng << std::endl; - file << d; - std::istringstream input(file.str()); - // std::cout << file.str() << std::endl; - URNG restored_engine; - input >> restored_engine; - input >> std::ws; - Dist restored_dist; - input >> restored_dist; -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - boost::variate_generator old(urng, d); - boost::variate_generator restored(restored_engine, restored_dist); - // advance some more so that state is exercised - for(int i = 0; i < 1000; ++i) { - (void) old(); - (void) restored(); - } - BOOST_CHECK_MESSAGE((std::abs(old()-restored()) < 0.0001), - (std::string(name) + " old == restored_dist")); -#endif // BOOST_MSVC - } -#endif // BOOST_RANDOM_NO_STREAM_OPERATORS -} - -template -void instantiate_real_dist(URNG& urng, RealType /* ignored */) -{ - std::cout << "Testing real distributions with " << typeid(RealType).name() << std::endl; - instantiate_dist(urng, "uniform_01", - boost::uniform_01()); - instantiate_dist(urng, "uniform_real", - boost::uniform_real(0, 2.1)); - instantiate_dist(urng, "triangle_distribution", - boost::triangle_distribution(1, 1.5, 7)); - instantiate_dist(urng, "exponential_distribution", - boost::exponential_distribution(5)); - instantiate_dist(urng, "normal_distribution", - boost::normal_distribution()); - instantiate_dist(urng, "lognormal_distribution", - boost::lognormal_distribution(1, 1)); - instantiate_dist(urng, "cauchy_distribution", - boost::cauchy_distribution(1)); - instantiate_dist(urng, "gamma_distribution", - boost::gamma_distribution(1)); -} - -template -void test_seed_conversion(URNG & urng, const T & t, const Converted &) { - Converted c = static_cast(t); - if(static_cast(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()); - } -} - -// rand48 uses non-standard seeding -template -void test_seed_conversion(boost::rand48 & urng, const T & t, const Converted &) { - boost::rand48 urng2(t); - urng2.seed(t); -} - -template -void test_seed(const URNG &, const ResultType & value) { - URNG urng(value); - - // integral types - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); -#if !defined(BOOST_NO_INT64_T) - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); -#endif - - // floating point types - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); - test_seed_conversion(urng, value, static_cast(0)); -} - -template -void instantiate_seed(const URNG & urng, const ResultType &) { - { - URNG urng; - URNG urng2; - urng2.seed(); - BOOST_CHECK(urng == urng2); - } - test_seed(urng, static_cast(0)); - test_seed(urng, static_cast(127)); - test_seed(urng, static_cast(539157235)); - test_seed(urng, static_cast(~0u)); -} - -// ranlux uses int32_t for seeding instead of result_type -template -void instantiate_seed(const boost::ranlux3 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -template -void instantiate_seed(const boost::ranlux4 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -template -void instantiate_seed(const boost::ranlux3_01 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -template -void instantiate_seed(const boost::ranlux4_01 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -template -void instantiate_seed(const boost::ranlux64_3 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -template -void instantiate_seed(const boost::ranlux64_4 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -#endif -template -void instantiate_seed(const boost::ranlux64_3_01 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} -template -void instantiate_seed(const boost::ranlux64_4_01 & urng, const ResultType &) { - instantiate_seed(urng, ResultType()); -} - - -template -void instantiate_urng(const std::string & s, const URNG & u, const ResultType & r) -{ - std::cout << "Basic tests for " << s << std::endl; - URNG urng; - instantiate_seed(u, r); // seed() member function - int a[URNG::has_fixed_range ? 5 : 10]; // compile-time constant - (void) a; // avoid "unused" warning - typename URNG::result_type x1 = urng(); - ResultType x2 = x1; - (void) &x2; // avoid "unused" warning - - URNG urng2 = urng; // copy constructor -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - BOOST_CHECK(urng == urng2); // operator== - BOOST_CHECK(!(urng != urng2)); // operator!= - urng(); - urng2 = urng; // copy assignment - BOOST_CHECK(urng == urng2); - urng2 = URNG(urng2); // copy constructor, not templated constructor - BOOST_CHECK(urng == urng2); -#endif // BOOST_MSVC - - const std::vector v(9999u, 0x41); - std::vector::const_iterator it = v.begin(); - std::vector::const_iterator it_end = v.end(); - URNG urng3(it, it_end); - BOOST_CHECK(it != v.begin()); - std::iterator_traits::const_iterator>::difference_type n_words = (it - v.begin()); - std::cout << "; seeding uses " << n_words << " words" << std::endl; - - it = v.end(); - BOOST_CHECK_THROW(urng3.seed(it, it_end), std::invalid_argument); - - if(n_words > 1) { - it = v.end(); - --it; - BOOST_CHECK_THROW(urng3.seed(it, it_end), std::invalid_argument); - } - - // check for min/max members - ResultType min = (urng3.min)(); - (void) &min; - ResultType max = (urng3.max)(); - (void) &max; - -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - // Streamable concept not supported for broken compilers - - std::cout << "Testing stream operators" << std::endl; - - // advance a little so that state is relatively arbitrary - for(int i = 0; i < 9307; ++i) - urng(); - urng2 = urng; - - { - // narrow stream first - std::ostringstream file; - file << urng; - // move forward - urng(); - // restore old state - std::istringstream input(file.str()); - input >> urng; - // std::cout << file.str() << std::endl; -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - // advance some more so that state is exercised - for(int i = 0; i < 10000; ++i) { - urng(); - urng2(); - } - BOOST_CHECK(urng == urng2); -#endif // BOOST_MSVC - } - - urng2 = urng; -#if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING) - { - // then wide stream - std::wostringstream file; - file << urng; - // move forward - urng(); - std::wistringstream input(file.str()); - input >> urng; -#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // MSVC brokenness - // advance some more so that state is exercised - for(int i = 0; i < 10000; ++i) { - urng(); - urng2(); - } - BOOST_CHECK(urng == urng2); -#endif // BOOST_MSVC - } -#endif // BOOST_NO_STD_WSTREAMBUF, BOOST_NO_STD_WSTRING -#endif // BOOST_RANDOM_NO_STREAM_OPERATORS - - // instantiate various distributions with this URNG - instantiate_dist(urng, "uniform_smallint", boost::uniform_smallint<>(0, 11)); - instantiate_dist(urng, "uniform_int", boost::uniform_int<>(-200, 20000)); - instantiate_dist(urng, "bernoulli_distribution", - boost::bernoulli_distribution<>(0.2)); - instantiate_dist(urng, "binomial_distribution", - boost::binomial_distribution<>(4, 0.2)); - instantiate_dist(urng, "geometric_distribution", - boost::geometric_distribution<>(0.8)); - instantiate_dist(urng, "poisson_distribution", - boost::poisson_distribution<>(1)); - - instantiate_real_dist(urng, 1.0f); - instantiate_real_dist(urng, 1.0); - instantiate_real_dist(urng, 1.0l); - -#if 0 - // We cannot compare the outcomes before/after save with std::abs(x-y) - instantiate_dist("uniform_on_sphere", - boost::uniform_on_sphere(urng, 2)); -#endif -} - -template -void extra_tests(T*) -{ -} - -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -void extra_tests(boost::rand48*) -{ - using namespace boost; - rand48 rnd(boost::int32_t(5)); - rand48 rnd2(boost::uint64_t(0x80000000) * 42); - rnd.seed(boost::int32_t(17)); - rnd2.seed(boost::uint64_t(0x80000000) * 49); -} -#endif - -void extra_tests(boost::minstd_rand*) -{ - using namespace boost; - minstd_rand mstd(42); - mstd.seed(17); -} - -void extra_tests(boost::mt19937*) -{ - using namespace boost; - minstd_rand mstd(42); - mstd.seed(17); - - mt19937 mt(boost::uint32_t(17)); // needs to be an exact type match for MSVC - int i = 42; - mt.seed(boost::uint32_t(i)); - mt19937 mt2(mstd); - mt2.seed(mstd); - - random_number_generator std_rng(mt2); - (void) std_rng(10); -} - -void instantiate_all() -{ - using namespace boost; - - typedef boost::random::lagged_fibonacci lagged_fibonacci; - - typedef BOOST_RANDOM_URNG_TEST::result_type result_type; - instantiate_urng(BOOST_PP_STRINGIZE(BOOST_RANDOM_URNG_TEST), BOOST_RANDOM_URNG_TEST(), static_cast(0)); - BOOST_RANDOM_URNG_TEST* type_ptr = 0; - extra_tests(type_ptr); - -} - - -#if defined(BOOST_MSVC) && _MSC_VER < 1300 - -// These explicit instantiations are necessary, otherwise MSVC does -// not find the inline friends. -// We ease the typing with a suitable preprocessor macro. -#define INSTANT(x) \ -template class boost::uniform_smallint; \ -template class boost::uniform_int; \ -template class boost::uniform_real; \ -template class boost::bernoulli_distribution; \ -template class boost::geometric_distribution; \ -template class boost::triangle_distribution; \ -template class boost::exponential_distribution; \ -template class boost::normal_distribution; \ -template class boost::uniform_on_sphere; \ -template class boost::lognormal_distribution; - -INSTANT(boost::minstd_rand0) -INSTANT(boost::minstd_rand) -INSTANT(boost::ecuyer1988) -INSTANT(boost::kreutzer1986) -INSTANT(boost::hellekalek1995) -INSTANT(boost::mt19937) -INSTANT(boost::mt11213b) - -#undef INSTANT -#endif - - -int test_main(int, char*[]) -{ - instantiate_all(); - return 0; -} diff --git a/test/random_test.cpp b/test/random_test.cpp deleted file mode 100644 index b6a8887..0000000 --- a/test/random_test.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* boost random_test.cpp various tests - * - * 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$ - */ - -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::abs; using ::fabs; using ::pow; } -#endif - - -/* - * General portability note: - * MSVC mis-compiles explicit function template instantiations. - * For example, f() and f() are both compiled to call f(). - * 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. - */ - -/* - * A few equidistribution tests - */ - -// yet to come... - -template -void check_uniform_int(Generator & gen, int iter) -{ - std::cout << "testing uniform_int(" << (gen.min)() << "," << (gen.max)() - << ")" << std::endl; - int range = (gen.max)()-(gen.min)()+1; - std::vector bucket(range); - for(int j = 0; j < iter; j++) { - int result = gen(); - if(result < (gen.min)() || result > (gen.max)()) - std::cerr << " ... delivers " << result << std::endl; - else - bucket[result-(gen.min)()]++; - } - int sum = 0; - // use a different variable name "k", because MSVC has broken "for" scoping - for(int k = 0; k < range; k++) - sum += bucket[k]; - double avg = static_cast(sum)/range; - double p = 1 / static_cast(range); - double threshold = 2*std::sqrt(static_cast(iter)*p*(1-p)); - for(int i = 0; i < range; i++) { - if(std::fabs(bucket[i] - avg) > threshold) { - // 95% confidence interval - std::cout << " ... has bucket[" << i << "] = " << bucket[i] - << " (distance " << (bucket[i] - avg) << ")" - << std::endl; - } - } -} - -template -void test_uniform_int(Generator & gen) -{ - typedef boost::uniform_int int_gen; - - // large range => small range (modulo case) - typedef boost::variate_generator 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::variate_generator 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::variate_generator level_three; - level_three uint1_4(uint05, int_gen(1, 4)); - check_uniform_int(uint1_4, 100000); - - typedef boost::uniform_int int8_gen; - typedef boost::variate_generator 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::variate_generator 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::variate_generator uniform_uint_from8; - uniform_uint_from8 uint0300(gen8_03, int_gen(0, 300)); - check_uniform_int(uint0300, 100000); -} - -#if defined(BOOST_MSVC) && _MSC_VER < 1300 - -// These explicit instantiations are necessary, otherwise MSVC does -// not find the inline friends. -// We ease the typing with a suitable preprocessor macro. -#define INSTANT(x) \ -template class boost::uniform_smallint; \ -template class boost::uniform_int; \ -template class boost::uniform_real; \ -template class boost::bernoulli_distribution; \ -template class boost::geometric_distribution; \ -template class boost::triangle_distribution; \ -template class boost::exponential_distribution; \ -template class boost::normal_distribution; \ -template class boost::uniform_on_sphere; \ -template class boost::lognormal_distribution; - -INSTANT(boost::minstd_rand0) -INSTANT(boost::minstd_rand) -INSTANT(boost::ecuyer1988) -INSTANT(boost::kreutzer1986) -INSTANT(boost::hellekalek1995) -INSTANT(boost::mt19937) -INSTANT(boost::mt11213b) - -#undef INSTANT -#endif - -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -// testcase by Mario 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::max BOOST_PREVENT_MACRO_SUBSTITUTION (); } - result_type operator()() { return state--; } -private: - result_type state; -}; - -void test_overflow_range() -{ - ruetti_gen gen; - boost::variate_generator > - rng(gen, boost::uniform_int<>(0, 10)); - for (int i=0;i<10;i++) - (void) rng(); -} -#else -void test_overflow_range() -{ } -#endif - -template -struct rand_for_random_shuffle -{ - explicit rand_for_random_shuffle(EngineT &engine) - : m_engine(engine) - { } - - template - IntT operator()(IntT upperBound) - { - assert(upperBound > 0); - - if (upperBound == 1) - { - return 0; - } - - typedef boost::uniform_int distribution_type; - typedef boost::variate_generator generator_type; - - return generator_type(m_engine, distribution_type(0, upperBound - 1))(); - } - - EngineT &m_engine; - -}; - -// Test that uniform_int<> can be used with std::random_shuffle -// Author: Jos Hickson -void test_random_shuffle() -{ - typedef boost::uniform_int<> distribution_type; - typedef boost::variate_generator generator_type; - - boost::mt19937 engine1(1234); - boost::mt19937 engine2(1234); - - rand_for_random_shuffle referenceRand(engine1); - - distribution_type dist(0,10); - generator_type testRand(engine2, dist); - - std::vector referenceVec; - - for (int i = 0; i < 200; ++i) - { - referenceVec.push_back(i); - } - - std::vector testVec(referenceVec); - - std::random_shuffle(referenceVec.begin(), referenceVec.end(), referenceRand); - std::random_shuffle(testVec.begin(), testVec.end(), testRand); - - typedef std::vector::iterator iter_type; - iter_type theEnd(referenceVec.end()); - - for (iter_type referenceIter(referenceVec.begin()), testIter(testVec.begin()); - referenceIter != theEnd; - ++referenceIter, ++testIter) - { - BOOST_CHECK_EQUAL(*referenceIter, *testIter); - } -} - - -int test_main(int, char*[]) -{ - -#if !defined(__INTEL_COMPILER) || !defined(_MSC_VER) || __INTEL_COMPILER > 700 - boost::mt19937 mt; - test_uniform_int(mt); - - // bug report from Ken Mahler: This used to lead to an endless loop. - typedef boost::uniform_int uint_dist; - boost::minstd_rand mr; - boost::variate_generator 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 > x(mr, boost::uniform_int<>(0, 8361)); - (void) x(); - - // bug report from Alan Stokes and others: this throws an assertion - boost::variate_generator > y(mr, boost::uniform_int<>(1,1)); - std::cout << "uniform_int(1,1) " << y() << ", " << y() << ", " << y() - << std::endl; - - test_overflow_range(); - test_random_shuffle(); - - return 0; -#else - std::cout << "Intel 7.00 on Win32 loops, so the test is disabled\n"; - return 1; -#endif -} diff --git a/test/statistic_tests.hpp b/test/statistic_tests.hpp index 1f09ccb..aad6ca4 100644 --- a/test/statistic_tests.hpp +++ b/test/statistic_tests.hpp @@ -19,9 +19,10 @@ #include #include -#include #include #include +#include +#include #include "integrate.hpp" @@ -93,7 +94,7 @@ public: for(int i = 0; i < n; ++i) count(f()); } - double probability(int i) const { return 1.0/classes(); } + double probability(int /*i*/) const { return 1.0/classes(); } }; // two-dimensional equidistribution experiment @@ -344,10 +345,12 @@ public: double probability(unsigned int r) const { if(r == classes()-1) - return 1-fac(d)/std::pow(d, static_cast(d+classes()-2))* + return 1-fac(d)/ + std::pow(static_cast(d), static_cast(d+classes()-2)) * stirling2(d+classes()-2, d); else - return fac(d)/std::pow(d, static_cast(d+r)) * + return fac(d)/ + std::pow(static_cast(d), static_cast(d+r)) * stirling2(d+r-1, d-1); } private: diff --git a/test/test_bernoulli.cpp b/test/test_bernoulli.cpp new file mode 100644 index 0000000..cab0c1c --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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 -t " << std::endl; + return 2; +} + +template +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast(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/test/test_bernoulli_distribution.cpp b/test/test_bernoulli_distribution.cpp new file mode 100644 index 0000000..ca021ce --- /dev/null +++ b/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$ + * + */ + +#include + +#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/test/test_binomial.cpp b/test/test_binomial.cpp new file mode 100644 index 0000000..51e707a --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include + +#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/test/test_binomial_distribution.cpp b/test/test_binomial_distribution.cpp new file mode 100644 index 0000000..47e80d6 --- /dev/null +++ b/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$ + * + */ + +#include + +#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/test/test_cauchy.cpp b/test/test_cauchy.cpp new file mode 100644 index 0000000..14c27d9 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_cauchy_distribution.cpp b/test/test_cauchy_distribution.cpp new file mode 100644 index 0000000..845ac7c --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_chi_squared.cpp b/test/test_chi_squared.cpp new file mode 100644 index 0000000..c315765 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_chi_squared_distribution.cpp b/test/test_chi_squared_distribution.cpp new file mode 100644 index 0000000..1df9f7e --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_const_mod.cpp b/test/test_const_mod.cpp new file mode 100644 index 0000000..5d18eba --- /dev/null +++ b/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$ + * + */ + +#include + +#include +#include + +#define BOOST_TEST_MAIN +#include + +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::mult(IntType(i), IntType(j))), i * j % 127); + } + } + int modulus = (std::numeric_limits::max)() + 1; + for(int i = 0; i < modulus; ++i) { + for(int j = 0; j < modulus; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod::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::add(IntType(i), IntType(j))), (i + j) % 127); + } + } + { + const int modulus = boost::integer_traits::const_max; + for(int i = 0; i < modulus; ++i) { + for(int j = 0; j < modulus; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod::add(IntType(i), IntType(j))), (i + j) % modulus); + } + } + } + { + int modulus = (std::numeric_limits::max)() + 1; + for(int i = 0; i < modulus; ++i) { + for(int j = 0; j < modulus; ++j) { + BOOST_CHECK_EQUAL((boost::random::const_mod::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::mult_add(IntType(i), IntType(j), IntType(k))), (i * j + k) % 127); + } + } + } + { + int modulus = (std::numeric_limits::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::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::invert(IntType(i)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult(IntType(i), inverse)), 1); + } + int modulus = (std::numeric_limits::max)() + 1; + for(int i = 1; i < modulus; i += 2) { + IntType inverse = boost::random::const_mod::invert(IntType(i)); + BOOST_CHECK_EQUAL((boost::random::const_mod::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::mult(0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult(0, 2147483562)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult(2147483562, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult(2147483562, 2147483562)), IntType(1)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult(1234567890, 1234657890)), IntType(813106682)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_add32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod::add(0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::add(0, 2147483562)), IntType(2147483562)); + BOOST_CHECK_EQUAL((boost::random::const_mod::add(2147483562, 0)), IntType(2147483562)); + BOOST_CHECK_EQUAL((boost::random::const_mod::add(2147483562, 2147483562)), IntType(2147483561)); + BOOST_CHECK_EQUAL((boost::random::const_mod::add(1234567890, 1234657890)), IntType(321742217)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_mult_add32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod::mult_add(0, 0, 0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult_add(0, 2147483562, 827364)), IntType(827364)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult_add(2147483562, 0, 827364)), IntType(827364)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult_add(2147483562, 2147483562, 2147483562)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult_add(1234567890, 1234657890, 1726384759)), IntType(392007878)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_invert32, IntType, int32_types) { + BOOST_CHECK_EQUAL((boost::random::const_mod::invert(0)), IntType(0)); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult_add(0, 0, 0)), IntType(0)); + IntType inverse; + inverse = boost::random::const_mod::invert(2147483562); + BOOST_CHECK_EQUAL((boost::random::const_mod::mult(2147483562, inverse)), IntType(1)); + inverse = boost::random::const_mod::invert(1234567890); + BOOST_CHECK_EQUAL((boost::random::const_mod::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 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 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 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 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/test/test_discrete.cpp b/test/test_discrete.cpp new file mode 100644 index 0000000..6a6d378 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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::iterator iter = expected.begin(), end = expected.end(); iter != end; ++iter) { + *iter /= sum; + } + } + + boost::random::discrete_distribution<> dist(expected); + boost::mt19937 gen; + std::vector 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 -n -t " << std::endl; + return 2; +} + +template +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast(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/test/test_discrete_distribution.cpp b/test/test_discrete_distribution.cpp new file mode 100644 index 0000000..cbe3029 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include + +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 _actual = (actual); \ + std::vector _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 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 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 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 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 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 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/test/test_distribution.ipp b/test/test_distribution.ipp new file mode 100644 index 0000000..69f17d9 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include + +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/test/test_ecuyer1988.cpp b/test/test_ecuyer1988.cpp new file mode 100644 index 0000000..19cd1e5 --- /dev/null +++ b/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$ + * + */ + +#include + +#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 1416886025U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 776923198U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x7AE0C087U, 0x948A8A31U, 0xBE5CCBA9U, 0x1316692CU } + +#include "test_generator.ipp" diff --git a/test/test_exponential.cpp b/test/test_exponential.cpp new file mode 100644 index 0000000..8a50840 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_exponential_distribution.cpp b/test/test_exponential_distribution.cpp new file mode 100644 index 0000000..169aab5 --- /dev/null +++ b/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$ + * + */ + +#include + +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::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/test/test_extreme_value.cpp b/test/test_extreme_value.cpp new file mode 100644 index 0000000..8df079c --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_extreme_value_distribution.cpp b/test/test_extreme_value_distribution.cpp new file mode 100644 index 0000000..fc9642c --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_fisher_f.cpp b/test/test_fisher_f.cpp new file mode 100644 index 0000000..24abb5a --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_fisher_f_distribution.cpp b/test/test_fisher_f_distribution.cpp new file mode 100644 index 0000000..4eaa96c --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0.0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0.0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_gamma.cpp b/test/test_gamma.cpp new file mode 100644 index 0000000..cbbc351 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_gamma_distribution.cpp b/test/test_gamma_distribution.cpp new file mode 100644 index 0000000..2e9696f --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_generate_canonical.cpp b/test/test_generate_canonical.cpp new file mode 100644 index 0000000..b10bf48 --- /dev/null +++ b/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$ + * + */ + +#include + +#include +#include +#include +#include + +#define BOOST_TEST_MAIN +#include + +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(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(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(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(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(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(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(eng)), 1); + BOOST_CHECK_LT((boost::random::generate_canonical(eng)), 1); + BOOST_CHECK_LT((boost::random::generate_canonical(eng)), 1); +} diff --git a/test/test_generator.ipp b/test/test_generator.ipp new file mode 100644 index 0000000..16c7b0b --- /dev/null +++ b/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$ + * + */ + +#include "concepts.hpp" +#include + +#define BOOST_TEST_MAIN +#include + +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::type seed_type; + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#endif + +template +void test_seed_conversion(URNG & urng, const T & t) +{ + Converted c = static_cast(t); + if(static_cast(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(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); +#if !defined(BOOST_NO_INT64_T) + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); +#endif + + // floating point types + test_seed_conversion(urng, value); + test_seed_conversion(urng, value); + test_seed_conversion(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(0)); + test_seed(static_cast(127)); + test_seed(static_cast(539157235)); + test_seed(static_cast(~0u)); +} + +BOOST_AUTO_TEST_CASE(test_iterator_seed) +{ + const std::vector v((std::max)(std::size_t(9999u), sizeof(BOOST_RANDOM_URNG) / 4), 0x41); + std::vector::const_iterator it = v.begin(); + std::vector::const_iterator it_end = v.end(); + BOOST_RANDOM_URNG urng(it, it_end); + BOOST_CHECK(it != v.begin()); + std::iterator_traits::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::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 +void do_test_streaming(const BOOST_RANDOM_URNG& urng) +{ + BOOST_RANDOM_URNG urng2; + std::basic_ostringstream output; + output << urng; + BOOST_CHECK_NE(urng, urng2); + // restore old state + std::basic_istringstream 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(urng); +#if !defined(BOOST_NO_STD_WSTREAMBUF) && !defined(BOOST_NO_STD_WSTRING) + do_test_streaming(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 v((std::max)(std::size_t(9999u), sizeof(BOOST_RANDOM_URNG) / 4), 0x41); + std::vector::const_iterator it = v.begin(); + std::vector::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/test/test_geometric.cpp b/test/test_geometric.cpp new file mode 100644 index 0000000..bd61dd4 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include + +#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(-5 / std::log(1-p)) + +#include "test_real_distribution.ipp" diff --git a/test/test_geometric_distribution.cpp b/test/test_geometric_distribution.cpp new file mode 100644 index 0000000..06b5a8d --- /dev/null +++ b/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$ + * + */ + +#include + +#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 1 +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits::max)() +#define BOOST_RANDOM_DIST1_MIN 1 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::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/test/test_hellekalek1995.cpp b/test/test_hellekalek1995.cpp new file mode 100644 index 0000000..1388397 --- /dev/null +++ b/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$ + * + */ + +#include + +#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 1081665111U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 618743552U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x5642A47BU, 0x1F6987E8U, 0xD35860E7U, 0xC8C661ABU } + +#include "test_generator.ipp" diff --git a/test/test_independent_bits31.cpp b/test/test_independent_bits31.cpp new file mode 100644 index 0000000..0c38f8a --- /dev/null +++ b/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$ + * + */ + +#include +#include + +typedef boost::random::independent_bits_engine 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 1147343739U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 1399154219U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC1A63AF0U, 0xD66C0614U, 0xADE076B1U, 0xC1DAE13FU } + +#include "test_generator.ipp" diff --git a/test/test_independent_bits32.cpp b/test/test_independent_bits32.cpp new file mode 100644 index 0000000..e5410dc --- /dev/null +++ b/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$ + * + */ + +#include +#include + +typedef boost::random::independent_bits_engine 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 3107690757U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3408548740U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xD091BB5CU, 0x22AE9EF6U, 0xE7E1FAEEU, 0xD5C31F79U } + +#include "test_generator.ipp" diff --git a/test/test_knuth_b.cpp b/test/test_knuth_b.cpp new file mode 100644 index 0000000..dcbcf38 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 160100893U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 1692601883U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x5D189C63U, 0xD0544F0EU, 0x15B0E78FU, 0xD814D654U } + +#include "test_generator.ipp" diff --git a/test/test_kreutzer1986.cpp b/test/test_kreutzer1986.cpp new file mode 100644 index 0000000..9401fe5 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 227233U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 163138U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x3EADAB08U, 0x85E481CEU, 0xCF84AEA5U, 0x39D4395BU } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci.cpp b/test/test_lagged_fibonacci.cpp new file mode 100644 index 0000000..25f8762 --- /dev/null +++ b/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$ + * + */ + +#include + +typedef boost::random::lagged_fibonacci_engine 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 7852929U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 4372778U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xF61A5094U, 0xFC4BA046U, 0xF1C41E92U, 0x3D82FE61U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci1279.cpp b/test/test_lagged_fibonacci1279.cpp new file mode 100644 index 0000000..b7bbba7 --- /dev/null +++ b/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$ + * + */ + +#include + +#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.37536953918742455 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.56042480761195179 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x4D102C47U, 0xC4E610D7U, 0xF29333BEU, 0x6E45EBE7U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci19937.cpp b/test/test_lagged_fibonacci19937.cpp new file mode 100644 index 0000000..c95972e --- /dev/null +++ b/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$ + * + */ + +#include + +#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.48319870930434661 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0029754638678802792 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x5CE9850CU, 0xAA20067BU, 0x4E48643BU, 0xA4A59F4BU } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci2281.cpp b/test/test_lagged_fibonacci2281.cpp new file mode 100644 index 0000000..39f5de8 --- /dev/null +++ b/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$ + * + */ + +#include + +#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.58796187519502041 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.087280273457821522 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x7EB0882AU, 0xCE09BE60U, 0xD53046CFU, 0x93257E41U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci23209.cpp b/test/test_lagged_fibonacci23209.cpp new file mode 100644 index 0000000..08f2cfa --- /dev/null +++ b/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$ + * + */ + +#include + +#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.59787206924233871 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0019836425785868528 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x4301DE0AU, 0xAD2584E3U, 0x7C28463CU, 0x74848542U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci3217.cpp b/test/test_lagged_fibonacci3217.cpp new file mode 100644 index 0000000..d2b52ce --- /dev/null +++ b/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$ + * + */ + +#include + +#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.51719299526538975 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.1805114746514036 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x4938F127U, 0x86C65CFEU, 0x65356579U, 0xA6CDC325U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci4423.cpp b/test/test_lagged_fibonacci4423.cpp new file mode 100644 index 0000000..98a93f0 --- /dev/null +++ b/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$ + * + */ + +#include + +#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.51262293730517783 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.012893676760814543 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x6D4DBAFU, 0x8039C1A9U, 0x3DA53D58U, 0x95155BE5U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci44497.cpp b/test/test_lagged_fibonacci44497.cpp new file mode 100644 index 0000000..4447773 --- /dev/null +++ b/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$ + * + */ + +#include + +#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.63574754742431594 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0019836425785868528 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x6A2DCEA9U, 0x4668EFB4U, 0x711E352FU, 0xA963C43BU } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci607.cpp b/test/test_lagged_fibonacci607.cpp new file mode 100644 index 0000000..393f49a --- /dev/null +++ b/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$ + * + */ + +#include + +#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.73011070026216984 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.72330291632639643 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x78EB0905U, 0x61766547U, 0xCB507F64U, 0x94FA3EC0U } + +#include "test_generator.ipp" diff --git a/test/test_lagged_fibonacci9689.cpp b/test/test_lagged_fibonacci9689.cpp new file mode 100644 index 0000000..af185ff --- /dev/null +++ b/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$ + * + */ + +#include + +#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.84199156986666068 +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 0.0039672851571737056 + +#define BOOST_RANDOM_GENERATE_VALUES { 0x32EF18BEU, 0x79277C11U, 0xA383438U, 0x32155952U } + +#include "test_generator.ipp" diff --git a/test/test_linear_feedback_shift.cpp b/test/test_linear_feedback_shift.cpp new file mode 100644 index 0000000..b0f0e98 --- /dev/null +++ b/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$ + * + */ + +#include + +typedef boost::random::linear_feedback_shift_engine 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 554836316U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3112279337U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x154005U, 0x54005502U, 0x5502BD4U, 0x2BD4005U } + +#include "test_generator.ipp" diff --git a/test/test_lognormal.cpp b/test/test_lognormal.cpp new file mode 100644 index 0000000..24cbe13 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_lognormal_distribution.cpp b/test/test_lognormal_distribution.cpp new file mode 100644 index 0000000..707d355 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0.0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0.0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_minstd_rand.cpp b/test/test_minstd_rand.cpp new file mode 100644 index 0000000..6fed691 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 2096435890U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 182651141U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x8400BC8EU, 0xF45B895FU, 0x145F0F91U, 0xE5F8F088U } + +#include "test_generator.ipp" diff --git a/test/test_minstd_rand0.cpp b/test/test_minstd_rand0.cpp new file mode 100644 index 0000000..bc5dc52 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 849515105U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 1263181168U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xC00041A6U, 0xCD8358EBU, 0x430A4B7AU, 0x31B781ADU } + +#include "test_generator.ipp" diff --git a/test/test_mt11213b.cpp b/test/test_mt11213b.cpp new file mode 100644 index 0000000..c9574de --- /dev/null +++ b/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$ + * + */ + +#include + +#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 770080327U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 2434563197U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xEF3F3F3FU, 0x70082175U, 0xDAF6EAF5U, 0x2A16A63EU } + +#include "test_generator.ipp" diff --git a/test/test_mt19937.cpp b/test/test_mt19937.cpp new file mode 100644 index 0000000..b2836c8 --- /dev/null +++ b/test/test_mt19937.cpp @@ -0,0 +1,25 @@ +/* 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$ + * + */ + +#include + +#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 3107690757U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3408548740U + +#define BOOST_RANDOM_GENERATE_VALUES { 0xD091BB5CU, 0x22AE9EF6U, 0xE7E1FAEEU, 0xD5C31F79U } + +#include "test_generator.ipp" diff --git a/test/test_mt19937_64.cpp b/test/test_mt19937_64.cpp new file mode 100644 index 0000000..937e557 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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(10059787671936601387) +#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/test/test_negative_binomial.cpp b/test/test_negative_binomial.cpp new file mode 100644 index 0000000..e296861 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include + +#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/test/test_negative_binomial_distribution.cpp b/test/test_negative_binomial_distribution.cpp new file mode 100644 index 0000000..c6cd6c9 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::max)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::max)() +#define BOOST_RANDOM_DIST2_MIN 0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_normal.cpp b/test/test_normal.cpp new file mode 100644 index 0000000..e7bbb30 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_normal_distribution.cpp b/test/test_normal_distribution.cpp new file mode 100644 index 0000000..47c8842 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/test_old_uniform_int.cpp b/test/test_old_uniform_int.cpp new file mode 100644 index 0000000..442f22f --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_old_uniform_int_distribution.cpp b/test/test_old_uniform_int_distribution.cpp new file mode 100644 index 0000000..f033ad0 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 +#include + +// 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 generator_type; + + boost::mt19937 engine1(1234); + boost::mt19937 engine2(1234); + + boost::random::random_number_generator referenceRand(engine1); + + distribution_type dist(0,10); + generator_type testRand(engine2, dist); + + std::vector referenceVec; + + for (int i = 0; i < 200; ++i) { + referenceVec.push_back(i); + } + + std::vector 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/test/test_old_uniform_real.cpp b/test/test_old_uniform_real.cpp new file mode 100644 index 0000000..7c65e88 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_old_uniform_real_distribution.cpp b/test/test_old_uniform_real_distribution.cpp new file mode 100644 index 0000000..1728fb3 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_piecewise_constant.cpp b/test/test_piecewise_constant.cpp new file mode 100644 index 0000000..8261def --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "statistic_tests.hpp" + +class piecewise_constant +{ +public: + piecewise_constant(const std::vector& intervals, const std::vector& weights) + : intervals(intervals), + cumulative(1, 0.0) + { + boost::partial_sum(weights, std::back_inserter(cumulative)); + for(std::vector::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 intervals; + std::vector 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 weights; + { + boost::mt19937 egen; + for(int i = 0; i < n; ++i) { + weights.push_back(egen()); + } + } + std::vector 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 > 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 -n -t " << std::endl; + return 2; +} + +template +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast(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/test/test_piecewise_constant_distribution.cpp b/test/test_piecewise_constant_distribution.cpp new file mode 100644 index 0000000..9c2dddd --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include + +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 _actual = (actual); \ + std::vector _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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector weights = boost::assign::list_of(1)(2)(1)(4); + std::vector intervals2 = boost::assign::list_of(99); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector weights = boost::assign::list_of(1)(2)(1)(4); + std::vector intervals2 = boost::assign::list_of(0); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector 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 intervals = boost::assign::list_of(1)(2); + std::vector 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/test/test_piecewise_linear.cpp b/test/test_piecewise_linear.cpp new file mode 100644 index 0000000..4a03c5f --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "statistic_tests.hpp" + +class piecewise_linear +{ +public: + piecewise_linear(const std::vector& intervals, const std::vector& 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::iterator iter = cumulative.begin(), end = cumulative.end(); + iter != end; ++iter) + { + *iter /= sum; + } + for(std::vector::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 intervals; + std::vector weights; + std::vector 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 weights; + { + boost::mt19937 egen; + for(int i = 0; i < n; ++i) { + weights.push_back(egen()); + } + } + std::vector 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 > 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 -n -t " << std::endl; + return 2; +} + +template +bool handle_option(int& argc, char**& argv, char opt, T& value) { + if(argv[0][1] == opt && argc > 1) { + --argc; + ++argv; + value = boost::lexical_cast(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/test/test_piecewise_linear_distribution.cpp b/test/test_piecewise_linear_distribution.cpp new file mode 100644 index 0000000..ea2f965 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include +#include +#include +#include "concepts.hpp" + +#define BOOST_TEST_MAIN +#include + +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 _actual = (actual); \ + std::vector _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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector weights = boost::assign::list_of(3)(1)(2)(1)(2); + std::vector intervals2 = boost::assign::list_of(99); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector weights = boost::assign::list_of(3)(1)(2)(1)(2); + std::vector intervals2 = boost::assign::list_of(99); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector 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 intervals = boost::assign::list_of(0)(1)(2)(3)(5); + std::vector 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 intervals = boost::assign::list_of(1)(2); + std::vector 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/test/test_poisson.cpp b/test/test_poisson.cpp new file mode 100644 index 0000000..519bf7e --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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(mean * 4) + +#include "test_real_distribution.ipp" diff --git a/test/test_poisson_distribution.cpp b/test/test_poisson_distribution.cpp new file mode 100644 index 0000000..a2cb5ae --- /dev/null +++ b/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$ + * + */ + +#include + +#include + +#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::max)() +#define BOOST_RANDOM_DIST1_MIN 0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::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/test/test_rand48.cpp b/test/test_rand48.cpp new file mode 100644 index 0000000..2a61b40 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 1127873718U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 839037874U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55424A4U, 0x3A2CCEF5U, 0x6ADB4A65U, 0x2B019719U } + +#include "test_generator.ipp" diff --git a/test/test_random_device.cpp b/test/test_random_device.cpp index 20363b5..2f9e61c 100644 --- a/test/test_random_device.cpp +++ b/test/test_random_device.cpp @@ -8,19 +8,22 @@ * $Id$ */ -#include +#include #include #include -int test_main(int argc, char** argv) { - 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)()); - } - return 0; +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/test/test_random_number_generator.cpp b/test/test_random_number_generator.cpp new file mode 100644 index 0000000..39c3e24 --- /dev/null +++ b/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$ + */ + +#include +#include + +#include +#include + +#define BOOST_TEST_MAIN +#include + +BOOST_AUTO_TEST_CASE(test_random_shuffle) +{ + boost::mt19937 engine(1234); + boost::random::random_number_generator generator(engine); + + std::vector testVec; + + for (int i = 0; i < 200; ++i) { + testVec.push_back(i); + } + + std::random_shuffle(testVec.begin(), testVec.end(), generator); +} diff --git a/test/test_ranlux24.cpp b/test/test_ranlux24.cpp new file mode 100644 index 0000000..cb3bdeb --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 4870344U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3888733U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/test/test_ranlux24_base.cpp b/test/test_ranlux24_base.cpp new file mode 100644 index 0000000..e5cea03 --- /dev/null +++ b/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$ + * + */ + +#include + +#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 836370U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 7739608U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/test/test_ranlux3.cpp b/test/test_ranlux3.cpp new file mode 100644 index 0000000..c9c5cb6 --- /dev/null +++ b/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$ + * + */ + +#include + +#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 1848500U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 11620328U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/test/test_ranlux3_01.cpp b/test/test_ranlux3_01.cpp new file mode 100644 index 0000000..7cce77a --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 1848500/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/test/test_ranlux4.cpp b/test/test_ranlux4.cpp new file mode 100644 index 0000000..8daacb7 --- /dev/null +++ b/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$ + * + */ + +#include + +#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 6375782U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 4515722U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x55E57B2CU, 0xF2DEF915U, 0x6D1A0CD9U, 0xCA0109F9U } + +#include "test_generator.ipp" diff --git a/test/test_ranlux48.cpp b/test/test_ranlux48.cpp new file mode 100644 index 0000000..846b520 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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(93216637457044) +#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/test/test_ranlux48_base.cpp b/test/test_ranlux48_base.cpp new file mode 100644 index 0000000..c9a3aca --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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(107228250000854) +#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/test/test_ranlux4_01.cpp b/test/test_ranlux4_01.cpp new file mode 100644 index 0000000..5335242 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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 6375782/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/test/test_ranlux64_3.cpp b/test/test_ranlux64_3.cpp new file mode 100644 index 0000000..240d642 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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(97179253367494) +#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/test/test_ranlux64_3_01.cpp b/test/test_ranlux64_3_01.cpp new file mode 100644 index 0000000..f3c9eab --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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(97179253367494)/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/test/test_ranlux64_4.cpp b/test/test_ranlux64_4.cpp new file mode 100644 index 0000000..667659e --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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(63570328604787) +#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/test/test_ranlux64_4_01.cpp b/test/test_ranlux64_4_01.cpp new file mode 100644 index 0000000..cd38a3d --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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(63570328604787)/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/test/test_real_distribution.ipp b/test/test_real_distribution.ipp new file mode 100644 index 0000000..4780939 --- /dev/null +++ b/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$ + * + */ + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 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 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(max)); + boost::variate_generator 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 +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 " + " -" BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG1_NAME) + " " +#ifdef BOOST_RANDOM_ARG2_NAME + " -" BOOST_PP_STRINGIZE(BOOST_RANDOM_ARG2_NAME) + " " +#endif + " -t " << std::endl; + return 2; +} + +template +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(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/test/test_seed_seq.cpp b/test/test_seed_seq.cpp new file mode 100644 index 0000000..79a0e1a --- /dev/null +++ b/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$ + */ + +#include +#include +#include +#include + +#define BOOST_TEST_MAIN +#include + +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] = { + 2571534471u, + 852093106u, + 3994144234u, + 904246505u, + 3404579686u, + 1508446734u, + 3679033230u, + 2550178480u, + 4205639301u, + 268720383u + }; + 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] = { + 249299179u, + 1602610063u, + 745496312u, + 3444440002u, + 1462959439u, + 4120764957u, + 2551678045u, + 2909251680u, + 3652199668u, + 1330108271u + }; + + std::vector 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/test/test_student_t.cpp b/test/test_student_t.cpp new file mode 100644 index 0000000..77f8221 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_student_t_distribution.cpp b/test/test_student_t_distribution.cpp new file mode 100644 index 0000000..3602f67 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MIN -(std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() + +#define BOOST_RANDOM_TEST1_PARAMS + +#define BOOST_RANDOM_TEST2_PARAMS (100.0) + +#include "test_distribution.ipp" diff --git a/test/test_taus88.cpp b/test/test_taus88.cpp new file mode 100644 index 0000000..b0e77ba --- /dev/null +++ b/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$ + * + */ + +#include + +#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 2005586065U +#define BOOST_RANDOM_ITERATOR_VALIDATION_VALUE 3762466828U + +#define BOOST_RANDOM_GENERATE_VALUES { 0x2B55504U, 0x5403F102U, 0xED45297EU, 0x6B84007U } + +#include "test_generator.ipp" diff --git a/test/test_triangle.cpp b/test/test_triangle.cpp new file mode 100644 index 0000000..dda1b2f --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_triangle_distribution.cpp b/test/test_triangle_distribution.cpp new file mode 100644 index 0000000..32ded62 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_uniform_int.cpp b/test/test_uniform_int.cpp new file mode 100644 index 0000000..b1ccc07 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_uniform_int.ipp b/test/test_uniform_int.ipp new file mode 100644 index 0000000..fe35c39 --- /dev/null +++ b/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$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chi_squared_test.hpp" + +#define BOOST_TEST_MAIN +#include + +template +void check_uniform_int(Generator & gen, int iter) +{ + int range = (gen.max)()-(gen.min)()+1; + std::vector 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 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_gen; + + // large range => small range (modulo case) + typedef boost::random::variate_generator 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_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_three; + level_three uint1_4(uint05, int_gen(1, 4)); + check_uniform_int(uint1_4, 100000); + + typedef BOOST_RANDOM_UNIFORM_INT int8_gen; + typedef boost::random::variate_generator 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 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 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::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 uint_dist; + boost::minstd_rand mr; + boost::variate_generator 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 x(mr, BOOST_RANDOM_DISTRIBUTION(0, 8361)); + x(); + + // bug report from Alan Stokes and others: this throws an assertion + boost::variate_generator y(mr, BOOST_RANDOM_DISTRIBUTION(1,1)); + y(); + y(); + y(); +} diff --git a/test/test_uniform_int_distribution.cpp b/test/test_uniform_int_distribution.cpp new file mode 100644 index 0000000..5863163 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_uniform_on_sphere_distribution.cpp b/test/test_uniform_on_sphere_distribution.cpp new file mode 100644 index 0000000..872d526 --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#include + +#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 min0 = boost::assign::list_of(-1.0)(0.0); +std::vector max0 = boost::assign::list_of(1.0)(0.0); +std::vector min1 = boost::assign::list_of(-1.0)(0.0)(0.0); +std::vector 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() +#define BOOST_RANDOM_TEST1_MAX std::vector() +#define BOOST_RANDOM_TEST2_PARAMS +#define BOOST_RANDOM_TEST2_MIN min0 +#define BOOST_RANDOM_TEST2_MAX max0 + +#include + +BOOST_TEST_DONT_PRINT_LOG_VALUE( std::vector ) + +#include "test_distribution.ipp" diff --git a/test/test_uniform_real.cpp b/test/test_uniform_real.cpp new file mode 100644 index 0000000..a920fd6 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_uniform_real_distribution.cpp b/test/test_uniform_real_distribution.cpp new file mode 100644 index 0000000..f5a868c --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_uniform_smallint.cpp b/test/test_uniform_smallint.cpp new file mode 100644 index 0000000..4950079 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_uniform_smallint_distribution.cpp b/test/test_uniform_smallint_distribution.cpp new file mode 100644 index 0000000..d943ebf --- /dev/null +++ b/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$ + * + */ + +#include +#include + +#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/test/test_weibull.cpp b/test/test_weibull.cpp new file mode 100644 index 0000000..1319cf0 --- /dev/null +++ b/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$ + * + */ + +#include +#include +#include + +#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/test/test_weibull_distribution.cpp b/test/test_weibull_distribution.cpp new file mode 100644 index 0000000..cd88b6d --- /dev/null +++ b/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$ + * + */ +#include +#include + +#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::infinity)() +#define BOOST_RANDOM_DIST1_MIN 0.0 +#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits::infinity)() +#define BOOST_RANDOM_DIST2_MIN 0.0 +#define BOOST_RANDOM_DIST2_MAX (std::numeric_limits::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/test/validate.cpp b/test/validate.cpp deleted file mode 100644 index 2a38cf2..0000000 --- a/test/validate.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* boost validate.cpp - * - * 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$ - */ - -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::abs; using ::fabs; using ::pow; } -#endif - - -/* - * General portability note: - * MSVC mis-compiles explicit function template instantiations. - * For example, f() and f() are both compiled to call f(). - * BCC is unable to implicitly convert a "const char *" to a std::string - * when using explicit function template instantiations. - * - * Therefore, avoid explicit function template instantiations. - */ - -/* - * Validate correct implementation - */ - -// own run -bool check_(unsigned long x, const boost::mt11213b&) { return x == 3809585648U; } - -// validation by experiment from mt19937.c -bool check_(unsigned long x, const boost::mt19937&) { return x == 4123659995U; } - -// validation values from the publications -bool check_(int x, const boost::minstd_rand0&) { return x == 1043618065; } - -// validation values from the publications -bool check_(int x, const boost::minstd_rand&) { return x == 399268537; } - -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) -// by experiment from lrand48() -bool check_(unsigned long x, const boost::rand48&) { return x == 1993516219; } -#endif - -// ???? -bool check_(unsigned long x, const boost::taus88&) { return x == 3535848941U; } - -// ???? -bool check_(int x, const boost::ecuyer1988&) { return x == 2060321752; } - -// validation by experiment from Harry Erwin's generator.h (private e-mail) -bool check_(unsigned int x, const boost::kreutzer1986&) { return x == 139726; } - -bool check_(double x, const boost::lagged_fibonacci607&) { return std::abs(x-0.401269) < 1e-5; } - -// principal operation validated with CLHEP, values by experiment -bool check_(unsigned long x, const boost::ranlux3&) { return x == 5957620; } -bool check_(unsigned long x, const boost::ranlux4&) { return x == 8587295; } - -bool check_(float x, const boost::ranlux3_01&) -{ return std::abs(x-5957620/std::pow(2.0f,24)) < 1e-6; } -bool check_(float x, const boost::ranlux4_01&) -{ return std::abs(x-8587295/std::pow(2.0f,24)) < 1e-6; } - -bool check_(double x, const boost::ranlux64_3_01&) -{ return std::abs(x-0.838413) < 1e-6; } -bool check_(double x, const boost::ranlux64_4_01&) -{ return std::abs(x-0.59839) < 1e-6; } - -template -void validate(const std::string & name, const PRNG &) -{ - std::cout << "validating " << name << ": "; - PRNG rng; // default ctor - for(int i = 0; i < 9999; i++) - rng(); - typename PRNG::result_type val = rng(); - // make sure the validation function is a static member - bool result = check_(val, rng); - - // allow for a simple eyeball check for MSVC instantiation brokenness - // (if the numbers for all generators are the same, it's obviously broken) - std::cout << val << std::endl; - BOOST_CHECK(result); -} - -void validate_all() -{ - using namespace boost; -#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T) - validate("rand48", rand48()); -#endif - validate("minstd_rand", minstd_rand()); - validate("minstd_rand0", minstd_rand0()); - validate("ecuyer combined", ecuyer1988()); - validate("mt11213b", mt11213b()); - validate("mt19937", mt19937()); - validate("kreutzer1986", kreutzer1986()); - validate("ranlux3", ranlux3()); - validate("ranlux4", ranlux4()); - validate("ranlux3_01", ranlux3_01()); - validate("ranlux4_01", ranlux4_01()); - validate("ranlux64_3_01", ranlux64_3_01()); - validate("ranlux64_4_01", ranlux64_4_01()); - validate("taus88", taus88()); - validate("lagged_fibonacci607", lagged_fibonacci607()); -} - -int test_main(int, char*[]) -{ - validate_all(); - return 0; -}