Chris@102
|
1 /* boost random/non_central_chi_squared_distribution.hpp header file
|
Chris@102
|
2 *
|
Chris@102
|
3 * Copyright Thijs van den Berg 2014
|
Chris@102
|
4 *
|
Chris@102
|
5 * Distributed under the Boost Software License, Version 1.0. (See
|
Chris@102
|
6 * accompanying file LICENSE_1_0.txt or copy at
|
Chris@102
|
7 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
8 *
|
Chris@102
|
9 * See http://www.boost.org for most recent version including documentation.
|
Chris@102
|
10 *
|
Chris@102
|
11 * $Id$
|
Chris@102
|
12 */
|
Chris@102
|
13
|
Chris@102
|
14 #ifndef BOOST_RANDOM_NON_CENTRAL_CHI_SQUARED_DISTRIBUTION_HPP
|
Chris@102
|
15 #define BOOST_RANDOM_NON_CENTRAL_CHI_SQUARED_DISTRIBUTION_HPP
|
Chris@102
|
16
|
Chris@102
|
17 #include <boost/config/no_tr1/cmath.hpp>
|
Chris@102
|
18 #include <iosfwd>
|
Chris@102
|
19 #include <istream>
|
Chris@102
|
20 #include <boost/limits.hpp>
|
Chris@102
|
21 #include <boost/random/detail/config.hpp>
|
Chris@102
|
22 #include <boost/random/detail/operators.hpp>
|
Chris@102
|
23 #include <boost/random/uniform_real_distribution.hpp>
|
Chris@102
|
24 #include <boost/random/normal_distribution.hpp>
|
Chris@102
|
25 #include <boost/random/chi_squared_distribution.hpp>
|
Chris@102
|
26 #include <boost/random/poisson_distribution.hpp>
|
Chris@102
|
27
|
Chris@102
|
28 namespace boost {
|
Chris@102
|
29 namespace random {
|
Chris@102
|
30
|
Chris@102
|
31 /**
|
Chris@102
|
32 * The noncentral chi-squared distribution is a real valued distribution with
|
Chris@102
|
33 * two parameter, @c k and @c lambda. The distribution produces values > 0.
|
Chris@102
|
34 *
|
Chris@102
|
35 * This is the distribution of the sum of squares of k Normal distributed
|
Chris@102
|
36 * variates each with variance one and \f$\lambda\f$ the sum of squares of the
|
Chris@102
|
37 * normal means.
|
Chris@102
|
38 *
|
Chris@102
|
39 * The distribution function is
|
Chris@102
|
40 * \f$\displaystyle P(x) = \frac{1}{2} e^{-(x+\lambda)/2} \left( \frac{x}{\lambda} \right)^{k/4-1/2} I_{k/2-1}( \sqrt{\lambda x} )\f$.
|
Chris@102
|
41 * where \f$\displaystyle I_\nu(z)\f$ is a modified Bessel function of the
|
Chris@102
|
42 * first kind.
|
Chris@102
|
43 *
|
Chris@102
|
44 * The algorithm is taken from
|
Chris@102
|
45 *
|
Chris@102
|
46 * @blockquote
|
Chris@102
|
47 * "Monte Carlo Methods in Financial Engineering", Paul Glasserman,
|
Chris@102
|
48 * 2003, XIII, 596 p, Stochastic Modelling and Applied Probability, Vol. 53,
|
Chris@102
|
49 * ISBN 978-0-387-21617-1, p 124, Fig. 3.5.
|
Chris@102
|
50 * @endblockquote
|
Chris@102
|
51 */
|
Chris@102
|
52 template <typename RealType = double>
|
Chris@102
|
53 class non_central_chi_squared_distribution {
|
Chris@102
|
54 public:
|
Chris@102
|
55 typedef RealType result_type;
|
Chris@102
|
56 typedef RealType input_type;
|
Chris@102
|
57
|
Chris@102
|
58 class param_type {
|
Chris@102
|
59 public:
|
Chris@102
|
60 typedef non_central_chi_squared_distribution distribution_type;
|
Chris@102
|
61
|
Chris@102
|
62 /**
|
Chris@102
|
63 * Constructs the parameters of a non_central_chi_squared_distribution.
|
Chris@102
|
64 * @c k and @c lambda are the parameter of the distribution.
|
Chris@102
|
65 *
|
Chris@102
|
66 * Requires: k > 0 && lambda > 0
|
Chris@102
|
67 */
|
Chris@102
|
68 explicit
|
Chris@102
|
69 param_type(RealType k_arg = RealType(1), RealType lambda_arg = RealType(1))
|
Chris@102
|
70 : _k(k_arg), _lambda(lambda_arg)
|
Chris@102
|
71 {
|
Chris@102
|
72 BOOST_ASSERT(k_arg > RealType(0));
|
Chris@102
|
73 BOOST_ASSERT(lambda_arg > RealType(0));
|
Chris@102
|
74 }
|
Chris@102
|
75
|
Chris@102
|
76 /** Returns the @c k parameter of the distribution */
|
Chris@102
|
77 RealType k() const { return _k; }
|
Chris@102
|
78
|
Chris@102
|
79 /** Returns the @c lambda parameter of the distribution */
|
Chris@102
|
80 RealType lambda() const { return _lambda; }
|
Chris@102
|
81
|
Chris@102
|
82 /** Writes the parameters of the distribution to a @c std::ostream. */
|
Chris@102
|
83 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
|
Chris@102
|
84 {
|
Chris@102
|
85 os << parm._k << ' ' << parm._lambda;
|
Chris@102
|
86 return os;
|
Chris@102
|
87 }
|
Chris@102
|
88
|
Chris@102
|
89 /** Reads the parameters of the distribution from a @c std::istream. */
|
Chris@102
|
90 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
|
Chris@102
|
91 {
|
Chris@102
|
92 is >> parm._k >> std::ws >> parm._lambda;
|
Chris@102
|
93 return is;
|
Chris@102
|
94 }
|
Chris@102
|
95
|
Chris@102
|
96 /** Returns true if the parameters have the same values. */
|
Chris@102
|
97 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
|
Chris@102
|
98 { return lhs._k == rhs._k && lhs._lambda == rhs._lambda; }
|
Chris@102
|
99
|
Chris@102
|
100 /** Returns true if the parameters have different values. */
|
Chris@102
|
101 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
|
Chris@102
|
102
|
Chris@102
|
103 private:
|
Chris@102
|
104 RealType _k;
|
Chris@102
|
105 RealType _lambda;
|
Chris@102
|
106 };
|
Chris@102
|
107
|
Chris@102
|
108 /**
|
Chris@102
|
109 * Construct a @c non_central_chi_squared_distribution object. @c k and
|
Chris@102
|
110 * @c lambda are the parameter of the distribution.
|
Chris@102
|
111 *
|
Chris@102
|
112 * Requires: k > 0 && lambda > 0
|
Chris@102
|
113 */
|
Chris@102
|
114 explicit
|
Chris@102
|
115 non_central_chi_squared_distribution(RealType k_arg = RealType(1), RealType lambda_arg = RealType(1))
|
Chris@102
|
116 : _param(k_arg, lambda_arg)
|
Chris@102
|
117 {
|
Chris@102
|
118 BOOST_ASSERT(k_arg > RealType(0));
|
Chris@102
|
119 BOOST_ASSERT(lambda_arg > RealType(0));
|
Chris@102
|
120 }
|
Chris@102
|
121
|
Chris@102
|
122 /**
|
Chris@102
|
123 * Construct a @c non_central_chi_squared_distribution object from the parameter.
|
Chris@102
|
124 */
|
Chris@102
|
125 explicit
|
Chris@102
|
126 non_central_chi_squared_distribution(const param_type& parm)
|
Chris@102
|
127 : _param( parm )
|
Chris@102
|
128 { }
|
Chris@102
|
129
|
Chris@102
|
130 /**
|
Chris@102
|
131 * Returns a random variate distributed according to the
|
Chris@102
|
132 * non central chi squared distribution specified by @c param.
|
Chris@102
|
133 */
|
Chris@102
|
134 template<typename URNG>
|
Chris@102
|
135 RealType operator()(URNG& eng, const param_type& parm) const
|
Chris@102
|
136 { return non_central_chi_squared_distribution(parm)(eng); }
|
Chris@102
|
137
|
Chris@102
|
138 /**
|
Chris@102
|
139 * Returns a random variate distributed according to the
|
Chris@102
|
140 * non central chi squared distribution.
|
Chris@102
|
141 */
|
Chris@102
|
142 template<typename URNG>
|
Chris@102
|
143 RealType operator()(URNG& eng)
|
Chris@102
|
144 {
|
Chris@102
|
145 using std::sqrt;
|
Chris@102
|
146 if (_param.k() > 1) {
|
Chris@102
|
147 boost::random::normal_distribution<RealType> n_dist;
|
Chris@102
|
148 boost::random::chi_squared_distribution<RealType> c_dist(_param.k() - RealType(1));
|
Chris@102
|
149 RealType _z = n_dist(eng);
|
Chris@102
|
150 RealType _x = c_dist(eng);
|
Chris@102
|
151 RealType term1 = _z + sqrt(_param.lambda());
|
Chris@102
|
152 return term1*term1 + _x;
|
Chris@102
|
153 }
|
Chris@102
|
154 else {
|
Chris@102
|
155 boost::random::poisson_distribution<> p_dist(_param.lambda()/RealType(2));
|
Chris@102
|
156 boost::random::poisson_distribution<>::result_type _p = p_dist(eng);
|
Chris@102
|
157 boost::random::chi_squared_distribution<RealType> c_dist(_param.k() + RealType(2)*_p);
|
Chris@102
|
158 return c_dist(eng);
|
Chris@102
|
159 }
|
Chris@102
|
160 }
|
Chris@102
|
161
|
Chris@102
|
162 /** Returns the @c k parameter of the distribution. */
|
Chris@102
|
163 RealType k() const { return _param.k(); }
|
Chris@102
|
164
|
Chris@102
|
165 /** Returns the @c lambda parameter of the distribution. */
|
Chris@102
|
166 RealType lambda() const { return _param.lambda(); }
|
Chris@102
|
167
|
Chris@102
|
168 /** Returns the parameters of the distribution. */
|
Chris@102
|
169 param_type param() const { return _param; }
|
Chris@102
|
170
|
Chris@102
|
171 /** Sets parameters of the distribution. */
|
Chris@102
|
172 void param(const param_type& parm) { _param = parm; }
|
Chris@102
|
173
|
Chris@102
|
174 /** Resets the distribution, so that subsequent uses does not depend on values already produced by it.*/
|
Chris@102
|
175 void reset() {}
|
Chris@102
|
176
|
Chris@102
|
177 /** Returns the smallest value that the distribution can produce. */
|
Chris@102
|
178 RealType min BOOST_PREVENT_MACRO_SUBSTITUTION() const
|
Chris@102
|
179 { return RealType(0); }
|
Chris@102
|
180
|
Chris@102
|
181 /** Returns the largest value that the distribution can produce. */
|
Chris@102
|
182 RealType max BOOST_PREVENT_MACRO_SUBSTITUTION() const
|
Chris@102
|
183 { return (std::numeric_limits<RealType>::infinity)(); }
|
Chris@102
|
184
|
Chris@102
|
185 /** Writes the parameters of the distribution to a @c std::ostream. */
|
Chris@102
|
186 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, non_central_chi_squared_distribution, dist)
|
Chris@102
|
187 {
|
Chris@102
|
188 os << dist.param();
|
Chris@102
|
189 return os;
|
Chris@102
|
190 }
|
Chris@102
|
191
|
Chris@102
|
192 /** reads the parameters of the distribution from a @c std::istream. */
|
Chris@102
|
193 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, non_central_chi_squared_distribution, dist)
|
Chris@102
|
194 {
|
Chris@102
|
195 param_type parm;
|
Chris@102
|
196 if(is >> parm) {
|
Chris@102
|
197 dist.param(parm);
|
Chris@102
|
198 }
|
Chris@102
|
199 return is;
|
Chris@102
|
200 }
|
Chris@102
|
201
|
Chris@102
|
202 /** Returns true if two distributions have the same parameters and produce
|
Chris@102
|
203 the same sequence of random numbers given equal generators.*/
|
Chris@102
|
204 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(non_central_chi_squared_distribution, lhs, rhs)
|
Chris@102
|
205 { return lhs.param() == rhs.param(); }
|
Chris@102
|
206
|
Chris@102
|
207 /** Returns true if two distributions have different parameters and/or can produce
|
Chris@102
|
208 different sequences of random numbers given equal generators.*/
|
Chris@102
|
209 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(non_central_chi_squared_distribution)
|
Chris@102
|
210
|
Chris@102
|
211 private:
|
Chris@102
|
212
|
Chris@102
|
213 /// @cond show_private
|
Chris@102
|
214 param_type _param;
|
Chris@102
|
215 /// @endcond
|
Chris@102
|
216 };
|
Chris@102
|
217
|
Chris@102
|
218 } // namespace random
|
Chris@102
|
219 } // namespace boost
|
Chris@102
|
220
|
Chris@102
|
221 #endif
|