RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
rice.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
8
9namespace randlib
10{
11
20template <typename RealType>
21class RiceRand 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 = 0;
27 double sigma = 1;
28 double halfNoncentrality = 0;
29 double logSigma = 0;
30
31public:
32 explicit RiceRand(double offset = 0, double scale = 1);
33
34 [[nodiscard]] std::string Name() const override;
35 [[nodiscard]] Support SupportType() const override { return Support::RightSemiFinite; }
36 [[nodiscard]] RealType MinValue() const override { return 0; }
37 [[nodiscard]] RealType MaxValue() const override { return INFINITY; }
38
39 void SetParameters(double offset, double scale);
40 [[nodiscard]] double GetOffset() const noexcept { return nu; }
41 [[nodiscard]] double GetScale() const noexcept { return sigma; }
42
43 [[nodiscard]] double f(const RealType &x) const override;
44 [[nodiscard]] double logf(const RealType &x) const override;
45 [[nodiscard]] double F(const RealType &x) const override;
46 [[nodiscard]] double S(const RealType &x) const override;
47
48 template <std::uniform_random_bit_generator G>
49 [[nodiscard]] RealType operator()(G &g) const;
50
51 [[nodiscard]] long double Mean() const override;
52 [[nodiscard]] long double Variance() const override;
53 [[nodiscard]] RealType Mode() const override;
54
55private:
56 std::complex<double> CFImpl(double t) const override;
57};
58
59} // namespace randlib
60
61namespace randlib
62{
63
64template <typename RealType>
65RiceRand<RealType>::RiceRand(double offset, double scale)
66{
67 SetParameters(offset, scale);
68}
69
70template <typename RealType>
71std::string RiceRand<RealType>::Name() const
72{
73 return "Rice(" + this->toStringWithPrecision(nu) + ", " + this->toStringWithPrecision(sigma) + ")";
74}
75
76template <typename RealType>
77void RiceRand<RealType>::SetParameters(double offset, double scale)
78{
79 if (!(offset >= 0) || !std::isfinite(offset))
80 throw std::invalid_argument("Rice distribution: offset should be finite and non-negative");
81 if (!(scale > 0) || !std::isfinite(scale))
82 throw std::invalid_argument("Rice distribution: scale should be finite and positive");
83 nu = offset;
84 sigma = scale;
85 const double standardizedOffset = nu / sigma;
86 halfNoncentrality = 0.5 * standardizedOffset * standardizedOffset;
87 logSigma = std::log(sigma);
88}
89
90template <typename RealType>
91double RiceRand<RealType>::f(const RealType &x) const
92{
93 return (x > 0 && std::isfinite(x)) ? std::exp(logf(x)) : 0;
94}
95
96template <typename RealType>
97double RiceRand<RealType>::logf(const RealType &x) const
98{
99 if (!(x > 0) || !std::isfinite(x))
100 return -INFINITY;
101 const double standardizedDifference = (static_cast<double>(x) - nu) / sigma;
102 const double z = (static_cast<double>(x) / sigma) * (nu / sigma);
103 double scaledLogBessel;
104 if (z > 50) {
105 const double inverseZ = 1 / z;
106 const double series =
107 1 + inverseZ * (1.0 / 8 + inverseZ * (9.0 / 128 + inverseZ * (225.0 / 3072 + inverseZ * 11025.0 / 98304)));
108 scaledLogBessel = -0.5 * std::log(2 * randlib::consts::pi * z) + std::log(series);
109 } else {
110 scaledLogBessel = math::logBesselI(0.0, z) - z;
111 }
112 return std::log(static_cast<double>(x)) - 2 * logSigma - 0.5 * standardizedDifference * standardizedDifference +
113 scaledLogBessel;
114}
115
116template <typename RealType>
117double RiceRand<RealType>::F(const RealType &x) const
118{
119 if (x <= 0)
120 return 0;
121 if (std::isinf(x))
122 return 1;
123 const double standardizedX = static_cast<double>(x) / sigma;
124 const double halfX = 0.5 * standardizedX * standardizedX;
125 if (halfNoncentrality == 0)
126 return -std::expm1(-halfX);
127 return math::MarcumP(1.0, halfNoncentrality, halfX);
128}
129
130template <typename RealType>
131double RiceRand<RealType>::S(const RealType &x) const
132{
133 if (x <= 0)
134 return 1;
135 if (std::isinf(x))
136 return 0;
137 const double standardizedX = static_cast<double>(x) / sigma;
138 const double halfX = 0.5 * standardizedX * standardizedX;
139 if (halfNoncentrality == 0)
140 return std::exp(-halfX);
141 return math::MarcumQ(1.0, halfNoncentrality, halfX);
142}
143
144template <typename RealType>
145template <std::uniform_random_bit_generator G>
147{
148 const RealType y = static_cast<RealType>(nu) + static_cast<RealType>(sigma) * detail::standardNormal<RealType>(g);
149 const RealType z = static_cast<RealType>(sigma) * detail::standardNormal<RealType>(g);
150 return std::hypot(y, z);
151}
152
153template <typename RealType>
154void RiceRand<RealType>::sample(detail::EngineRef g, std::span<RealType> outputData) const
155{
156 for (RealType &value : outputData)
157 value = (*this)(g);
158}
159
160template <typename RealType>
161long double RiceRand<RealType>::Mean() const
162{
163 const long double k = halfNoncentrality;
164 const long double h = 0.5L * k;
167 static constexpr long double HANKEL_ARGUMENT = 50;
168 long double scaledI0 = 0, ratio = 0;
169 if (h > HANKEL_ARGUMENT) {
170 const long double logSeries0 = math::detail::logHankelSeries<long double>(0, h, -1);
171 scaledI0 = std::exp(logSeries0) / std::sqrt(2 * static_cast<long double>(randlib::consts::pi) * h);
172 ratio = std::exp(math::detail::logHankelSeries<long double>(1, h, -1) - logSeries0);
173 } else {
174 const long double logI0 = math::logBesselI(0.0L, h);
175 scaledI0 = std::exp(logI0 - h);
176 ratio = (h == 0) ? 0 : std::exp(math::logBesselI(1.0L, h) - logI0);
177 }
178 return static_cast<long double>(sigma) * std::sqrt(randlib::consts::pi / 2.0L) * scaledI0 * (1 + k + k * ratio);
179}
180
181template <typename RealType>
183{
184 const long double mean = Mean();
185 return 2 * static_cast<long double>(sigma) * sigma + static_cast<long double>(nu) * nu - mean * mean;
186}
187
188template <typename RealType>
190{
191 return (nu == 0) ? static_cast<RealType>(sigma) : ContinuousDistribution<RealType>::Mode();
192}
193
194template <typename RealType>
195std::complex<double> RiceRand<RealType>::CFImpl(double t) const
196{
197 return this->integrateCharacteristicFunction(t);
198}
199
200} // 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
Rice distribution.
Definition rice.hpp:22
RiceRand(double offset=0, double scale=1)
Definition rice.hpp:65
RealType MinValue() const override
Definition rice.hpp:36
RealType operator()(G &g) const
Definition rice.hpp:146
std::string Name() const override
Definition rice.hpp:71
long double Variance() const override
Definition rice.hpp:182
Support SupportType() const override
Definition rice.hpp:35
double logf(const RealType &x) const override
Definition rice.hpp:97
RealType Mode() const override
Mode is the value, which has the largest probability to happen, or, in the case of continuous distrib...
Definition rice.hpp:189
double f(const RealType &x) const override
Definition rice.hpp:91
double GetOffset() const noexcept
Definition rice.hpp:40
double F(const RealType &x) const override
Definition rice.hpp:117
long double Mean() const override
Definition rice.hpp:161
RealType MaxValue() const override
Definition rice.hpp:37
double S(const RealType &x) const override
Definition rice.hpp:131
double GetScale() const noexcept
Definition rice.hpp:41
void SetParameters(double offset, double scale)
Definition rice.hpp:77
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
constexpr long double pi
Definition constants.hpp:22
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
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
Definition bivariate_normal.hpp:10
Support
Shape of the support of a univariate distribution.
Definition univariate.hpp:15
@ RightSemiFinite
[a, ∞)