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