RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
normal.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
5#include <array>
6
12
14
15namespace randlib
16{
17
29template <typename RealType>
30class NormalRand final : public StableDistribution<RealType>, public ExponentialFamily<RealType, DoublePair>
31{
32 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
33
34 double sigma = 1;
35
36public:
37 NormalRand(double location = 0, double variance = 1);
38
44 [[nodiscard]] static NormalRand FromMeanStd(double mean, double standardDeviation)
45 {
46 NormalRand X(mean);
47 X.SetScale(standardDeviation);
48 return X;
49 }
50
56 [[nodiscard]] static NormalRand FromMeanVariance(double mean, double variance)
57 {
58 return NormalRand(mean, variance);
59 }
60 [[nodiscard]] std::string Name() const override;
61
62 void SetScale(double scale);
63 void SetVariance(double variance);
67 [[nodiscard]] inline double GetScale() const noexcept { return sigma; }
71 [[nodiscard]] inline double GetLogScale() const
72 {
74 }
78 [[nodiscard]] inline double GetPrecision() const { return 1.0 / this->Variance(); }
79
80 DoublePair SufficientStatistic(RealType x) const override;
81 DoublePair SourceParameters() const override;
82 DoublePair SourceToNatural(DoublePair sourceParameters) const override;
83 double LogNormalizer(DoublePair theta) const override;
84 DoublePair LogNormalizerGradient(DoublePair theta) const override;
85 double CarrierMeasure(RealType) const override;
86
87 [[nodiscard]] double f(const RealType &x) const override;
88 [[nodiscard]] double logf(const RealType &x) const override;
89 [[nodiscard]] double F(const RealType &x) const override;
90 [[nodiscard]] double S(const RealType &x) const override;
91 template <std::uniform_random_bit_generator G>
92 [[nodiscard]] RealType operator()(G &g) const;
93
94 template <std::uniform_random_bit_generator G>
95 [[nodiscard]] static RealType StandardVariate(G &g);
96
97private:
98 RealType quantileImpl(double p) const override;
99 RealType quantileImpl1m(double p) const override;
100
101 std::complex<double> CFImpl(double t) const override;
102
103public:
104 [[nodiscard]] long double Moment(size_t n) const;
105 [[nodiscard]] long double ThirdMoment() const override { return Moment(3); }
106 [[nodiscard]] long double FourthMoment() const override { return Moment(4); }
107
112 RANDLIB_DEPRECATED_FIT_MEMBER void FitLocation(std::span<const RealType> sample);
113
121 RANDLIB_DEPRECATED_FIT_MEMBER void FitLocation(std::span<const RealType> sample, DoublePair &confidenceInterval,
122 double significanceLevel);
123
128 RANDLIB_DEPRECATED_FIT_MEMBER void FitVariance(std::span<const RealType> sample);
129
136 RANDLIB_DEPRECATED_FIT_MEMBER void FitVariance(std::span<const RealType> sample, DoublePair &confidenceInterval,
137 double significanceLevel, bool unbiased = false);
138
145 RANDLIB_DEPRECATED_FIT_MEMBER void FitScale(std::span<const RealType> sample, bool unbiased = false);
146
153 RANDLIB_DEPRECATED_FIT_MEMBER void Fit(std::span<const RealType> sample, bool unbiased = false);
154
164 RANDLIB_DEPRECATED_FIT_MEMBER void Fit(std::span<const RealType> sample, DoublePair &confidenceIntervalForMean,
165 DoublePair &confidenceIntervalForVariance, double significanceLevel,
166 bool unbiased = false);
167
176 FitLocationBayes(std::span<const RealType> sample, const NormalRand<RealType> &priorDistribution, bool MAP = false);
177
186 FitVarianceBayes(std::span<const RealType> sample, const InverseGammaRand<RealType> &priorDistribution,
187 bool MAP = false);
188
197 FitBayes(std::span<const RealType> sample, const NormalInverseGammaRand<RealType> &priorDistribution,
198 bool MAP = false);
199};
200
201} // namespace randlib
202
209
210namespace randlib
211{
212
213template <typename RealType>
214NormalRand<RealType>::NormalRand(double location, double variance)
215 : StableDistribution<RealType>(2.0, 0.0, 1.0, location)
216{
217 SetVariance(variance);
218}
219
220template <typename RealType>
221std::string NormalRand<RealType>::Name() const
222{
223 return "Normal(" + this->toStringWithPrecision(this->GetLocation()) + ", " +
224 this->toStringWithPrecision(this->Variance()) + ")";
225}
226
227template <typename RealType>
229{
230 if (!(scale > 0.0))
231 throw std::invalid_argument("Normal distribution: scale should be positive, but it's equal to " +
232 std::to_string(scale));
233 sigma = scale;
235}
236
237template <typename RealType>
239{
240 if (!(variance > 0.0))
241 throw std::invalid_argument("Variance of Normal distribution should be positive, but it's equal to " +
242 std::to_string(variance));
243 SetScale(std::sqrt(variance));
244}
245
246template <typename RealType>
248{
249 return {x, x * x};
250}
251
252template <typename RealType>
254{
255 return {this->mu, this->sigma * this->sigma};
256}
257
258template <typename RealType>
260{
261 double mean = sourceParameters.first;
262 double scaleSq = sourceParameters.second;
263 return {mean / scaleSq, -0.5 / scaleSq};
264}
265
266template <typename RealType>
268{
269 double theta1 = theta.first, theta2 = theta.second;
270 double F = -0.25 * theta1 * theta1 / theta2;
271 F += 0.5 * std::log(-randlib::consts::pi / theta2);
272 return F;
273}
274
275template <typename RealType>
277{
278 double theta1 = theta.first, theta2 = theta.second;
279 double grad1 = -0.5 * theta1 / theta2;
280 double grad2 = -0.5 / theta2 + grad1 * grad1;
281 return {grad1, grad2};
282}
283
284template <typename RealType>
286{
287 return 0.0;
288}
289
290template <typename RealType>
291double NormalRand<RealType>::f(const RealType &x) const
292{
293 return this->pdfNormal(x);
294}
295
296template <typename RealType>
297double NormalRand<RealType>::logf(const RealType &x) const
298{
299 return this->logpdfNormal(x);
300}
301
302template <typename RealType>
303double NormalRand<RealType>::F(const RealType &x) const
304{
305 return this->cdfNormal(x);
306}
307
308template <typename RealType>
309double NormalRand<RealType>::S(const RealType &x) const
310{
311 return this->cdfNormalCompl(x);
312}
313
314template <typename RealType>
315template <std::uniform_random_bit_generator G>
317{
318 return this->mu + sigma * StandardVariate(g);
319}
320
321template <typename RealType>
322template <std::uniform_random_bit_generator G>
327
328template <typename RealType>
329std::complex<double> NormalRand<RealType>::CFImpl(double t) const
330{
331 return this->cfNormal(t);
332}
333
334template <typename RealType>
335RealType NormalRand<RealType>::quantileImpl(double p) const
336{
337 return this->quantileNormal(p);
338}
339
340template <typename RealType>
341RealType NormalRand<RealType>::quantileImpl1m(double p) const
342{
343 return this->quantileNormal1m(p);
344}
345
346template <typename RealType>
347long double NormalRand<RealType>::Moment(size_t n) const
348{
350 long double sum = 0.0;
351 for (size_t k = 0; k <= n; k += 2) {
352 long double centralMoment = (k == 0) ? 1.0 : std::exp(k * std::log(sigma) + math::ldfact(k - 1));
353 sum += math::binom(n, k) * std::pow(static_cast<long double>(this->mu), static_cast<long double>(n - k)) *
354 centralMoment;
355 }
356 return sum;
357}
358
359template <typename RealType>
360void NormalRand<RealType>::FitLocation(std::span<const RealType> sample)
361{
362 this->SetLocation(this->GetSampleMean(sample));
363}
364
365template <typename RealType>
366void NormalRand<RealType>::FitLocation(std::span<const RealType> sample, DoublePair &confidenceInterval,
367 double significanceLevel)
368{
369 if (significanceLevel <= 0 || significanceLevel > 1)
370 throw this->fitError(FitErrorCode::WrongLevel,
371 "Input level is equal to " + this->toStringWithPrecision(significanceLevel));
372
373 FitLocation(sample);
374
375 int n = sample.size();
376 NormalRand<RealType> NormalRV(0, 1);
377 double halfAlpha = 0.5 * significanceLevel;
378 double interval = NormalRV.Quantile1m(halfAlpha) * sigma / std::sqrt(n);
379 confidenceInterval.first = this->mu - interval;
380 confidenceInterval.second = this->mu + interval;
381}
382
383template <typename RealType>
384void NormalRand<RealType>::FitVariance(std::span<const RealType> sample)
385{
386 this->SetVariance(this->GetSampleVariance(sample, this->mu));
387}
388
389template <typename RealType>
390void NormalRand<RealType>::FitVariance(std::span<const RealType> sample, DoublePair &confidenceInterval,
391 double significanceLevel, bool unbiased)
392{
393 if (significanceLevel <= 0 || significanceLevel > 1)
394 throw this->fitError(FitErrorCode::WrongLevel,
395 "Input level is equal to " + this->toStringWithPrecision(significanceLevel));
396
397 FitVariance(sample);
398
399 size_t n = sample.size();
400 double halfAlpha = 0.5 * significanceLevel;
401 ChiSquaredRand ChiSqRV(n);
402 double numerator = sigma * sigma * (unbiased ? n : (n - 1));
403 confidenceInterval.first = numerator / ChiSqRV.Quantile1m(halfAlpha);
404 confidenceInterval.second = numerator / ChiSqRV.Quantile(halfAlpha);
405}
406
407template <typename RealType>
408void NormalRand<RealType>::FitScale(std::span<const RealType> sample, bool unbiased)
409{
410 if (unbiased == false)
411 return FitVariance(sample);
412 size_t n = sample.size();
413 double halfN = 0.5 * n;
414 double s = this->GetSampleVariance(sample, this->mu);
415 s *= halfN;
416 s = 0.5 * std::log(s);
417 s -= std::lgammal(halfN + 0.5);
418 s += std::lgammal(halfN);
419 SetScale(std::exp(s));
420}
421
422template <typename RealType>
423void NormalRand<RealType>::Fit(std::span<const RealType> sample, bool unbiased)
424{
425 double adjustment = 1.0;
426 if (unbiased == true) {
427 size_t n = sample.size();
428 if (n <= 1)
429 throw this->fitError(FitErrorCode::TooFewElements, "There should be at least 2 elements");
430 adjustment = static_cast<double>(n) / (n - 1);
431 }
432 DoublePair stats = this->GetSampleMeanAndVariance(sample);
433 this->SetLocation(stats.first);
434 this->SetVariance(stats.second * adjustment);
435}
436
437template <typename RealType>
438void NormalRand<RealType>::Fit(std::span<const RealType> sample, DoublePair &confidenceIntervalForMean,
439 DoublePair &confidenceIntervalForVariance, double significanceLevel, bool unbiased)
440{
441 if (significanceLevel <= 0 || significanceLevel > 1)
442 throw this->fitError(FitErrorCode::WrongLevel,
443 "Input level is equal to " + this->toStringWithPrecision(significanceLevel));
444
445 Fit(sample, unbiased);
446
447 size_t n = sample.size();
448 double sigmaAdj = unbiased ? sigma : (sigma * n) / (n - 1);
450 double halfAlpha = 0.5 * significanceLevel;
451 StudentTRand<RealType> tRV(n - 1);
452 double interval = tRV.Quantile1m(halfAlpha) * sigmaAdj / std::sqrt(n);
453 confidenceIntervalForMean.first = this->mu - interval;
454 confidenceIntervalForMean.second = this->mu + interval;
455
457 ChiSquaredRand<RealType> ChiSqRV(n - 1);
458 double numerator = (n - 1) * sigmaAdj * sigmaAdj;
459 confidenceIntervalForVariance.first = numerator / ChiSqRV.Quantile1m(halfAlpha);
460 confidenceIntervalForVariance.second = numerator / ChiSqRV.Quantile(halfAlpha);
461}
462
463template <typename RealType>
465 const NormalRand<RealType> &priorDistribution, bool MAP)
466{
467 double mu0 = priorDistribution.GetLocation();
468 double tau0 = priorDistribution.GetPrecision();
469 double tau = GetPrecision();
470 double numerator = this->GetSampleSum(sample) * tau + tau0 * mu0;
471 double denominator = sample.size() * tau + tau0;
472 NormalRand<RealType> posteriorDistribution(numerator / denominator, 1.0 / denominator);
473 this->SetLocation(MAP ? posteriorDistribution.Mode() : posteriorDistribution.Mean());
474 return posteriorDistribution;
475}
476
477template <typename RealType>
479 const InverseGammaRand<RealType> &priorDistribution,
480 bool MAP)
481{
482 double halfN = 0.5 * sample.size();
483 double alphaPrior = priorDistribution.GetShape();
484 double betaPrior = priorDistribution.GetRate();
485 double alphaPosterior = alphaPrior + halfN;
486 double betaPosterior = betaPrior + halfN * this->GetSampleVariance(sample, this->mu);
487 InverseGammaRand<RealType> posteriorDistribution(alphaPosterior, betaPosterior);
488 SetVariance(MAP ? posteriorDistribution.Mode() : posteriorDistribution.Mean());
489 return posteriorDistribution;
490}
491
492template <typename RealType>
494NormalRand<RealType>::FitBayes(std::span<const RealType> sample,
495 const NormalInverseGammaRand<RealType> &priorDistribution, bool MAP)
496{
497 size_t n = sample.size();
498 double alphaPrior = priorDistribution.GetShape();
499 double betaPrior = priorDistribution.GetRate();
500 double muPrior = priorDistribution.GetLocation();
501 double lambdaPrior = priorDistribution.GetPrecision();
502 DoublePair stats = this->GetSampleMeanAndVariance(sample);
503 double lambdaPosterior = lambdaPrior + n;
504 double muPosterior = (lambdaPrior * muPrior + n * stats.first) / lambdaPosterior;
505 double halfN = 0.5 * n;
506 double alphaPosterior = alphaPrior + halfN;
507 double aux = muPrior - stats.first;
508 double betaPosterior = betaPrior + halfN * (stats.second + lambdaPrior / lambdaPosterior * aux * aux);
509 NormalInverseGammaRand<RealType> posteriorDistribution(muPosterior, lambdaPosterior, alphaPosterior, betaPosterior);
510 DoublePair newParams = MAP ? static_cast<DoublePair>(posteriorDistribution.Mode())
511 : static_cast<DoublePair>(posteriorDistribution.Mean());
512 this->SetLocation(newParams.first);
513 this->SetVariance(newParams.second);
514 return posteriorDistribution;
515}
516
517} // namespace randlib
518
The ChiSquaredRand class Chi-squared distribution.
Definition continuous/gamma.hpp:355
Definition exponential_family.hpp:14
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
The NormalInverseGammaRand class Normal-inverse-gamma distribution.
Definition normal_inverse_gamma.hpp:24
double GetLocation() const noexcept
Definition normal_inverse_gamma.hpp:38
double GetPrecision() const noexcept
Definition normal_inverse_gamma.hpp:39
double GetShape() const noexcept
Definition normal_inverse_gamma.hpp:40
double GetRate() const noexcept
Definition normal_inverse_gamma.hpp:41
The NormalRand class Normal distribution.
Definition normal.hpp:31
DoublePair SourceToNatural(DoublePair sourceParameters) const override
Definition normal.hpp:259
double CarrierMeasure(RealType) const override
Definition normal.hpp:285
DoublePair LogNormalizerGradient(DoublePair theta) const override
Definition normal.hpp:276
static RealType StandardVariate(G &g)
Definition normal.hpp:323
std::string Name() const override
Definition normal.hpp:221
DoublePair SourceParameters() const override
Definition normal.hpp:253
DoublePair SufficientStatistic(RealType x) const override
Definition normal.hpp:247
void FitVariance(std::span< const RealType > sample)
set variance, returned by maximium-likelihood estimator
Definition normal.hpp:384
double GetLogScale() const
Definition normal.hpp:71
NormalInverseGammaRand< RealType > FitBayes(std::span< const RealType > sample, const NormalInverseGammaRand< RealType > &priorDistribution, bool MAP=false)
set parameters, returned by bayesian estimation
Definition normal.hpp:494
void FitScale(std::span< const RealType > sample, bool unbiased=false)
set scale, returned via maximum-likelihood estimation or unbiased estimator (which might be different...
Definition normal.hpp:408
double LogNormalizer(DoublePair theta) const override
Definition normal.hpp:267
double GetScale() const noexcept
Definition normal.hpp:67
void FitLocation(std::span< const RealType > sample)
set location, returned by maximium-likelihood estimator
Definition normal.hpp:360
static NormalRand FromMeanStd(double mean, double standardDeviation)
Definition normal.hpp:44
double F(const RealType &x) const override
Definition normal.hpp:303
void SetScale(double scale)
Definition normal.hpp:228
NormalRand< RealType > FitLocationBayes(std::span< const RealType > sample, const NormalRand< RealType > &priorDistribution, bool MAP=false)
set location, returned by bayesian estimation
Definition normal.hpp:464
double GetPrecision() const
Definition normal.hpp:78
long double FourthMoment() const override
Definition normal.hpp:106
long double Moment(size_t n) const
Definition normal.hpp:347
InverseGammaRand< RealType > FitVarianceBayes(std::span< const RealType > sample, const InverseGammaRand< RealType > &priorDistribution, bool MAP=false)
set variance, returned by bayesian estimation
Definition normal.hpp:478
double S(const RealType &x) const override
Definition normal.hpp:309
void SetVariance(double variance)
Definition normal.hpp:238
void Fit(std::span< const RealType > sample, bool unbiased=false)
set parameters, returned by maximium-likelihood estimator if unbiased = false, otherwise set paramete...
Definition normal.hpp:423
RealType operator()(G &g) const
Definition normal.hpp:316
double logf(const RealType &x) const override
Definition normal.hpp:297
NormalRand(double location=0, double variance=1)
Definition normal.hpp:214
long double ThirdMoment() const override
Definition normal.hpp:105
static NormalRand FromMeanVariance(double mean, double variance)
Definition normal.hpp:56
double f(const RealType &x) const override
Definition normal.hpp:291
The StableDistribution class Abstract class for Stable distribution.
Definition stable.hpp:74
double GetLogScale() const noexcept
Definition stable.hpp:176
long double Variance() const override
Definition stable.hpp:1800
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition stable.hpp:1806
void SetScale(double scale)
Definition stable.hpp:730
double GetLocation() const noexcept
Definition stable.hpp:168
long double Mean() const override
Definition stable.hpp:1790
The StudentTRand class Student's t-distribution.
Definition student_t.hpp:22
T Quantile(double p) const
Definition univariate.hpp:307
T Quantile1m(double p) const
Definition univariate.hpp:324
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
#define RANDLIB_DETAIL_SUPPRESS_DEPRECATED_END
Definition fwd.hpp:26
#define RANDLIB_DETAIL_SUPPRESS_DEPRECATED_BEGIN
Definition fwd.hpp:25
#define RANDLIB_DEPRECATED_FIT_MEMBER
Definition fwd.hpp:9
constexpr long double ln2
Definition constants.hpp:18
constexpr long double pi
Definition constants.hpp:22
constexpr long double inv_sqrt2
Definition constants.hpp:28
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
Real ldfact(size_t n)
ldoublefact
Definition math/gamma.hpp:639
Real binom(size_t n, size_t k)
Calculate binomial coefficient.
Definition math/gamma.hpp:648
Definition bivariate_normal.hpp:10
@ WrongLevel
the significance level is not in (0, 1)
@ TooFewElements
the sample is too small
Pair< double > DoublePair
Definition fwd.hpp:39