RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
zipf.hpp
Go to the documentation of this file.
1#pragma once
2
7
8namespace randlib
9{
10
17template <typename IntType>
18class ZipfRand final : public DiscreteDistribution<IntType>
19{
20 IntType variate(detail::EngineRef g) const override { return (*this)(g); }
21
22 double s = 2;
23 IntType n = 1;
24 double invHarmonicNumber = 1;
25
26 static constexpr int tableSize = 16;
27 int hashedVarNum = 1;
28 double table[tableSize];
29
30public:
31 ZipfRand(double exponent = 2.0, IntType number = 1);
32
33 [[nodiscard]] std::string Name() const override;
34 [[nodiscard]] Support SupportType() const override { return Support::Finite; }
35 [[nodiscard]] IntType MinValue() const override { return 1; }
36 [[nodiscard]] IntType MaxValue() const override { return n; }
37
38 void SetParameters(double exponent, IntType number);
39 [[nodiscard]] inline double GetExponent() const noexcept { return s; }
40 [[nodiscard]] inline IntType GetNumber() const noexcept { return n; }
41
42 [[nodiscard]] double P(const IntType &k) const override;
43 [[nodiscard]] double logP(const IntType &k) const override;
44 [[nodiscard]] double F(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
54private:
55 std::complex<double> CFImpl(double t) const override;
56};
57
58} // namespace randlib
59
61
62namespace randlib
63{
64
65template <typename IntType>
66ZipfRand<IntType>::ZipfRand(double exponent, IntType number)
67{
68 SetParameters(exponent, number);
69}
70
71template <typename IntType>
72std::string ZipfRand<IntType>::Name() const
73{
74 return "Zipf(" + this->toStringWithPrecision(GetExponent()) + ", " + this->toStringWithPrecision(GetNumber()) + ")";
75}
76
77template <typename IntType>
78void ZipfRand<IntType>::SetParameters(double exponent, IntType number)
79{
80 if (!(exponent > 1.0))
81 throw std::invalid_argument("Zipf distribution: exponent should be greater than 1, but it's equal to " +
82 std::to_string(exponent));
83 if (!(number > 0))
84 throw std::invalid_argument("Zipf distribution: number should be positive, but it's equal to " +
85 std::to_string(number));
86 s = exponent;
87 n = number;
88
89 invHarmonicNumber = 1.0 / math::harmonicNumber(s, n);
90
91 // WARNING: we calculate pow here and in invHarmonic number
92 hashedVarNum = n > tableSize ? tableSize : n;
93 table[0] = 1.0;
94 for (int i = 1; i < hashedVarNum - 1; ++i)
95 table[i] = table[i - 1] + std::pow(i + 1, -s);
96 if (hashedVarNum == n)
97 table[hashedVarNum - 1] = 1.0 / invHarmonicNumber;
98 else
99 table[hashedVarNum - 1] = table[hashedVarNum - 2] + std::pow(hashedVarNum, -s);
100 for (int i = 0; i < hashedVarNum; ++i)
101 table[i] *= invHarmonicNumber;
102}
103
104template <typename IntType>
105double ZipfRand<IntType>::P(const IntType &k) const
106{
107 return (k < 1 || k > n) ? 0.0 : std::pow(k, -s) * invHarmonicNumber;
108}
109
110template <typename IntType>
111double ZipfRand<IntType>::logP(const IntType &k) const
112{
113 return (k < 1 || k > n) ? -INFINITY : -s * std::log(k) + std::log(invHarmonicNumber); // can be hashed
114}
115
116template <typename IntType>
117double ZipfRand<IntType>::F(const IntType &k) const
118{
119 if (k < 1.0)
120 return 0.0;
121 if (k >= n)
122 return 1.0;
123 return math::harmonicNumber(s, k) * invHarmonicNumber;
124}
125
126template <typename IntType>
127template <std::uniform_random_bit_generator G>
129{
130 double U = detail::uniform01<double>(g);
131 int k = 1;
133 if (U > table[hashedVarNum - 1]) {
134 k = hashedVarNum;
135 double sum = table[hashedVarNum - 1];
136 do {
137 ++k;
138 sum += std::pow(k, -s) * invHarmonicNumber;
139 } while (sum < U);
140 } else {
141 while (k <= hashedVarNum && table[k - 1] < U)
142 ++k;
143 }
144 return k;
145}
146
147template <typename IntType>
148long double ZipfRand<IntType>::Mean() const
149{
150 return math::harmonicNumber(s - 1, n) * invHarmonicNumber;
151}
152
153template <typename IntType>
155{
156 double numerator = math::harmonicNumber(s - 1, n);
157 numerator *= numerator;
158 numerator = math::harmonicNumber(s - 2, n) * math::harmonicNumber(s, n) - numerator;
159 return numerator * invHarmonicNumber * invHarmonicNumber;
160}
161
162template <typename IntType>
164{
165 return 1;
166}
167
168template <typename IntType>
169std::complex<double> ZipfRand<IntType>::CFImpl(double t) const
170{
171 std::complex<double> sum(0.0, 0.0);
172 for (int i = 1; i <= n; ++i) {
173 std::complex<double> addon(-s * std::log(i), i * t);
174 sum += std::exp(addon);
175 }
176 return invHarmonicNumber * sum;
177}
178
179template <typename IntType>
181{
182 long double harmonic0 = 1.0 / invHarmonicNumber;
183 long double harmonic1 = math::harmonicNumber(s - 1, n);
184 long double harmonic2 = math::harmonicNumber(s - 2, n);
185 long double harmonic3 = math::harmonicNumber(s - 3, n);
186 long double first = harmonic3 * harmonic0 * harmonic0;
187 long double harmonic2prod0 = harmonic2 * harmonic0;
188 long double second = -3 * harmonic1 * harmonic2prod0;
189 long double harmonic1Sq = harmonic1 * harmonic1;
190 long double third = 2 * harmonic1 * harmonic1Sq;
191 long double numerator = first + second + third;
192 long double denominator = harmonic2prod0 - harmonic1Sq;
193 denominator *= std::sqrt(denominator);
194 return numerator / denominator;
195}
196
197template <typename IntType>
199{
200 long double harmonic0 = 1.0 / invHarmonicNumber;
201 long double harmonic1 = math::harmonicNumber(s - 1, n);
202 long double harmonic2 = math::harmonicNumber(s - 2, n);
203 long double harmonic3 = math::harmonicNumber(s - 3, n);
204 long double harmonic4 = math::harmonicNumber(s - 4, n);
205 long double harmonic2prod0 = harmonic2 * harmonic0;
206 long double harmonic0Sq = harmonic0 * harmonic0;
207 long double harmonic1Sq = harmonic1 * harmonic1;
208 long double denominator = harmonic2prod0 - harmonic1Sq;
209 denominator *= denominator;
210 long double numerator = harmonic0Sq * harmonic0 * harmonic4;
211 numerator -= 4 * harmonic0Sq * harmonic1 * harmonic3;
212 numerator += 6 * harmonic2prod0 * harmonic1Sq;
213 numerator -= 3 * harmonic1Sq * harmonic1Sq;
214 return numerator / denominator - 3;
215}
216
217} // namespace randlib
The DiscreteDistribution class Abstract class for all discrete distributions.
Definition discrete.hpp:21
The ZipfRand class Zipf distribution.
Definition zipf.hpp:19
IntType MaxValue() const override
Definition zipf.hpp:36
long double Variance() const override
Definition zipf.hpp:154
std::string Name() const override
Definition zipf.hpp:72
void SetParameters(double exponent, IntType number)
Definition zipf.hpp:78
long double Skewness() const override
Definition zipf.hpp:180
double P(const IntType &k) const override
Definition zipf.hpp:105
ZipfRand(double exponent=2.0, IntType number=1)
Definition zipf.hpp:66
long double Mean() const override
Definition zipf.hpp:148
Support SupportType() const override
Definition zipf.hpp:34
double F(const IntType &k) const override
Definition zipf.hpp:117
IntType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition zipf.hpp:163
double GetExponent() const noexcept
Definition zipf.hpp:39
IntType GetNumber() const noexcept
Definition zipf.hpp:40
double logP(const IntType &k) const override
Definition zipf.hpp:111
IntType operator()(G &g) const
Definition zipf.hpp:128
long double ExcessKurtosis() const override
Definition zipf.hpp:198
IntType MinValue() const override
Definition zipf.hpp:35
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
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
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15