Chris@16
|
1 // boost\math\distributions\non_central_chi_squared.hpp
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright John Maddock 2008.
|
Chris@16
|
4
|
Chris@16
|
5 // Use, modification and distribution are subject to the
|
Chris@16
|
6 // Boost Software License, Version 1.0.
|
Chris@16
|
7 // (See accompanying file LICENSE_1_0.txt
|
Chris@16
|
8 // or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9
|
Chris@16
|
10 #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
|
Chris@16
|
11 #define BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/math/distributions/fwd.hpp>
|
Chris@16
|
14 #include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
|
Chris@16
|
15 #include <boost/math/special_functions/bessel.hpp> // for cyl_bessel_i
|
Chris@16
|
16 #include <boost/math/special_functions/round.hpp> // for iround
|
Chris@16
|
17 #include <boost/math/distributions/complement.hpp> // complements
|
Chris@16
|
18 #include <boost/math/distributions/chi_squared.hpp> // central distribution
|
Chris@16
|
19 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
|
Chris@16
|
20 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
|
Chris@16
|
21 #include <boost/math/tools/roots.hpp> // for root finding.
|
Chris@16
|
22 #include <boost/math/distributions/detail/generic_mode.hpp>
|
Chris@16
|
23 #include <boost/math/distributions/detail/generic_quantile.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 namespace boost
|
Chris@16
|
26 {
|
Chris@16
|
27 namespace math
|
Chris@16
|
28 {
|
Chris@16
|
29
|
Chris@16
|
30 template <class RealType, class Policy>
|
Chris@16
|
31 class non_central_chi_squared_distribution;
|
Chris@16
|
32
|
Chris@16
|
33 namespace detail{
|
Chris@16
|
34
|
Chris@16
|
35 template <class T, class Policy>
|
Chris@16
|
36 T non_central_chi_square_q(T x, T f, T theta, const Policy& pol, T init_sum = 0)
|
Chris@16
|
37 {
|
Chris@16
|
38 //
|
Chris@16
|
39 // Computes the complement of the Non-Central Chi-Square
|
Chris@16
|
40 // Distribution CDF by summing a weighted sum of complements
|
Chris@16
|
41 // of the central-distributions. The weighting factor is
|
Chris@16
|
42 // a Poisson Distribution.
|
Chris@16
|
43 //
|
Chris@16
|
44 // This is an application of the technique described in:
|
Chris@16
|
45 //
|
Chris@16
|
46 // Computing discrete mixtures of continuous
|
Chris@16
|
47 // distributions: noncentral chisquare, noncentral t
|
Chris@16
|
48 // and the distribution of the square of the sample
|
Chris@16
|
49 // multiple correlation coeficient.
|
Chris@16
|
50 // D. Benton, K. Krishnamoorthy.
|
Chris@16
|
51 // Computational Statistics & Data Analysis 43 (2003) 249 - 267
|
Chris@16
|
52 //
|
Chris@16
|
53 BOOST_MATH_STD_USING
|
Chris@16
|
54
|
Chris@16
|
55 // Special case:
|
Chris@16
|
56 if(x == 0)
|
Chris@16
|
57 return 1;
|
Chris@16
|
58
|
Chris@16
|
59 //
|
Chris@16
|
60 // Initialize the variables we'll be using:
|
Chris@16
|
61 //
|
Chris@16
|
62 T lambda = theta / 2;
|
Chris@16
|
63 T del = f / 2;
|
Chris@16
|
64 T y = x / 2;
|
Chris@16
|
65 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
66 T errtol = boost::math::policies::get_epsilon<T, Policy>();
|
Chris@16
|
67 T sum = init_sum;
|
Chris@16
|
68 //
|
Chris@16
|
69 // k is the starting location for iteration, we'll
|
Chris@16
|
70 // move both forwards and backwards from this point.
|
Chris@16
|
71 // k is chosen as the peek of the Poisson weights, which
|
Chris@16
|
72 // will occur *before* the largest term.
|
Chris@16
|
73 //
|
Chris@16
|
74 int k = iround(lambda, pol);
|
Chris@16
|
75 // Forwards and backwards Poisson weights:
|
Chris@16
|
76 T poisf = boost::math::gamma_p_derivative(1 + k, lambda, pol);
|
Chris@16
|
77 T poisb = poisf * k / lambda;
|
Chris@16
|
78 // Initial forwards central chi squared term:
|
Chris@16
|
79 T gamf = boost::math::gamma_q(del + k, y, pol);
|
Chris@16
|
80 // Forwards and backwards recursion terms on the central chi squared:
|
Chris@16
|
81 T xtermf = boost::math::gamma_p_derivative(del + 1 + k, y, pol);
|
Chris@16
|
82 T xtermb = xtermf * (del + k) / y;
|
Chris@16
|
83 // Initial backwards central chi squared term:
|
Chris@16
|
84 T gamb = gamf - xtermb;
|
Chris@16
|
85
|
Chris@16
|
86 //
|
Chris@16
|
87 // Forwards iteration first, this is the
|
Chris@16
|
88 // stable direction for the gamma function
|
Chris@16
|
89 // recurrences:
|
Chris@16
|
90 //
|
Chris@16
|
91 int i;
|
Chris@16
|
92 for(i = k; static_cast<boost::uintmax_t>(i-k) < max_iter; ++i)
|
Chris@16
|
93 {
|
Chris@16
|
94 T term = poisf * gamf;
|
Chris@16
|
95 sum += term;
|
Chris@16
|
96 poisf *= lambda / (i + 1);
|
Chris@16
|
97 gamf += xtermf;
|
Chris@16
|
98 xtermf *= y / (del + i + 1);
|
Chris@16
|
99 if(((sum == 0) || (fabs(term / sum) < errtol)) && (term >= poisf * gamf))
|
Chris@16
|
100 break;
|
Chris@16
|
101 }
|
Chris@16
|
102 //Error check:
|
Chris@16
|
103 if(static_cast<boost::uintmax_t>(i-k) >= max_iter)
|
Chris@101
|
104 return policies::raise_evaluation_error(
|
Chris@16
|
105 "cdf(non_central_chi_squared_distribution<%1%>, %1%)",
|
Chris@16
|
106 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
107 //
|
Chris@16
|
108 // Now backwards iteration: the gamma
|
Chris@16
|
109 // function recurrences are unstable in this
|
Chris@16
|
110 // direction, we rely on the terms deminishing in size
|
Chris@16
|
111 // faster than we introduce cancellation errors.
|
Chris@16
|
112 // For this reason it's very important that we start
|
Chris@16
|
113 // *before* the largest term so that backwards iteration
|
Chris@16
|
114 // is strictly converging.
|
Chris@16
|
115 //
|
Chris@16
|
116 for(i = k - 1; i >= 0; --i)
|
Chris@16
|
117 {
|
Chris@16
|
118 T term = poisb * gamb;
|
Chris@16
|
119 sum += term;
|
Chris@16
|
120 poisb *= i / lambda;
|
Chris@16
|
121 xtermb *= (del + i) / y;
|
Chris@16
|
122 gamb -= xtermb;
|
Chris@16
|
123 if((sum == 0) || (fabs(term / sum) < errtol))
|
Chris@16
|
124 break;
|
Chris@16
|
125 }
|
Chris@16
|
126
|
Chris@16
|
127 return sum;
|
Chris@16
|
128 }
|
Chris@16
|
129
|
Chris@16
|
130 template <class T, class Policy>
|
Chris@16
|
131 T non_central_chi_square_p_ding(T x, T f, T theta, const Policy& pol, T init_sum = 0)
|
Chris@16
|
132 {
|
Chris@16
|
133 //
|
Chris@16
|
134 // This is an implementation of:
|
Chris@16
|
135 //
|
Chris@16
|
136 // Algorithm AS 275:
|
Chris@16
|
137 // Computing the Non-Central #2 Distribution Function
|
Chris@16
|
138 // Cherng G. Ding
|
Chris@16
|
139 // Applied Statistics, Vol. 41, No. 2. (1992), pp. 478-482.
|
Chris@16
|
140 //
|
Chris@16
|
141 // This uses a stable forward iteration to sum the
|
Chris@16
|
142 // CDF, unfortunately this can not be used for large
|
Chris@16
|
143 // values of the non-centrality parameter because:
|
Chris@16
|
144 // * The first term may underfow to zero.
|
Chris@16
|
145 // * We may need an extra-ordinary number of terms
|
Chris@16
|
146 // before we reach the first *significant* term.
|
Chris@16
|
147 //
|
Chris@16
|
148 BOOST_MATH_STD_USING
|
Chris@16
|
149 // Special case:
|
Chris@16
|
150 if(x == 0)
|
Chris@16
|
151 return 0;
|
Chris@16
|
152 T tk = boost::math::gamma_p_derivative(f/2 + 1, x/2, pol);
|
Chris@16
|
153 T lambda = theta / 2;
|
Chris@16
|
154 T vk = exp(-lambda);
|
Chris@16
|
155 T uk = vk;
|
Chris@16
|
156 T sum = init_sum + tk * vk;
|
Chris@16
|
157 if(sum == 0)
|
Chris@16
|
158 return sum;
|
Chris@16
|
159
|
Chris@16
|
160 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
161 T errtol = boost::math::policies::get_epsilon<T, Policy>();
|
Chris@16
|
162
|
Chris@16
|
163 int i;
|
Chris@16
|
164 T lterm(0), term(0);
|
Chris@16
|
165 for(i = 1; static_cast<boost::uintmax_t>(i) < max_iter; ++i)
|
Chris@16
|
166 {
|
Chris@16
|
167 tk = tk * x / (f + 2 * i);
|
Chris@16
|
168 uk = uk * lambda / i;
|
Chris@16
|
169 vk = vk + uk;
|
Chris@16
|
170 lterm = term;
|
Chris@16
|
171 term = vk * tk;
|
Chris@16
|
172 sum += term;
|
Chris@16
|
173 if((fabs(term / sum) < errtol) && (term <= lterm))
|
Chris@16
|
174 break;
|
Chris@16
|
175 }
|
Chris@16
|
176 //Error check:
|
Chris@16
|
177 if(static_cast<boost::uintmax_t>(i) >= max_iter)
|
Chris@101
|
178 return policies::raise_evaluation_error(
|
Chris@16
|
179 "cdf(non_central_chi_squared_distribution<%1%>, %1%)",
|
Chris@16
|
180 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
181 return sum;
|
Chris@16
|
182 }
|
Chris@16
|
183
|
Chris@16
|
184
|
Chris@16
|
185 template <class T, class Policy>
|
Chris@16
|
186 T non_central_chi_square_p(T y, T n, T lambda, const Policy& pol, T init_sum)
|
Chris@16
|
187 {
|
Chris@16
|
188 //
|
Chris@16
|
189 // This is taken more or less directly from:
|
Chris@16
|
190 //
|
Chris@16
|
191 // Computing discrete mixtures of continuous
|
Chris@16
|
192 // distributions: noncentral chisquare, noncentral t
|
Chris@16
|
193 // and the distribution of the square of the sample
|
Chris@16
|
194 // multiple correlation coeficient.
|
Chris@16
|
195 // D. Benton, K. Krishnamoorthy.
|
Chris@16
|
196 // Computational Statistics & Data Analysis 43 (2003) 249 - 267
|
Chris@16
|
197 //
|
Chris@16
|
198 // We're summing a Poisson weighting term multiplied by
|
Chris@16
|
199 // a central chi squared distribution.
|
Chris@16
|
200 //
|
Chris@16
|
201 BOOST_MATH_STD_USING
|
Chris@16
|
202 // Special case:
|
Chris@16
|
203 if(y == 0)
|
Chris@16
|
204 return 0;
|
Chris@16
|
205 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
206 T errtol = boost::math::policies::get_epsilon<T, Policy>();
|
Chris@16
|
207 T errorf(0), errorb(0);
|
Chris@16
|
208
|
Chris@16
|
209 T x = y / 2;
|
Chris@16
|
210 T del = lambda / 2;
|
Chris@16
|
211 //
|
Chris@16
|
212 // Starting location for the iteration, we'll iterate
|
Chris@16
|
213 // both forwards and backwards from this point. The
|
Chris@16
|
214 // location chosen is the maximum of the Poisson weight
|
Chris@16
|
215 // function, which ocurrs *after* the largest term in the
|
Chris@16
|
216 // sum.
|
Chris@16
|
217 //
|
Chris@16
|
218 int k = iround(del, pol);
|
Chris@16
|
219 T a = n / 2 + k;
|
Chris@16
|
220 // Central chi squared term for forward iteration:
|
Chris@16
|
221 T gamkf = boost::math::gamma_p(a, x, pol);
|
Chris@16
|
222
|
Chris@16
|
223 if(lambda == 0)
|
Chris@16
|
224 return gamkf;
|
Chris@16
|
225 // Central chi squared term for backward iteration:
|
Chris@16
|
226 T gamkb = gamkf;
|
Chris@16
|
227 // Forwards Poisson weight:
|
Chris@16
|
228 T poiskf = gamma_p_derivative(k+1, del, pol);
|
Chris@16
|
229 // Backwards Poisson weight:
|
Chris@16
|
230 T poiskb = poiskf;
|
Chris@16
|
231 // Forwards gamma function recursion term:
|
Chris@16
|
232 T xtermf = boost::math::gamma_p_derivative(a, x, pol);
|
Chris@16
|
233 // Backwards gamma function recursion term:
|
Chris@16
|
234 T xtermb = xtermf * x / a;
|
Chris@16
|
235 T sum = init_sum + poiskf * gamkf;
|
Chris@16
|
236 if(sum == 0)
|
Chris@16
|
237 return sum;
|
Chris@16
|
238 int i = 1;
|
Chris@16
|
239 //
|
Chris@16
|
240 // Backwards recursion first, this is the stable
|
Chris@16
|
241 // direction for gamma function recurrences:
|
Chris@16
|
242 //
|
Chris@16
|
243 while(i <= k)
|
Chris@16
|
244 {
|
Chris@16
|
245 xtermb *= (a - i + 1) / x;
|
Chris@16
|
246 gamkb += xtermb;
|
Chris@16
|
247 poiskb = poiskb * (k - i + 1) / del;
|
Chris@16
|
248 errorf = errorb;
|
Chris@16
|
249 errorb = gamkb * poiskb;
|
Chris@16
|
250 sum += errorb;
|
Chris@16
|
251 if((fabs(errorb / sum) < errtol) && (errorb <= errorf))
|
Chris@16
|
252 break;
|
Chris@16
|
253 ++i;
|
Chris@16
|
254 }
|
Chris@16
|
255 i = 1;
|
Chris@16
|
256 //
|
Chris@16
|
257 // Now forwards recursion, the gamma function
|
Chris@16
|
258 // recurrence relation is unstable in this direction,
|
Chris@16
|
259 // so we rely on the magnitude of successive terms
|
Chris@16
|
260 // decreasing faster than we introduce cancellation error.
|
Chris@16
|
261 // For this reason it's vital that k is chosen to be *after*
|
Chris@16
|
262 // the largest term, so that successive forward iterations
|
Chris@16
|
263 // are strictly (and rapidly) converging.
|
Chris@16
|
264 //
|
Chris@16
|
265 do
|
Chris@16
|
266 {
|
Chris@16
|
267 xtermf = xtermf * x / (a + i - 1);
|
Chris@16
|
268 gamkf = gamkf - xtermf;
|
Chris@16
|
269 poiskf = poiskf * del / (k + i);
|
Chris@16
|
270 errorf = poiskf * gamkf;
|
Chris@16
|
271 sum += errorf;
|
Chris@16
|
272 ++i;
|
Chris@16
|
273 }while((fabs(errorf / sum) > errtol) && (static_cast<boost::uintmax_t>(i) < max_iter));
|
Chris@16
|
274
|
Chris@16
|
275 //Error check:
|
Chris@16
|
276 if(static_cast<boost::uintmax_t>(i) >= max_iter)
|
Chris@101
|
277 return policies::raise_evaluation_error(
|
Chris@16
|
278 "cdf(non_central_chi_squared_distribution<%1%>, %1%)",
|
Chris@16
|
279 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
280
|
Chris@16
|
281 return sum;
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 template <class T, class Policy>
|
Chris@16
|
285 T non_central_chi_square_pdf(T x, T n, T lambda, const Policy& pol)
|
Chris@16
|
286 {
|
Chris@16
|
287 //
|
Chris@16
|
288 // As above but for the PDF:
|
Chris@16
|
289 //
|
Chris@16
|
290 BOOST_MATH_STD_USING
|
Chris@16
|
291 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
292 T errtol = boost::math::policies::get_epsilon<T, Policy>();
|
Chris@16
|
293 T x2 = x / 2;
|
Chris@16
|
294 T n2 = n / 2;
|
Chris@16
|
295 T l2 = lambda / 2;
|
Chris@16
|
296 T sum = 0;
|
Chris@16
|
297 int k = itrunc(l2);
|
Chris@16
|
298 T pois = gamma_p_derivative(k + 1, l2, pol) * gamma_p_derivative(n2 + k, x2);
|
Chris@16
|
299 if(pois == 0)
|
Chris@16
|
300 return 0;
|
Chris@16
|
301 T poisb = pois;
|
Chris@16
|
302 for(int i = k; ; ++i)
|
Chris@16
|
303 {
|
Chris@16
|
304 sum += pois;
|
Chris@16
|
305 if(pois / sum < errtol)
|
Chris@16
|
306 break;
|
Chris@16
|
307 if(static_cast<boost::uintmax_t>(i - k) >= max_iter)
|
Chris@16
|
308 return policies::raise_evaluation_error(
|
Chris@16
|
309 "pdf(non_central_chi_squared_distribution<%1%>, %1%)",
|
Chris@16
|
310 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
311 pois *= l2 * x2 / ((i + 1) * (n2 + i));
|
Chris@16
|
312 }
|
Chris@16
|
313 for(int i = k - 1; i >= 0; --i)
|
Chris@16
|
314 {
|
Chris@16
|
315 poisb *= (i + 1) * (n2 + i) / (l2 * x2);
|
Chris@16
|
316 sum += poisb;
|
Chris@16
|
317 if(poisb / sum < errtol)
|
Chris@16
|
318 break;
|
Chris@16
|
319 }
|
Chris@16
|
320 return sum / 2;
|
Chris@16
|
321 }
|
Chris@16
|
322
|
Chris@16
|
323 template <class RealType, class Policy>
|
Chris@16
|
324 inline RealType non_central_chi_squared_cdf(RealType x, RealType k, RealType l, bool invert, const Policy&)
|
Chris@16
|
325 {
|
Chris@16
|
326 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
327 typedef typename policies::normalise<
|
Chris@16
|
328 Policy,
|
Chris@16
|
329 policies::promote_float<false>,
|
Chris@16
|
330 policies::promote_double<false>,
|
Chris@16
|
331 policies::discrete_quantile<>,
|
Chris@16
|
332 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
333
|
Chris@16
|
334 BOOST_MATH_STD_USING
|
Chris@16
|
335 value_type result;
|
Chris@16
|
336 if(l == 0)
|
Chris@16
|
337 result = cdf(boost::math::chi_squared_distribution<RealType, Policy>(k), x);
|
Chris@16
|
338 else if(x > k + l)
|
Chris@16
|
339 {
|
Chris@16
|
340 // Complement is the smaller of the two:
|
Chris@16
|
341 result = detail::non_central_chi_square_q(
|
Chris@16
|
342 static_cast<value_type>(x),
|
Chris@16
|
343 static_cast<value_type>(k),
|
Chris@16
|
344 static_cast<value_type>(l),
|
Chris@16
|
345 forwarding_policy(),
|
Chris@16
|
346 static_cast<value_type>(invert ? 0 : -1));
|
Chris@16
|
347 invert = !invert;
|
Chris@16
|
348 }
|
Chris@16
|
349 else if(l < 200)
|
Chris@16
|
350 {
|
Chris@16
|
351 // For small values of the non-centrality parameter
|
Chris@16
|
352 // we can use Ding's method:
|
Chris@16
|
353 result = detail::non_central_chi_square_p_ding(
|
Chris@16
|
354 static_cast<value_type>(x),
|
Chris@16
|
355 static_cast<value_type>(k),
|
Chris@16
|
356 static_cast<value_type>(l),
|
Chris@16
|
357 forwarding_policy(),
|
Chris@16
|
358 static_cast<value_type>(invert ? -1 : 0));
|
Chris@16
|
359 }
|
Chris@16
|
360 else
|
Chris@16
|
361 {
|
Chris@16
|
362 // For largers values of the non-centrality
|
Chris@16
|
363 // parameter Ding's method will consume an
|
Chris@16
|
364 // extra-ordinary number of terms, and worse
|
Chris@16
|
365 // may return zero when the result is in fact
|
Chris@16
|
366 // finite, use Krishnamoorthy's method instead:
|
Chris@16
|
367 result = detail::non_central_chi_square_p(
|
Chris@16
|
368 static_cast<value_type>(x),
|
Chris@16
|
369 static_cast<value_type>(k),
|
Chris@16
|
370 static_cast<value_type>(l),
|
Chris@16
|
371 forwarding_policy(),
|
Chris@16
|
372 static_cast<value_type>(invert ? -1 : 0));
|
Chris@16
|
373 }
|
Chris@16
|
374 if(invert)
|
Chris@16
|
375 result = -result;
|
Chris@16
|
376 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
377 result,
|
Chris@16
|
378 "boost::math::non_central_chi_squared_cdf<%1%>(%1%, %1%, %1%)");
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 template <class T, class Policy>
|
Chris@16
|
382 struct nccs_quantile_functor
|
Chris@16
|
383 {
|
Chris@16
|
384 nccs_quantile_functor(const non_central_chi_squared_distribution<T,Policy>& d, T t, bool c)
|
Chris@16
|
385 : dist(d), target(t), comp(c) {}
|
Chris@16
|
386
|
Chris@16
|
387 T operator()(const T& x)
|
Chris@16
|
388 {
|
Chris@16
|
389 return comp ?
|
Chris@16
|
390 target - cdf(complement(dist, x))
|
Chris@16
|
391 : cdf(dist, x) - target;
|
Chris@16
|
392 }
|
Chris@16
|
393
|
Chris@16
|
394 private:
|
Chris@16
|
395 non_central_chi_squared_distribution<T,Policy> dist;
|
Chris@16
|
396 T target;
|
Chris@16
|
397 bool comp;
|
Chris@16
|
398 };
|
Chris@16
|
399
|
Chris@16
|
400 template <class RealType, class Policy>
|
Chris@16
|
401 RealType nccs_quantile(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& p, bool comp)
|
Chris@16
|
402 {
|
Chris@16
|
403 BOOST_MATH_STD_USING
|
Chris@16
|
404 static const char* function = "quantile(non_central_chi_squared_distribution<%1%>, %1%)";
|
Chris@16
|
405 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
406 typedef typename policies::normalise<
|
Chris@16
|
407 Policy,
|
Chris@16
|
408 policies::promote_float<false>,
|
Chris@16
|
409 policies::promote_double<false>,
|
Chris@16
|
410 policies::discrete_quantile<>,
|
Chris@16
|
411 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
412
|
Chris@16
|
413 value_type k = dist.degrees_of_freedom();
|
Chris@16
|
414 value_type l = dist.non_centrality();
|
Chris@16
|
415 value_type r;
|
Chris@16
|
416 if(!detail::check_df(
|
Chris@16
|
417 function,
|
Chris@16
|
418 k, &r, Policy())
|
Chris@16
|
419 ||
|
Chris@16
|
420 !detail::check_non_centrality(
|
Chris@16
|
421 function,
|
Chris@16
|
422 l,
|
Chris@16
|
423 &r,
|
Chris@16
|
424 Policy())
|
Chris@16
|
425 ||
|
Chris@16
|
426 !detail::check_probability(
|
Chris@16
|
427 function,
|
Chris@16
|
428 static_cast<value_type>(p),
|
Chris@16
|
429 &r,
|
Chris@16
|
430 Policy()))
|
Chris@16
|
431 return (RealType)r;
|
Chris@16
|
432 //
|
Chris@16
|
433 // Special cases get short-circuited first:
|
Chris@16
|
434 //
|
Chris@16
|
435 if(p == 0)
|
Chris@101
|
436 return comp ? policies::raise_overflow_error<RealType>(function, 0, Policy()) : 0;
|
Chris@16
|
437 if(p == 1)
|
Chris@101
|
438 return comp ? 0 : policies::raise_overflow_error<RealType>(function, 0, Policy());
|
Chris@16
|
439 //
|
Chris@16
|
440 // This is Pearson's approximation to the quantile, see
|
Chris@16
|
441 // Pearson, E. S. (1959) "Note on an approximation to the distribution of
|
Chris@16
|
442 // noncentral chi squared", Biometrika 46: 364.
|
Chris@16
|
443 // See also:
|
Chris@16
|
444 // "A comparison of approximations to percentiles of the noncentral chi2-distribution",
|
Chris@16
|
445 // Hardeo Sahai and Mario Miguel Ojeda, Revista de Matematica: Teoria y Aplicaciones 2003 10(1–2) : 57–76.
|
Chris@16
|
446 // Note that the latter reference refers to an approximation of the CDF, when they really mean the quantile.
|
Chris@16
|
447 //
|
Chris@16
|
448 value_type b = -(l * l) / (k + 3 * l);
|
Chris@16
|
449 value_type c = (k + 3 * l) / (k + 2 * l);
|
Chris@16
|
450 value_type ff = (k + 2 * l) / (c * c);
|
Chris@16
|
451 value_type guess;
|
Chris@16
|
452 if(comp)
|
Chris@16
|
453 {
|
Chris@16
|
454 guess = b + c * quantile(complement(chi_squared_distribution<value_type, forwarding_policy>(ff), p));
|
Chris@16
|
455 }
|
Chris@16
|
456 else
|
Chris@16
|
457 {
|
Chris@16
|
458 guess = b + c * quantile(chi_squared_distribution<value_type, forwarding_policy>(ff), p);
|
Chris@16
|
459 }
|
Chris@16
|
460 //
|
Chris@16
|
461 // Sometimes guess goes very small or negative, in that case we have
|
Chris@16
|
462 // to do something else for the initial guess, this approximation
|
Chris@16
|
463 // was provided in a private communication from Thomas Luu, PhD candidate,
|
Chris@16
|
464 // University College London. It's an asymptotic expansion for the
|
Chris@16
|
465 // quantile which usually gets us within an order of magnitude of the
|
Chris@16
|
466 // correct answer.
|
Chris@16
|
467 //
|
Chris@16
|
468 if(guess < 0.005)
|
Chris@16
|
469 {
|
Chris@16
|
470 value_type pp = comp ? 1 - p : p;
|
Chris@16
|
471 //guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k, 2 / k);
|
Chris@16
|
472 guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k * boost::math::tgamma(k / 2, forwarding_policy()), (2 / k));
|
Chris@16
|
473 if(guess == 0)
|
Chris@16
|
474 guess = tools::min_value<value_type>();
|
Chris@16
|
475 }
|
Chris@16
|
476 value_type result = detail::generic_quantile(
|
Chris@16
|
477 non_central_chi_squared_distribution<value_type, forwarding_policy>(k, l),
|
Chris@16
|
478 p,
|
Chris@16
|
479 guess,
|
Chris@16
|
480 comp,
|
Chris@16
|
481 function);
|
Chris@16
|
482
|
Chris@16
|
483 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
484 result,
|
Chris@16
|
485 function);
|
Chris@16
|
486 }
|
Chris@16
|
487
|
Chris@16
|
488 template <class RealType, class Policy>
|
Chris@16
|
489 RealType nccs_pdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
|
Chris@16
|
490 {
|
Chris@16
|
491 BOOST_MATH_STD_USING
|
Chris@16
|
492 static const char* function = "pdf(non_central_chi_squared_distribution<%1%>, %1%)";
|
Chris@16
|
493 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
494 typedef typename policies::normalise<
|
Chris@16
|
495 Policy,
|
Chris@16
|
496 policies::promote_float<false>,
|
Chris@16
|
497 policies::promote_double<false>,
|
Chris@16
|
498 policies::discrete_quantile<>,
|
Chris@16
|
499 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
500
|
Chris@16
|
501 value_type k = dist.degrees_of_freedom();
|
Chris@16
|
502 value_type l = dist.non_centrality();
|
Chris@16
|
503 value_type r;
|
Chris@16
|
504 if(!detail::check_df(
|
Chris@16
|
505 function,
|
Chris@16
|
506 k, &r, Policy())
|
Chris@16
|
507 ||
|
Chris@16
|
508 !detail::check_non_centrality(
|
Chris@16
|
509 function,
|
Chris@16
|
510 l,
|
Chris@16
|
511 &r,
|
Chris@16
|
512 Policy())
|
Chris@16
|
513 ||
|
Chris@16
|
514 !detail::check_positive_x(
|
Chris@16
|
515 function,
|
Chris@16
|
516 (value_type)x,
|
Chris@16
|
517 &r,
|
Chris@16
|
518 Policy()))
|
Chris@16
|
519 return (RealType)r;
|
Chris@16
|
520
|
Chris@16
|
521 if(l == 0)
|
Chris@16
|
522 return pdf(boost::math::chi_squared_distribution<RealType, forwarding_policy>(dist.degrees_of_freedom()), x);
|
Chris@16
|
523
|
Chris@16
|
524 // Special case:
|
Chris@16
|
525 if(x == 0)
|
Chris@16
|
526 return 0;
|
Chris@16
|
527 if(l > 50)
|
Chris@16
|
528 {
|
Chris@16
|
529 r = non_central_chi_square_pdf(static_cast<value_type>(x), k, l, forwarding_policy());
|
Chris@16
|
530 }
|
Chris@16
|
531 else
|
Chris@16
|
532 {
|
Chris@16
|
533 r = log(x / l) * (k / 4 - 0.5f) - (x + l) / 2;
|
Chris@16
|
534 if(fabs(r) >= tools::log_max_value<RealType>() / 4)
|
Chris@16
|
535 {
|
Chris@16
|
536 r = non_central_chi_square_pdf(static_cast<value_type>(x), k, l, forwarding_policy());
|
Chris@16
|
537 }
|
Chris@16
|
538 else
|
Chris@16
|
539 {
|
Chris@16
|
540 r = exp(r);
|
Chris@16
|
541 r = 0.5f * r
|
Chris@16
|
542 * boost::math::cyl_bessel_i(k/2 - 1, sqrt(l * x), forwarding_policy());
|
Chris@16
|
543 }
|
Chris@16
|
544 }
|
Chris@16
|
545 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
546 r,
|
Chris@16
|
547 function);
|
Chris@16
|
548 }
|
Chris@16
|
549
|
Chris@16
|
550 template <class RealType, class Policy>
|
Chris@16
|
551 struct degrees_of_freedom_finder
|
Chris@16
|
552 {
|
Chris@16
|
553 degrees_of_freedom_finder(
|
Chris@16
|
554 RealType lam_, RealType x_, RealType p_, bool c)
|
Chris@16
|
555 : lam(lam_), x(x_), p(p_), comp(c) {}
|
Chris@16
|
556
|
Chris@16
|
557 RealType operator()(const RealType& v)
|
Chris@16
|
558 {
|
Chris@16
|
559 non_central_chi_squared_distribution<RealType, Policy> d(v, lam);
|
Chris@16
|
560 return comp ?
|
Chris@16
|
561 RealType(p - cdf(complement(d, x)))
|
Chris@16
|
562 : RealType(cdf(d, x) - p);
|
Chris@16
|
563 }
|
Chris@16
|
564 private:
|
Chris@16
|
565 RealType lam;
|
Chris@16
|
566 RealType x;
|
Chris@16
|
567 RealType p;
|
Chris@16
|
568 bool comp;
|
Chris@16
|
569 };
|
Chris@16
|
570
|
Chris@16
|
571 template <class RealType, class Policy>
|
Chris@16
|
572 inline RealType find_degrees_of_freedom(
|
Chris@16
|
573 RealType lam, RealType x, RealType p, RealType q, const Policy& pol)
|
Chris@16
|
574 {
|
Chris@16
|
575 const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
|
Chris@16
|
576 if((p == 0) || (q == 0))
|
Chris@16
|
577 {
|
Chris@16
|
578 //
|
Chris@16
|
579 // Can't a thing if one of p and q is zero:
|
Chris@16
|
580 //
|
Chris@16
|
581 return policies::raise_evaluation_error<RealType>(function,
|
Chris@16
|
582 "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%",
|
Chris@16
|
583 RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy());
|
Chris@16
|
584 }
|
Chris@16
|
585 degrees_of_freedom_finder<RealType, Policy> f(lam, x, p < q ? p : q, p < q ? false : true);
|
Chris@16
|
586 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
|
Chris@16
|
587 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
588 //
|
Chris@16
|
589 // Pick an initial guess that we know will give us a probability
|
Chris@16
|
590 // right around 0.5.
|
Chris@16
|
591 //
|
Chris@16
|
592 RealType guess = x - lam;
|
Chris@16
|
593 if(guess < 1)
|
Chris@16
|
594 guess = 1;
|
Chris@16
|
595 std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
|
Chris@16
|
596 f, guess, RealType(2), false, tol, max_iter, pol);
|
Chris@16
|
597 RealType result = ir.first + (ir.second - ir.first) / 2;
|
Chris@16
|
598 if(max_iter >= policies::get_max_root_iterations<Policy>())
|
Chris@16
|
599 {
|
Chris@101
|
600 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
|
Chris@16
|
601 " or there is no answer to problem. Current best guess is %1%", result, Policy());
|
Chris@16
|
602 }
|
Chris@16
|
603 return result;
|
Chris@16
|
604 }
|
Chris@16
|
605
|
Chris@16
|
606 template <class RealType, class Policy>
|
Chris@16
|
607 struct non_centrality_finder
|
Chris@16
|
608 {
|
Chris@16
|
609 non_centrality_finder(
|
Chris@16
|
610 RealType v_, RealType x_, RealType p_, bool c)
|
Chris@16
|
611 : v(v_), x(x_), p(p_), comp(c) {}
|
Chris@16
|
612
|
Chris@16
|
613 RealType operator()(const RealType& lam)
|
Chris@16
|
614 {
|
Chris@16
|
615 non_central_chi_squared_distribution<RealType, Policy> d(v, lam);
|
Chris@16
|
616 return comp ?
|
Chris@16
|
617 RealType(p - cdf(complement(d, x)))
|
Chris@16
|
618 : RealType(cdf(d, x) - p);
|
Chris@16
|
619 }
|
Chris@16
|
620 private:
|
Chris@16
|
621 RealType v;
|
Chris@16
|
622 RealType x;
|
Chris@16
|
623 RealType p;
|
Chris@16
|
624 bool comp;
|
Chris@16
|
625 };
|
Chris@16
|
626
|
Chris@16
|
627 template <class RealType, class Policy>
|
Chris@16
|
628 inline RealType find_non_centrality(
|
Chris@16
|
629 RealType v, RealType x, RealType p, RealType q, const Policy& pol)
|
Chris@16
|
630 {
|
Chris@16
|
631 const char* function = "non_central_chi_squared<%1%>::find_non_centrality";
|
Chris@16
|
632 if((p == 0) || (q == 0))
|
Chris@16
|
633 {
|
Chris@16
|
634 //
|
Chris@16
|
635 // Can't do a thing if one of p and q is zero:
|
Chris@16
|
636 //
|
Chris@16
|
637 return policies::raise_evaluation_error<RealType>(function,
|
Chris@16
|
638 "Can't find non centrality parameter when the probability is 0 or 1, only possible answer is %1%",
|
Chris@16
|
639 RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy());
|
Chris@16
|
640 }
|
Chris@16
|
641 non_centrality_finder<RealType, Policy> f(v, x, p < q ? p : q, p < q ? false : true);
|
Chris@16
|
642 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
|
Chris@16
|
643 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
644 //
|
Chris@16
|
645 // Pick an initial guess that we know will give us a probability
|
Chris@16
|
646 // right around 0.5.
|
Chris@16
|
647 //
|
Chris@16
|
648 RealType guess = x - v;
|
Chris@16
|
649 if(guess < 1)
|
Chris@16
|
650 guess = 1;
|
Chris@16
|
651 std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
|
Chris@16
|
652 f, guess, RealType(2), false, tol, max_iter, pol);
|
Chris@16
|
653 RealType result = ir.first + (ir.second - ir.first) / 2;
|
Chris@16
|
654 if(max_iter >= policies::get_max_root_iterations<Policy>())
|
Chris@16
|
655 {
|
Chris@101
|
656 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
|
Chris@16
|
657 " or there is no answer to problem. Current best guess is %1%", result, Policy());
|
Chris@16
|
658 }
|
Chris@16
|
659 return result;
|
Chris@16
|
660 }
|
Chris@16
|
661
|
Chris@16
|
662 }
|
Chris@16
|
663
|
Chris@16
|
664 template <class RealType = double, class Policy = policies::policy<> >
|
Chris@16
|
665 class non_central_chi_squared_distribution
|
Chris@16
|
666 {
|
Chris@16
|
667 public:
|
Chris@16
|
668 typedef RealType value_type;
|
Chris@16
|
669 typedef Policy policy_type;
|
Chris@16
|
670
|
Chris@16
|
671 non_central_chi_squared_distribution(RealType df_, RealType lambda) : df(df_), ncp(lambda)
|
Chris@16
|
672 {
|
Chris@16
|
673 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::non_central_chi_squared_distribution(%1%,%1%)";
|
Chris@16
|
674 RealType r;
|
Chris@16
|
675 detail::check_df(
|
Chris@16
|
676 function,
|
Chris@16
|
677 df, &r, Policy());
|
Chris@16
|
678 detail::check_non_centrality(
|
Chris@16
|
679 function,
|
Chris@16
|
680 ncp,
|
Chris@16
|
681 &r,
|
Chris@16
|
682 Policy());
|
Chris@16
|
683 } // non_central_chi_squared_distribution constructor.
|
Chris@16
|
684
|
Chris@16
|
685 RealType degrees_of_freedom() const
|
Chris@16
|
686 { // Private data getter function.
|
Chris@16
|
687 return df;
|
Chris@16
|
688 }
|
Chris@16
|
689 RealType non_centrality() const
|
Chris@16
|
690 { // Private data getter function.
|
Chris@16
|
691 return ncp;
|
Chris@16
|
692 }
|
Chris@16
|
693 static RealType find_degrees_of_freedom(RealType lam, RealType x, RealType p)
|
Chris@16
|
694 {
|
Chris@16
|
695 const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
|
Chris@16
|
696 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
697 typedef typename policies::normalise<
|
Chris@16
|
698 Policy,
|
Chris@16
|
699 policies::promote_float<false>,
|
Chris@16
|
700 policies::promote_double<false>,
|
Chris@16
|
701 policies::discrete_quantile<>,
|
Chris@16
|
702 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
703 value_type result = detail::find_degrees_of_freedom(
|
Chris@16
|
704 static_cast<value_type>(lam),
|
Chris@16
|
705 static_cast<value_type>(x),
|
Chris@16
|
706 static_cast<value_type>(p),
|
Chris@16
|
707 static_cast<value_type>(1-p),
|
Chris@16
|
708 forwarding_policy());
|
Chris@16
|
709 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
710 result,
|
Chris@16
|
711 function);
|
Chris@16
|
712 }
|
Chris@16
|
713 template <class A, class B, class C>
|
Chris@16
|
714 static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
|
Chris@16
|
715 {
|
Chris@16
|
716 const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
|
Chris@16
|
717 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
718 typedef typename policies::normalise<
|
Chris@16
|
719 Policy,
|
Chris@16
|
720 policies::promote_float<false>,
|
Chris@16
|
721 policies::promote_double<false>,
|
Chris@16
|
722 policies::discrete_quantile<>,
|
Chris@16
|
723 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
724 value_type result = detail::find_degrees_of_freedom(
|
Chris@16
|
725 static_cast<value_type>(c.dist),
|
Chris@16
|
726 static_cast<value_type>(c.param1),
|
Chris@16
|
727 static_cast<value_type>(1-c.param2),
|
Chris@16
|
728 static_cast<value_type>(c.param2),
|
Chris@16
|
729 forwarding_policy());
|
Chris@16
|
730 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
731 result,
|
Chris@16
|
732 function);
|
Chris@16
|
733 }
|
Chris@16
|
734 static RealType find_non_centrality(RealType v, RealType x, RealType p)
|
Chris@16
|
735 {
|
Chris@16
|
736 const char* function = "non_central_chi_squared<%1%>::find_non_centrality";
|
Chris@16
|
737 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
738 typedef typename policies::normalise<
|
Chris@16
|
739 Policy,
|
Chris@16
|
740 policies::promote_float<false>,
|
Chris@16
|
741 policies::promote_double<false>,
|
Chris@16
|
742 policies::discrete_quantile<>,
|
Chris@16
|
743 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
744 value_type result = detail::find_non_centrality(
|
Chris@16
|
745 static_cast<value_type>(v),
|
Chris@16
|
746 static_cast<value_type>(x),
|
Chris@16
|
747 static_cast<value_type>(p),
|
Chris@16
|
748 static_cast<value_type>(1-p),
|
Chris@16
|
749 forwarding_policy());
|
Chris@16
|
750 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
751 result,
|
Chris@16
|
752 function);
|
Chris@16
|
753 }
|
Chris@16
|
754 template <class A, class B, class C>
|
Chris@16
|
755 static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
|
Chris@16
|
756 {
|
Chris@16
|
757 const char* function = "non_central_chi_squared<%1%>::find_non_centrality";
|
Chris@16
|
758 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
759 typedef typename policies::normalise<
|
Chris@16
|
760 Policy,
|
Chris@16
|
761 policies::promote_float<false>,
|
Chris@16
|
762 policies::promote_double<false>,
|
Chris@16
|
763 policies::discrete_quantile<>,
|
Chris@16
|
764 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
765 value_type result = detail::find_non_centrality(
|
Chris@16
|
766 static_cast<value_type>(c.dist),
|
Chris@16
|
767 static_cast<value_type>(c.param1),
|
Chris@16
|
768 static_cast<value_type>(1-c.param2),
|
Chris@16
|
769 static_cast<value_type>(c.param2),
|
Chris@16
|
770 forwarding_policy());
|
Chris@16
|
771 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
772 result,
|
Chris@16
|
773 function);
|
Chris@16
|
774 }
|
Chris@16
|
775 private:
|
Chris@16
|
776 // Data member, initialized by constructor.
|
Chris@16
|
777 RealType df; // degrees of freedom.
|
Chris@16
|
778 RealType ncp; // non-centrality parameter
|
Chris@16
|
779 }; // template <class RealType, class Policy> class non_central_chi_squared_distribution
|
Chris@16
|
780
|
Chris@16
|
781 typedef non_central_chi_squared_distribution<double> non_central_chi_squared; // Reserved name of type double.
|
Chris@16
|
782
|
Chris@16
|
783 // Non-member functions to give properties of the distribution.
|
Chris@16
|
784
|
Chris@16
|
785 template <class RealType, class Policy>
|
Chris@16
|
786 inline const std::pair<RealType, RealType> range(const non_central_chi_squared_distribution<RealType, Policy>& /* dist */)
|
Chris@16
|
787 { // Range of permissible values for random variable k.
|
Chris@16
|
788 using boost::math::tools::max_value;
|
Chris@16
|
789 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // Max integer?
|
Chris@16
|
790 }
|
Chris@16
|
791
|
Chris@16
|
792 template <class RealType, class Policy>
|
Chris@16
|
793 inline const std::pair<RealType, RealType> support(const non_central_chi_squared_distribution<RealType, Policy>& /* dist */)
|
Chris@16
|
794 { // Range of supported values for random variable k.
|
Chris@16
|
795 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
|
Chris@16
|
796 using boost::math::tools::max_value;
|
Chris@16
|
797 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
|
Chris@16
|
798 }
|
Chris@16
|
799
|
Chris@16
|
800 template <class RealType, class Policy>
|
Chris@16
|
801 inline RealType mean(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
802 { // Mean of poisson distribution = lambda.
|
Chris@16
|
803 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::mean()";
|
Chris@16
|
804 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
805 RealType l = dist.non_centrality();
|
Chris@16
|
806 RealType r;
|
Chris@16
|
807 if(!detail::check_df(
|
Chris@16
|
808 function,
|
Chris@16
|
809 k, &r, Policy())
|
Chris@16
|
810 ||
|
Chris@16
|
811 !detail::check_non_centrality(
|
Chris@16
|
812 function,
|
Chris@16
|
813 l,
|
Chris@16
|
814 &r,
|
Chris@16
|
815 Policy()))
|
Chris@16
|
816 return r;
|
Chris@16
|
817 return k + l;
|
Chris@16
|
818 } // mean
|
Chris@16
|
819
|
Chris@16
|
820 template <class RealType, class Policy>
|
Chris@16
|
821 inline RealType mode(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
822 { // mode.
|
Chris@16
|
823 static const char* function = "mode(non_central_chi_squared_distribution<%1%> const&)";
|
Chris@16
|
824
|
Chris@16
|
825 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
826 RealType l = dist.non_centrality();
|
Chris@16
|
827 RealType r;
|
Chris@16
|
828 if(!detail::check_df(
|
Chris@16
|
829 function,
|
Chris@16
|
830 k, &r, Policy())
|
Chris@16
|
831 ||
|
Chris@16
|
832 !detail::check_non_centrality(
|
Chris@16
|
833 function,
|
Chris@16
|
834 l,
|
Chris@16
|
835 &r,
|
Chris@16
|
836 Policy()))
|
Chris@16
|
837 return (RealType)r;
|
Chris@16
|
838 return detail::generic_find_mode(dist, 1 + k, function);
|
Chris@16
|
839 }
|
Chris@16
|
840
|
Chris@16
|
841 template <class RealType, class Policy>
|
Chris@16
|
842 inline RealType variance(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
843 { // variance.
|
Chris@16
|
844 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::variance()";
|
Chris@16
|
845 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
846 RealType l = dist.non_centrality();
|
Chris@16
|
847 RealType r;
|
Chris@16
|
848 if(!detail::check_df(
|
Chris@16
|
849 function,
|
Chris@16
|
850 k, &r, Policy())
|
Chris@16
|
851 ||
|
Chris@16
|
852 !detail::check_non_centrality(
|
Chris@16
|
853 function,
|
Chris@16
|
854 l,
|
Chris@16
|
855 &r,
|
Chris@16
|
856 Policy()))
|
Chris@16
|
857 return r;
|
Chris@16
|
858 return 2 * (2 * l + k);
|
Chris@16
|
859 }
|
Chris@16
|
860
|
Chris@16
|
861 // RealType standard_deviation(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
862 // standard_deviation provided by derived accessors.
|
Chris@16
|
863
|
Chris@16
|
864 template <class RealType, class Policy>
|
Chris@16
|
865 inline RealType skewness(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
866 { // skewness = sqrt(l).
|
Chris@16
|
867 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::skewness()";
|
Chris@16
|
868 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
869 RealType l = dist.non_centrality();
|
Chris@16
|
870 RealType r;
|
Chris@16
|
871 if(!detail::check_df(
|
Chris@16
|
872 function,
|
Chris@16
|
873 k, &r, Policy())
|
Chris@16
|
874 ||
|
Chris@16
|
875 !detail::check_non_centrality(
|
Chris@16
|
876 function,
|
Chris@16
|
877 l,
|
Chris@16
|
878 &r,
|
Chris@16
|
879 Policy()))
|
Chris@16
|
880 return r;
|
Chris@16
|
881 BOOST_MATH_STD_USING
|
Chris@16
|
882 return pow(2 / (k + 2 * l), RealType(3)/2) * (k + 3 * l);
|
Chris@16
|
883 }
|
Chris@16
|
884
|
Chris@16
|
885 template <class RealType, class Policy>
|
Chris@16
|
886 inline RealType kurtosis_excess(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
887 {
|
Chris@16
|
888 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::kurtosis_excess()";
|
Chris@16
|
889 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
890 RealType l = dist.non_centrality();
|
Chris@16
|
891 RealType r;
|
Chris@16
|
892 if(!detail::check_df(
|
Chris@16
|
893 function,
|
Chris@16
|
894 k, &r, Policy())
|
Chris@16
|
895 ||
|
Chris@16
|
896 !detail::check_non_centrality(
|
Chris@16
|
897 function,
|
Chris@16
|
898 l,
|
Chris@16
|
899 &r,
|
Chris@16
|
900 Policy()))
|
Chris@16
|
901 return r;
|
Chris@16
|
902 return 12 * (k + 4 * l) / ((k + 2 * l) * (k + 2 * l));
|
Chris@16
|
903 } // kurtosis_excess
|
Chris@16
|
904
|
Chris@16
|
905 template <class RealType, class Policy>
|
Chris@16
|
906 inline RealType kurtosis(const non_central_chi_squared_distribution<RealType, Policy>& dist)
|
Chris@16
|
907 {
|
Chris@16
|
908 return kurtosis_excess(dist) + 3;
|
Chris@16
|
909 }
|
Chris@16
|
910
|
Chris@16
|
911 template <class RealType, class Policy>
|
Chris@16
|
912 inline RealType pdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
|
Chris@16
|
913 { // Probability Density/Mass Function.
|
Chris@16
|
914 return detail::nccs_pdf(dist, x);
|
Chris@16
|
915 } // pdf
|
Chris@16
|
916
|
Chris@16
|
917 template <class RealType, class Policy>
|
Chris@16
|
918 RealType cdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
|
Chris@16
|
919 {
|
Chris@16
|
920 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)";
|
Chris@16
|
921 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
922 RealType l = dist.non_centrality();
|
Chris@16
|
923 RealType r;
|
Chris@16
|
924 if(!detail::check_df(
|
Chris@16
|
925 function,
|
Chris@16
|
926 k, &r, Policy())
|
Chris@16
|
927 ||
|
Chris@16
|
928 !detail::check_non_centrality(
|
Chris@16
|
929 function,
|
Chris@16
|
930 l,
|
Chris@16
|
931 &r,
|
Chris@16
|
932 Policy())
|
Chris@16
|
933 ||
|
Chris@16
|
934 !detail::check_positive_x(
|
Chris@16
|
935 function,
|
Chris@16
|
936 x,
|
Chris@16
|
937 &r,
|
Chris@16
|
938 Policy()))
|
Chris@16
|
939 return r;
|
Chris@16
|
940
|
Chris@16
|
941 return detail::non_central_chi_squared_cdf(x, k, l, false, Policy());
|
Chris@16
|
942 } // cdf
|
Chris@16
|
943
|
Chris@16
|
944 template <class RealType, class Policy>
|
Chris@16
|
945 RealType cdf(const complemented2_type<non_central_chi_squared_distribution<RealType, Policy>, RealType>& c)
|
Chris@16
|
946 { // Complemented Cumulative Distribution Function
|
Chris@16
|
947 const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)";
|
Chris@16
|
948 non_central_chi_squared_distribution<RealType, Policy> const& dist = c.dist;
|
Chris@16
|
949 RealType x = c.param;
|
Chris@16
|
950 RealType k = dist.degrees_of_freedom();
|
Chris@16
|
951 RealType l = dist.non_centrality();
|
Chris@16
|
952 RealType r;
|
Chris@16
|
953 if(!detail::check_df(
|
Chris@16
|
954 function,
|
Chris@16
|
955 k, &r, Policy())
|
Chris@16
|
956 ||
|
Chris@16
|
957 !detail::check_non_centrality(
|
Chris@16
|
958 function,
|
Chris@16
|
959 l,
|
Chris@16
|
960 &r,
|
Chris@16
|
961 Policy())
|
Chris@16
|
962 ||
|
Chris@16
|
963 !detail::check_positive_x(
|
Chris@16
|
964 function,
|
Chris@16
|
965 x,
|
Chris@16
|
966 &r,
|
Chris@16
|
967 Policy()))
|
Chris@16
|
968 return r;
|
Chris@16
|
969
|
Chris@16
|
970 return detail::non_central_chi_squared_cdf(x, k, l, true, Policy());
|
Chris@16
|
971 } // ccdf
|
Chris@16
|
972
|
Chris@16
|
973 template <class RealType, class Policy>
|
Chris@16
|
974 inline RealType quantile(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& p)
|
Chris@16
|
975 { // Quantile (or Percent Point) function.
|
Chris@16
|
976 return detail::nccs_quantile(dist, p, false);
|
Chris@16
|
977 } // quantile
|
Chris@16
|
978
|
Chris@16
|
979 template <class RealType, class Policy>
|
Chris@16
|
980 inline RealType quantile(const complemented2_type<non_central_chi_squared_distribution<RealType, Policy>, RealType>& c)
|
Chris@16
|
981 { // Quantile (or Percent Point) function.
|
Chris@16
|
982 return detail::nccs_quantile(c.dist, c.param, true);
|
Chris@16
|
983 } // quantile complement.
|
Chris@16
|
984
|
Chris@16
|
985 } // namespace math
|
Chris@16
|
986 } // namespace boost
|
Chris@16
|
987
|
Chris@16
|
988 // This include must be at the end, *after* the accessors
|
Chris@16
|
989 // for this distribution have been defined, in order to
|
Chris@16
|
990 // keep compilers that support two-phase lookup happy.
|
Chris@16
|
991 #include <boost/math/distributions/detail/derived_accessors.hpp>
|
Chris@16
|
992
|
Chris@16
|
993 #endif // BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
|
Chris@16
|
994
|
Chris@16
|
995
|
Chris@16
|
996
|