• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright John Maddock 2012.
2 
3 // Use, modification and distribution are subject to the
4 // Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_MATH_TEST_OUT_OF_RANGE_HPP
9 #define BOOST_MATH_TEST_OUT_OF_RANGE_HPP
10 
11 #include <boost/math/special_functions/next.hpp>
12 #include <boost/test/test_tools.hpp>
13 
14 /*` check_out_of_range functions check that bad parameters
15 passed to constructors and functions throw domain_error exceptions.
16 
17 Usage is `check_out_of_range<DistributionType >(list-of-params);`
18 Where list-of-params is a list of *valid* parameters from which the distribution can be constructed
19 - ie the same number of args are passed to the function,
20 as are passed to the distribution constructor.
21 
22 Checks:
23 
24 * Infinity or NaN passed in place of each of the valid params.
25 * Infinity or NaN as a random variable.
26 * Out-of-range random variable passed to pdf and cdf (ie outside of "range(distro)").
27 * Out-of-range probability passed to quantile function and complement.
28 
29 but does *not* check finite but out-of-range parameters to the constructor
30 because these are specific to each distribution.
31 */
32 
33 #ifdef BOOST_MSVC
34 #pragma warning(push)
35 #pragma warning(disable:4127)
36 #endif
37 
38 //! \tparam Distro distribution class name, for example: @c students_t_distribution<RealType>.
39 //! \tparam Infinite only true if support includes infinity (default false means do not allow infinity).
40 template <class Distro>
check_support(const Distro & d,bool Infinite=false)41 void check_support(const Distro& d, bool Infinite = false)
42 { // Checks that support and function calls are within expected limits.
43    typedef typename Distro::value_type value_type;
44    if (Infinite == false)
45    {
46      if ((boost::math::isfinite)(range(d).first) && (range(d).first != -boost::math::tools::max_value<value_type>()))
47      { // If possible, check that a random variable value just less than the bottom of the supported range throws domain errors.
48        value_type m = (range(d).first == 0) ? -boost::math::tools::min_value<value_type>() : boost::math::float_prior(range(d).first);
49        BOOST_ASSERT(m != range(d).first);
50        BOOST_ASSERT(m < range(d).first);
51        BOOST_MATH_CHECK_THROW(pdf(d, m), std::domain_error);
52        BOOST_MATH_CHECK_THROW(cdf(d, m), std::domain_error);
53        BOOST_MATH_CHECK_THROW(cdf(complement(d, m)), std::domain_error);
54      }
55      if ((boost::math::isfinite)(range(d).second) && (range(d).second != boost::math::tools::max_value<value_type>()))
56      { // If possible, check that a random variable value just more than the top of the supported range throws domain errors.
57        value_type m = (range(d).second == 0) ? boost::math::tools::min_value<value_type>() : boost::math::float_next(range(d).second);
58        BOOST_ASSERT(m != range(d).first);
59        BOOST_ASSERT(m > range(d).first);
60        BOOST_MATH_CHECK_THROW(pdf(d, m), std::domain_error);
61        BOOST_MATH_CHECK_THROW(cdf(d, m), std::domain_error);
62        BOOST_MATH_CHECK_THROW(cdf(complement(d, m)), std::domain_error);
63      }
64      if (std::numeric_limits<value_type>::has_infinity)
65      { // Infinity is available,
66        if ((boost::math::isfinite)(range(d).second))
67        {  // and top of range doesn't include infinity,
68           // check that using infinity throws domain errors.
69          BOOST_MATH_CHECK_THROW(pdf(d, std::numeric_limits<value_type>::infinity()), std::domain_error);
70          BOOST_MATH_CHECK_THROW(cdf(d, std::numeric_limits<value_type>::infinity()), std::domain_error);
71          BOOST_MATH_CHECK_THROW(cdf(complement(d, std::numeric_limits<value_type>::infinity())), std::domain_error);
72        }
73        if ((boost::math::isfinite)(range(d).first))
74        {  // and bottom of range doesn't include infinity,
75           // check that using infinity throws domain_error exception.
76          BOOST_MATH_CHECK_THROW(pdf(d, -std::numeric_limits<value_type>::infinity()), std::domain_error);
77          BOOST_MATH_CHECK_THROW(cdf(d, -std::numeric_limits<value_type>::infinity()), std::domain_error);
78          BOOST_MATH_CHECK_THROW(cdf(complement(d, -std::numeric_limits<value_type>::infinity())), std::domain_error);
79        }
80        // Check that using infinity with quantiles always throws domain_error exception.
81        BOOST_MATH_CHECK_THROW(quantile(d, std::numeric_limits<value_type>::infinity()), std::domain_error);
82        BOOST_MATH_CHECK_THROW(quantile(d, -std::numeric_limits<value_type>::infinity()), std::domain_error);
83        BOOST_MATH_CHECK_THROW(quantile(complement(d, std::numeric_limits<value_type>::infinity())), std::domain_error);
84        BOOST_MATH_CHECK_THROW(quantile(complement(d, -std::numeric_limits<value_type>::infinity())), std::domain_error);
85      }
86    }
87    if(std::numeric_limits<value_type>::has_quiet_NaN)
88    { // NaN is available.
89       BOOST_MATH_CHECK_THROW(pdf(d, std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
90       BOOST_MATH_CHECK_THROW(cdf(d, std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
91       BOOST_MATH_CHECK_THROW(cdf(complement(d, std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
92       BOOST_MATH_CHECK_THROW(pdf(d, -std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
93       BOOST_MATH_CHECK_THROW(cdf(d, -std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
94       BOOST_MATH_CHECK_THROW(cdf(complement(d, -std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
95       BOOST_MATH_CHECK_THROW(quantile(d, std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
96       BOOST_MATH_CHECK_THROW(quantile(d, -std::numeric_limits<value_type>::quiet_NaN()), std::domain_error);
97       BOOST_MATH_CHECK_THROW(quantile(complement(d, std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
98       BOOST_MATH_CHECK_THROW(quantile(complement(d, -std::numeric_limits<value_type>::quiet_NaN())), std::domain_error);
99    }
100    // Check that using probability outside [0,1] with quantiles always throws domain_error exception.
101    BOOST_MATH_CHECK_THROW(quantile(d, -1), std::domain_error);
102    BOOST_MATH_CHECK_THROW(quantile(d, 2), std::domain_error);
103    BOOST_MATH_CHECK_THROW(quantile(complement(d, -1)), std::domain_error);
104    BOOST_MATH_CHECK_THROW(quantile(complement(d, 2)), std::domain_error);
105 }
106 
107 // Four check_out_of_range versions for distributions with zero to 3 constructor parameters.
108 
109 template <class Distro>
check_out_of_range()110 void check_out_of_range()
111 {
112    Distro d;
113    check_support(d);
114 }
115 
116 template <class Distro>
check_out_of_range(typename Distro::value_type p1)117 void check_out_of_range(typename Distro::value_type p1)
118 {
119    typedef typename Distro::value_type value_type;
120    Distro d(p1);
121    check_support(d);
122    if(std::numeric_limits<value_type>::has_infinity)
123    {
124       BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity()), range(d).first), std::domain_error);
125  //     BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity()), range(d).second), std::domain_error);
126    }
127    if(std::numeric_limits<value_type>::has_quiet_NaN)
128    {
129       BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::quiet_NaN()), range(d).first), std::domain_error);
130    }
131 }
132 
133 template <class Distro>
check_out_of_range(typename Distro::value_type p1,typename Distro::value_type p2)134 void check_out_of_range(typename Distro::value_type p1, typename Distro::value_type p2)
135 {
136    typedef typename Distro::value_type value_type;
137    Distro d(p1, p2);
138    check_support(d);
139    if(std::numeric_limits<value_type>::has_infinity)
140    {
141       BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity(), p2), range(d).first), std::domain_error);
142       BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::infinity()), range(d).first), std::domain_error);
143    }
144    if(std::numeric_limits<value_type>::has_quiet_NaN)
145    {
146       BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::quiet_NaN(), p2), range(d).first), std::domain_error);
147       BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::quiet_NaN()), range(d).first), std::domain_error);
148    }
149 }
150 
151 template <class Distro>
check_out_of_range(typename Distro::value_type p1,typename Distro::value_type p2,typename Distro::value_type p3)152 void check_out_of_range(typename Distro::value_type p1, typename Distro::value_type p2, typename Distro::value_type p3)
153 {
154    typedef typename Distro::value_type value_type;
155    Distro d(p1, p2, p3);
156    check_support(d);
157    if(std::numeric_limits<value_type>::has_infinity)
158    {
159       BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::infinity(), p2, p3), range(d).first), std::domain_error);
160       BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::infinity(), p3), range(d).first), std::domain_error);
161       BOOST_MATH_CHECK_THROW(pdf(Distro(p1, p2, std::numeric_limits<value_type>::infinity()), range(d).first), std::domain_error);
162    }
163    if(std::numeric_limits<value_type>::has_quiet_NaN)
164    {
165       BOOST_MATH_CHECK_THROW(pdf(Distro(std::numeric_limits<value_type>::quiet_NaN(), p2, p3), range(d).first), std::domain_error);
166       BOOST_MATH_CHECK_THROW(pdf(Distro(p1, std::numeric_limits<value_type>::quiet_NaN(), p3), range(d).first), std::domain_error);
167       BOOST_MATH_CHECK_THROW(pdf(Distro(p1, p2, std::numeric_limits<value_type>::quiet_NaN()), range(d).first), std::domain_error);
168    }
169 }
170 
171 #ifdef BOOST_MSVC
172 #pragma warning(pop)
173 #endif
174 
175 #endif // BOOST_MATH_TEST_OUT_OF_RANGE_HPP
176