Remove PrivateImplPointer in favour of std::unique_ptr
[alexxy/gromacs.git] / src / gromacs / random / exponentialdistribution.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2015,2016,2019,2021, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 /*! \file
37  * \brief The exponential distribution
38  *
39  * Portable version of the exponential distribution that generates the same
40  * sequence on all platforms. Since stdlibc++ and libc++ provide different
41  * sequences we prefer this one so unit tests produce the same values on all
42  * platforms.
43  *
44  * \author Erik Lindahl <erik.lindahl@gmail.com>
45  * \inpublicapi
46  * \ingroup module_random
47  */
48
49 #ifndef GMX_RANDOM_EXPONENTIALDISTRIBUTION_H
50 #define GMX_RANDOM_EXPONENTIALDISTRIBUTION_H
51
52 #include <cmath>
53
54 #include <limits>
55 #include <memory>
56
57 #include "gromacs/random/uniformrealdistribution.h"
58 #include "gromacs/utility/classhelpers.h"
59
60 /*
61  * The portable version of the exponential distribution (to make sure we get the
62  * same values on all platforms) has been modified from the LLVM libcxx headers,
63  * distributed under the MIT license:
64  *
65  * Copyright (c) The LLVM compiler infrastructure
66  *
67  * Permission is hereby granted, free of charge, to any person obtaining a copy
68  * of this software and associated documentation files (the "Software"), to deal
69  * in the Software without restriction, including without limitation the rights
70  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71  * copies of the Software, and to permit persons to whom the Software is
72  * furnished to do so, subject to the following conditions:
73  *
74  * The above copyright notice and this permission notice shall be included in
75  * all copies or substantial portions of the Software.
76  *
77  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
83  * THE SOFTWARE.
84  */
85
86 namespace gmx
87 {
88
89 /*! \brief Exponential distribution
90  *
91  *  The C++ standard library does provide an exponential distribution, but even
92  *  though they all sample from a correct distribution, different standard
93  *  library implementations appear to return different sequences of numbers
94  *  for the same random number generator. To make it easier to use GROMACS
95  *  unit tests that depend on random numbers we have our own implementation.
96  *
97  * \tparam RealType Floating-point type, real by default in GROMACS.
98  */
99 template<class RealType = real>
100 class ExponentialDistribution
101 {
102 public:
103     /*! \brief Type of values returned */
104     typedef RealType result_type;
105
106     /*! \brief Exponential distribution parameters */
107     class param_type
108     {
109         /*! \brief The lambda/decay parameter */
110         result_type lambda_;
111
112     public:
113         /*! \brief Reference back to the distribution class */
114         typedef ExponentialDistribution distribution_type;
115
116         /*! \brief Construct parameter block
117          *
118          * \param lambda   lambda/decay parameter
119          */
120         explicit param_type(result_type lambda = 1.0) : lambda_(lambda) {}
121
122         /*! \brief Return lambda parameter */
123         result_type lambda() const { return lambda_; }
124
125         /*! \brief True if two parameter sets will return the same exponential distribution.
126          *
127          * \param x  Instance to compare with.
128          */
129         bool operator==(const param_type& x) const { return lambda_ == x.lambda_; }
130
131         /*! \brief True if two parameter sets will return different exponential distributions
132          *
133          * \param x  Instance to compare with.
134          */
135         bool operator!=(const param_type& x) const { return !operator==(x); }
136     };
137
138 public:
139     /*! \brief Construct new distribution with given floating-point parameter.
140      *
141      * \param lambda   lambda/decay parameter
142
143      */
144     explicit ExponentialDistribution(result_type lambda = 1.0) : param_(param_type(lambda)) {}
145
146     /*! \brief Construct new distribution from parameter class
147      *
148      * \param param  Parameter class as defined inside gmx::ExponentialDistribution.
149      */
150     explicit ExponentialDistribution(const param_type& param) : param_(param) {}
151
152     /*! \brief Flush all internal saved values  */
153     void reset() {}
154
155     /*! \brief Return values from exponential distribution with internal parameters
156      *
157      *  \tparam Rng   Random engine class
158      *
159      *  \param  g     Random engine
160      */
161     template<class Rng>
162     result_type operator()(Rng& g)
163     {
164         return (*this)(g, param_);
165     }
166
167     /*! \brief Return value from exponential distribution with given parameters
168      *
169      *  \tparam Rng   Random engine class
170      *
171      *  \param  g     Random engine
172      *  \param  param Parameters to use
173      */
174     template<class Rng>
175     result_type operator()(Rng& g, const param_type& param)
176     {
177         return -std::log(result_type(1)
178                          - generateCanonical<result_type, std::numeric_limits<result_type>::digits>(g))
179                / param.lambda();
180     }
181
182     /*! \brief Return the lambda parameter of the exponential distribution */
183     result_type lambda() const { return param_.lambda(); }
184
185     /*! \brief Return the full parameter class of exponential distribution */
186     param_type param() const { return param_; }
187
188     /*! \brief Smallest value that can be returned from exponential distribution */
189     result_type min() const { return 0; }
190
191     /*! \brief Largest value that can be returned from exponential distribution */
192     result_type max() const { return std::numeric_limits<result_type>::infinity(); }
193
194     /*! \brief True if two exponential distributions will produce the same values.
195      *
196      * \param  x     Instance to compare with.
197      */
198     bool operator==(const ExponentialDistribution& x) const { return param_ == x.param_; }
199
200     /*! \brief True if two exponential distributions will produce different values.
201      *
202      * \param  x     Instance to compare with.
203      */
204     bool operator!=(const ExponentialDistribution& x) const { return !operator==(x); }
205
206 private:
207     /*! \brief Internal value for parameters, can be overridden at generation time. */
208     param_type param_;
209
210     GMX_DISALLOW_COPY_AND_ASSIGN(ExponentialDistribution);
211 };
212
213 } // namespace gmx
214
215 #endif // GMX_MATH_RANDOM_H