Line data Source code
1 : /** \file randomT.hpp
2 : * \author Jared R. Males
3 : * \brief Defines a random number type
4 : * \ingroup gen_math_files
5 : *
6 : */
7 :
8 : //***********************************************************************//
9 : // Copyright 2015, 2016, 2017, 2020 Jared R. Males (jaredmales@gmail.com)
10 : //
11 : // This file is part of mxlib.
12 : //
13 : // mxlib is free software: you can redistribute it and/or modify
14 : // it under the terms of the GNU General Public License as published by
15 : // the Free Software Foundation, either version 3 of the License, or
16 : // (at your option) any later version.
17 : //
18 : // mxlib is distributed in the hope that it will be useful,
19 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : // GNU General Public License for more details.
22 : //
23 : // You should have received a copy of the GNU General Public License
24 : // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 : //***********************************************************************//
26 :
27 : #ifndef mx_math_randomT_hpp
28 : #define mx_math_randomT_hpp
29 :
30 : #include <random>
31 :
32 : #include "randomSeed.hpp"
33 :
34 : namespace mx
35 : {
36 : namespace math
37 : {
38 :
39 : /// A random number type, which functions like any other arithmetic type.
40 : /**
41 : * Combines a random engine, and a random distribution. Using the type conversion operator
42 : * randomT returns the next random deviate whenever it is referenced.
43 : *
44 : * Example:
45 : *
46 : \code
47 : //This can also be done using the alias definition mx::math::normDistT.
48 : randomT<double, std::mt19937_64, std::normal_distribution<double> > norm_distd;
49 : norm_distd.seed(); //
50 :
51 : double d1 = norm_distd; //get a normally distributed value
52 : double d2 = norm_distd; //get the next normally distributed value
53 : \endcode
54 : *
55 : * Tests:
56 : * - Verify compilation and basic operation of randomT with std::distributions \ref tests_math_randomT_basic "[test doc]"
57 : * - Verify compilation and basic operation of randomT with the Laplace distribution \ref
58 : tests_math_randomT_basic_laplace "[test doc]"
59 : *
60 : * \ingroup random
61 : */
62 : template <class typeT, class _ranengT, class _randistT>
63 : class randomT
64 : {
65 :
66 : public:
67 : /// Typedef for the distribution type
68 : typedef _randistT randistT;
69 :
70 : /// Typedef for the engine type
71 : typedef _ranengT ranengT;
72 :
73 : /// Constructor
74 : /** By default this calls the seed method, which will use /dev/random to seed the generator on linux, and time(0) on
75 : * other systems. Set to false to suppress seeding, and/or set a seed with seed(x).
76 : */
77 21 : randomT( bool doSeed = true /**< [in] [optional] if true then the seed method is called upon construction.*/ )
78 26 : {
79 21 : if( doSeed )
80 : {
81 9 : seed();
82 : }
83 21 : }
84 :
85 : /// The random distribution
86 : _randistT distribution;
87 :
88 : /// The random engine
89 : ranengT engine;
90 :
91 : /// The conversion operator, returns the next value in the sequence, according to the distribution.
92 14540818 : operator typeT()
93 : {
94 14540818 : return distribution( engine );
95 : }
96 :
97 : /// Set the seed of the random engine.
98 : /** Calls the engines seed member function.
99 : *
100 : */
101 21 : void seed( typename ranengT::result_type seedval /**< [in] the argument to pass to ranengT::seed() */ )
102 : {
103 21 : engine.seed( seedval );
104 21 : }
105 :
106 : /// Seed the random engine with a good value
107 : /** Calls \ref mx::randomSeed to get the value. On linux this uses /dev/urandom. On other sytems, this uses
108 : * time(0).
109 : */
110 9 : void seed()
111 : {
112 : typename ranengT::result_type seedval;
113 9 : randomSeed( seedval );
114 9 : seed( seedval );
115 9 : }
116 : };
117 :
118 : /**
119 : * @brief The Laplace (double exponential) continuous distribution for random numbers.
120 : *
121 : * The formula for the exponential probability density function is
122 : * @f$p(x|\lambda) = \frac{\lambda}{2} e^{-\lambda x}@f$.
123 : *
124 : * <table border=1 cellpadding=10 cellspacing=0>
125 : * <caption align=top>Distribution Statistics</caption>
126 : * <tr><td>Mean</td><td>@f$0@f$</td></tr>
127 : * <tr><td>Median</td><td>@f$0@f$</td></tr>
128 : * <tr><td>Mode</td><td>@f$0@f$</td></tr>
129 : * <tr><td>Range</td><td>@f$[-\infty, \infty]@f$</td></tr>
130 : * <tr><td>Standard Deviation</td><td>@f$\frac{\sqrt{2}}{\lambda}@f$</td></tr>
131 : * </table>
132 : *
133 : * This is based on the implementation of the exponential distribution in the GNU ISO C++ Library version 4.6.
134 : *
135 : * Tests:
136 : * - Verify compilation and basic operation of randomT with the Laplace distribution \ref tests_math_randomT_basic_laplace "[test doc]"
137 : * -
138 : * \ingroup random
139 : */
140 : template <typename _RealType = double>
141 : class laplace_distribution
142 : {
143 : static_assert( std::is_floating_point<_RealType>::value, "template argument not a floating point type" );
144 :
145 : public:
146 : /** The type of the range of the distribution. */
147 : typedef _RealType result_type;
148 :
149 : /** Parameter type. */
150 : struct param_type
151 : {
152 : typedef laplace_distribution<_RealType> distribution_type;
153 :
154 5 : explicit param_type( _RealType __lambda = _RealType( 1 ) ) : _M_lambda( __lambda )
155 : {
156 5 : }
157 :
158 6 : _RealType lambda() const
159 : {
160 6 : return _M_lambda;
161 : }
162 :
163 : friend bool operator==( const param_type &__p1, const param_type &__p2 )
164 : {
165 : return __p1._M_lambda == __p2._M_lambda;
166 : }
167 :
168 : private:
169 : _RealType _M_lambda;
170 : };
171 :
172 : public:
173 : /**
174 : * @brief Constructs a Laplace (double exponential) distribution with inverse scale
175 : * parameter @f$\lambda@f$.
176 : */
177 10 : explicit laplace_distribution( const result_type &__lambda = result_type( 1 ) ) : _M_param( __lambda )
178 : {
179 5 : }
180 :
181 : explicit laplace_distribution( const param_type &__p ) : _M_param( __p )
182 : {
183 : }
184 :
185 : /**
186 : * @brief Resets the distribution state.
187 : *
188 : * Has no effect on Laplace distributions.
189 : */
190 : void reset()
191 : {
192 : }
193 :
194 : /**
195 : * @brief Returns the inverse scale parameter of the distribution.
196 : */
197 : _RealType lambda() const
198 : {
199 : return _M_param.lambda();
200 : }
201 :
202 : /**
203 : * @brief Returns the parameter set of the distribution.
204 : */
205 6 : param_type param() const
206 : {
207 6 : return _M_param;
208 : }
209 :
210 : /**
211 : * @brief Sets the parameter set of the distribution.
212 : * @param __param The new parameter set of the distribution.
213 : */
214 : void param( const param_type &__param )
215 : {
216 : _M_param = __param;
217 : }
218 :
219 : /**
220 : * @brief Returns the greatest lower bound value of the distribution.
221 : */
222 : result_type min() const
223 : {
224 : return std::numeric_limits<result_type>::min();
225 : }
226 :
227 : /**
228 : * @brief Returns the least upper bound value of the distribution.
229 : */
230 : result_type max() const
231 : {
232 : return std::numeric_limits<result_type>::max();
233 : }
234 :
235 : /**
236 : * @brief Generating functions.
237 : */
238 : template <typename _UniformRandomNumberGenerator>
239 6 : result_type operator()( _UniformRandomNumberGenerator &__urng )
240 : {
241 6 : return this->operator()( __urng, this->param() );
242 : }
243 :
244 : template <typename _UniformRandomNumberGenerator>
245 6 : result_type operator()( _UniformRandomNumberGenerator &__urng, const param_type &__p )
246 : {
247 6 : int sgnx = 1;
248 :
249 6 : result_type __aurng = 0.5 - std::generate_canonical<result_type,
250 : std::numeric_limits<result_type>::digits,
251 6 : _UniformRandomNumberGenerator>( __urng );
252 :
253 6 : if( __aurng < 0 )
254 : {
255 3 : sgnx = -1;
256 3 : __aurng *= -1;
257 : }
258 :
259 6 : return 0. - __p.lambda() * sgnx * std::log( 1. - 2. * __aurng );
260 : }
261 :
262 : private:
263 : param_type _M_param;
264 : };
265 :
266 : /**
267 : * @brief Return true if two exponential distributions have the same
268 : * parameters.
269 : */
270 : template <typename _RealType>
271 : bool operator==( const laplace_distribution<_RealType> &__d1, const laplace_distribution<_RealType> &__d2 )
272 : {
273 : return __d1.param() == __d2.param();
274 : }
275 :
276 : /**
277 : * @brief Return true if two exponential distributions have different
278 : * parameters.
279 : */
280 : template <typename _RealType>
281 : bool operator!=( const laplace_distribution<_RealType> &__d1, const laplace_distribution<_RealType> &__d2 )
282 : {
283 : return !( __d1 == __d2 );
284 : }
285 :
286 : /**
287 : * @brief Inserts a %laplace_distribution random number distribution
288 : * @p __x into the output stream @p __os.
289 : *
290 : * @param __os An output stream.
291 : * @param __x A %laplace_distribution random number distribution.
292 : *
293 : * @returns The output stream with the state of @p __x inserted or in
294 : * an error state.
295 : */
296 : template <typename _RealType, typename _CharT, typename _Traits>
297 : std::basic_ostream<_CharT, _Traits> &operator<<( std::basic_ostream<_CharT, _Traits> &,
298 : const laplace_distribution<_RealType> & );
299 :
300 : /**
301 : * @brief Extracts a %laplace_distribution random number distribution
302 : * @p __x from the input stream @p __is.
303 : *
304 : * @param __is An input stream.
305 : * @param __x A %laplace_distribution random number
306 : * generator engine.
307 : *
308 : * @returns The input stream with @p __x extracted or in an error state.
309 : */
310 : template <typename _RealType, typename _CharT, typename _Traits>
311 : std::basic_istream<_CharT, _Traits> &operator>>( std::basic_istream<_CharT, _Traits> &,
312 : laplace_distribution<_RealType> & );
313 :
314 : /** \ingroup random
315 : * @{
316 : */
317 :
318 : /// Alias for a uniform random variate
319 : template <typename realT>
320 : using uniDistT = randomT<realT, std::mt19937_64, std::uniform_real_distribution<realT>>;
321 :
322 : /// Alias for a standard normal random variate
323 : template <typename realT>
324 : using normDistT = randomT<realT, std::mt19937_64, std::normal_distribution<realT>>;
325 :
326 : /// Alias for an exponential random variate
327 : template <typename realT>
328 : using expDistT = randomT<realT, std::mt19937_64, std::exponential_distribution<realT>>;
329 :
330 : /// Alias for a laplace random variate
331 : template <typename realT>
332 : using lapDistT = randomT<realT, std::mt19937_64, laplace_distribution<realT>>;
333 :
334 : /// Alias for a poisson random variate
335 : template <typename intT>
336 : using poissonDistT = randomT<intT, std::mt19937_64, std::poisson_distribution<intT>>;
337 :
338 : /// Alias for a log normal variate
339 : template <typename realT>
340 : using lognormDistT = randomT<realT, std::mt19937_64, std::lognormal_distribution<realT>>;
341 :
342 : /// @}
343 :
344 : } // namespace math
345 : } // namespace mx
346 :
347 : #endif // mx_math_randomT_hpp
348 :
349 : /*5/22/06: added 64 bit mersenne twister support
350 : */
|