uniform_on_sphere.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* boost random/uniform_on_sphere.hpp header file
  2. *
  3. * Copyright Jens Maurer 2000-2001
  4. * Copyright Steven Watanabe 2011
  5. * Distributed under the Boost Software License, Version 1.0. (See
  6. * accompanying file LICENSE_1_0.txt or copy at
  7. * http://www.boost.org/LICENSE_1_0.txt)
  8. *
  9. * See http://www.boost.org for most recent version including documentation.
  10. *
  11. * $Id: uniform_on_sphere.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $
  12. *
  13. * Revision history
  14. * 2001-02-18 moved to individual header files
  15. */
  16. #ifndef BOOST_RANDOM_UNIFORM_ON_SPHERE_HPP
  17. #define BOOST_RANDOM_UNIFORM_ON_SPHERE_HPP
  18. #include <vector>
  19. #include <algorithm> // std::transform
  20. #include <functional> // std::bind2nd, std::divides
  21. #include <boost/assert.hpp>
  22. #include <boost/random/detail/config.hpp>
  23. #include <boost/random/detail/operators.hpp>
  24. #include <boost/random/normal_distribution.hpp>
  25. namespace boost {
  26. namespace random {
  27. /**
  28. * Instantiations of class template uniform_on_sphere model a
  29. * \random_distribution. Such a distribution produces random
  30. * numbers uniformly distributed on the unit sphere of arbitrary
  31. * dimension @c dim. The @c Cont template parameter must be a STL-like
  32. * container type with begin and end operations returning non-const
  33. * ForwardIterators of type @c Cont::iterator.
  34. */
  35. template<class RealType = double, class Cont = std::vector<RealType> >
  36. class uniform_on_sphere
  37. {
  38. public:
  39. typedef RealType input_type;
  40. typedef Cont result_type;
  41. class param_type
  42. {
  43. public:
  44. typedef uniform_on_sphere distribution_type;
  45. /**
  46. * Constructs the parameters of a uniform_on_sphere
  47. * distribution, given the dimension of the sphere.
  48. */
  49. explicit param_type(int dim_arg = 2) : _dim(dim_arg)
  50. {
  51. BOOST_ASSERT(_dim >= 0);
  52. }
  53. /** Returns the dimension of the sphere. */
  54. int dim() const { return _dim; }
  55. /** Writes the parameters to a @c std::ostream. */
  56. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
  57. {
  58. os << parm._dim;
  59. return os;
  60. }
  61. /** Reads the parameters from a @c std::istream. */
  62. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
  63. {
  64. is >> parm._dim;
  65. return is;
  66. }
  67. /** Returns true if the two sets of parameters are equal. */
  68. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
  69. { return lhs._dim == rhs._dim; }
  70. /** Returns true if the two sets of parameters are different. */
  71. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
  72. private:
  73. int _dim;
  74. };
  75. /**
  76. * Constructs a @c uniform_on_sphere distribution.
  77. * @c dim is the dimension of the sphere.
  78. *
  79. * Requires: dim >= 0
  80. */
  81. explicit uniform_on_sphere(int dim_arg = 2)
  82. : _container(dim_arg), _dim(dim_arg) { }
  83. /**
  84. * Constructs a @c uniform_on_sphere distribution from its parameters.
  85. */
  86. explicit uniform_on_sphere(const param_type& parm)
  87. : _container(parm.dim()), _dim(parm.dim()) { }
  88. // compiler-generated copy ctor and assignment operator are fine
  89. /** Returns the dimension of the sphere. */
  90. int dim() const { return _dim; }
  91. /** Returns the parameters of the distribution. */
  92. param_type param() const { return param_type(_dim); }
  93. /** Sets the parameters of the distribution. */
  94. void param(const param_type& parm)
  95. {
  96. _dim = parm.dim();
  97. _container.resize(_dim);
  98. }
  99. /**
  100. * Returns the smallest value that the distribution can produce.
  101. * Note that this is required to approximate the standard library's
  102. * requirements. The behavior is defined according to lexicographical
  103. * comparison so that for a container type of std::vector,
  104. * dist.min() <= x <= dist.max() where x is any value produced
  105. * by the distribution.
  106. */
  107. result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
  108. {
  109. result_type result(_dim);
  110. if(_dim != 0) {
  111. result.front() = RealType(-1.0);
  112. }
  113. return result;
  114. }
  115. /**
  116. * Returns the largest value that the distribution can produce.
  117. * Note that this is required to approximate the standard library's
  118. * requirements. The behavior is defined according to lexicographical
  119. * comparison so that for a container type of std::vector,
  120. * dist.min() <= x <= dist.max() where x is any value produced
  121. * by the distribution.
  122. */
  123. result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
  124. {
  125. result_type result(_dim);
  126. if(_dim != 0) {
  127. result.front() = RealType(1.0);
  128. }
  129. return result;
  130. }
  131. /**
  132. * Effects: Subsequent uses of the distribution do not depend
  133. * on values produced by any engine prior to invoking reset.
  134. */
  135. void reset() { _normal.reset(); }
  136. /**
  137. * Returns a point uniformly distributed over the surface of
  138. * a sphere of dimension dim().
  139. */
  140. template<class Engine>
  141. const result_type & operator()(Engine& eng)
  142. {
  143. RealType sqsum = 0;
  144. for(typename Cont::iterator it = _container.begin();
  145. it != _container.end();
  146. ++it) {
  147. RealType val = _normal(eng);
  148. *it = val;
  149. sqsum += val * val;
  150. }
  151. using std::sqrt;
  152. // for all i: result[i] /= sqrt(sqsum)
  153. std::transform(_container.begin(), _container.end(), _container.begin(),
  154. std::bind2nd(std::divides<RealType>(), sqrt(sqsum)));
  155. return _container;
  156. }
  157. /**
  158. * Returns a point uniformly distributed over the surface of
  159. * a sphere of dimension param.dim().
  160. */
  161. template<class Engine>
  162. result_type operator()(Engine& eng, const param_type& parm) const
  163. {
  164. return uniform_on_sphere(parm)(eng);
  165. }
  166. /** Writes the distribution to a @c std::ostream. */
  167. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_on_sphere, sd)
  168. {
  169. os << sd._dim;
  170. return os;
  171. }
  172. /** Reads the distribution from a @c std::istream. */
  173. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_on_sphere, sd)
  174. {
  175. is >> sd._dim;
  176. sd._container.resize(sd._dim);
  177. return is;
  178. }
  179. /**
  180. * Returns true if the two distributions will produce identical
  181. * sequences of values, given equal generators.
  182. */
  183. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_on_sphere, lhs, rhs)
  184. { return lhs._dim == rhs._dim && lhs._normal == rhs._normal; }
  185. /**
  186. * Returns true if the two distributions may produce different
  187. * sequences of values, given equal generators.
  188. */
  189. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_on_sphere)
  190. private:
  191. normal_distribution<RealType> _normal;
  192. result_type _container;
  193. int _dim;
  194. };
  195. } // namespace random
  196. using random::uniform_on_sphere;
  197. } // namespace boost
  198. #endif // BOOST_RANDOM_UNIFORM_ON_SPHERE_HPP