RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
zeta.hpp
Go to the documentation of this file.
1#pragma once
2
7
8namespace randlib
9{
10
19template <typename IntType>
20class ZetaRand final : public DiscreteDistribution<IntType>
21{
22 IntType variate(detail::EngineRef g) const override { return (*this)(g); }
23
24 double s = 2;
25 double sm1 = 1;
26 double zetaS = randlib::consts::pi_sq / 6.0;
28 double b = 0.5;
29 static constexpr int DIRECT_TERMS = 16;
30
31public:
32 explicit ZetaRand(double exponent = 2.0);
33 [[nodiscard]] std::string Name() const override;
34
35 [[nodiscard]] Support SupportType() const override { return Support::RightSemiFinite; }
36 [[nodiscard]] IntType MinValue() const override { return 1; }
37 [[nodiscard]] IntType MaxValue() const override { return std::numeric_limits<IntType>::max(); }
38
39 void SetExponent(double exponent);
40 [[nodiscard]] inline double GetExponent() const noexcept { return s; }
41
42 [[nodiscard]] double logP(const IntType &k) const override;
43 [[nodiscard]] double F(const IntType &k) const override;
44 [[nodiscard]] double S(const IntType &k) const override;
45 template <std::uniform_random_bit_generator G>
46 [[nodiscard]] IntType operator()(G &g) const;
47
48 [[nodiscard]] long double Mean() const override;
49 [[nodiscard]] long double Variance() const override;
50 [[nodiscard]] IntType Mode() const override;
51 [[nodiscard]] long double Skewness() const override;
52 [[nodiscard]] long double ExcessKurtosis() const override;
53 [[nodiscard]] long double Moment(int n) const;
54 [[nodiscard]] long double ThirdMoment() const override { return Moment(3); }
55 [[nodiscard]] long double FourthMoment() const override { return Moment(4); }
56
57 [[nodiscard]] inline long double GetZetaFunction() const noexcept { return zetaS; }
58 [[nodiscard]] inline long double GetLogZetaFunction() const noexcept { return logZetaS; }
59};
60
61} // namespace randlib
62
65
66namespace randlib
67{
68
69namespace detail
70{
71
72inline long double zetaTail(double exponent, long double firstTerm)
73{
74 static constexpr long double B2jOverFact[] = {1.0L / 12,
75 -1.0L / 720,
76 1.0L / 30240,
77 -1.0L / 1209600,
78 1.0L / 47900160,
79 -691.0L / 1307674368000.0L,
80 1.0L / 74724249600.0L,
81 -3617.0L / 10670622842880000.0L,
82 43867.0L / 5109094217170944000.0L,
83 -174611.0L / 802857662698291200000.0L};
84 long double nPow = std::pow(firstTerm, -static_cast<long double>(exponent));
85 long double sum = firstTerm * nPow / (exponent - 1.0L) + 0.5L * nPow;
86 long double rising = exponent, term = nPow / firstTerm;
87 for (int j = 0; j < 10; ++j) {
88 sum += B2jOverFact[j] * rising * term;
89 rising *= (exponent + 2 * j + 1) * (exponent + 2 * j + 2);
91 }
92 return sum;
93}
94
95} // namespace detail
96
97template <typename IntType>
99{
100 SetExponent(exponent);
101}
102
103template <typename IntType>
104std::string ZetaRand<IntType>::Name() const
105{
106 return "Zeta(" + this->toStringWithPrecision(GetExponent()) + ")";
107}
108
109template <typename IntType>
111{
112 if (!(exponent > 1.0))
113 throw std::invalid_argument("Zeta distribution: exponent should be greater than 1, but it's equal to " +
114 std::to_string(exponent));
115 s = exponent;
116 sm1 = s - 1.0;
117 zetaS = math::riemannZeta(s);
118 logZetaS = std::log(zetaS);
119 b = -std::expm1l(-sm1 * randlib::consts::ln2);
120}
121
122template <typename IntType>
123double ZetaRand<IntType>::logP(const IntType &k) const
124{
125 return (k < 1) ? -INFINITY : -logZetaS - s * std::log(k);
126}
127
128template <typename IntType>
129double ZetaRand<IntType>::F(const IntType &k) const
130{
131 if (k < 1)
132 return 0.0;
133 return (k < DIRECT_TERMS) ? math::harmonicNumber(s, k) / zetaS : 1.0 - S(k);
134}
135
136template <typename IntType>
137double ZetaRand<IntType>::S(const IntType &k) const
138{
139 if (k < 1)
140 return 1.0;
142 long double tail = 0;
143 long long first = static_cast<long long>(k) + 1;
144 for (; first < DIRECT_TERMS; ++first)
145 tail += std::pow(static_cast<long double>(first), -static_cast<long double>(s));
146 tail += detail::zetaTail(s, static_cast<long double>(first));
147 return static_cast<double>(tail / zetaS);
148}
149
150template <typename IntType>
151template <std::uniform_random_bit_generator G>
153{
156 size_t iter = 0;
157 do {
158 float X = std::floor(ParetoRand<float>::StandardVariate(sm1, g));
159 float V = detail::uniform01<float>(g);
160 if (X < 1e4) {
161 float T = std::pow(1.0 + 1.0 / X, sm1);
163 if (V * X * (T - 1) <= b * T)
164 return X;
165 } else {
166 long double logT = sm1 * std::log1pl(1.0 / X);
167 long double TM1 = std::expm1l(logT);
168 if (V * X * TM1 <= b * std::exp(logT))
169 return X < this->MaxValue() ? (IntType)X : this->MaxValue();
170 }
171
173 throw std::runtime_error("Zeta distribution: sampling failed");
174}
175
176template <typename IntType>
177long double ZetaRand<IntType>::Mean() const
178{
179 return (s > 2) ? math::riemannZeta(sm1) / zetaS : INFINITY;
180}
181
182template <typename IntType>
184{
185 if (s <= 3)
186 return INFINITY;
187 double y = Mean();
188 double z = math::riemannZeta(s - 2) / zetaS;
189 return z - y * y;
190}
191
192template <typename IntType>
194{
195 return 1;
196}
197
198template <typename IntType>
200{
201 if (s <= 4)
202 return INFINITY;
203 long double z1 = math::riemannZeta(sm1), z1Sq = z1 * z1;
204 long double z2 = math::riemannZeta(s - 2);
205 long double z3 = math::riemannZeta(s - 3);
206 long double z = zetaS, zSq = z * z;
207 long double logskew = zSq * z3;
208 logskew -= 3 * z2 * z1 * z;
209 logskew += 2 * z1 * z1Sq;
210 logskew = std::log(logskew);
211 logskew -= 1.5 * std::log(z * z2 - z1Sq);
212 logskew -= 2 * logZetaS;
213 return std::exp(logskew);
214}
215
216template <typename IntType>
218{
219 if (s <= 5)
220 return INFINITY;
221 long double mean = Mean();
222 long double secondMoment = this->SecondMoment();
223 long double thirdMoment = ThirdMoment();
224 long double fourthMoment = FourthMoment();
225 long double meanSq = mean * mean;
226 long double variance = secondMoment - meanSq;
227 long double numerator = fourthMoment - 4 * thirdMoment * mean + 6 * secondMoment * meanSq - 3 * meanSq * meanSq;
228 long double denominator = variance * variance;
229 return numerator / denominator - 3.0;
230}
231
232template <typename IntType>
233long double ZetaRand<IntType>::Moment(int n) const
234{
235 return (s > n + 1) ? math::riemannZeta(s - n) / zetaS : INFINITY;
236}
237
238} // namespace randlib
The DiscreteDistribution class Abstract class for all discrete distributions.
Definition discrete.hpp:21
The ParetoRand class Pareto distribution.
Definition pareto.hpp:24
The ProbabilityDistribution class Abstract class for all probability distributions.
Definition distribution.hpp:28
The ZetaRand class Zeta distribution.
Definition zeta.hpp:21
Support SupportType() const override
Definition zeta.hpp:35
long double Moment(int n) const
Definition zeta.hpp:233
double GetExponent() const noexcept
Definition zeta.hpp:40
double S(const IntType &k) const override
Definition zeta.hpp:137
long double Skewness() const override
Definition zeta.hpp:199
long double GetLogZetaFunction() const noexcept
Definition zeta.hpp:58
void SetExponent(double exponent)
Definition zeta.hpp:110
long double GetZetaFunction() const noexcept
Definition zeta.hpp:57
IntType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition zeta.hpp:193
long double ThirdMoment() const override
Definition zeta.hpp:54
long double Variance() const override
Definition zeta.hpp:183
double F(const IntType &k) const override
Definition zeta.hpp:129
long double FourthMoment() const override
Definition zeta.hpp:55
ZetaRand(double exponent=2.0)
Definition zeta.hpp:98
long double Mean() const override
Definition zeta.hpp:177
std::string Name() const override
Definition zeta.hpp:104
IntType operator()(G &g) const
Definition zeta.hpp:152
IntType MinValue() const override
Definition zeta.hpp:36
long double ExcessKurtosis() const override
Definition zeta.hpp:217
IntType MaxValue() const override
Definition zeta.hpp:37
double logP(const IntType &k) const override
Definition zeta.hpp:123
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_sq
Definition constants.hpp:39
constexpr long double ln3
Definition constants.hpp:19
constexpr long double lnpi
Definition constants.hpp:21
long double zetaTail(double exponent, long double firstTerm)
Definition zeta.hpp:72
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
Real harmonicNumber(Real exponent, int number)
Definition functions.hpp:533
Real riemannZeta(Real s)
Definition special_functions.hpp:340
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ RightSemiFinite
[a, ∞)