RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
pareto.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
9
10namespace randlib
11{
12
22template <typename RealType>
23class ParetoRand final : public ContinuousDistribution<RealType>
24{
25 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
26 void sample(detail::EngineRef g, std::span<RealType> outputData) const override;
27
28 double alpha = 1;
29 double sigma = 1;
30 double logAlpha = 0;
31 double logSigma = 0;
32
33public:
34 ParetoRand(double shape = 1, double scale = 1);
35
36 [[nodiscard]] std::string Name() const override;
37 [[nodiscard]] Support SupportType() const override { return Support::RightSemiFinite; }
38 [[nodiscard]] RealType MinValue() const override { return sigma; }
39 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
40
41 void SetShape(double shape);
42 void SetScale(double scale);
43 [[nodiscard]] inline double GetShape() const noexcept { return alpha; }
44 [[nodiscard]] inline double GetScale() const noexcept { return sigma; }
45 [[nodiscard]] inline double GetLogShape() const noexcept { return logAlpha; }
46 [[nodiscard]] inline double GetLogScale() const noexcept { return logSigma; }
47
48 [[nodiscard]] double f(const RealType &x) const override;
49 [[nodiscard]] double logf(const RealType &x) const override;
50 [[nodiscard]] double F(const RealType &x) const override;
51 [[nodiscard]] double S(const RealType &x) const override;
52
53private:
54 template <std::uniform_random_bit_generator G>
55 static RealType variateForAlphaEqualOne(G &g);
56 template <std::uniform_random_bit_generator G>
57 static RealType variateForAlphaEqualTwo(G &g);
58 template <std::uniform_random_bit_generator G>
59 static RealType variateForGeneralAlpha(double shape, G &g);
60
61public:
62 template <std::uniform_random_bit_generator G>
63 [[nodiscard]] RealType operator()(G &g) const;
64
65 template <std::uniform_random_bit_generator G>
66 [[nodiscard]] static RealType StandardVariate(double shape, G &g);
67
68 [[nodiscard]] long double Mean() const override;
69 [[nodiscard]] long double Variance() const override;
70 [[nodiscard]] RealType Median() const override;
71 [[nodiscard]] RealType Mode() const override;
72 [[nodiscard]] long double Skewness() const override;
73 [[nodiscard]] long double ExcessKurtosis() const override;
74
75private:
76 RealType quantileImpl(double p) const override;
77 RealType quantileImpl1m(double p) const override;
78 std::complex<double> CFImpl(double t) const override;
79
80public:
81 [[nodiscard]] long double Entropy() const;
82
89 RANDLIB_DEPRECATED_FIT_MEMBER void FitShape(std::span<const RealType> sample, bool unbiased = false);
90
97 RANDLIB_DEPRECATED_FIT_MEMBER void FitScale(std::span<const RealType> sample, bool unbiased = false);
98
105 RANDLIB_DEPRECATED_FIT_MEMBER void Fit(std::span<const RealType> sample, bool unbiased = false);
106
115 FitShapeBayes(std::span<const RealType> sample, const GammaDistribution<RealType> &priorDistribution,
116 bool MAP = false);
117};
118
119} // namespace randlib
120
123
124namespace randlib
125{
126
127template <typename RealType>
128ParetoRand<RealType>::ParetoRand(double shape, double scale)
129{
130 SetShape(shape);
131 SetScale(scale);
132}
133
134template <typename RealType>
135std::string ParetoRand<RealType>::Name() const
136{
137 return "Pareto(" + this->toStringWithPrecision(GetShape()) + ", " + this->toStringWithPrecision(GetScale()) + ")";
138}
139
140template <typename RealType>
142{
143 if (!(shape > 0.0))
144 throw std::invalid_argument("Pareto distribution: shape should be positive");
145 alpha = shape;
146 logAlpha = std::log(alpha);
147}
148
149template <typename RealType>
151{
152 if (!(scale > 0.0))
153 throw std::invalid_argument("Pareto distribution: scale should be positive");
154 sigma = scale;
155 logSigma = std::log(sigma);
156}
157
158template <typename RealType>
159double ParetoRand<RealType>::f(const RealType &x) const
160{
161 return (x < sigma) ? 0.0 : std::exp(logf(x));
162}
163
164template <typename RealType>
165double ParetoRand<RealType>::logf(const RealType &x) const
166{
167 if (x < sigma)
168 return -INFINITY;
169 double logX = std::log(x);
170 double y = logSigma - logX;
171 y *= alpha;
172 y -= logX;
173 y += logAlpha;
174 return y;
175}
176
177template <typename RealType>
178double ParetoRand<RealType>::F(const RealType &x) const
179{
180 return (x > sigma) ? -std::expm1l(alpha * std::log(sigma / x)) : 0.0;
181}
182
183template <typename RealType>
184double ParetoRand<RealType>::S(const RealType &x) const
185{
186 return (x > sigma) ? std::pow(sigma / x, alpha) : 1.0;
187}
188
189template <typename RealType>
190template <std::uniform_random_bit_generator G>
192{
193 return 1.0 / detail::uniform01<RealType>(g);
194}
195
196template <typename RealType>
197template <std::uniform_random_bit_generator G>
198RealType ParetoRand<RealType>::variateForAlphaEqualTwo(G &g)
199{
200 return 1.0 / std::sqrt(detail::uniform01<RealType>(g));
201}
202
203template <typename RealType>
204template <std::uniform_random_bit_generator G>
205RealType ParetoRand<RealType>::variateForGeneralAlpha(double shape, G &g)
206{
207 return std::exp(detail::standardExponential<RealType>(g) / shape);
208}
209
210template <typename RealType>
211template <std::uniform_random_bit_generator G>
213{
214 return sigma * StandardVariate(alpha, g);
215}
216
217template <typename RealType>
218template <std::uniform_random_bit_generator G>
219RealType ParetoRand<RealType>::StandardVariate(double shape, G &g)
220{
221 if (math::detail::areClose(shape, 1.0))
222 return variateForAlphaEqualOne(g);
223 if (math::detail::areClose(shape, 2.0))
224 return variateForAlphaEqualTwo(g);
225 return variateForGeneralAlpha(shape, g);
226}
227
228template <typename RealType>
229void ParetoRand<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
230{
231 if (math::detail::areClose(alpha, 1.0)) {
232 for (RealType &var : outputData)
233 var = sigma * variateForAlphaEqualOne(g);
234 } else if (math::detail::areClose(alpha, 2.0)) {
235 for (RealType &var : outputData)
236 var = sigma * variateForAlphaEqualTwo(g);
237 } else {
238 for (RealType &var : outputData)
239 var = sigma * variateForGeneralAlpha(alpha, g);
240 }
241}
242
243template <typename RealType>
244long double ParetoRand<RealType>::Mean() const
245{
246 return (alpha > 1) ? alpha * sigma / (alpha - 1) : INFINITY;
247}
248
249template <typename RealType>
251{
252 if (alpha > 2) {
253 long double var = sigma / (alpha - 1);
254 var *= var;
255 return alpha * var / (alpha - 2);
256 }
257 return (alpha > 1) ? INFINITY : NAN;
258}
259
260template <typename RealType>
262{
263 return std::exp(logSigma + randlib::consts::ln2 / alpha);
264}
265
266template <typename RealType>
268{
269 return sigma;
270}
271
272template <typename RealType>
274{
275 if (alpha <= 3)
276 return INFINITY;
277 double skewness = (alpha - 2.0) / alpha;
278 skewness = std::sqrt(skewness);
279 skewness *= (1 + alpha) / (alpha - 3);
280 return skewness + skewness;
281}
282
283template <typename RealType>
285{
286 if (alpha <= 4)
287 return INFINITY;
288 double numerator = alpha + 1;
289 numerator *= alpha;
290 numerator -= 6;
291 numerator *= alpha;
292 numerator -= 2;
293 double denominator = alpha * (alpha - 3) * (alpha - 4);
294 return 6.0 * numerator / denominator;
295}
296
297template <typename RealType>
298RealType ParetoRand<RealType>::quantileImpl(double p) const
299{
300 double y = logSigma - std::log1pl(-p) / alpha;
301 return std::exp(y);
302}
303
304template <typename RealType>
305RealType ParetoRand<RealType>::quantileImpl1m(double p) const
306{
307 double y = logSigma - std::log(p) / alpha;
308 return std::exp(y);
309}
310
311template <typename RealType>
312std::complex<double> ParetoRand<RealType>::CFImpl(double t) const
313{
314 return this->integrateCharacteristicFunction(t);
315}
316
317template <typename RealType>
319{
320 return logSigma - logAlpha + 1.0 / alpha + 1;
321}
322
323template <typename RealType>
324void ParetoRand<RealType>::FitShape(std::span<const RealType> sample, bool unbiased)
325{
326 if (!this->allElementsAreNotSmallerThan(sigma, sample))
327 throw this->fitError(FitErrorCode::WrongSample,
328 this->LOWER_LIMIT_VIOLATION + this->toStringWithPrecision(sigma));
329 double invShape = this->GetSampleLogMean(sample) - logSigma;
330 if (invShape == 0.0)
331 throw this->fitError(FitErrorCode::WrongSample,
332 "Possibly all the elements of the sample coincide with the lower boundary σ.");
333 double shape = 1.0 / invShape;
334 if (unbiased)
335 shape *= (1.0 - 1.0 / sample.size());
336 SetShape(shape);
337}
338
339template <typename RealType>
340void ParetoRand<RealType>::FitScale(std::span<const RealType> sample, bool unbiased)
341{
342 RealType minVar = *std::min_element(sample.begin(), sample.end());
343 if (minVar <= 0)
344 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
345 double scale = unbiased ? (1.0 - 1.0 / (sample.size() * alpha)) * minVar : minVar;
346 SetScale(scale);
347}
348
349template <typename RealType>
350void ParetoRand<RealType>::Fit(std::span<const RealType> sample, bool unbiased)
351{
352 RealType minVar = *std::min_element(sample.begin(), sample.end());
353 if (minVar <= 0)
354 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
355
356 double logBiasedSigma = std::log(minVar);
357 double invShape = this->GetSampleLogMean(sample) - logBiasedSigma;
358 if (invShape == 0.0)
359 throw this->fitError(FitErrorCode::WrongSample, "Possibly all the elements of the sample are the same.");
360 double shape = 1.0 / invShape;
361
362 double scale = minVar;
363 if (unbiased) {
364 int n = sample.size();
365 shape *= 1.0 - 2.0 / n;
366 scale *= 1.0 - invShape / (n - 1);
367 }
368 SetScale(scale);
369 SetShape(shape);
370}
371
372template <typename RealType>
374 const GammaDistribution<RealType> &priorDistribution, bool MAP)
375{
376 if (!this->allElementsAreNotSmallerThan(sigma, sample))
377 throw this->fitError(FitErrorCode::WrongSample,
378 this->LOWER_LIMIT_VIOLATION + this->toStringWithPrecision(sigma));
379 int n = sample.size();
380 double newShape = priorDistribution.GetShape() + n;
381 double newRate = priorDistribution.GetRate() + n * (this->GetSampleLogMean(sample) - logSigma);
382 GammaRand<RealType> posteriorDistribution(newShape, newRate);
383 SetShape(MAP ? posteriorDistribution.Mode() : posteriorDistribution.Mean());
384 return posteriorDistribution;
385}
386
387} // namespace randlib
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
The GammaDistribution class Abstract class for Gamma distribution.
Definition continuous/gamma.hpp:31
double GetShape() const noexcept
Definition continuous/gamma.hpp:78
double GetRate() const noexcept
Definition continuous/gamma.hpp:86
The GammaRand class Gamma distribution.
Definition continuous/gamma.hpp:295
The ParetoRand class Pareto distribution.
Definition pareto.hpp:24
long double Variance() const override
Definition pareto.hpp:250
double S(const RealType &x) const override
Definition pareto.hpp:184
Support SupportType() const override
Definition pareto.hpp:37
double f(const RealType &x) const override
Definition pareto.hpp:159
void Fit(std::span< const RealType > sample, bool unbiased=false)
Fit parameters to maximum-likelihood estimators or to UMVU if unbiased == true.
Definition pareto.hpp:350
double GetScale() const noexcept
Definition pareto.hpp:44
void FitShape(std::span< const RealType > sample, bool unbiased=false)
Fit α to maximum-likelihood estimator or to UMVU if unbiased == true.
Definition pareto.hpp:324
long double Skewness() const override
Definition pareto.hpp:273
RealType MinValue() const override
Definition pareto.hpp:38
double GetShape() const noexcept
Definition pareto.hpp:43
GammaRand< RealType > FitShapeBayes(std::span< const RealType > sample, const GammaDistribution< RealType > &priorDistribution, bool MAP=false)
Fit α, using bayesian inference.
Definition pareto.hpp:373
double GetLogScale() const noexcept
Definition pareto.hpp:46
long double Mean() const override
Definition pareto.hpp:244
RealType operator()(G &g) const
Definition pareto.hpp:212
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition pareto.hpp:267
std::string Name() const override
Definition pareto.hpp:135
ParetoRand(double shape=1, double scale=1)
Definition pareto.hpp:128
double logf(const RealType &x) const override
Definition pareto.hpp:165
void FitScale(std::span< const RealType > sample, bool unbiased=false)
Fit σ to maximum-likelihood estimator or to UMVU if unbiased == true.
Definition pareto.hpp:340
long double Entropy() const
Definition pareto.hpp:318
RealType Median() const override
Definition pareto.hpp:261
void SetShape(double shape)
Definition pareto.hpp:141
void SetScale(double scale)
Definition pareto.hpp:150
RealType MaxValue() const override
Definition pareto.hpp:39
double F(const RealType &x) const override
Definition pareto.hpp:178
static RealType StandardVariate(double shape, G &g)
Definition pareto.hpp:219
double GetLogShape() const noexcept
Definition pareto.hpp:45
long double ExcessKurtosis() const override
Definition pareto.hpp:284
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
#define RANDLIB_DEPRECATED_FIT_MEMBER
Definition fwd.hpp:9
constexpr long double ln2
Definition constants.hpp:18
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
bool areClose(RealType a, RealType b, RealType eps=1e-6)
Definition functions.hpp:38
Definition bivariate_normal.hpp:10
@ WrongSample
the sample could not have been drawn from this distribution
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ RightSemiFinite
[a, ∞)