From 10da5b7cbc2ec4520700c8281133fcb348506bd7 Mon Sep 17 00:00:00 2001 From: Edward Smith-Rowland <3dw4rd@verizon.net> Date: Wed, 26 Oct 2016 15:34:18 +0000 Subject: [PATCH] Implement uniform_inside_sphere_distribution extension. 2016-10-26 Edward Smith-Rowland <3dw4rd@verizon.net> Implement uniform_inside_sphere_distribution extension. * include/ext/random: Implement uniform_inside_sphere_distribution. * include/ext/random.tcc: Ditto. * testsuite/ext/random/uniform_inside_sphere_distribution/ cons/default.cc: New. * testsuite/ext/random/uniform_inside_sphere_distribution/ cons/parms.cc: New. * testsuite/ext/random/uniform_inside_sphere_distribution/ operators/equal.cc: New. * testsuite/ext/random/uniform_inside_sphere_distribution/ operators/generate.cc: New. * testsuite/ext/random/uniform_inside_sphere_distribution/ operators/inequal.cc: New. * testsuite/ext/random/uniform_inside_sphere_distribution/ operators/serialize.cc: New. From-SVN: r241562 --- libstdc++-v3/ChangeLog | 18 ++ libstdc++-v3/include/ext/random | 212 ++++++++++++++++++ libstdc++-v3/include/ext/random.tcc | 162 ++++++++++++- .../cons/default.cc | 43 ++++ .../cons/parms.cc | 44 ++++ .../operators/equal.cc | 41 ++++ .../operators/generate.cc | 60 +++++ .../operators/inequal.cc | 41 ++++ .../operators/serialize.cc | 50 +++++ 9 files changed, 670 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/default.cc create mode 100644 libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/parms.cc create mode 100644 libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/equal.cc create mode 100644 libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/generate.cc create mode 100644 libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/inequal.cc create mode 100644 libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/serialize.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index dbbb2ff97f0..9b73a082891 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,21 @@ +2016-10-26 Edward Smith-Rowland <3dw4rd@verizon.net> + + Implement uniform_inside_sphere_distribution extension. + * include/ext/random: Implement uniform_inside_sphere_distribution. + * include/ext/random.tcc: Ditto. + * testsuite/ext/random/uniform_inside_sphere_distribution/ + cons/default.cc: New. + * testsuite/ext/random/uniform_inside_sphere_distribution/ + cons/parms.cc: New. + * testsuite/ext/random/uniform_inside_sphere_distribution/ + operators/equal.cc: New. + * testsuite/ext/random/uniform_inside_sphere_distribution/ + operators/generate.cc: New. + * testsuite/ext/random/uniform_inside_sphere_distribution/ + operators/inequal.cc: New. + * testsuite/ext/random/uniform_inside_sphere_distribution/ + operators/serialize.cc: New. + 2016-10-26 Jonathan Wakely * include/experimental/bits/fs_dir.h (recursive_directory_iterator): diff --git a/libstdc++-v3/include/ext/random b/libstdc++-v3/include/ext/random index cdd3ec1b352..167c5601048 100644 --- a/libstdc++-v3/include/ext/random +++ b/libstdc++-v3/include/ext/random @@ -3493,6 +3493,218 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _RealType>& __d2) { return !(__d1 == __d2); } + + /** + * @brief A distribution for random coordinates inside a unit sphere. + */ + template + class uniform_inside_sphere_distribution + { + static_assert(std::is_floating_point<_RealType>::value, + "template argument not a floating point type"); + static_assert(_Dimen != 0, "dimension is zero"); + + public: + /** The type of the range of the distribution. */ + using result_type = std::array<_RealType, _Dimen>; + + /** Parameter type. */ + struct param_type + { + using distribution_type + = uniform_inside_sphere_distribution<_Dimen, _RealType>; + friend class uniform_inside_sphere_distribution<_Dimen, _RealType>; + + explicit + param_type(_RealType __radius = _RealType(1)) + : _M_radius(__radius) + { + __glibcxx_assert(_M_radius > _RealType(0)); + } + + _RealType + radius() const + { return _M_radius; } + + friend bool + operator==(const param_type& __p1, const param_type& __p2) + { return __p1._M_radius == __p2._M_radius; } + + private: + _RealType _M_radius; + }; + + /** + * @brief Constructors. + */ + explicit + uniform_inside_sphere_distribution(_RealType __radius = _RealType(1)) + : _M_param(__radius), _M_uosd() + { } + + explicit + uniform_inside_sphere_distribution(const param_type& __p) + : _M_param(__p), _M_uosd() + { } + + /** + * @brief Resets the distribution state. + */ + void + reset() + { _M_uosd.reset(); } + + /** + * @brief Returns the @f$radius@f$ of the distribution. + */ + _RealType + radius() const + { return _M_param.radius(); } + + /** + * @brief Returns the parameter set of the distribution. + */ + param_type + param() const + { return _M_param; } + + /** + * @brief Sets the parameter set of the distribution. + * @param __param The new parameter set of the distribution. + */ + void + param(const param_type& __param) + { _M_param = __param; } + + /** + * @brief Returns the greatest lower bound value of the distribution. + * This function makes no sense for this distribution. + */ + result_type + min() const + { + result_type __res; + __res.fill(0); + return __res; + } + + /** + * @brief Returns the least upper bound value of the distribution. + * This function makes no sense for this distribution. + */ + result_type + max() const + { + result_type __res; + __res.fill(0); + return __res; + } + + /** + * @brief Generating functions. + */ + template + result_type + operator()(_UniformRandomNumberGenerator& __urng) + { return this->operator()(__urng, _M_param); } + + template + result_type + operator()(_UniformRandomNumberGenerator& __urng, + const param_type& __p); + + template + void + __generate(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng) + { this->__generate(__f, __t, __urng, this->param()); } + + template + void + __generate(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __p) + { this->__generate_impl(__f, __t, __urng, __p); } + + template + void + __generate(result_type* __f, result_type* __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __p) + { this->__generate_impl(__f, __t, __urng, __p); } + + /** + * @brief Return true if two uniform on sphere distributions have + * the same parameters and the sequences that would be + * generated are equal. + */ + friend bool + operator==(const uniform_inside_sphere_distribution& __d1, + const uniform_inside_sphere_distribution& __d2) + { return __d1._M_param == __d2._M_param && __d1._M_uosd == __d2._M_uosd; } + + /** + * @brief Inserts a %uniform_inside_sphere_distribution random number + * distribution @p __x into the output stream @p __os. + * + * @param __os An output stream. + * @param __x A %uniform_inside_sphere_distribution random number + * distribution. + * + * @returns The output stream with the state of @p __x inserted or in + * an error state. + */ + template + friend std::basic_ostream<_CharT, _Traits>& + operator<<(std::basic_ostream<_CharT, _Traits>& __os, + const __gnu_cxx::uniform_inside_sphere_distribution<_Dimen1, + _RealType1>& + ); + + /** + * @brief Extracts a %uniform_inside_sphere_distribution random number + * distribution + * @p __x from the input stream @p __is. + * + * @param __is An input stream. + * @param __x A %uniform_inside_sphere_distribution random number + * generator engine. + * + * @returns The input stream with @p __x extracted or in an error state. + */ + template + friend std::basic_istream<_CharT, _Traits>& + operator>>(std::basic_istream<_CharT, _Traits>& __is, + __gnu_cxx::uniform_inside_sphere_distribution<_Dimen1, + _RealType1>&); + + private: + template + void + __generate_impl(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __p); + + param_type _M_param; + uniform_on_sphere_distribution<_Dimen, _RealType> _M_uosd; + }; + + /** + * @brief Return true if two uniform on sphere distributions are different. + */ + template + inline bool + operator!=(const __gnu_cxx::uniform_inside_sphere_distribution<_Dimen, + _RealType>& __d1, + const __gnu_cxx::uniform_inside_sphere_distribution<_Dimen, + _RealType>& __d2) + { return !(__d1 == __d2); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace __gnu_cxx diff --git a/libstdc++-v3/include/ext/random.tcc b/libstdc++-v3/include/ext/random.tcc index 52350e87314..e1fd88d6408 100644 --- a/libstdc++-v3/include/ext/random.tcc +++ b/libstdc++-v3/include/ext/random.tcc @@ -1669,8 +1669,168 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __is >> __x._M_nd; } + + namespace { + + // Helper class for the uniform_inside_sphere_distribution generation + // function. + template + class uniform_inside_sphere_helper; + + template + class uniform_inside_sphere_helper<_Dimen, false, _RealType> + { + using result_type + = typename uniform_inside_sphere_distribution<_Dimen, _RealType>:: + result_type; + + public: + template + result_type + operator()(_UniformOnSphereDistribution& __uosd, + _UniformRandomNumberGenerator& __urng, + _RealType __radius) + { + std::__detail::_Adaptor<_UniformRandomNumberGenerator, + _RealType> __aurng(__urng); + + _RealType __pow = 1 / _RealType(_Dimen); + _RealType __urt = __radius * std::pow(__aurng(), __pow); + result_type __ret = __uosd(__aurng); + + std::transform(__ret.begin(), __ret.end(), __ret.begin(), + [__urt](_RealType __val) + { return __val * __urt; }); + + return __ret; + } + }; + + // Helper class for the uniform_inside_sphere_distribution generation + // function specialized for small dimensions. + template + class uniform_inside_sphere_helper<_Dimen, true, _RealType> + { + using result_type + = typename uniform_inside_sphere_distribution<_Dimen, _RealType>:: + result_type; + + public: + template + result_type + operator()(_UniformOnSphereDistribution&, + _UniformRandomNumberGenerator& __urng, + _RealType __radius) + { + result_type __ret; + _RealType __sq; + _RealType __radsq = __radius * __radius; + std::__detail::_Adaptor<_UniformRandomNumberGenerator, + _RealType> __aurng(__urng); + + do + { + __sq = _RealType(0); + for (int i = 0; i < _Dimen; ++i) + { + __ret[i] = _RealType(2) * __aurng() - _RealType(1); + __sq += __ret[i] * __ret[i]; + } + } + while (__sq > _RealType(1)); + + for (int i = 0; i < _Dimen; ++i) + __ret[i] *= __radius; + + return __ret; + } + }; + } // namespace + + // + // Experiments have shown that rejection is more efficient than transform + // for dimensions less than 8. + // + template + template + typename uniform_inside_sphere_distribution<_Dimen, _RealType>::result_type + uniform_inside_sphere_distribution<_Dimen, _RealType>:: + operator()(_UniformRandomNumberGenerator& __urng, + const param_type& __p) + { + uniform_inside_sphere_helper<_Dimen, _Dimen < 8, _RealType> __helper; + return __helper(_M_uosd, __urng, __p.radius()); + } + + template + template + void + uniform_inside_sphere_distribution<_Dimen, _RealType>:: + __generate_impl(_OutputIterator __f, _OutputIterator __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __param) + { + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator>) + + while (__f != __t) + *__f++ = this->operator()(__urng, __param); + } + + template + std::basic_ostream<_CharT, _Traits>& + operator<<(std::basic_ostream<_CharT, _Traits>& __os, + const __gnu_cxx::uniform_inside_sphere_distribution<_Dimen, + _RealType>& __x) + { + typedef std::basic_ostream<_CharT, _Traits> __ostream_type; + typedef typename __ostream_type::ios_base __ios_base; + + const typename __ios_base::fmtflags __flags = __os.flags(); + const _CharT __fill = __os.fill(); + const std::streamsize __precision = __os.precision(); + const _CharT __space = __os.widen(' '); + __os.flags(__ios_base::scientific | __ios_base::left); + __os.fill(__space); + __os.precision(std::numeric_limits<_RealType>::max_digits10); + + __os << __x.radius() << __space << __x._M_uosd; + + __os.flags(__flags); + __os.fill(__fill); + __os.precision(__precision); + + return __os; + } + + template + std::basic_istream<_CharT, _Traits>& + operator>>(std::basic_istream<_CharT, _Traits>& __is, + __gnu_cxx::uniform_inside_sphere_distribution<_Dimen, + _RealType>& __x) + { + typedef std::basic_istream<_CharT, _Traits> __istream_type; + typedef typename __istream_type::ios_base __ios_base; + + const typename __ios_base::fmtflags __flags = __is.flags(); + __is.flags(__ios_base::dec | __ios_base::skipws); + + _RealType __radius_val; + __is >> __radius_val >> __x._M_uosd; + __x.param(typename uniform_inside_sphere_distribution<_Dimen, _RealType>:: + param_type(__radius_val)); + + __is.flags(__flags); + + return __is; + } + _GLIBCXX_END_NAMESPACE_VERSION -} // namespace +} // namespace __gnu_cxx #endif // _EXT_RANDOM_TCC diff --git a/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/default.cc b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/default.cc new file mode 100644 index 00000000000..79ae488913a --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/default.cc @@ -0,0 +1,43 @@ +// { dg-do run { target cxx11 } } +// { dg-require-cstdint "" } +// +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template uniform_on_sphere +// 26.5.1.6 Random number distribution requirements [rand.req.dist] + +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + + __gnu_cxx::uniform_inside_sphere_distribution<2> u2; + __gnu_cxx::uniform_inside_sphere_distribution<3> u3; + __gnu_cxx::uniform_inside_sphere_distribution<4, double> u4; + __gnu_cxx::uniform_inside_sphere_distribution<5, float> u5; +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/parms.cc b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/parms.cc new file mode 100644 index 00000000000..924b997bb8f --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/cons/parms.cc @@ -0,0 +1,44 @@ +// { dg-do run { target cxx11 } } +// { dg-require-cstdint "" } +// +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template logistic_distribution +// 26.5.1.6 Random number distribution requirements [rand.req.dist] + +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + + __gnu_cxx::uniform_inside_sphere_distribution<2> u(1.5); + VERIFY( u.radius() == 1.5 ); + + __gnu_cxx::uniform_inside_sphere_distribution<3> v(3.0); + VERIFY( v.radius() == 3.0 ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/equal.cc b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/equal.cc new file mode 100644 index 00000000000..370ee5664fc --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/equal.cc @@ -0,0 +1,41 @@ +// { dg-do run { target cxx11 } } +// { dg-require-cstdint "" } +// +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template uniform_inside_sphere_distribution + +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + + __gnu_cxx::uniform_inside_sphere_distribution<3> u(2.0), v(2.0); + + VERIFY( u == v ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/generate.cc b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/generate.cc new file mode 100644 index 00000000000..60d76f30ffb --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/generate.cc @@ -0,0 +1,60 @@ +// { dg-do run { target cxx11 } } +// { dg-require-cstdint "" } +// +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template uniform_inside_sphere_distribution +// 26.5.1.6 Random number distribution requirements [rand.req.dist] + +#include +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + std::minstd_rand0 rng; + + __gnu_cxx::uniform_inside_sphere_distribution<3> u3(2.0); + + for (size_t n = 0; n < 1000; ++n) + { + auto r = u3(rng); + + VERIFY (std::abs(r[0]) < 2.0 + && std::abs(r[1]) < 2.0 + && std::abs(r[2]) < 2.0); + } + + __gnu_cxx::uniform_inside_sphere_distribution<2> u2(4000.0); + + for (size_t n = 0; n < 1000; ++n) + { + auto r = u2(rng); + + VERIFY (std::abs(r[0]) < 4000.0 && std::abs(r[1]) < 4000.0); + } +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/inequal.cc b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/inequal.cc new file mode 100644 index 00000000000..0256d47a2f4 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/inequal.cc @@ -0,0 +1,41 @@ +// { dg-do run { target cxx11 } } +// { dg-require-cstdint "" } +// +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template uniform_inside_sphere_distribution + +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + + __gnu_cxx::uniform_inside_sphere_distribution<3> u(4.0), v(4.0); + + VERIFY( !(u != v) ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/serialize.cc b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/serialize.cc new file mode 100644 index 00000000000..d03ce35b29c --- /dev/null +++ b/libstdc++-v3/testsuite/ext/random/uniform_inside_sphere_distribution/operators/serialize.cc @@ -0,0 +1,50 @@ +// { dg-do run { target cxx11 } } +// { dg-require-cstdint "" } +// +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Class template uniform_inside_sphere_distribution +// 26.5.1.6 Random number distribution requirements [rand.req.dist] + +#include +#include +#include + +void +test01() +{ + bool test [[gnu::unused]] = true; + + std::stringstream str; + __gnu_cxx::uniform_inside_sphere_distribution<3> u(8.0), v(8.0); + std::minstd_rand0 rng; + + u(rng); // advance + str << u; + + str >> v; + + VERIFY( u == v ); +} + +int +main() +{ + test01(); + return 0; +}