• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* boost random/normal_distribution.hpp header file
2  *
3  * Copyright Jens Maurer 2000-2001
4  * Copyright Steven Watanabe 2010-2011
5  * Distributed under the Boost Software License, Version 1.0. (See
6  * accompanying file LICENSE_1_0.txt or copy at
7  * http://www.boost.org/LICENSE_1_0.txt)
8  *
9  * See http://www.boost.org for most recent version including documentation.
10  *
11  * $Id$
12  *
13  * Revision history
14  *  2001-02-18  moved to individual header files
15  */
16 
17 #ifndef BOOST_RANDOM_NORMAL_DISTRIBUTION_HPP
18 #define BOOST_RANDOM_NORMAL_DISTRIBUTION_HPP
19 
20 #include <boost/config/no_tr1/cmath.hpp>
21 #include <istream>
22 #include <iosfwd>
23 #include <boost/assert.hpp>
24 #include <boost/limits.hpp>
25 #include <boost/static_assert.hpp>
26 #include <boost/random/detail/config.hpp>
27 #include <boost/random/detail/operators.hpp>
28 #include <boost/random/detail/int_float_pair.hpp>
29 #include <boost/random/uniform_01.hpp>
30 #include <boost/random/exponential_distribution.hpp>
31 
32 namespace boost {
33 namespace random {
34 
35 namespace detail {
36 
37 // tables for the ziggurat algorithm
38 template<class RealType>
39 struct normal_table {
40     static const RealType table_x[129];
41     static const RealType table_y[129];
42 };
43 
44 template<class RealType>
45 const RealType normal_table<RealType>::table_x[129] = {
46     3.7130862467403632609, 3.4426198558966521214, 3.2230849845786185446, 3.0832288582142137009,
47     2.9786962526450169606, 2.8943440070186706210, 2.8231253505459664379, 2.7611693723841538514,
48     2.7061135731187223371, 2.6564064112581924999, 2.6109722484286132035, 2.5690336259216391328,
49     2.5300096723854666170, 2.4934545220919507609, 2.4590181774083500943, 2.4264206455302115930,
50     2.3954342780074673425, 2.3658713701139875435, 2.3375752413355307354, 2.3104136836950021558,
51     2.2842740596736568056, 2.2590595738653295251, 2.2346863955870569803, 2.2110814088747278106,
52     2.1881804320720206093, 2.1659267937448407377, 2.1442701823562613518, 2.1231657086697899595,
53     2.1025731351849988838, 2.0824562379877246441, 2.0627822745039633575, 2.0435215366506694976,
54     2.0246469733729338782, 2.0061338699589668403, 1.9879595741230607243, 1.9701032608497132242,
55     1.9525457295488889058, 1.9352692282919002011, 1.9182573008597320303, 1.9014946531003176140,
56     1.8849670357028692380, 1.8686611409895420085, 1.8525645117230870617, 1.8366654602533840447,
57     1.8209529965910050740, 1.8054167642140487420, 1.7900469825946189862, 1.7748343955807692457,
58     1.7597702248942318749, 1.7448461281083765085, 1.7300541605582435350, 1.7153867407081165482,
59     1.7008366185643009437, 1.6863968467734863258, 1.6720607540918522072, 1.6578219209482075462,
60     1.6436741568569826489, 1.6296114794646783962, 1.6156280950371329644, 1.6017183802152770587,
61     1.5878768648844007019, 1.5740982160167497219, 1.5603772223598406870, 1.5467087798535034608,
62     1.5330878776675560787, 1.5195095847593707806, 1.5059690368565502602, 1.4924614237746154081,
63     1.4789819769830978546, 1.4655259573357946276, 1.4520886428822164926, 1.4386653166774613138,
64     1.4252512545068615734, 1.4118417124397602509, 1.3984319141236063517, 1.3850170377251486449,
65     1.3715922024197322698, 1.3581524543224228739, 1.3446927517457130432, 1.3312079496576765017,
66     1.3176927832013429910, 1.3041418501204215390, 1.2905495919178731508, 1.2769102735516997175,
67     1.2632179614460282310, 1.2494664995643337480, 1.2356494832544811749, 1.2217602305309625678,
68     1.2077917504067576028, 1.1937367078237721994, 1.1795873846544607035, 1.1653356361550469083,
69     1.1509728421389760651, 1.1364898520030755352, 1.1218769225722540661, 1.1071236475235353980,
70     1.0922188768965537614, 1.0771506248819376573, 1.0619059636836193998, 1.0464709007525802629,
71     1.0308302360564555907, 1.0149673952392994716, 0.99886423348064351303, 0.98250080350276038481,
72     0.96585507938813059489, 0.94890262549791195381, 0.93161619660135381056, 0.91396525100880177644,
73     0.89591535256623852894, 0.87742742909771569142, 0.85845684317805086354, 0.83895221428120745572,
74     0.81885390668331772331, 0.79809206062627480454, 0.77658398787614838598, 0.75423066443451007146,
75     0.73091191062188128150, 0.70647961131360803456, 0.68074791864590421664, 0.65347863871504238702,
76     0.62435859730908822111, 0.59296294244197797913, 0.55869217837551797140, 0.52065603872514491759,
77     0.47743783725378787681, 0.42654798630330512490, 0.36287143102841830424, 0.27232086470466385065,
78     0
79 };
80 
81 template<class RealType>
82 const RealType normal_table<RealType>::table_y[129] = {
83     0, 0.0026696290839025035092, 0.0055489952208164705392, 0.0086244844129304709682,
84     0.011839478657982313715, 0.015167298010672042468, 0.018592102737165812650, 0.022103304616111592615,
85     0.025693291936149616572, 0.029356317440253829618, 0.033087886146505155566, 0.036884388786968774128,
86     0.040742868074790604632, 0.044660862200872429800, 0.048636295860284051878, 0.052667401903503169793,
87     0.056752663481538584188, 0.060890770348566375972, 0.065080585213631873753, 0.069321117394180252601,
88     0.073611501884754893389, 0.077950982514654714188, 0.082338898242957408243, 0.086774671895542968998,
89     0.091257800827634710201, 0.09578784912257815216, 0.10036444102954554013, 0.10498725541035453978,
90     0.10965602101581776100, 0.11437051244988827452, 0.11913054670871858767, 0.12393598020398174246,
91     0.12878670619710396109, 0.13368265258464764118, 0.13862377998585103702, 0.14361008009193299469,
92     0.14864157424369696566, 0.15371831220958657066, 0.15884037114093507813, 0.16400785468492774791,
93     0.16922089223892475176, 0.17447963833240232295, 0.17978427212496211424, 0.18513499701071343216,
94     0.19053204032091372112, 0.19597565311811041399, 0.20146611007620324118, 0.20700370944187380064,
95     0.21258877307373610060, 0.21822164655637059599, 0.22390269938713388747, 0.22963232523430270355,
96     0.23541094226572765600, 0.24123899354775131610, 0.24711694751469673582, 0.25304529850976585934,
97     0.25902456739871074263, 0.26505530225816194029, 0.27113807914102527343, 0.27727350292189771153,
98     0.28346220822601251779, 0.28970486044581049771, 0.29600215684985583659, 0.30235482778947976274,
99     0.30876363800925192282, 0.31522938806815752222, 0.32175291587920862031, 0.32833509837615239609,
100     0.33497685331697116147, 0.34167914123501368412, 0.34844296754987246935, 0.35526938485154714435,
101     0.36215949537303321162, 0.36911445366827513952, 0.37613546951445442947, 0.38322381105988364587,
102     0.39038080824138948916, 0.39760785649804255208, 0.40490642081148835099, 0.41227804010702462062,
103     0.41972433205403823467, 0.42724699830956239880, 0.43484783025466189638, 0.44252871528024661483,
104     0.45029164368692696086, 0.45813871627287196483, 0.46607215269457097924, 0.47409430069824960453,
105     0.48220764633483869062, 0.49041482528932163741, 0.49871863547658432422, 0.50712205108130458951,
106     0.51562823824987205196, 0.52424057267899279809, 0.53296265938998758838, 0.54179835503172412311,
107     0.55075179312105527738, 0.55982741271069481791, 0.56902999107472161225, 0.57836468112670231279,
108     0.58783705444182052571, 0.59745315095181228217, 0.60721953663260488551, 0.61714337082656248870,
109     0.62723248525781456578, 0.63749547734314487428, 0.64794182111855080873, 0.65858200005865368016,
110     0.66942766735770616891, 0.68049184100641433355, 0.69178914344603585279, 0.70333609902581741633,
111     0.71515150742047704368, 0.72725691835450587793, 0.73967724368333814856, 0.75244155918570380145,
112     0.76558417390923599480, 0.77914608594170316563, 0.79317701178385921053, 0.80773829469612111340,
113     0.82290721139526200050, 0.83878360531064722379, 0.85550060788506428418, 0.87324304892685358879,
114     0.89228165080230272301, 0.91304364799203805999, 0.93628268170837107547, 0.96359969315576759960,
115     1
116 };
117 
118 
119 template<class RealType = double>
120 struct unit_normal_distribution
121 {
122     template<class Engine>
operator ()boost::random::detail::unit_normal_distribution123     RealType operator()(Engine& eng) {
124         const double * const table_x = normal_table<double>::table_x;
125         const double * const table_y = normal_table<double>::table_y;
126         for(;;) {
127             std::pair<RealType, int> vals = generate_int_float_pair<RealType, 8>(eng);
128             int i = vals.second;
129             int sign = (i & 1) * 2 - 1;
130             i = i >> 1;
131             RealType x = vals.first * RealType(table_x[i]);
132             if(x < table_x[i + 1]) return x * sign;
133             if(i == 0) return generate_tail(eng) * sign;
134 
135             RealType y01 = uniform_01<RealType>()(eng);
136             RealType y = RealType(table_y[i]) + y01 * RealType(table_y[i + 1] - table_y[i]);
137 
138             // These store the value y - bound, or something proportional to that difference:
139             RealType y_above_ubound, y_above_lbound;
140 
141             // There are three cases to consider:
142             // - convex regions (where x[i] > x[j] >= 1)
143             // - concave regions (where 1 <= x[i] < x[j])
144             // - region containing the inflection point (where x[i] > 1 > x[j])
145             // For convex (concave), exp^(-x^2/2) is bounded below (above) by the tangent at
146             // (x[i],y[i]) and is bounded above (below) by the diagonal line from (x[i+1],y[i+1]) to
147             // (x[i],y[i]).
148             //
149             // *If* the inflection point region satisfies slope(x[i+1]) < slope(diagonal), then we
150             // can treat the inflection region as a convex region: this condition is necessary and
151             // sufficient to ensure that the curve lies entirely below the diagonal (that, in turn,
152             // also implies that it will be above the tangent at x[i]).
153             //
154             // For the current table size (128), this is satisfied: slope(x[i+1]) = -0.60653 <
155             // slope(diag) = -0.60649, and so we have only two cases below instead of three.
156 
157             if (table_x[i] >= 1) { // convex (incl. inflection)
158                 y_above_ubound = RealType(table_x[i] - table_x[i+1]) * y01 - (RealType(table_x[i]) - x);
159                 y_above_lbound = y - (RealType(table_y[i]) + (RealType(table_x[i]) - x) * RealType(table_y[i]) * RealType(table_x[i]));
160             }
161             else { // concave
162                 y_above_lbound = RealType(table_x[i] - table_x[i+1]) * y01 - (RealType(table_x[i]) - x);
163                 y_above_ubound = y - (RealType(table_y[i]) + (RealType(table_x[i]) - x) * RealType(table_y[i]) * RealType(table_x[i]));
164             }
165 
166             if (y_above_ubound < 0 // if above the upper bound reject immediately
167                     &&
168                     (
169                      y_above_lbound < 0 // If below the lower bound accept immediately
170                      ||
171                      y < f(x) // Otherwise it's between the bounds and we need a full check
172                     )
173                ) {
174                 return x * sign;
175             }
176         }
177     }
fboost::random::detail::unit_normal_distribution178     static RealType f(RealType x) {
179         using std::exp;
180         return exp(-(x*x/2));
181     }
182     // Generate from the tail using rejection sampling from the exponential(x_1) distribution,
183     // shifted by x_1.  This looks a little different from the usual rejection sampling because it
184     // transforms the condition by taking the log of both sides, thus avoiding the costly exp() call
185     // on the RHS, then takes advantage of the fact that -log(unif01) is simply generating an
186     // exponential (by inverse cdf sampling) by replacing the log(unif01) on the LHS with a
187     // exponential(1) draw, y.
188     template<class Engine>
generate_tailboost::random::detail::unit_normal_distribution189     RealType generate_tail(Engine& eng) {
190         const RealType tail_start = RealType(normal_table<double>::table_x[1]);
191         boost::random::exponential_distribution<RealType> exp_x(tail_start);
192         boost::random::exponential_distribution<RealType> exp_y;
193         for(;;) {
194             RealType x = exp_x(eng);
195             RealType y = exp_y(eng);
196             // If we were doing non-transformed rejection sampling, this condition would be:
197             // if (unif01 < exp(-.5*x*x)) return x + tail_start;
198             if(2*y > x*x) return x + tail_start;
199         }
200     }
201 };
202 
203 } // namespace detail
204 
205 
206 /**
207  * Instantiations of class template normal_distribution model a
208  * \random_distribution. Such a distribution produces random numbers
209  * @c x distributed with probability density function
210  * \f$\displaystyle p(x) =
211  *   \frac{1}{\sqrt{2\pi}\sigma} e^{-\frac{(x-\mu)^2}{2\sigma^2}}
212  * \f$,
213  * where mean and sigma are the parameters of the distribution.
214  *
215  * The implementation uses the "ziggurat" algorithm, as described in
216  *
217  *  @blockquote
218  *  "The Ziggurat Method for Generating Random Variables",
219  *  George Marsaglia and Wai Wan Tsang, Journal of Statistical Software,
220  *  Volume 5, Number 8 (2000), 1-7.
221  *  @endblockquote
222  */
223 template<class RealType = double>
224 class normal_distribution
225 {
226 public:
227     typedef RealType input_type;
228     typedef RealType result_type;
229 
230     class param_type {
231     public:
232         typedef normal_distribution distribution_type;
233 
234         /**
235          * Constructs a @c param_type with a given mean and
236          * standard deviation.
237          *
238          * Requires: sigma >= 0
239          */
param_type(RealType mean_arg=RealType (0.0),RealType sigma_arg=RealType (1.0))240         explicit param_type(RealType mean_arg = RealType(0.0),
241                             RealType sigma_arg = RealType(1.0))
242           : _mean(mean_arg),
243             _sigma(sigma_arg)
244         {}
245 
246         /** Returns the mean of the distribution. */
mean() const247         RealType mean() const { return _mean; }
248 
249         /** Returns the standand deviation of the distribution. */
sigma() const250         RealType sigma() const { return _sigma; }
251 
252         /** Writes a @c param_type to a @c std::ostream. */
BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os,param_type,parm)253         BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
254         { os << parm._mean << " " << parm._sigma ; return os; }
255 
256         /** Reads a @c param_type from a @c std::istream. */
BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,param_type,parm)257         BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
258         { is >> parm._mean >> std::ws >> parm._sigma; return is; }
259 
260         /** Returns true if the two sets of parameters are the same. */
BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type,lhs,rhs)261         BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
262         { return lhs._mean == rhs._mean && lhs._sigma == rhs._sigma; }
263 
264         /** Returns true if the two sets of parameters are the different. */
265         BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
266 
267     private:
268         RealType _mean;
269         RealType _sigma;
270     };
271 
272     /**
273      * Constructs a @c normal_distribution object. @c mean and @c sigma are
274      * the parameters for the distribution.
275      *
276      * Requires: sigma >= 0
277      */
normal_distribution(const RealType & mean_arg=RealType (0.0),const RealType & sigma_arg=RealType (1.0))278     explicit normal_distribution(const RealType& mean_arg = RealType(0.0),
279                                  const RealType& sigma_arg = RealType(1.0))
280       : _mean(mean_arg), _sigma(sigma_arg)
281     {
282         BOOST_ASSERT(_sigma >= RealType(0));
283     }
284 
285     /**
286      * Constructs a @c normal_distribution object from its parameters.
287      */
normal_distribution(const param_type & parm)288     explicit normal_distribution(const param_type& parm)
289       : _mean(parm.mean()), _sigma(parm.sigma())
290     {}
291 
292     /**  Returns the mean of the distribution. */
mean() const293     RealType mean() const { return _mean; }
294     /** Returns the standard deviation of the distribution. */
sigma() const295     RealType sigma() const { return _sigma; }
296 
297     /** Returns the smallest value that the distribution can produce. */
BOOST_PREVENT_MACRO_SUBSTITUTION() const298     RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const
299     { return -std::numeric_limits<RealType>::infinity(); }
300     /** Returns the largest value that the distribution can produce. */
BOOST_PREVENT_MACRO_SUBSTITUTION() const301     RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const
302     { return std::numeric_limits<RealType>::infinity(); }
303 
304     /** Returns the parameters of the distribution. */
param() const305     param_type param() const { return param_type(_mean, _sigma); }
306     /** Sets the parameters of the distribution. */
param(const param_type & parm)307     void param(const param_type& parm)
308     {
309         _mean = parm.mean();
310         _sigma = parm.sigma();
311     }
312 
313     /**
314      * Effects: Subsequent uses of the distribution do not depend
315      * on values produced by any engine prior to invoking reset.
316      */
reset()317     void reset() { }
318 
319     /**  Returns a normal variate. */
320     template<class Engine>
operator ()(Engine & eng)321     result_type operator()(Engine& eng)
322     {
323         detail::unit_normal_distribution<RealType> impl;
324         return impl(eng) * _sigma + _mean;
325     }
326 
327     /** Returns a normal variate with parameters specified by @c param. */
328     template<class URNG>
operator ()(URNG & urng,const param_type & parm)329     result_type operator()(URNG& urng, const param_type& parm)
330     {
331         return normal_distribution(parm)(urng);
332     }
333 
334     /** Writes a @c normal_distribution to a @c std::ostream. */
BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os,normal_distribution,nd)335     BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, normal_distribution, nd)
336     {
337         os << nd._mean << " " << nd._sigma;
338         return os;
339     }
340 
341     /** Reads a @c normal_distribution from a @c std::istream. */
BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is,normal_distribution,nd)342     BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, normal_distribution, nd)
343     {
344         is >> std::ws >> nd._mean >> std::ws >> nd._sigma;
345         return is;
346     }
347 
348     /**
349      * Returns true if the two instances of @c normal_distribution will
350      * return identical sequences of values given equal generators.
351      */
BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(normal_distribution,lhs,rhs)352     BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(normal_distribution, lhs, rhs)
353     {
354         return lhs._mean == rhs._mean && lhs._sigma == rhs._sigma;
355     }
356 
357     /**
358      * Returns true if the two instances of @c normal_distribution will
359      * return different sequences of values given equal generators.
360      */
361     BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(normal_distribution)
362 
363 private:
364     RealType _mean, _sigma;
365 
366 };
367 
368 } // namespace random
369 
370 using random::normal_distribution;
371 
372 } // namespace boost
373 
374 #endif // BOOST_RANDOM_NORMAL_DISTRIBUTION_HPP
375