To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / any / include / boost / math / distributions / poisson.hpp @ 160:cff480c41f97

History | View | Annotate | Download (20.3 KB)

1
// boost\math\distributions\poisson.hpp
2

    
3
// Copyright John Maddock 2006.
4
// Copyright Paul A. Bristow 2007.
5

    
6
// Use, modification and distribution are subject to the
7
// Boost Software License, Version 1.0.
8
// (See accompanying file LICENSE_1_0.txt
9
// or copy at http://www.boost.org/LICENSE_1_0.txt)
10

    
11
// Poisson distribution is a discrete probability distribution.
12
// It expresses the probability of a number (k) of
13
// events, occurrences, failures or arrivals occurring in a fixed time,
14
// assuming these events occur with a known average or mean rate (lambda)
15
// and are independent of the time since the last event.
16
// The distribution was discovered by Simeon-Denis Poisson (1781-1840).
17

    
18
// Parameter lambda is the mean number of events in the given time interval.
19
// The random variate k is the number of events, occurrences or arrivals.
20
// k argument may be integral, signed, or unsigned, or floating point.
21
// If necessary, it has already been promoted from an integral type.
22

    
23
// Note that the Poisson distribution
24
// (like others including the binomial, negative binomial & Bernoulli)
25
// is strictly defined as a discrete function:
26
// only integral values of k are envisaged.
27
// However because the method of calculation uses a continuous gamma function,
28
// it is convenient to treat it as if a continous function,
29
// and permit non-integral values of k.
30
// To enforce the strict mathematical model, users should use floor or ceil functions
31
// on k outside this function to ensure that k is integral.
32

    
33
// See http://en.wikipedia.org/wiki/Poisson_distribution
34
// http://documents.wolfram.com/v5/Add-onsLinks/StandardPackages/Statistics/DiscreteDistributions.html
35

    
36
#ifndef BOOST_MATH_SPECIAL_POISSON_HPP
37
#define BOOST_MATH_SPECIAL_POISSON_HPP
38

    
39
#include <boost/math/distributions/fwd.hpp>
40
#include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
41
#include <boost/math/special_functions/trunc.hpp> // for incomplete gamma. gamma_q
42
#include <boost/math/distributions/complement.hpp> // complements
43
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
44
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
45
#include <boost/math/special_functions/factorials.hpp> // factorials.
46
#include <boost/math/tools/roots.hpp> // for root finding.
47
#include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
48

    
49
#include <utility>
50

    
51
namespace boost
52
{
53
  namespace math
54
  {
55
    namespace poisson_detail
56
    {
57
      // Common error checking routines for Poisson distribution functions.
58
      // These are convoluted, & apparently redundant, to try to ensure that
59
      // checks are always performed, even if exceptions are not enabled.
60

    
61
      template <class RealType, class Policy>
62
      inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol)
63
      {
64
        if(!(boost::math::isfinite)(mean) || (mean < 0))
65
        {
66
          *result = policies::raise_domain_error<RealType>(
67
            function,
68
            "Mean argument is %1%, but must be >= 0 !", mean, pol);
69
          return false;
70
        }
71
        return true;
72
      } // bool check_mean
73

    
74
      template <class RealType, class Policy>
75
      inline bool check_mean_NZ(const char* function, const RealType& mean, RealType* result, const Policy& pol)
76
      { // mean == 0 is considered an error.
77
        if( !(boost::math::isfinite)(mean) || (mean <= 0))
78
        {
79
          *result = policies::raise_domain_error<RealType>(
80
            function,
81
            "Mean argument is %1%, but must be > 0 !", mean, pol);
82
          return false;
83
        }
84
        return true;
85
      } // bool check_mean_NZ
86

    
87
      template <class RealType, class Policy>
88
      inline bool check_dist(const char* function, const RealType& mean, RealType* result, const Policy& pol)
89
      { // Only one check, so this is redundant really but should be optimized away.
90
        return check_mean_NZ(function, mean, result, pol);
91
      } // bool check_dist
92

    
93
      template <class RealType, class Policy>
94
      inline bool check_k(const char* function, const RealType& k, RealType* result, const Policy& pol)
95
      {
96
        if((k < 0) || !(boost::math::isfinite)(k))
97
        {
98
          *result = policies::raise_domain_error<RealType>(
99
            function,
100
            "Number of events k argument is %1%, but must be >= 0 !", k, pol);
101
          return false;
102
        }
103
        return true;
104
      } // bool check_k
105

    
106
      template <class RealType, class Policy>
107
      inline bool check_dist_and_k(const char* function, RealType mean, RealType k, RealType* result, const Policy& pol)
108
      {
109
        if((check_dist(function, mean, result, pol) == false) ||
110
          (check_k(function, k, result, pol) == false))
111
        {
112
          return false;
113
        }
114
        return true;
115
      } // bool check_dist_and_k
116

    
117
      template <class RealType, class Policy>
118
      inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
119
      { // Check 0 <= p <= 1
120
        if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
121
        {
122
          *result = policies::raise_domain_error<RealType>(
123
            function,
124
            "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
125
          return false;
126
        }
127
        return true;
128
      } // bool check_prob
129

    
130
      template <class RealType, class Policy>
131
      inline bool check_dist_and_prob(const char* function, RealType mean,  RealType p, RealType* result, const Policy& pol)
132
      {
133
        if((check_dist(function, mean, result, pol) == false) ||
134
          (check_prob(function, p, result, pol) == false))
135
        {
136
          return false;
137
        }
138
        return true;
139
      } // bool check_dist_and_prob
140

    
141
    } // namespace poisson_detail
142

    
143
    template <class RealType = double, class Policy = policies::policy<> >
144
    class poisson_distribution
145
    {
146
    public:
147
      typedef RealType value_type;
148
      typedef Policy policy_type;
149

    
150
      poisson_distribution(RealType l_mean = 1) : m_l(l_mean) // mean (lambda).
151
      { // Expected mean number of events that occur during the given interval.
152
        RealType r;
153
        poisson_detail::check_dist(
154
           "boost::math::poisson_distribution<%1%>::poisson_distribution",
155
          m_l,
156
          &r, Policy());
157
      } // poisson_distribution constructor.
158

    
159
      RealType mean() const
160
      { // Private data getter function.
161
        return m_l;
162
      }
163
    private:
164
      // Data member, initialized by constructor.
165
      RealType m_l; // mean number of occurrences.
166
    }; // template <class RealType, class Policy> class poisson_distribution
167

    
168
    typedef poisson_distribution<double> poisson; // Reserved name of type double.
169

    
170
    // Non-member functions to give properties of the distribution.
171

    
172
    template <class RealType, class Policy>
173
    inline const std::pair<RealType, RealType> range(const poisson_distribution<RealType, Policy>& /* dist */)
174
    { // Range of permissible values for random variable k.
175
       using boost::math::tools::max_value;
176
       return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // Max integer?
177
    }
178

    
179
    template <class RealType, class Policy>
180
    inline const std::pair<RealType, RealType> support(const poisson_distribution<RealType, Policy>& /* dist */)
181
    { // Range of supported values for random variable k.
182
       // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
183
       using boost::math::tools::max_value;
184
       return std::pair<RealType, RealType>(static_cast<RealType>(0),  max_value<RealType>());
185
    }
186

    
187
    template <class RealType, class Policy>
188
    inline RealType mean(const poisson_distribution<RealType, Policy>& dist)
189
    { // Mean of poisson distribution = lambda.
190
      return dist.mean();
191
    } // mean
192

    
193
    template <class RealType, class Policy>
194
    inline RealType mode(const poisson_distribution<RealType, Policy>& dist)
195
    { // mode.
196
      BOOST_MATH_STD_USING // ADL of std functions.
197
      return floor(dist.mean());
198
    }
199

    
200
    //template <class RealType, class Policy>
201
    //inline RealType median(const poisson_distribution<RealType, Policy>& dist)
202
    //{ // median = approximately lambda + 1/3 - 0.2/lambda
203
    //  RealType l = dist.mean();
204
    //  return dist.mean() + static_cast<RealType>(0.3333333333333333333333333333333333333333333333)
205
    //   - static_cast<RealType>(0.2) / l;
206
    //} // BUT this formula appears to be out-by-one compared to quantile(half)
207
    // Query posted on Wikipedia.
208
    // Now implemented via quantile(half) in derived accessors.
209

    
210
    template <class RealType, class Policy>
211
    inline RealType variance(const poisson_distribution<RealType, Policy>& dist)
212
    { // variance.
213
      return dist.mean();
214
    }
215

    
216
    // RealType standard_deviation(const poisson_distribution<RealType, Policy>& dist)
217
    // standard_deviation provided by derived accessors.
218

    
219
    template <class RealType, class Policy>
220
    inline RealType skewness(const poisson_distribution<RealType, Policy>& dist)
221
    { // skewness = sqrt(l).
222
      BOOST_MATH_STD_USING // ADL of std functions.
223
      return 1 / sqrt(dist.mean());
224
    }
225

    
226
    template <class RealType, class Policy>
227
    inline RealType kurtosis_excess(const poisson_distribution<RealType, Policy>& dist)
228
    { // skewness = sqrt(l).
229
      return 1 / dist.mean(); // kurtosis_excess 1/mean from Wiki & MathWorld eq 31.
230
      // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess
231
      // is more convenient because the kurtosis excess of a normal distribution is zero
232
      // whereas the true kurtosis is 3.
233
    } // RealType kurtosis_excess
234

    
235
    template <class RealType, class Policy>
236
    inline RealType kurtosis(const poisson_distribution<RealType, Policy>& dist)
237
    { // kurtosis is 4th moment about the mean = u4 / sd ^ 4
238
      // http://en.wikipedia.org/wiki/Curtosis
239
      // kurtosis can range from -2 (flat top) to +infinity (sharp peak & heavy tails).
240
      // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm
241
      return 3 + 1 / dist.mean(); // NIST.
242
      // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess
243
      // is more convenient because the kurtosis excess of a normal distribution is zero
244
      // whereas the true kurtosis is 3.
245
    } // RealType kurtosis
246

    
247
    template <class RealType, class Policy>
248
    RealType pdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
249
    { // Probability Density/Mass Function.
250
      // Probability that there are EXACTLY k occurrences (or arrivals).
251
      BOOST_FPU_EXCEPTION_GUARD
252

    
253
      BOOST_MATH_STD_USING // for ADL of std functions.
254

    
255
      RealType mean = dist.mean();
256
      // Error check:
257
      RealType result = 0;
258
      if(false == poisson_detail::check_dist_and_k(
259
        "boost::math::pdf(const poisson_distribution<%1%>&, %1%)",
260
        mean,
261
        k,
262
        &result, Policy()))
263
      {
264
        return result;
265
      }
266

    
267
      // Special case of mean zero, regardless of the number of events k.
268
      if (mean == 0)
269
      { // Probability for any k is zero.
270
        return 0;
271
      }
272
      if (k == 0)
273
      { // mean ^ k = 1, and k! = 1, so can simplify.
274
        return exp(-mean);
275
      }
276
      return boost::math::gamma_p_derivative(k+1, mean, Policy());
277
    } // pdf
278

    
279
    template <class RealType, class Policy>
280
    RealType cdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
281
    { // Cumulative Distribution Function Poisson.
282
      // The random variate k is the number of occurrences(or arrivals)
283
      // k argument may be integral, signed, or unsigned, or floating point.
284
      // If necessary, it has already been promoted from an integral type.
285
      // Returns the sum of the terms 0 through k of the Poisson Probability Density or Mass (pdf).
286

    
287
      // But note that the Poisson distribution
288
      // (like others including the binomial, negative binomial & Bernoulli)
289
      // is strictly defined as a discrete function: only integral values of k are envisaged.
290
      // However because of the method of calculation using a continuous gamma function,
291
      // it is convenient to treat it as if it is a continous function
292
      // and permit non-integral values of k.
293
      // To enforce the strict mathematical model, users should use floor or ceil functions
294
      // outside this function to ensure that k is integral.
295

    
296
      // The terms are not summed directly (at least for larger k)
297
      // instead the incomplete gamma integral is employed,
298

    
299
      BOOST_MATH_STD_USING // for ADL of std function exp.
300

    
301
      RealType mean = dist.mean();
302
      // Error checks:
303
      RealType result = 0;
304
      if(false == poisson_detail::check_dist_and_k(
305
        "boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
306
        mean,
307
        k,
308
        &result, Policy()))
309
      {
310
        return result;
311
      }
312
      // Special cases:
313
      if (mean == 0)
314
      { // Probability for any k is zero.
315
        return 0;
316
      }
317
      if (k == 0)
318
      { // return pdf(dist, static_cast<RealType>(0));
319
        // but mean (and k) have already been checked,
320
        // so this avoids unnecessary repeated checks.
321
       return exp(-mean);
322
      }
323
      // For small integral k could use a finite sum -
324
      // it's cheaper than the gamma function.
325
      // BUT this is now done efficiently by gamma_q function.
326
      // Calculate poisson cdf using the gamma_q function.
327
      return gamma_q(k+1, mean, Policy());
328
    } // binomial cdf
329

    
330
    template <class RealType, class Policy>
331
    RealType cdf(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
332
    { // Complemented Cumulative Distribution Function Poisson
333
      // The random variate k is the number of events, occurrences or arrivals.
334
      // k argument may be integral, signed, or unsigned, or floating point.
335
      // If necessary, it has already been promoted from an integral type.
336
      // But note that the Poisson distribution
337
      // (like others including the binomial, negative binomial & Bernoulli)
338
      // is strictly defined as a discrete function: only integral values of k are envisaged.
339
      // However because of the method of calculation using a continuous gamma function,
340
      // it is convenient to treat it as is it is a continous function
341
      // and permit non-integral values of k.
342
      // To enforce the strict mathematical model, users should use floor or ceil functions
343
      // outside this function to ensure that k is integral.
344

    
345
      // Returns the sum of the terms k+1 through inf of the Poisson Probability Density/Mass (pdf).
346
      // The terms are not summed directly (at least for larger k)
347
      // instead the incomplete gamma integral is employed,
348

    
349
      RealType const& k = c.param;
350
      poisson_distribution<RealType, Policy> const& dist = c.dist;
351

    
352
      RealType mean = dist.mean();
353

    
354
      // Error checks:
355
      RealType result = 0;
356
      if(false == poisson_detail::check_dist_and_k(
357
        "boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
358
        mean,
359
        k,
360
        &result, Policy()))
361
      {
362
        return result;
363
      }
364
      // Special case of mean, regardless of the number of events k.
365
      if (mean == 0)
366
      { // Probability for any k is unity, complement of zero.
367
        return 1;
368
      }
369
      if (k == 0)
370
      { // Avoid repeated checks on k and mean in gamma_p.
371
         return -boost::math::expm1(-mean, Policy());
372
      }
373
      // Unlike un-complemented cdf (sum from 0 to k),
374
      // can't use finite sum from k+1 to infinity for small integral k,
375
      // anyway it is now done efficiently by gamma_p.
376
      return gamma_p(k + 1, mean, Policy()); // Calculate Poisson cdf using the gamma_p function.
377
      // CCDF = gamma_p(k+1, lambda)
378
    } // poisson ccdf
379

    
380
    template <class RealType, class Policy>
381
    inline RealType quantile(const poisson_distribution<RealType, Policy>& dist, const RealType& p)
382
    { // Quantile (or Percent Point) Poisson function.
383
      // Return the number of expected events k for a given probability p.
384
      static const char* function = "boost::math::quantile(const poisson_distribution<%1%>&, %1%)";
385
      RealType result = 0; // of Argument checks:
386
      if(false == poisson_detail::check_prob(
387
        function,
388
        p,
389
        &result, Policy()))
390
      {
391
        return result;
392
      }
393
      // Special case:
394
      if (dist.mean() == 0)
395
      { // if mean = 0 then p = 0, so k can be anything?
396
         if (false == poisson_detail::check_mean_NZ(
397
         function,
398
         dist.mean(),
399
         &result, Policy()))
400
        {
401
          return result;
402
        }
403
      }
404
      if(p == 0)
405
      {
406
         return 0; // Exact result regardless of discrete-quantile Policy
407
      }
408
      if(p == 1)
409
      {
410
         return policies::raise_overflow_error<RealType>(function, 0, Policy());
411
      }
412
      typedef typename Policy::discrete_quantile_type discrete_type;
413
      boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
414
      RealType guess, factor = 8;
415
      RealType z = dist.mean();
416
      if(z < 1)
417
         guess = z;
418
      else
419
         guess = boost::math::detail::inverse_poisson_cornish_fisher(z, p, RealType(1-p), Policy());
420
      if(z > 5)
421
      {
422
         if(z > 1000)
423
            factor = 1.01f;
424
         else if(z > 50)
425
            factor = 1.1f;
426
         else if(guess > 10)
427
            factor = 1.25f;
428
         else
429
            factor = 2;
430
         if(guess < 1.1)
431
            factor = 8;
432
      }
433

    
434
      return detail::inverse_discrete_quantile(
435
         dist,
436
         p,
437
         false,
438
         guess,
439
         factor,
440
         RealType(1),
441
         discrete_type(),
442
         max_iter);
443
   } // quantile
444

    
445
    template <class RealType, class Policy>
446
    inline RealType quantile(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
447
    { // Quantile (or Percent Point) of Poisson function.
448
      // Return the number of expected events k for a given
449
      // complement of the probability q.
450
      //
451
      // Error checks:
452
      static const char* function = "boost::math::quantile(complement(const poisson_distribution<%1%>&, %1%))";
453
      RealType q = c.param;
454
      const poisson_distribution<RealType, Policy>& dist = c.dist;
455
      RealType result = 0;  // of argument checks.
456
      if(false == poisson_detail::check_prob(
457
        function,
458
        q,
459
        &result, Policy()))
460
      {
461
        return result;
462
      }
463
      // Special case:
464
      if (dist.mean() == 0)
465
      { // if mean = 0 then p = 0, so k can be anything?
466
         if (false == poisson_detail::check_mean_NZ(
467
         function,
468
         dist.mean(),
469
         &result, Policy()))
470
        {
471
          return result;
472
        }
473
      }
474
      if(q == 0)
475
      {
476
         return policies::raise_overflow_error<RealType>(function, 0, Policy());
477
      }
478
      if(q == 1)
479
      {
480
         return 0;  // Exact result regardless of discrete-quantile Policy
481
      }
482
      typedef typename Policy::discrete_quantile_type discrete_type;
483
      boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
484
      RealType guess, factor = 8;
485
      RealType z = dist.mean();
486
      if(z < 1)
487
         guess = z;
488
      else
489
         guess = boost::math::detail::inverse_poisson_cornish_fisher(z, RealType(1-q), q, Policy());
490
      if(z > 5)
491
      {
492
         if(z > 1000)
493
            factor = 1.01f;
494
         else if(z > 50)
495
            factor = 1.1f;
496
         else if(guess > 10)
497
            factor = 1.25f;
498
         else
499
            factor = 2;
500
         if(guess < 1.1)
501
            factor = 8;
502
      }
503

    
504
      return detail::inverse_discrete_quantile(
505
         dist,
506
         q,
507
         true,
508
         guess,
509
         factor,
510
         RealType(1),
511
         discrete_type(),
512
         max_iter);
513
   } // quantile complement.
514

    
515
  } // namespace math
516
} // namespace boost
517

    
518
// This include must be at the end, *after* the accessors
519
// for this distribution have been defined, in order to
520
// keep compilers that support two-phase lookup happy.
521
#include <boost/math/distributions/detail/derived_accessors.hpp>
522
#include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
523

    
524
#endif // BOOST_MATH_SPECIAL_POISSON_HPP
525

    
526

    
527