RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
normal_inverse_gamma.hpp
Go to the documentation of this file.
1#pragma once
2
9
10#include <algorithm>
11
12namespace randlib
13{
14
21template <typename RealType>
23 : public ContinuousBivariateDistribution<StudentTRand<RealType>, InverseGammaRand<RealType>, RealType>
24{
25 Pair<RealType> variate(detail::EngineRef g) const override { return (*this)(g); }
26
27 double mu = 0;
28 double lambda = 1;
29 double alpha = 1;
30 double beta = 1;
31 double pdfCoef = 0.5 * (randlib::consts::lnpi - randlib::consts::ln2);
32
33public:
34 NormalInverseGammaRand(double location = 0, double precision = 1, double shape = 1, double rate = 1);
35 [[nodiscard]] std::string Name() const override;
36
37 void SetParameters(double location, double precision, double shape, double rate);
38 [[nodiscard]] inline double GetLocation() const noexcept { return mu; }
39 [[nodiscard]] inline double GetPrecision() const noexcept { return lambda; }
40 [[nodiscard]] inline double GetShape() const noexcept { return alpha; }
41 [[nodiscard]] inline double GetRate() const noexcept { return beta; }
42
43 [[nodiscard]] double f(const Pair<RealType> &point) const override;
44 [[nodiscard]] double logf(const Pair<RealType> &point) const override;
45 [[nodiscard]] double F(const Pair<RealType> &point) const override;
46 template <std::uniform_random_bit_generator G>
47 [[nodiscard]] Pair<RealType> operator()(G &g) const;
48
49 long double Correlation() const override;
50
51 [[nodiscard]] Pair<RealType> Mode() const override;
52};
53
54} // namespace randlib
55
57
58namespace randlib
59{
60
61template <typename RealType>
62NormalInverseGammaRand<RealType>::NormalInverseGammaRand(double location, double precision, double shape, double rate)
63{
64 SetParameters(location, precision, shape, rate);
65}
66
67template <typename RealType>
69{
70 return "Normal-Inverse-Gamma(" + this->toStringWithPrecision(GetLocation()) + ", " +
71 this->toStringWithPrecision(GetPrecision()) + ", " + this->toStringWithPrecision(GetShape()) + ", " +
72 this->toStringWithPrecision(GetRate()) + ")";
73}
74
75template <typename RealType>
76void NormalInverseGammaRand<RealType>::SetParameters(double location, double precision, double shape, double rate)
77{
78 if (!std::isfinite(location))
79 throw std::invalid_argument("Normal-Inverse-Gamma distribution: location should be finite");
80 if (!(precision > 0.0))
81 throw std::invalid_argument(
82 "Precision of Normal-Inverse-Gamma distribution should be positive, but it's equal to " +
83 std::to_string(precision));
84 if (!(shape > 0.0))
85 throw std::invalid_argument(
86 "Shape of Normal-Inverse-Gamma distribution should be positive, but it's equal to " +
87 std::to_string(shape));
88 if (!(rate > 0.0))
89 throw std::invalid_argument("Rate of Normal-Inverse-Gamma distribution should be positive, but it's equal to " +
90 std::to_string(rate));
91
92 mu = location;
93 lambda = precision;
94
95 this->Y.SetParameters(shape, rate);
96 alpha = this->Y.GetShape();
97 beta = this->Y.GetRate();
98 this->X.SetDegree(2 * alpha);
99 this->X.SetLocation(mu);
100 this->X.SetScale(std::sqrt(beta / (alpha * lambda)));
101
102 pdfCoef = 0.5 * std::log(0.5 * lambda / randlib::consts::pi);
103 pdfCoef += alpha * this->Y.GetLogRate() - this->Y.GetLogGammaShape();
104}
105
106template <typename RealType>
108{
109 return (point.second > 0.0) ? std::exp(logf(point)) : 0.0;
110}
111
112template <typename RealType>
114{
115 RealType sigmaSq = point.second;
116 if (sigmaSq <= 0)
117 return -INFINITY;
118 RealType x = point.first;
119 RealType y = (alpha + 1.5) * std::log(sigmaSq);
120 RealType degree = x - mu;
121 degree *= degree;
122 degree *= lambda;
123 degree += 2 * beta;
124 degree *= 0.5 / sigmaSq;
125 y += degree;
126 return pdfCoef - y;
127}
128
129template <typename RealType>
131{
132 RealType sigmaSq = point.second;
133 if (sigmaSq <= 0)
134 return 0.0;
135 RealType x = point.first;
136 if (x == -INFINITY)
137 return 0.0;
138 double marginalY = this->Y.F(sigmaSq);
139 if (x == INFINITY)
140 return marginalY;
141 if (sigmaSq == INFINITY)
142 return this->X.F(x);
143 if (x == mu)
144 return 0.5 * marginalY;
145
146 double lower = beta / sigmaSq;
147 double normalCoef = (x - mu) * std::sqrt(lambda / beta);
148 double logGammaAlpha = this->Y.GetLogGammaShape();
149 double shape = alpha;
150 double joint = math::integrate(
151 [lower, normalCoef, logGammaAlpha, shape](double t) {
152 double oneMinusT = 1.0 - t;
153 double u = lower + t / oneMinusT;
154 double logWeight = (shape - 1.0) * std::log(u) - u - logGammaAlpha;
155 logWeight -= 2.0 * std::log(oneMinusT);
156 double conditional = 0.5 * std::erfc(-normalCoef * std::sqrt(0.5 * u));
157 return std::exp(logWeight) * conditional;
158 },
159 0.0, 1.0);
160 return std::clamp(joint, 0.0, std::min(this->X.F(x), marginalY));
161}
162
163template <typename RealType>
164template <std::uniform_random_bit_generator G>
166{
167 Pair<RealType> var;
168 var.second = this->Y(g);
169 double coef = std::sqrt(var.second / lambda);
170 var.first = mu + coef * detail::standardNormal<RealType>(g);
171 return var;
172}
173
174template <typename RealType>
176{
177 return (alpha > 2.0) ? 0.0 : NAN;
178}
179
180template <typename RealType>
182{
183 return std::make_pair(mu, 2 * beta / (2 * alpha + 3));
184}
185
186} // namespace randlib
The ContinuousBivariateDistribution class Abstract class for all bivariate probability distribution...
Definition continuous_bivariate.hpp:18
The NormalInverseGammaRand class Normal-inverse-gamma distribution.
Definition normal_inverse_gamma.hpp:24
long double Correlation() const override
Definition normal_inverse_gamma.hpp:175
double f(const Pair< RealType > &point) const override
Definition normal_inverse_gamma.hpp:107
double logf(const Pair< RealType > &point) const override
Definition normal_inverse_gamma.hpp:113
void SetParameters(double location, double precision, double shape, double rate)
Definition normal_inverse_gamma.hpp:76
NormalInverseGammaRand(double location=0, double precision=1, double shape=1, double rate=1)
Definition normal_inverse_gamma.hpp:62
std::string Name() const override
Definition normal_inverse_gamma.hpp:68
Pair< RealType > Mode() const override
Definition normal_inverse_gamma.hpp:181
double GetLocation() const noexcept
Definition normal_inverse_gamma.hpp:38
double GetPrecision() const noexcept
Definition normal_inverse_gamma.hpp:39
Pair< RealType > operator()(G &g) const
Definition normal_inverse_gamma.hpp:165
double GetShape() const noexcept
Definition normal_inverse_gamma.hpp:40
double GetRate() const noexcept
Definition normal_inverse_gamma.hpp:41
double F(const Pair< RealType > &point) const override
Definition normal_inverse_gamma.hpp:130
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
constexpr long double ln2
Definition constants.hpp:18
constexpr long double pi
Definition constants.hpp:22
constexpr long double lnpi
Definition constants.hpp:21
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
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
std::pair< T, T > Pair
Definition fwd.hpp:33