1 //  Copyright John Maddock 2006.
2 //  Use, modification and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 // distributions.hpp provides definitions of the concept of a distribution
7 // and non-member accessor functions that must be implemented by all distributions.
8 // This is used to verify that
9 // all the features of a distributions have been fully implemented.
10 
11 #ifndef BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
12 #define BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
13 
14 #include <boost/math/distributions/complement.hpp>
15 #include <boost/math/distributions/fwd.hpp>
16 #ifdef BOOST_MSVC
17 #pragma warning(push)
18 #pragma warning(disable: 4100)
19 #pragma warning(disable: 4510)
20 #pragma warning(disable: 4610)
21 #pragma warning(disable: 4189) // local variable is initialized but not referenced.
22 #endif
23 #include <boost/concept_check.hpp>
24 #ifdef BOOST_MSVC
25 #pragma warning(pop)
26 #endif
27 #include <utility>
28 
29 namespace boost{
30 namespace math{
31 
32 namespace concepts
33 {
34 // Begin by defining a concept archetype
35 // for a distribution class:
36 //
37 template <class RealType>
38 class distribution_archetype
39 {
40 public:
41    typedef RealType value_type;
42 
43    distribution_archetype(const distribution_archetype&); // Copy constructible.
44    distribution_archetype& operator=(const distribution_archetype&); // Assignable.
45 
46    // There is no default constructor,
47    // but we need a way to instantiate the archetype:
get_object()48    static distribution_archetype& get_object()
49    {
50       // will never get caled:
51       return *reinterpret_cast<distribution_archetype*>(0);
52    }
53 }; // template <class RealType>class distribution_archetype
54 
55 // Non-member accessor functions:
56 // (This list defines the functions that must be implemented by all distributions).
57 
58 template <class RealType>
59 RealType pdf(const distribution_archetype<RealType>& dist, const RealType& x);
60 
61 template <class RealType>
62 RealType cdf(const distribution_archetype<RealType>& dist, const RealType& x);
63 
64 template <class RealType>
65 RealType quantile(const distribution_archetype<RealType>& dist, const RealType& p);
66 
67 template <class RealType>
68 RealType cdf(const complemented2_type<distribution_archetype<RealType>, RealType>& c);
69 
70 template <class RealType>
71 RealType quantile(const complemented2_type<distribution_archetype<RealType>, RealType>& c);
72 
73 template <class RealType>
74 RealType mean(const distribution_archetype<RealType>& dist);
75 
76 template <class RealType>
77 RealType standard_deviation(const distribution_archetype<RealType>& dist);
78 
79 template <class RealType>
80 RealType variance(const distribution_archetype<RealType>& dist);
81 
82 template <class RealType>
83 RealType hazard(const distribution_archetype<RealType>& dist);
84 
85 template <class RealType>
86 RealType chf(const distribution_archetype<RealType>& dist);
87 // http://en.wikipedia.org/wiki/Characteristic_function_%28probability_theory%29
88 
89 template <class RealType>
90 RealType coefficient_of_variation(const distribution_archetype<RealType>& dist);
91 
92 template <class RealType>
93 RealType mode(const distribution_archetype<RealType>& dist);
94 
95 template <class RealType>
96 RealType skewness(const distribution_archetype<RealType>& dist);
97 
98 template <class RealType>
99 RealType kurtosis_excess(const distribution_archetype<RealType>& dist);
100 
101 template <class RealType>
102 RealType kurtosis(const distribution_archetype<RealType>& dist);
103 
104 template <class RealType>
105 RealType median(const distribution_archetype<RealType>& dist);
106 
107 template <class RealType>
108 std::pair<RealType, RealType> range(const distribution_archetype<RealType>& dist);
109 
110 template <class RealType>
111 std::pair<RealType, RealType> support(const distribution_archetype<RealType>& dist);
112 
113 //
114 // Next comes the concept checks for verifying that a class
115 // fullfils the requirements of a Distribution:
116 //
117 template <class Distribution>
118 struct DistributionConcept
119 {
120    typedef typename Distribution::value_type value_type;
121 
constraintsboost::math::concepts::DistributionConcept122    void constraints()
123    {
124       function_requires<CopyConstructibleConcept<Distribution> >();
125       function_requires<AssignableConcept<Distribution> >();
126 
127       const Distribution& dist = DistributionConcept<Distribution>::get_object();
128 
129       value_type x = 0;
130        // The result values are ignored in all these checks.
131        value_type v = cdf(dist, x);
132       v = cdf(complement(dist, x));
133       suppress_unused_variable_warning(v);
134       v = pdf(dist, x);
135       suppress_unused_variable_warning(v);
136       v = quantile(dist, x);
137       suppress_unused_variable_warning(v);
138       v = quantile(complement(dist, x));
139       suppress_unused_variable_warning(v);
140       v = mean(dist);
141       suppress_unused_variable_warning(v);
142       v = mode(dist);
143       suppress_unused_variable_warning(v);
144       v = standard_deviation(dist);
145       suppress_unused_variable_warning(v);
146       v = variance(dist);
147       suppress_unused_variable_warning(v);
148       v = hazard(dist, x);
149       suppress_unused_variable_warning(v);
150       v = chf(dist, x);
151       suppress_unused_variable_warning(v);
152       v = coefficient_of_variation(dist);
153       suppress_unused_variable_warning(v);
154       v = skewness(dist);
155       suppress_unused_variable_warning(v);
156       v = kurtosis(dist);
157       suppress_unused_variable_warning(v);
158       v = kurtosis_excess(dist);
159       suppress_unused_variable_warning(v);
160       v = median(dist);
161       suppress_unused_variable_warning(v);
162       std::pair<value_type, value_type> pv;
163       pv = range(dist);
164       suppress_unused_variable_warning(pv);
165       pv = support(dist);
166       suppress_unused_variable_warning(pv);
167 
168       float f = 1;
169       v = cdf(dist, f);
170       suppress_unused_variable_warning(v);
171       v = cdf(complement(dist, f));
172       suppress_unused_variable_warning(v);
173       v = pdf(dist, f);
174       suppress_unused_variable_warning(v);
175       v = quantile(dist, f);
176       suppress_unused_variable_warning(v);
177       v = quantile(complement(dist, f));
178       suppress_unused_variable_warning(v);
179       v = hazard(dist, f);
180       suppress_unused_variable_warning(v);
181       v = chf(dist, f);
182       suppress_unused_variable_warning(v);
183       double d = 1;
184       v = cdf(dist, d);
185       suppress_unused_variable_warning(v);
186       v = cdf(complement(dist, d));
187       suppress_unused_variable_warning(v);
188       v = pdf(dist, d);
189       suppress_unused_variable_warning(v);
190       v = quantile(dist, d);
191       suppress_unused_variable_warning(v);
192       v = quantile(complement(dist, d));
193       suppress_unused_variable_warning(v);
194       v = hazard(dist, d);
195       suppress_unused_variable_warning(v);
196       v = chf(dist, d);
197       suppress_unused_variable_warning(v);
198 #ifndef TEST_MPFR
199       long double ld = 1;
200       v = cdf(dist, ld);
201       suppress_unused_variable_warning(v);
202       v = cdf(complement(dist, ld));
203       suppress_unused_variable_warning(v);
204       v = pdf(dist, ld);
205       suppress_unused_variable_warning(v);
206       v = quantile(dist, ld);
207       suppress_unused_variable_warning(v);
208       v = quantile(complement(dist, ld));
209       suppress_unused_variable_warning(v);
210       v = hazard(dist, ld);
211       suppress_unused_variable_warning(v);
212       v = chf(dist, ld);
213       suppress_unused_variable_warning(v);
214 #endif
215       int i = 1;
216       v = cdf(dist, i);
217       suppress_unused_variable_warning(v);
218       v = cdf(complement(dist, i));
219       suppress_unused_variable_warning(v);
220       v = pdf(dist, i);
221       suppress_unused_variable_warning(v);
222       v = quantile(dist, i);
223       suppress_unused_variable_warning(v);
224       v = quantile(complement(dist, i));
225       suppress_unused_variable_warning(v);
226       v = hazard(dist, i);
227       suppress_unused_variable_warning(v);
228       v = chf(dist, i);
229       suppress_unused_variable_warning(v);
230       unsigned long li = 1;
231       v = cdf(dist, li);
232       suppress_unused_variable_warning(v);
233       v = cdf(complement(dist, li));
234       suppress_unused_variable_warning(v);
235       v = pdf(dist, li);
236       suppress_unused_variable_warning(v);
237       v = quantile(dist, li);
238       suppress_unused_variable_warning(v);
239       v = quantile(complement(dist, li));
240       suppress_unused_variable_warning(v);
241       v = hazard(dist, li);
242       suppress_unused_variable_warning(v);
243       v = chf(dist, li);
244       suppress_unused_variable_warning(v);
245       test_extra_members(dist);
246    }
247    template <class D>
test_extra_membersboost::math::concepts::DistributionConcept248    static void test_extra_members(const D&)
249    {}
250    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept251    static void test_extra_members(const boost::math::bernoulli_distribution<R, P>& d)
252    {
253       value_type r = d.success_fraction();
254       (void)r; // warning suppression
255    }
256    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept257    static void test_extra_members(const boost::math::beta_distribution<R, P>& d)
258    {
259       value_type r1 = d.alpha();
260       value_type r2 = d.beta();
261       r1 = boost::math::beta_distribution<R, P>::find_alpha(r1, r2);
262       suppress_unused_variable_warning(r1);
263       r1 = boost::math::beta_distribution<R, P>::find_beta(r1, r2);
264       suppress_unused_variable_warning(r1);
265       r1 = boost::math::beta_distribution<R, P>::find_alpha(r1, r2, r1);
266       suppress_unused_variable_warning(r1);
267       r1 = boost::math::beta_distribution<R, P>::find_beta(r1, r2, r1);
268       suppress_unused_variable_warning(r1);
269    }
270    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept271    static void test_extra_members(const boost::math::binomial_distribution<R, P>& d)
272    {
273       value_type r = d.success_fraction();
274       r = d.trials();
275       r = Distribution::find_lower_bound_on_p(r, r, r);
276       r = Distribution::find_lower_bound_on_p(r, r, r, Distribution::clopper_pearson_exact_interval);
277       r = Distribution::find_lower_bound_on_p(r, r, r, Distribution::jeffreys_prior_interval);
278       r = Distribution::find_upper_bound_on_p(r, r, r);
279       r = Distribution::find_upper_bound_on_p(r, r, r, Distribution::clopper_pearson_exact_interval);
280       r = Distribution::find_upper_bound_on_p(r, r, r, Distribution::jeffreys_prior_interval);
281       r = Distribution::find_minimum_number_of_trials(r, r, r);
282       r = Distribution::find_maximum_number_of_trials(r, r, r);
283       suppress_unused_variable_warning(r);
284    }
285    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept286    static void test_extra_members(const boost::math::cauchy_distribution<R, P>& d)
287    {
288       value_type r = d.location();
289       r = d.scale();
290       suppress_unused_variable_warning(r);
291    }
292    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept293    static void test_extra_members(const boost::math::chi_squared_distribution<R, P>& d)
294    {
295       value_type r = d.degrees_of_freedom();
296       r = Distribution::find_degrees_of_freedom(r, r, r, r);
297       r = Distribution::find_degrees_of_freedom(r, r, r, r, r);
298       suppress_unused_variable_warning(r);
299    }
300    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept301    static void test_extra_members(const boost::math::exponential_distribution<R, P>& d)
302    {
303       value_type r = d.lambda();
304       suppress_unused_variable_warning(r);
305    }
306    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept307    static void test_extra_members(const boost::math::extreme_value_distribution<R, P>& d)
308    {
309       value_type r = d.scale();
310       r = d.location();
311       suppress_unused_variable_warning(r);
312    }
313    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept314    static void test_extra_members(const boost::math::fisher_f_distribution<R, P>& d)
315    {
316       value_type r = d.degrees_of_freedom1();
317       r = d.degrees_of_freedom2();
318       suppress_unused_variable_warning(r);
319    }
320    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept321    static void test_extra_members(const boost::math::gamma_distribution<R, P>& d)
322    {
323       value_type r = d.scale();
324       r = d.shape();
325       suppress_unused_variable_warning(r);
326    }
327    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept328    static void test_extra_members(const boost::math::inverse_chi_squared_distribution<R, P>& d)
329    {
330       value_type r = d.scale();
331       r = d.degrees_of_freedom();
332       suppress_unused_variable_warning(r);
333    }
334    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept335    static void test_extra_members(const boost::math::inverse_gamma_distribution<R, P>& d)
336    {
337       value_type r = d.scale();
338       r = d.shape();
339       suppress_unused_variable_warning(r);
340    }
341    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept342    static void test_extra_members(const boost::math::hypergeometric_distribution<R, P>& d)
343    {
344       unsigned u = d.defective();
345       u = d.sample_count();
346       u = d.total();
347       suppress_unused_variable_warning(u);
348    }
349    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept350    static void test_extra_members(const boost::math::laplace_distribution<R, P>& d)
351    {
352       value_type r = d.scale();
353       r = d.location();
354       suppress_unused_variable_warning(r);
355    }
356    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept357    static void test_extra_members(const boost::math::logistic_distribution<R, P>& d)
358    {
359       value_type r = d.scale();
360       r = d.location();
361       suppress_unused_variable_warning(r);
362    }
363    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept364    static void test_extra_members(const boost::math::lognormal_distribution<R, P>& d)
365    {
366       value_type r = d.scale();
367       r = d.location();
368       suppress_unused_variable_warning(r);
369    }
370    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept371    static void test_extra_members(const boost::math::negative_binomial_distribution<R, P>& d)
372    {
373       value_type r = d.success_fraction();
374       r = d.successes();
375       r = Distribution::find_lower_bound_on_p(r, r, r);
376       r = Distribution::find_upper_bound_on_p(r, r, r);
377       r = Distribution::find_minimum_number_of_trials(r, r, r);
378       r = Distribution::find_maximum_number_of_trials(r, r, r);
379       suppress_unused_variable_warning(r);
380    }
381    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept382    static void test_extra_members(const boost::math::non_central_beta_distribution<R, P>& d)
383    {
384       value_type r1 = d.alpha();
385       value_type r2 = d.beta();
386       r1 = d.non_centrality();
387       (void)r1; // warning suppression
388       (void)r2; // warning suppression
389    }
390    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept391    static void test_extra_members(const boost::math::non_central_chi_squared_distribution<R, P>& d)
392    {
393       value_type r = d.degrees_of_freedom();
394       r = d.non_centrality();
395       r = Distribution::find_degrees_of_freedom(r, r, r);
396       r = Distribution::find_degrees_of_freedom(boost::math::complement(r, r, r));
397       r = Distribution::find_non_centrality(r, r, r);
398       r = Distribution::find_non_centrality(boost::math::complement(r, r, r));
399       (void)r; // warning suppression
400    }
401    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept402    static void test_extra_members(const boost::math::non_central_f_distribution<R, P>& d)
403    {
404       value_type r = d.degrees_of_freedom1();
405       r = d.degrees_of_freedom2();
406       r = d.non_centrality();
407       (void)r; // warning suppression
408    }
409    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept410    static void test_extra_members(const boost::math::non_central_t_distribution<R, P>& d)
411    {
412       value_type r = d.degrees_of_freedom();
413       r = d.non_centrality();
414       (void)r; // warning suppression
415    }
416    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept417    static void test_extra_members(const boost::math::normal_distribution<R, P>& d)
418    {
419       value_type r = d.scale();
420       r = d.location();
421       r = d.mean();
422       r = d.standard_deviation();
423       (void)r; // warning suppression
424    }
425    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept426    static void test_extra_members(const boost::math::pareto_distribution<R, P>& d)
427    {
428       value_type r = d.scale();
429       r = d.shape();
430       (void)r; // warning suppression
431    }
432    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept433    static void test_extra_members(const boost::math::poisson_distribution<R, P>& d)
434    {
435       value_type r = d.mean();
436       (void)r; // warning suppression
437    }
438    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept439    static void test_extra_members(const boost::math::rayleigh_distribution<R, P>& d)
440    {
441       value_type r = d.sigma();
442       (void)r; // warning suppression
443    }
444    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept445    static void test_extra_members(const boost::math::students_t_distribution<R, P>& d)
446    {
447       value_type r = d.degrees_of_freedom();
448       r = d.find_degrees_of_freedom(r, r, r, r);
449       r = d.find_degrees_of_freedom(r, r, r, r, r);
450       (void)r; // warning suppression
451    }
452    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept453    static void test_extra_members(const boost::math::triangular_distribution<R, P>& d)
454    {
455       value_type r = d.lower();
456       r = d.mode();
457       r = d.upper();
458       (void)r; // warning suppression
459    }
460    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept461    static void test_extra_members(const boost::math::weibull_distribution<R, P>& d)
462    {
463       value_type r = d.scale();
464       r = d.shape();
465       (void)r; // warning suppression
466    }
467    template <class R, class P>
test_extra_membersboost::math::concepts::DistributionConcept468    static void test_extra_members(const boost::math::uniform_distribution<R, P>& d)
469    {
470       value_type r = d.lower();
471       r = d.upper();
472       (void)r; // warning suppression
473    }
474 private:
475    static Distribution* pd;
get_objectboost::math::concepts::DistributionConcept476    static Distribution& get_object()
477    {
478       // In reality this will never get called:
479       return *pd;
480    }
481 }; // struct DistributionConcept
482 
483 template <class Distribution>
484 Distribution* DistributionConcept<Distribution>::pd = 0;
485 
486 } // namespace concepts
487 } // namespace math
488 } // namespace boost
489 
490 #endif // BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
491 
492