Chris@102: /* boost random/non_central_chi_squared_distribution.hpp header file Chris@102: * Chris@102: * Copyright Thijs van den Berg 2014 Chris@102: * Chris@102: * Distributed under the Boost Software License, Version 1.0. (See Chris@102: * accompanying file LICENSE_1_0.txt or copy at Chris@102: * http://www.boost.org/LICENSE_1_0.txt) Chris@102: * Chris@102: * See http://www.boost.org for most recent version including documentation. Chris@102: * Chris@102: * $Id$ Chris@102: */ Chris@102: Chris@102: #ifndef BOOST_RANDOM_NON_CENTRAL_CHI_SQUARED_DISTRIBUTION_HPP Chris@102: #define BOOST_RANDOM_NON_CENTRAL_CHI_SQUARED_DISTRIBUTION_HPP Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: namespace boost { Chris@102: namespace random { Chris@102: Chris@102: /** Chris@102: * The noncentral chi-squared distribution is a real valued distribution with Chris@102: * two parameter, @c k and @c lambda. The distribution produces values > 0. Chris@102: * Chris@102: * This is the distribution of the sum of squares of k Normal distributed Chris@102: * variates each with variance one and \f$\lambda\f$ the sum of squares of the Chris@102: * normal means. Chris@102: * Chris@102: * The distribution function is Chris@102: * \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: * where \f$\displaystyle I_\nu(z)\f$ is a modified Bessel function of the Chris@102: * first kind. Chris@102: * Chris@102: * The algorithm is taken from Chris@102: * Chris@102: * @blockquote Chris@102: * "Monte Carlo Methods in Financial Engineering", Paul Glasserman, Chris@102: * 2003, XIII, 596 p, Stochastic Modelling and Applied Probability, Vol. 53, Chris@102: * ISBN 978-0-387-21617-1, p 124, Fig. 3.5. Chris@102: * @endblockquote Chris@102: */ Chris@102: template Chris@102: class non_central_chi_squared_distribution { Chris@102: public: Chris@102: typedef RealType result_type; Chris@102: typedef RealType input_type; Chris@102: Chris@102: class param_type { Chris@102: public: Chris@102: typedef non_central_chi_squared_distribution distribution_type; Chris@102: Chris@102: /** Chris@102: * Constructs the parameters of a non_central_chi_squared_distribution. Chris@102: * @c k and @c lambda are the parameter of the distribution. Chris@102: * Chris@102: * Requires: k > 0 && lambda > 0 Chris@102: */ Chris@102: explicit Chris@102: param_type(RealType k_arg = RealType(1), RealType lambda_arg = RealType(1)) Chris@102: : _k(k_arg), _lambda(lambda_arg) Chris@102: { Chris@102: BOOST_ASSERT(k_arg > RealType(0)); Chris@102: BOOST_ASSERT(lambda_arg > RealType(0)); Chris@102: } Chris@102: Chris@102: /** Returns the @c k parameter of the distribution */ Chris@102: RealType k() const { return _k; } Chris@102: Chris@102: /** Returns the @c lambda parameter of the distribution */ Chris@102: RealType lambda() const { return _lambda; } Chris@102: Chris@102: /** Writes the parameters of the distribution to a @c std::ostream. */ Chris@102: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) Chris@102: { Chris@102: os << parm._k << ' ' << parm._lambda; Chris@102: return os; Chris@102: } Chris@102: Chris@102: /** Reads the parameters of the distribution from a @c std::istream. */ Chris@102: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) Chris@102: { Chris@102: is >> parm._k >> std::ws >> parm._lambda; Chris@102: return is; Chris@102: } Chris@102: Chris@102: /** Returns true if the parameters have the same values. */ Chris@102: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) Chris@102: { return lhs._k == rhs._k && lhs._lambda == rhs._lambda; } Chris@102: Chris@102: /** Returns true if the parameters have different values. */ Chris@102: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) Chris@102: Chris@102: private: Chris@102: RealType _k; Chris@102: RealType _lambda; Chris@102: }; Chris@102: Chris@102: /** Chris@102: * Construct a @c non_central_chi_squared_distribution object. @c k and Chris@102: * @c lambda are the parameter of the distribution. Chris@102: * Chris@102: * Requires: k > 0 && lambda > 0 Chris@102: */ Chris@102: explicit Chris@102: non_central_chi_squared_distribution(RealType k_arg = RealType(1), RealType lambda_arg = RealType(1)) Chris@102: : _param(k_arg, lambda_arg) Chris@102: { Chris@102: BOOST_ASSERT(k_arg > RealType(0)); Chris@102: BOOST_ASSERT(lambda_arg > RealType(0)); Chris@102: } Chris@102: Chris@102: /** Chris@102: * Construct a @c non_central_chi_squared_distribution object from the parameter. Chris@102: */ Chris@102: explicit Chris@102: non_central_chi_squared_distribution(const param_type& parm) Chris@102: : _param( parm ) Chris@102: { } Chris@102: Chris@102: /** Chris@102: * Returns a random variate distributed according to the Chris@102: * non central chi squared distribution specified by @c param. Chris@102: */ Chris@102: template Chris@102: RealType operator()(URNG& eng, const param_type& parm) const Chris@102: { return non_central_chi_squared_distribution(parm)(eng); } Chris@102: Chris@102: /** Chris@102: * Returns a random variate distributed according to the Chris@102: * non central chi squared distribution. Chris@102: */ Chris@102: template Chris@102: RealType operator()(URNG& eng) Chris@102: { Chris@102: using std::sqrt; Chris@102: if (_param.k() > 1) { Chris@102: boost::random::normal_distribution n_dist; Chris@102: boost::random::chi_squared_distribution c_dist(_param.k() - RealType(1)); Chris@102: RealType _z = n_dist(eng); Chris@102: RealType _x = c_dist(eng); Chris@102: RealType term1 = _z + sqrt(_param.lambda()); Chris@102: return term1*term1 + _x; Chris@102: } Chris@102: else { Chris@102: boost::random::poisson_distribution<> p_dist(_param.lambda()/RealType(2)); Chris@102: boost::random::poisson_distribution<>::result_type _p = p_dist(eng); Chris@102: boost::random::chi_squared_distribution c_dist(_param.k() + RealType(2)*_p); Chris@102: return c_dist(eng); Chris@102: } Chris@102: } Chris@102: Chris@102: /** Returns the @c k parameter of the distribution. */ Chris@102: RealType k() const { return _param.k(); } Chris@102: Chris@102: /** Returns the @c lambda parameter of the distribution. */ Chris@102: RealType lambda() const { return _param.lambda(); } Chris@102: Chris@102: /** Returns the parameters of the distribution. */ Chris@102: param_type param() const { return _param; } Chris@102: Chris@102: /** Sets parameters of the distribution. */ Chris@102: void param(const param_type& parm) { _param = parm; } Chris@102: Chris@102: /** Resets the distribution, so that subsequent uses does not depend on values already produced by it.*/ Chris@102: void reset() {} Chris@102: Chris@102: /** Returns the smallest value that the distribution can produce. */ Chris@102: RealType min BOOST_PREVENT_MACRO_SUBSTITUTION() const Chris@102: { return RealType(0); } Chris@102: Chris@102: /** Returns the largest value that the distribution can produce. */ Chris@102: RealType max BOOST_PREVENT_MACRO_SUBSTITUTION() const Chris@102: { return (std::numeric_limits::infinity)(); } Chris@102: Chris@102: /** Writes the parameters of the distribution to a @c std::ostream. */ Chris@102: BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, non_central_chi_squared_distribution, dist) Chris@102: { Chris@102: os << dist.param(); Chris@102: return os; Chris@102: } Chris@102: Chris@102: /** reads the parameters of the distribution from a @c std::istream. */ Chris@102: BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, non_central_chi_squared_distribution, dist) Chris@102: { Chris@102: param_type parm; Chris@102: if(is >> parm) { Chris@102: dist.param(parm); Chris@102: } Chris@102: return is; Chris@102: } Chris@102: Chris@102: /** Returns true if two distributions have the same parameters and produce Chris@102: the same sequence of random numbers given equal generators.*/ Chris@102: BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(non_central_chi_squared_distribution, lhs, rhs) Chris@102: { return lhs.param() == rhs.param(); } Chris@102: Chris@102: /** Returns true if two distributions have different parameters and/or can produce Chris@102: different sequences of random numbers given equal generators.*/ Chris@102: BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(non_central_chi_squared_distribution) Chris@102: Chris@102: private: Chris@102: Chris@102: /// @cond show_private Chris@102: param_type _param; Chris@102: /// @endcond Chris@102: }; Chris@102: Chris@102: } // namespace random Chris@102: } // namespace boost Chris@102: Chris@102: #endif