uniform_on_sphere.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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$
  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() {}
  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. using std::sqrt;
  144. switch(_dim)
  145. {
  146. case 0: break;
  147. case 1:
  148. {
  149. if(uniform_01<RealType>()(eng) < 0.5) {
  150. *_container.begin() = -1;
  151. } else {
  152. *_container.begin() = 1;
  153. }
  154. break;
  155. }
  156. case 2:
  157. {
  158. uniform_01<RealType> uniform;
  159. RealType sqsum;
  160. RealType x, y;
  161. do {
  162. x = uniform(eng) * 2 - 1;
  163. y = uniform(eng) * 2 - 1;
  164. sqsum = x*x + y*y;
  165. } while(sqsum == 0 || sqsum > 1);
  166. RealType mult = 1/sqrt(sqsum);
  167. typename Cont::iterator iter = _container.begin();
  168. *iter = x * mult;
  169. iter++;
  170. *iter = y * mult;
  171. break;
  172. }
  173. case 3:
  174. {
  175. uniform_01<RealType> uniform;
  176. RealType sqsum;
  177. RealType x, y;
  178. do {
  179. x = uniform(eng) * 2 - 1;
  180. y = uniform(eng) * 2 - 1;
  181. sqsum = x*x + y*y;
  182. } while(sqsum > 1);
  183. RealType mult = 2 * sqrt(1 - sqsum);
  184. typename Cont::iterator iter = _container.begin();
  185. *iter = x * mult;
  186. ++iter;
  187. *iter = y * mult;
  188. ++iter;
  189. *iter = 2 * sqsum - 1;
  190. break;
  191. }
  192. default:
  193. {
  194. detail::unit_normal_distribution<RealType> normal;
  195. RealType sqsum;
  196. do {
  197. sqsum = 0;
  198. for(typename Cont::iterator it = _container.begin();
  199. it != _container.end();
  200. ++it) {
  201. RealType val = normal(eng);
  202. *it = val;
  203. sqsum += val * val;
  204. }
  205. } while(sqsum == 0);
  206. // for all i: result[i] /= sqrt(sqsum)
  207. RealType inverse_distance = 1 / sqrt(sqsum);
  208. for(typename Cont::iterator it = _container.begin();
  209. it != _container.end();
  210. ++it) {
  211. *it *= inverse_distance;
  212. }
  213. }
  214. }
  215. return _container;
  216. }
  217. /**
  218. * Returns a point uniformly distributed over the surface of
  219. * a sphere of dimension param.dim().
  220. */
  221. template<class Engine>
  222. result_type operator()(Engine& eng, const param_type& parm) const
  223. {
  224. return uniform_on_sphere(parm)(eng);
  225. }
  226. /** Writes the distribution to a @c std::ostream. */
  227. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_on_sphere, sd)
  228. {
  229. os << sd._dim;
  230. return os;
  231. }
  232. /** Reads the distribution from a @c std::istream. */
  233. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_on_sphere, sd)
  234. {
  235. is >> sd._dim;
  236. sd._container.resize(sd._dim);
  237. return is;
  238. }
  239. /**
  240. * Returns true if the two distributions will produce identical
  241. * sequences of values, given equal generators.
  242. */
  243. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_on_sphere, lhs, rhs)
  244. { return lhs._dim == rhs._dim; }
  245. /**
  246. * Returns true if the two distributions may produce different
  247. * sequences of values, given equal generators.
  248. */
  249. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_on_sphere)
  250. private:
  251. result_type _container;
  252. int _dim;
  253. };
  254. } // namespace random
  255. using random::uniform_on_sphere;
  256. } // namespace boost
  257. #endif // BOOST_RANDOM_UNIFORM_ON_SPHERE_HPP