RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
noncentral_chi_squared.hpp
Go to the documentation of this file.
1#pragma once
2
8
9namespace randlib
10{
11
22template <typename 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 k = 1;
29 double lambda = 2;
30 double halfK = 0.5;
31 double halfLambda = 1;
32 double sqrtLambda = randlib::consts::sqrt2;
33 double logLambda = randlib::consts::ln2;
34
36
37public:
38 explicit NoncentralChiSquaredRand(double degree = 1, double noncentrality = 0);
39
40 [[nodiscard]] std::string Name() const override;
41 [[nodiscard]] Support SupportType() const override { return Support::RightSemiFinite; }
42 [[nodiscard]] RealType MinValue() const override { return 0; }
43 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
44
45 void SetParameters(double degree, double noncentrality);
46 [[nodiscard]] inline double GetDegree() const noexcept { return k; }
47 [[nodiscard]] inline double GetNoncentrality() const noexcept { return lambda; }
48
49 [[nodiscard]] double f(const RealType &x) const override;
50 [[nodiscard]] double logf(const RealType &x) const override;
51 [[nodiscard]] double F(const RealType &x) const override;
52 [[nodiscard]] double S(const RealType &x) const override;
53
54private:
55 template <std::uniform_random_bit_generator G>
56 RealType variateForDegreeEqualOne(G &g) const;
57
58public:
59 template <std::uniform_random_bit_generator G>
60 [[nodiscard]] static RealType Variate(double degree, double noncentrality, G &g);
61 template <std::uniform_random_bit_generator G>
62 [[nodiscard]] RealType operator()(G &g) const;
63
64 [[nodiscard]] long double Mean() const override;
65 [[nodiscard]] long double Variance() const override;
66 [[nodiscard]] RealType Mode() const override;
67 [[nodiscard]] long double Skewness() const override;
68 [[nodiscard]] long double ExcessKurtosis() const override;
69
70private:
71 std::complex<double> CFImpl(double t) const override;
72};
73
74} // namespace randlib
75
78
79namespace randlib
80{
81
82template <typename RealType>
84{
85 SetParameters(degree, noncentrality);
86}
87
88template <typename RealType>
90{
91 return "Noncentral Chi-Squared(" + this->toStringWithPrecision(GetDegree()) + ", " +
92 this->toStringWithPrecision(GetNoncentrality()) + ")";
93}
94
95template <typename RealType>
96void NoncentralChiSquaredRand<RealType>::SetParameters(double degree, double noncentrality)
97{
98 if (!(degree > 0.0))
99 throw std::invalid_argument("Noncentral Chi-Squared distribution: degree parameter should be positive");
100 if (!(noncentrality >= 0.0) || !std::isfinite(noncentrality))
101 throw std::invalid_argument(
102 "Noncentral Chi-Squared distribution: noncentrality parameter should be non-negative and finite");
103
104 k = degree;
105 halfK = 0.5 * k;
106
107 lambda = noncentrality;
108 halfLambda = 0.5 * lambda;
109 sqrtLambda = std::sqrt(lambda);
110 logLambda = (lambda == 0.0) ? -INFINITY : std::log(lambda);
111
112 if (k < 1 && lambda > 0.0)
113 Y.SetRate(halfLambda);
114}
115
116template <typename RealType>
117double NoncentralChiSquaredRand<RealType>::f(const RealType &x) const
118{
119 if (x < 0.0)
120 return 0.0;
121 if (x == 0.0) {
122 if (k == 2)
123 return 0.5 * std::exp(-halfLambda);
124 return (k > 2) ? 0.0 : INFINITY;
125 }
126 return std::exp(logf(x));
127}
128
129template <typename RealType>
130double NoncentralChiSquaredRand<RealType>::logf(const RealType &x) const
131{
132 if (x < 0.0)
133 return -INFINITY;
134 if (x == 0.0) {
135 if (k == 2)
136 return -halfLambda - randlib::consts::ln2;
137 return (k > 2) ? -INFINITY : INFINITY;
138 }
139 if (lambda == 0.0)
140 return -halfK * randlib::consts::ln2 - std::lgamma(halfK) + (halfK - 1) * std::log(x) - 0.5 * x;
141 double halfKm1 = halfK - 1;
142 double y = math::logBesselI(halfKm1, std::sqrt(lambda * x));
143 double z = halfKm1 * (std::log(x) - logLambda);
144 z -= x + lambda;
145 return y + 0.5 * z - randlib::consts::ln2;
146}
147
148template <typename RealType>
149double NoncentralChiSquaredRand<RealType>::F(const RealType &x) const
150{
151 if (x <= 0.0)
152 return 0.0;
153 if (std::isinf(x))
154 return 1.0;
155 double halfX = 0.5 * x;
156 if (lambda == 0.0)
157 return math::pgamma(halfK, halfX, std::log(halfK), std::lgamma(halfK));
158 double sqrtHalfX = std::sqrt(halfX);
159 double logHalfX = std::log(halfX);
160 return math::MarcumP(halfK, halfLambda, halfX, sqrtLambda / randlib::consts::sqrt2, sqrtHalfX,
161 logLambda - randlib::consts::ln2, logHalfX);
162}
163
164template <typename RealType>
165double NoncentralChiSquaredRand<RealType>::S(const RealType &x) const
166{
167 if (x <= 0.0)
168 return 1.0;
169 if (std::isinf(x))
170 return 0.0;
171 double halfX = 0.5 * x;
172 if (lambda == 0.0)
173 return math::qgamma(halfK, halfX, std::log(halfK), std::lgamma(halfK));
174 double sqrtHalfX = std::sqrt(halfX);
175 double logHalfX = std::log(halfX);
176 return math::MarcumQ(halfK, halfLambda, halfX, sqrtLambda / randlib::consts::sqrt2, sqrtHalfX,
177 logLambda - randlib::consts::ln2, logHalfX);
178}
179
180template <typename RealType>
181template <std::uniform_random_bit_generator G>
183{
184 RealType y = sqrtLambda + detail::standardNormal<RealType>(g);
185 return y * y;
186}
187
188template <typename RealType>
189template <std::uniform_random_bit_generator G>
190RealType NoncentralChiSquaredRand<RealType>::Variate(double degree, double noncentrality, G &g)
191{
192 if (!(degree > 0.0))
193 throw std::invalid_argument("Noncentral Chi-Squared distribution: degree parameter should be positive");
194 if (!(noncentrality >= 0.0) || !std::isfinite(noncentrality))
195 throw std::invalid_argument(
196 "Noncentral Chi-Squared distribution: noncentrality parameter should be non-negative and finite");
197
198 if (noncentrality == 0.0)
199 return 2 * GammaDistribution<RealType>::StandardVariate(0.5 * degree, g);
200
201 if (degree >= 1) {
202 RealType rv = (degree == 1) ? 0.0 : 2 * GammaDistribution<RealType>::StandardVariate(0.5 * degree - 0.5, g);
203 RealType y = std::sqrt(noncentrality) + detail::standardNormal<RealType>(g);
204 return rv + y * y;
205 }
206 RealType shape = 0.5 * degree + PoissonRand<int>::Variate(0.5 * noncentrality, g);
208}
209
210template <typename RealType>
211template <std::uniform_random_bit_generator G>
213{
214 if (lambda == 0.0)
216 if (k < 1)
217 return 2 * GammaDistribution<RealType>::StandardVariate(halfK + Y(g), g);
218 double X = variateForDegreeEqualOne(g);
219 if (k > 1)
220 X += 2 * GammaDistribution<RealType>::StandardVariate(halfK - 0.5, g);
221 return X;
222}
223
224template <typename RealType>
225void NoncentralChiSquaredRand<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
226{
227 if (lambda == 0.0) {
228 for (RealType &var : outputData)
229 var = 2 * GammaDistribution<RealType>::StandardVariate(halfK, g);
230 return;
231 }
232 if (k >= 1) {
233 for (RealType &var : outputData)
234 var = variateForDegreeEqualOne(g);
235 double halfKmHalf = halfK - 0.5;
236 if (halfKmHalf == 0)
237 return;
238 for (RealType &var : outputData)
239 var += 2 * GammaDistribution<RealType>::StandardVariate(halfKmHalf, g);
240 } else {
241 for (RealType &var : outputData)
242 var = 2 * GammaDistribution<RealType>::StandardVariate(halfK + Y(g), g);
243 }
244}
245
246template <typename RealType>
248{
249 return k + lambda;
250}
251
252template <typename RealType>
254{
255 return 2 * (k + 2 * lambda);
256}
257
258template <typename RealType>
260{
261 if (lambda == 0.0)
262 return std::max(0.0, k - 2);
265 if (k < 2)
266 return 0.0;
268 return (mode > 0 && this->f(mode) > this->f(0)) ? mode : 0.0;
269}
270
271template <typename RealType>
273{
274 long double y = k + 2 * lambda;
275 y = 2.0 / y;
276 long double z = y * std::sqrt(y);
277 return z * (k + 3 * lambda);
278}
279
280template <typename RealType>
282{
283 long double y = k + 2 * lambda;
284 return 12 * (k + 4 * lambda) / (y * y);
285}
286
287template <typename RealType>
288std::complex<double> NoncentralChiSquaredRand<RealType>::CFImpl(double t) const
289{
290 std::complex<double> aux(1, -2 * t);
291 std::complex<double> y(0, lambda * t);
292 y /= aux;
293 y -= halfK * std::log(aux);
294 return std::exp(y);
295}
296
297} // namespace randlib
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition continuous.hpp:285
The GammaDistribution class Abstract class for Gamma distribution.
Definition continuous/gamma.hpp:31
static RealType StandardVariate(double shape, G &g)
Definition continuous/gamma.hpp:605
The NoncentralChiSquaredRand class Noncentral Chi-Squared distribution.
Definition noncentral_chi_squared.hpp:24
double f(const RealType &x) const override
Definition noncentral_chi_squared.hpp:117
long double ExcessKurtosis() const override
Definition noncentral_chi_squared.hpp:281
long double Mean() const override
Definition noncentral_chi_squared.hpp:247
double logf(const RealType &x) const override
Definition noncentral_chi_squared.hpp:130
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition noncentral_chi_squared.hpp:259
long double Variance() const override
Definition noncentral_chi_squared.hpp:253
NoncentralChiSquaredRand(double degree=1, double noncentrality=0)
Definition noncentral_chi_squared.hpp:83
RealType MinValue() const override
Definition noncentral_chi_squared.hpp:42
long double Skewness() const override
Definition noncentral_chi_squared.hpp:272
double GetNoncentrality() const noexcept
Definition noncentral_chi_squared.hpp:47
double F(const RealType &x) const override
Definition noncentral_chi_squared.hpp:149
RealType MaxValue() const override
Definition noncentral_chi_squared.hpp:43
double S(const RealType &x) const override
Definition noncentral_chi_squared.hpp:165
double GetDegree() const noexcept
Definition noncentral_chi_squared.hpp:46
RealType operator()(G &g) const
Definition noncentral_chi_squared.hpp:212
std::string Name() const override
Definition noncentral_chi_squared.hpp:89
void SetParameters(double degree, double noncentrality)
Definition noncentral_chi_squared.hpp:96
Support SupportType() const override
Definition noncentral_chi_squared.hpp:41
The PoissonRand class Poisson distribution.
Definition poisson.hpp:26
T Variate() const
Uses the engine of this object, so it is not thread-safe for one object; use operator() with one engi...
Definition distribution.hpp:133
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 sqrt2
Definition constants.hpp:27
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
Real qgamma(std::type_identity_t< Real > a, Real x, std::type_identity_t< Real > logA, std::type_identity_t< Real > lgammaA)
Calculate upper regularized incomplete gamma function, accelerated by using precalculated values of l...
Definition math/gamma.hpp:938
Real logBesselI(std::type_identity_t< Real > nu, Real x)
Calculates logarithm of modified Bessel function of the 1st kind.
Definition functions.hpp:577
Real MarcumP(std::type_identity_t< Real > mu, Real x, std::type_identity_t< Real > y, std::type_identity_t< Real > sqrtX, std::type_identity_t< Real > sqrtY, std::type_identity_t< Real > logX, std::type_identity_t< Real > logY)
Definition functions.hpp:1023
Real MarcumQ(std::type_identity_t< Real > mu, Real x, std::type_identity_t< Real > y, std::type_identity_t< Real > sqrtX, std::type_identity_t< Real > sqrtY, std::type_identity_t< Real > logX, std::type_identity_t< Real > logY)
Definition functions.hpp:1079
Real pgamma(std::type_identity_t< Real > a, Real x, std::type_identity_t< Real > logA, std::type_identity_t< Real > lgammaA)
Calculate lower regularized incomplete gamma function, accelerated by using precalculated value of lo...
Definition math/gamma.hpp:896
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ RightSemiFinite
[a, ∞)