diff --git a/include/boost/random/uniform_on_sphere.hpp b/include/boost/random/uniform_on_sphere.hpp index 899f336..dcb95ff 100644 --- a/include/boost/random/uniform_on_sphere.hpp +++ b/include/boost/random/uniform_on_sphere.hpp @@ -1,6 +1,7 @@ /* boost random/uniform_on_sphere.hpp header file * * Copyright Jens Maurer 2000-2001 + * Copyright Steven Watanabe 2011 * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -20,9 +21,11 @@ #include // std::transform #include // std::bind2nd, std::divides #include +#include #include namespace boost { +namespace random { /** * Instantiations of class template uniform_on_sphere model a @@ -30,72 +33,196 @@ namespace boost { * numbers uniformly distributed on the unit sphere of arbitrary * dimension @c dim. The @c Cont template parameter must be a STL-like * container type with begin and end operations returning non-const - * ForwardIterators of type @c Cont::iterator. Each invocation of the - * @c UniformRandomNumberGenerator shall result in a floating-point - * value in the range [0,1). + * ForwardIterators of type @c Cont::iterator. */ template > class uniform_on_sphere { public: - typedef RealType input_type; - typedef Cont result_type; + typedef RealType input_type; + typedef Cont result_type; - /** - * Constructs a @c uniform_on_sphere distribution. - * @c dim is the dimension of the sphere. - */ - explicit uniform_on_sphere(int dim = 2) : _container(dim), _dim(dim) { } + class param_type + { + public: - // compiler-generated copy ctor and assignment operator are fine + typedef uniform_on_sphere distribution_type; - void reset() { _normal.reset(); } + /** + * Constructs the parameters of a uniform_on_sphere + * distribution, given the dimension of the sphere. + */ + explicit param_type(int dim_arg = 2) : _dim(dim_arg) + { + assert(_dim >= 0); + } - template - const result_type & operator()(Engine& eng) - { - RealType sqsum = 0; - for(typename Cont::iterator it = _container.begin(); - it != _container.end(); - ++it) { - RealType val = _normal(eng); - *it = val; - sqsum += val * val; + /** Returns the dimension of the sphere. */ + int dim() const { return _dim; } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + os << parm._dim; + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + is >> parm._dim; + return is; + } + + /** Returns true if the two sets of parameters are equal. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { return lhs._dim == rhs._dim; } + + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + int _dim; + }; + + /** + * Constructs a @c uniform_on_sphere distribution. + * @c dim is the dimension of the sphere. + * + * Requires: dim >= 0 + */ + explicit uniform_on_sphere(int dim_arg = 2) + : _container(dim_arg), _dim(dim_arg) { } + + /** + * Constructs a @c uniform_on_sphere distribution from its parameters. + */ + explicit uniform_on_sphere(const param_type& parm) + : _container(parm.dim()), _dim(parm.dim()) { } + + // compiler-generated copy ctor and assignment operator are fine + + /** Returns the dimension of the sphere. */ + int dim() const { return _dim; } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_dim); } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + _dim = parm.dim(); + _container.resize(_dim); } -#ifndef BOOST_NO_STDC_NAMESPACE - using std::sqrt; -#endif - // for all i: result[i] /= sqrt(sqsum) - std::transform(_container.begin(), _container.end(), _container.begin(), - std::bind2nd(std::divides(), sqrt(sqsum))); - return _container; - } -#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const uniform_on_sphere& sd) - { - os << sd._dim; - return os; - } + /** + * Returns the smallest value that the distribution can produce. + * Note that this is required to approximate the standard library's + * requirements. The behavior is defined according to lexicographical + * comparison so that for a container type of std::vector, + * dist.min() <= x <= dist.max() where x is any value produced + * by the distribution. + */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { + result_type result(_dim); + if(_dim != 0) { + result.front() = RealType(-1.0); + } + return result; + } + /** + * Returns the largest value that the distribution can produce. + * Note that this is required to approximate the standard library's + * requirements. The behavior is defined according to lexicographical + * comparison so that for a container type of std::vector, + * dist.min() <= x <= dist.max() where x is any value produced + * by the distribution. + */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { + result_type result(_dim); + if(_dim != 0) { + result.front() = RealType(1.0); + } + return result; + } - template - friend std::basic_istream& - operator>>(std::basic_istream& is, uniform_on_sphere& sd) - { - is >> std::ws >> sd._dim; - sd._container.resize(sd._dim); - return is; - } -#endif + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _normal.reset(); } + + /** + * Returns a point uniformly distributed over the surface of + * a sphere of dimension dim(). + */ + template + const result_type & operator()(Engine& eng) + { + RealType sqsum = 0; + for(typename Cont::iterator it = _container.begin(); + it != _container.end(); + ++it) { + RealType val = _normal(eng); + *it = val; + sqsum += val * val; + } + using std::sqrt; + // for all i: result[i] /= sqrt(sqsum) + std::transform(_container.begin(), _container.end(), _container.begin(), + std::bind2nd(std::divides(), sqrt(sqsum))); + return _container; + } + + /** + * Returns a point uniformly distributed over the surface of + * a sphere of dimension param.dim(). + */ + template + result_type operator()(Engine& eng, const param_type& parm) const + { + return uniform_on_sphere(parm)(eng); + } + + /** Writes the distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, uniform_on_sphere, sd) + { + os << sd._dim; + return os; + } + + /** Reads the distribution from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, uniform_on_sphere, sd) + { + is >> sd._dim; + sd._container.resize(sd._dim); + return is; + } + + /** + * Returns true if the two distributions will produce identical + * sequences of values, given equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(uniform_on_sphere, lhs, rhs) + { return lhs._dim == rhs._dim && lhs._normal == rhs._normal; } + + /** + * Returns true if the two distributions may produce different + * sequences of values, given equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(uniform_on_sphere) private: - normal_distribution _normal; - result_type _container; - int _dim; + normal_distribution _normal; + result_type _container; + int _dim; }; +} // namespace random + +using random::uniform_on_sphere; + } // namespace boost #endif // BOOST_RANDOM_UNIFORM_ON_SPHERE_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 05f06b6..78b94e3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -89,6 +89,7 @@ run test_uniform_int.cpp ; run test_uniform_int_distribution.cpp /boost//unit_test_framework ; run test_uniform_real.cpp ; run test_uniform_real_distribution.cpp /boost//unit_test_framework ; +run test_uniform_on_sphere_distribution.cpp /boost//unit_test_framework ; # run nondet_random_speed.cpp ; # run random_device.cpp ; diff --git a/test/test_uniform_on_sphere_distribution.cpp b/test/test_uniform_on_sphere_distribution.cpp new file mode 100644 index 0000000..872d526 --- /dev/null +++ b/test/test_uniform_on_sphere_distribution.cpp @@ -0,0 +1,43 @@ +/* test_uniform_on_sphere_distribution.cpp + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * $Id$ + * + */ + +#include +#include + +#include + +#define BOOST_RANDOM_DISTRIBUTION boost::random::uniform_on_sphere<> +#define BOOST_RANDOM_ARG1 dim +#define BOOST_RANDOM_ARG1_DEFAULT 2 +#define BOOST_RANDOM_ARG1_VALUE 3 + +std::vector min0 = boost::assign::list_of(-1.0)(0.0); +std::vector max0 = boost::assign::list_of(1.0)(0.0); +std::vector min1 = boost::assign::list_of(-1.0)(0.0)(0.0); +std::vector max1 = boost::assign::list_of(1.0)(0.0)(0.0); + +#define BOOST_RANDOM_DIST0_MIN min0 +#define BOOST_RANDOM_DIST0_MAX max0 +#define BOOST_RANDOM_DIST1_MIN min1 +#define BOOST_RANDOM_DIST1_MAX max1 + +#define BOOST_RANDOM_TEST1_PARAMS (0) +#define BOOST_RANDOM_TEST1_MIN std::vector() +#define BOOST_RANDOM_TEST1_MAX std::vector() +#define BOOST_RANDOM_TEST2_PARAMS +#define BOOST_RANDOM_TEST2_MIN min0 +#define BOOST_RANDOM_TEST2_MAX max0 + +#include + +BOOST_TEST_DONT_PRINT_LOG_VALUE( std::vector ) + +#include "test_distribution.ipp"