RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
student_t.hpp
Go to the documentation of this file.
1#pragma once
2
8
9namespace randlib
10{
11
20template <typename RealType>
21class StudentTRand final : public ContinuousDistribution<RealType>
22{
23 RealType variate(detail::EngineRef g) const override { return (*this)(g); }
24 void sample(detail::EngineRef g, std::span<RealType> outputData) const override;
25
26 double nu = 1;
27 double mu = 0;
28 double sigma = 1;
29 double logSigma = 0;
31 double pdfCoef = -randlib::consts::lnpi;
32 double nup1Half = 1;
33 double logBetaFun = randlib::consts::lnpi;
34
35public:
36 explicit StudentTRand(double degree = 1.0, double location = 0.0, double scale = 1.0);
37
38 [[nodiscard]] std::string Name() const override;
39 [[nodiscard]] Support SupportType() const override { return Support::Infinite; }
40 [[nodiscard]] RealType MinValue() const override { return -INFINITY; }
41 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
42
43 void SetDegree(double degree);
44 void SetLocation(double location);
45 void SetScale(double scale);
46 [[nodiscard]] inline double GetDegree() const noexcept { return nu; }
47 [[nodiscard]] inline double GetLocation() const noexcept { return mu; }
48 [[nodiscard]] inline double GetScale() const noexcept { return sigma; }
49
50 [[nodiscard]] double f(const RealType &x) const override;
51 [[nodiscard]] double logf(const RealType &x) const override;
52
53private:
54 double log1pSquareOverDegree(double x0) const;
55 double lowerTail(double x0) const;
56
57public:
58 [[nodiscard]] double F(const RealType &x) const override;
59 [[nodiscard]] double S(const RealType &x) const override;
60 template <std::uniform_random_bit_generator G>
61 [[nodiscard]] RealType operator()(G &g) const;
62
63 [[nodiscard]] long double Mean() const override;
64 [[nodiscard]] long double Variance() const override;
65 [[nodiscard]] RealType Median() 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 RealType quantileImpl(double p) const override;
72 RealType quantileImpl1m(double p) const override;
73 std::complex<double> CFImpl(double t) const override;
74};
75
76} // namespace randlib
77
80
81namespace randlib
82{
83
84template <typename RealType>
85StudentTRand<RealType>::StudentTRand(double degree, double location, double scale)
86{
87 SetDegree(degree);
88 SetLocation(location);
89 SetScale(scale);
90}
91
92template <typename RealType>
94{
95 if (mu == 0.0 && sigma == 1.0)
96 return "Student-t(" + this->toStringWithPrecision(GetDegree()) + ")";
97 return "Student-t(" + this->toStringWithPrecision(GetDegree()) + ", " + this->toStringWithPrecision(GetLocation()) +
98 ", " + this->toStringWithPrecision(GetScale()) + ")";
99}
100
101template <typename RealType>
103{
104 if (!(degree > 0.0))
105 throw std::invalid_argument("Student-t distribution: degree parameter should be positive");
106 nu = degree;
107 Y.SetParameters(0.5 * nu, 1.0);
108
109 nup1Half = 0.5 * (nu + 1);
110 pdfCoef = Y.GetLogGammaShapeRatio();
111 pdfCoef -= 0.5 * randlib::consts::lnpi;
112 logBetaFun = -pdfCoef;
113 pdfCoef -= 0.5 * std::log(nu);
114}
115
116template <typename RealType>
118{
119 if (!std::isfinite(location))
120 throw std::invalid_argument("Student-t distribution: location should be finite");
121 mu = location;
122}
123
124template <typename RealType>
126{
127 if (!(scale > 0.0))
128 throw std::invalid_argument("Student-t distribution: scale should be positive");
129 sigma = scale;
130 logSigma = std::log(sigma);
131}
132
133template <typename RealType>
134double StudentTRand<RealType>::f(const RealType &x) const
135{
137 double x0 = x - mu;
138 x0 /= sigma;
139 double xSq = x0 * x0;
140 if (nu == 1)
141 return randlib::consts::inv_pi / (sigma * (1 + xSq));
142 if (nu == 2) {
143 double tmp = 2.0 + xSq;
144 return 1.0 / (sigma * tmp * std::sqrt(tmp));
145 }
146 if (nu == 3) {
147 double y = 3 + xSq;
148 return 6 * randlib::consts::sqrt3 * randlib::consts::inv_pi / (sigma * y * y);
149 }
150 return std::exp(logf(x));
151}
152
153template <typename RealType>
155{
157 double absX = std::fabs(x0);
158 if (absX < 1e100)
159 return std::log1pl(x0 * x0 / nu);
160 double logRatio = 2 * std::log(absX) - std::log(nu);
161 return logRatio + std::log1pl(std::exp(-logRatio));
162}
163
164template <typename RealType>
165double StudentTRand<RealType>::logf(const RealType &x) const
166{
168 double x0 = x - mu;
169 x0 /= sigma;
170 double log1pXsqNu = log1pSquareOverDegree(x0);
171 if (nu == 1)
172 return -logSigma - randlib::consts::lnpi - log1pXsqNu;
173 if (nu == 2)
174 return -logSigma - 1.5 * (randlib::consts::ln2 + log1pXsqNu);
175 if (nu == 3) {
176 double y = -2 * (randlib::consts::ln3 + log1pXsqNu);
178 return y;
179 }
180 double y = -nup1Half * log1pXsqNu;
181 return pdfCoef + y - logSigma;
182}
183
184template <typename RealType>
185double StudentTRand<RealType>::lowerTail(double x0) const
186{
188 if (nu == 1)
190 ((x0 < -1.0) ? std::atan(-1.0 / x0) : randlib::consts::half_pi + std::atan(x0));
191 if (x0 * x0 < nu) {
193 double xSq = x0 * x0, u = xSq / (nu + xSq);
194 return 0.5 - 0.5 * math::ibeta(u, 0.5, 0.5 * nu, logBetaFun, std::log(xSq) - std::log(nu + xSq),
195 std::log(nu) - std::log(nu + xSq));
196 }
197 double logT = -log1pSquareOverDegree(x0);
198 double t = std::exp(logT);
199 if (t < 1e-280) {
201 return 0.5 * std::exp(0.5 * nu * logT - std::log(0.5 * nu) - logBetaFun);
202 }
203 double log1mT = std::log1pl(-t);
204 return 0.5 * math::ibeta(t, 0.5 * nu, 0.5, logBetaFun, logT, log1mT);
205}
206
207template <typename RealType>
208double StudentTRand<RealType>::F(const RealType &x) const
209{
210 double x0 = (x - mu) / sigma;
211 if (x0 == 0.0)
212 return 0.5;
213 return (x0 < 0.0) ? lowerTail(x0) : 1.0 - lowerTail(-x0);
214}
215
216template <typename RealType>
217double StudentTRand<RealType>::S(const RealType &x) const
218{
219 double x0 = (x - mu) / sigma;
220 if (x0 == 0.0)
221 return 0.5;
222 return (x0 > 0.0) ? lowerTail(-x0) : 1.0 - lowerTail(x0);
223}
224
225template <typename RealType>
226template <std::uniform_random_bit_generator G>
228{
229 if (nu == 1)
230 return mu + sigma * CauchyRand<RealType>::StandardVariate(g);
231 return mu + sigma * detail::standardNormal<RealType>(g) / Y(g);
232}
233
234template <typename RealType>
235void StudentTRand<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
236{
237 if (nu == 1) {
238 for (RealType &var : outputData)
239 var = mu + sigma * CauchyRand<RealType>::StandardVariate(g);
240 } else {
241 Y.Sample(g, outputData);
242 for (RealType &var : outputData)
243 var = mu + sigma * detail::standardNormal<RealType>(g) / var;
244 }
245}
246
247template <typename RealType>
249{
250 return (nu > 1) ? mu : NAN;
251}
252
253template <typename RealType>
255{
256 if (nu > 2)
257 return sigma * sigma * nu / (nu - 2);
258 return (nu > 1) ? INFINITY : NAN;
259}
260
261template <typename RealType>
262std::complex<double> StudentTRand<RealType>::CFImpl(double t) const
263{
264 double x = std::sqrt(nu) * t * sigma; // value of sqrt(nu) can be hashed
265 double vHalf = 0.5 * nu;
266 double y = vHalf * std::log(x);
267 y -= Y.GetLogGammaFunction();
268 y -= (vHalf - 1) * randlib::consts::ln2;
269 y += math::logBesselK(vHalf, x);
270 double costmu = std::cos(t * mu), sintmu = std::sin(t * mu);
271 std::complex<double> cf(costmu, sintmu);
272 return std::exp(y) * cf;
273}
274
275template <typename RealType>
276RealType StudentTRand<RealType>::quantileImpl(double p) const
277{
278 double temp = p - 0.5;
279 if (nu == 1)
280 return std::tan(randlib::consts::pi * temp) * sigma + mu;
281 double pq = p * (1.0 - p);
282 if (nu == 2)
283 return sigma * 2.0 * temp * std::sqrt(0.5 / pq) + mu;
284 if (nu == 4) {
285 double alpha = 2 * std::sqrt(pq);
286 double beta = std::cos(std::acos(alpha) / 3.0) / alpha - 1;
287 return mu + sigma * 2 * math::sign(temp) * std::sqrt(beta);
288 }
290}
291
292template <typename RealType>
293RealType StudentTRand<RealType>::quantileImpl1m(double p) const
294{
295 double temp = 0.5 - p;
296 if (nu == 1)
297 return std::tan(randlib::consts::pi * temp) * sigma + mu;
298 double pq = p * (1.0 - p);
299 if (nu == 2)
300 return sigma * 2 * temp * std::sqrt(0.5 / pq) + mu;
301 if (nu == 4) {
302 double alpha = 2 * std::sqrt(pq);
303 double beta = std::cos(std::acos(alpha) / 3.0) / alpha - 1;
304 return mu + sigma * 2 * math::sign(temp) * std::sqrt(beta);
305 }
307}
308
309template <typename RealType>
311{
312 return mu;
313}
314
315template <typename RealType>
317{
318 return mu;
319}
320
321template <typename RealType>
323{
324 return (nu > 3) ? 0.0 : NAN;
325}
326
327template <typename RealType>
329{
330 if (nu > 4)
331 return 6.0 / (nu - 4);
332 return (nu > 2) ? INFINITY : NAN;
333}
334
335} // namespace randlib
The CauchyRand class Cauchy distribution.
Definition cauchy.hpp:26
static RealType StandardVariate(G &g)
Definition cauchy.hpp:101
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
RealType quantileImpl(double p, RealType initValue) const override
Definition continuous.hpp:140
RealType quantileImpl1m(double p, RealType initValue) const override
Definition continuous.hpp:152
The NakagamiRand class Nakagami distribution.
Definition nakagami.hpp:96
void Sample(std::span< T > outputData) const
Fills the output with variates drawn with the engine of this object.
Definition distribution.hpp:139
The StudentTRand class Student's t-distribution.
Definition student_t.hpp:22
double GetLocation() const noexcept
Definition student_t.hpp:47
long double Variance() const override
Definition student_t.hpp:254
long double ExcessKurtosis() const override
Definition student_t.hpp:328
StudentTRand(double degree=1.0, double location=0.0, double scale=1.0)
Definition student_t.hpp:85
RealType MaxValue() const override
Definition student_t.hpp:41
double f(const RealType &x) const override
Definition student_t.hpp:134
std::string Name() const override
Definition student_t.hpp:93
long double Skewness() const override
Definition student_t.hpp:322
void SetScale(double scale)
Definition student_t.hpp:125
void SetLocation(double location)
Definition student_t.hpp:117
double S(const RealType &x) const override
Definition student_t.hpp:217
void SetDegree(double degree)
Definition student_t.hpp:102
RealType operator()(G &g) const
Definition student_t.hpp:227
long double Mean() const override
Definition student_t.hpp:248
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition student_t.hpp:316
double GetScale() const noexcept
Definition student_t.hpp:48
RealType Median() const override
Definition student_t.hpp:310
double F(const RealType &x) const override
Definition student_t.hpp:208
RealType MinValue() const override
Definition student_t.hpp:40
double logf(const RealType &x) const override
Definition student_t.hpp:165
Support SupportType() const override
Definition student_t.hpp:39
double GetDegree() const noexcept
Definition student_t.hpp:46
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
constexpr long double inv_pi
Definition constants.hpp:24
constexpr long double ln2
Definition constants.hpp:18
constexpr long double pi
Definition constants.hpp:22
constexpr long double ln3
Definition constants.hpp:19
constexpr long double sqrt3
Definition constants.hpp:29
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
int sign(Real x)
Definition functions.hpp:232
Real ibeta(Real x, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > logBetaFun, std::type_identity_t< Real > logX, std::type_identity_t< Real > log1mX)
Fast calculation of regularized beta function, using precalculated values.
Definition math/beta.hpp:250
Real logBesselK(std::type_identity_t< Real > nu, Real x)
Calculates logarithm of modified Bessel function of the 2nd kind.
Definition functions.hpp:637
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ Infinite
(-∞, ∞)