RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
weibull.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
9
10namespace randlib
11{
12
19template <typename RealType>
20class WeibullRand final : public ContinuousDistribution<RealType>
21{
22 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
23
24 double lambda = 1;
25 double k = 1;
26 double kInv = 1;
27 double logk_lambda = 0;
28
29public:
30 WeibullRand(double scale = 1, double shape = 1);
31
32 [[nodiscard]] std::string Name() const override;
33 [[nodiscard]] Support SupportType() const override { return Support::RightSemiFinite; }
34 [[nodiscard]] RealType MinValue() const override { return 0; }
35 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
36
37 void SetParameters(double scale, double shape);
38 [[nodiscard]] inline double GetScale() const noexcept { return lambda; }
39 [[nodiscard]] inline double GetShape() const noexcept { return k; }
40
41 [[nodiscard]] double f(const RealType &x) const override;
42 [[nodiscard]] double logf(const RealType &x) const override;
43 [[nodiscard]] double F(const RealType &x) const override;
44 [[nodiscard]] double S(const RealType &x) const override;
45 template <std::uniform_random_bit_generator G>
46 [[nodiscard]] RealType operator()(G &g) const;
47
48 [[nodiscard]] long double Mean() const override;
49 [[nodiscard]] long double Variance() const override;
50 [[nodiscard]] RealType Median() const override;
51 [[nodiscard]] RealType Mode() const override;
52 [[nodiscard]] long double Skewness() const override;
53 [[nodiscard]] long double ExcessKurtosis() const override;
54
55private:
56 RealType quantileImpl(double p) const override;
57 RealType quantileImpl1m(double p) const override;
58
59 std::complex<double> CFImpl(double t) const override;
60
61public:
62 [[nodiscard]] long double Entropy() const;
63
64private:
70 double getNorm(std::span<const RealType> sample) const;
71
72public:
77 RANDLIB_DEPRECATED_FIT_MEMBER void FitScale(std::span<const RealType> sample);
78
87 FitScaleBayes(std::span<const RealType> sample, const InverseGammaRand<RealType> &priorDistribution,
88 bool MAP = false);
89};
90
91} // namespace randlib
92
95
96namespace randlib
97{
98
99template <typename RealType>
100WeibullRand<RealType>::WeibullRand(double scale, double shape)
101{
102 SetParameters(scale, shape);
103}
104
105template <typename RealType>
107{
108 return "Weibull(" + this->toStringWithPrecision(GetScale()) + ", " + this->toStringWithPrecision(GetShape()) + ")";
109}
110
111template <typename RealType>
112void WeibullRand<RealType>::SetParameters(double scale, double shape)
113{
114 if (!(scale > 0.0))
115 throw std::invalid_argument("Weibull distribution: scale should be positive");
116 if (!(shape > 0.0))
117 throw std::invalid_argument("Weibull distribution: shape should be positive");
118 lambda = scale;
119 k = shape;
120 kInv = 1.0 / k;
121 logk_lambda = std::log(k / lambda);
122}
123
124template <typename RealType>
125double WeibullRand<RealType>::f(const RealType &x) const
126{
127 if (x < 0)
128 return 0;
129 if (x == 0) {
130 if (k == 1)
131 return 1.0 / lambda;
132 return (k > 1) ? 0.0 : INFINITY;
133 }
134 return std::exp(this->logf(x));
135}
136
137template <typename RealType>
138double WeibullRand<RealType>::logf(const RealType &x) const
139{
140 if (x < 0)
141 return -INFINITY;
142 if (x == 0) {
143 if (k == 1)
144 return logk_lambda;
145 return (k > 1) ? -INFINITY : INFINITY;
146 }
147 double xAdj = x / lambda;
148 double xAdjPow = std::pow(xAdj, k);
149 return logk_lambda + (k - 1) * std::log(xAdj) - xAdjPow;
150}
151
152template <typename RealType>
153double WeibullRand<RealType>::F(const RealType &x) const
154{
155 return (x > 0.0) ? -std::expm1l(-std::pow(x / lambda, k)) : 0.0;
156}
157
158template <typename RealType>
159double WeibullRand<RealType>::S(const RealType &x) const
160{
161 return (x > 0.0) ? std::exp(-std::pow(x / lambda, k)) : 1.0;
162}
163
164template <typename RealType>
165template <std::uniform_random_bit_generator G>
167{
168 return lambda * std::pow(detail::standardExponential<RealType>(g), kInv);
169}
170
171template <typename RealType>
173{
174 return lambda * std::tgammal(1 + kInv);
175}
176
177template <typename RealType>
179{
180 double res = std::tgammal(1 + kInv);
181 res *= -res;
182 res += std::tgammal(1 + kInv + kInv);
183 return lambda * lambda * res;
184}
185
186template <typename RealType>
188{
189 return lambda * std::pow(randlib::consts::ln2, kInv);
190}
191
192template <typename RealType>
194{
195 if (k <= 1)
196 return 0;
197 double y = std::log1pl(-kInv);
198 y = std::exp(kInv * y);
199 return lambda * y;
200}
201
202template <typename RealType>
204{
205 long double mu = Mean();
206 long double var = Variance();
207 long double sigma = std::sqrt(var);
208 long double numerator = std::tgammal(1 + 3.0 * kInv);
209 numerator *= lambda * lambda * lambda;
210 numerator -= 3 * mu * var;
211 numerator -= mu * mu * mu;
212 long double denominator = var * sigma;
213 return numerator / denominator;
214}
215
216template <typename RealType>
218{
219 long double mu = Mean();
220 long double var = Variance();
221 long double sigma = std::sqrt(var);
222 long double skewness = Skewness();
223 long double numerator = lambda * lambda;
224 numerator *= numerator;
225 numerator *= std::tgammal(1 + 4.0 * kInv);
226 numerator -= 4 * skewness * var * sigma * mu;
227 long double mu2 = mu * mu;
228 numerator -= 6 * mu2 * var;
229 numerator -= mu2 * mu2;
230 long double kurtosis = numerator / (var * var);
231 return kurtosis - 3;
232}
233
234template <typename RealType>
235RealType WeibullRand<RealType>::quantileImpl(double p) const
236{
237 double x = -std::log1pl(-p);
238 x = std::pow(x, kInv);
239 return lambda * x;
240}
241
242template <typename RealType>
243RealType WeibullRand<RealType>::quantileImpl1m(double p) const
244{
245 double x = -std::log(p);
246 x = std::pow(x, kInv);
247 return lambda * x;
248}
249
250template <typename RealType>
251std::complex<double> WeibullRand<RealType>::CFImpl(double t) const
252{
253 double lambdaT = lambda * t;
254 if (k >= 1) {
255 if (lambdaT > 0.5)
258 long double re = 0.0, im = 0.0;
259 long double addon = 0.0;
260 long double logLambdaT = std::log(lambdaT);
262 int n = 0;
263 do {
264 int n2 = n + n;
265 addon = n2 * logLambdaT;
266 addon += std::lgammal(1.0 + n2 / k);
267 addon -= std::lgammal(1.0 + n2);
268 addon = std::exp(addon);
269 re += (n & 1) ? -addon : addon;
270 ++n;
271 } while (std::fabs(addon) > math::detail::minimumTolerance * std::fabs(re));
273 n = 0;
274 do {
275 int n2p1 = n + n + 1;
276 addon = n2p1 * logLambdaT;
277 addon += std::lgammal(1.0 + n2p1 / k);
278 addon -= std::lgammal(1.0 + n2p1);
279 addon = std::exp(addon);
280 im += (n & 1) ? -addon : addon;
281 ++n;
282 } while (std::fabs(addon) > math::detail::minimumTolerance * std::fabs(im));
283 return std::complex<double>(re, im);
284 }
285
287 double re1 = math::integrate(
288 [this, t](double x) {
289 if (x <= 0.0 || x > 1.0)
290 return 0.0;
291 double xAdj = x / lambda;
292 double xAdjPow = std::pow(xAdj, k - 1);
293 double y = k / lambda * xAdjPow * std::expm1l(-xAdj * xAdjPow);
294 return std::cos(t * x) * y;
295 },
296 0.0, 1.0);
297
298 double re2 = this->ExpectedValue([t](double x) { return std::cos(t * x); }, 1.0, INFINITY);
299
300 double re3 = t * math::integrate(
301 [this, t](double x) {
302 if (x <= 0.0)
303 return 0.0;
304 return std::sin(t * x) * std::pow(x, k);
305 },
306 0.0, 1.0);
307 re3 += std::cos(t);
308 re3 /= std::pow(lambda, k);
309
310 double re = re1 + re2 + re3;
311
312 double im = this->ExpectedValue([t](double x) { return std::sin(t * x); }, 0.0, INFINITY);
313
314 return std::complex<double>(re, im);
315}
316
317template <typename RealType>
319{
320 return randlib::consts::egamma * (1.0 - kInv) + std::log(lambda * kInv) + 1.0;
321}
322
323template <typename RealType>
324double WeibullRand<RealType>::getNorm(std::span<const RealType> sample) const
325{
326 long double sum = 0;
327 RealType maxVar = *std::max_element(sample.begin(), sample.end());
328 for (const RealType &var : sample) {
329 sum += std::pow(var / maxVar, k);
330 }
331 long double avg = sum / sample.size();
332 return maxVar * std::pow(avg, kInv);
333}
334
335template <typename RealType>
336void WeibullRand<RealType>::FitScale(std::span<const RealType> sample)
337{
338 if (!this->allElementsArePositive(sample))
339 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
340 double knorm = getNorm(sample);
341 SetParameters(knorm, k);
342}
343
344template <typename RealType>
346 const InverseGammaRand<RealType> &priorDistribution,
347 bool MAP)
348{
349 if (!this->allElementsArePositive(sample))
350 throw this->fitError(FitErrorCode::WrongSample, this->POSITIVITY_VIOLATION);
351 int n = sample.size();
352 double newShape = priorDistribution.GetShape() + n;
353 double knorm = getNorm(sample);
354 double newRate = priorDistribution.GetRate() + n * std::pow(knorm, k);
355 InverseGammaRand<RealType> posteriorDistribution(newShape, newRate);
356 double powScale = MAP ? posteriorDistribution.Mode() : posteriorDistribution.Mean();
357 SetParameters(std::pow(powScale, kInv), k);
358 return posteriorDistribution;
359}
360
361} // namespace randlib
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
The InverseGammaRand class Inverse-Gamma distribution.
Definition inverse_gamma.hpp:23
double GetRate() const noexcept
Definition inverse_gamma.hpp:49
double GetShape() const noexcept
Definition inverse_gamma.hpp:48
long double Mean() const override
Definition inverse_gamma.hpp:146
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition inverse_gamma.hpp:168
virtual void sample(detail::EngineRef g, std::span< T > outputData) const
Fills the output with variate(g); distributions with a faster bulk algorithm override it.
Definition distribution.hpp:66
virtual std::complex< double > CFImpl(double t) const
Definition univariate.hpp:365
The WeibullRand class Weibull distribution.
Definition weibull.hpp:21
double F(const RealType &x) const override
Definition weibull.hpp:153
long double ExcessKurtosis() const override
Definition weibull.hpp:217
void SetParameters(double scale, double shape)
Definition weibull.hpp:112
void FitScale(std::span< const RealType > sample)
Fit λ by maximum-likelihood.
Definition weibull.hpp:336
RealType operator()(G &g) const
Definition weibull.hpp:166
double logf(const RealType &x) const override
Definition weibull.hpp:138
double GetScale() const noexcept
Definition weibull.hpp:38
RealType Median() const override
Definition weibull.hpp:187
double f(const RealType &x) const override
Definition weibull.hpp:125
long double Variance() const override
Definition weibull.hpp:178
RealType MinValue() const override
Definition weibull.hpp:34
double GetShape() const noexcept
Definition weibull.hpp:39
long double Entropy() const
Definition weibull.hpp:318
RealType MaxValue() const override
Definition weibull.hpp:35
InverseGammaRand< RealType > FitScaleBayes(std::span< const RealType > sample, const InverseGammaRand< RealType > &priorDistribution, bool MAP=false)
Fit λ, using bayesian inference.
Definition weibull.hpp:345
long double Skewness() const override
Definition weibull.hpp:203
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition weibull.hpp:193
long double Mean() const override
Definition weibull.hpp:172
std::string Name() const override
Definition weibull.hpp:106
WeibullRand(double scale=1, double shape=1)
log(k/λ)
Definition weibull.hpp:100
double S(const RealType &x) const override
Definition weibull.hpp:159
Support SupportType() const override
Definition weibull.hpp:33
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
constexpr long double egamma
Definition constants.hpp:36
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
constexpr long double minimumTolerance
Definition constants.hpp:44
Real integrate(const F &f, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > tolerance=1e-11, int maxSubdivisions=512)
Global adaptive Gauss-Kronrod quadrature (QUADPACK QAG).
Definition quadrature.hpp:226
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, ∞)