20template <
typename RealType>
23 static_assert(std::is_floating_point_v<RealType>,
"Continuous distribution supports only floating-point types");
37 [[nodiscard]]
virtual double f(
const RealType &x)
const {
return std::exp(this->
logf(x)); }
43 [[nodiscard]]
virtual double logf(
const RealType &x)
const = 0;
59 [[nodiscard]] RealType
Mode()
const override;
63 RealType
quantileImpl(
double p, RealType initValue)
const override;
67 long double ExpectedValue(
const std::function<
double(RealType)> &funPtr, RealType minPoint,
68 RealType maxPoint)
const override;
81 RealType
searchQuantile(
double p,
bool upperTail, RealType guess,
double relativeStep = 1e-3)
const;
84 [[nodiscard]]
double Hazard(
const RealType &x)
const override;
104template <
typename RealType>
111 static constexpr double NEGLIGIBLE_MASS = 1e-15, PHASE_TOLERANCE = 1e-11;
112 const double minimum = this->MinValue();
113 const bool bounded = std::isfinite(minimum);
114 const double head = bounded ? minimum + PHASE_TOLERANCE / t : -INFINITY;
115 const double lower = std::max(head,
static_cast<double>(this->
Quantile(NEGLIGIBLE_MASS)));
116 const std::complex<double> headMass = bounded ? this->F(head) * std::polar(1.0, t * minimum) : 0.0;
118 [
this](
double x) {
return this->S(x); });
121template <
typename RealType>
123 std::span<double> y)
const
125 const size_t size = std::min(x.size(), y.size());
126 for (
size_t i = 0; i != size; ++i)
127 y[i] = this->f(x[i]);
130template <
typename RealType>
132 std::span<double> y)
const
134 const size_t size = std::min(x.size(), y.size());
135 for (
size_t i = 0; i != size; ++i)
136 y[i] = this->logf(x[i]);
139template <
typename RealType>
142 return searchQuantile(p,
false, initValue);
145template <
typename RealType>
148 return searchQuantile(p,
false, std::numeric_limits<RealType>::quiet_NaN());
151template <
typename RealType>
154 return searchQuantile(p,
true, initValue);
157template <
typename RealType>
160 return searchQuantile(p,
true, std::numeric_limits<RealType>::quiet_NaN());
163template <
typename RealType>
165 double relativeStep)
const
171 upperTail = !upperTail;
174 const bool logScale = p < 1e-3;
175 const double logP = std::log(p);
176 auto g = [
this, p, upperTail, logScale, logP](RealType x) {
177 double v = upperTail ? this->S(x) : this->F(x);
179 return upperTail ? p - v : v - p;
180 double logV = (v > 0) ? std::log(v) : -INFINITY;
181 return upperTail ? logP - logV : logV - logP;
183 const RealType lo = this->MinValue(), hi = this->MaxValue();
184 const bool loFinite = std::isfinite(lo), hiFinite = std::isfinite(hi);
188 const bool useGuess = std::isfinite(guess) && guess > lo && guess < hi;
189 const RealType origin = useGuess ? guess : (loFinite ? lo : (hiFinite ? hi : 0));
190 RealType a = lo, b = hi;
191 double ga = -INFINITY, gb = INFINITY;
192 if (useGuess || !(loFinite && hiFinite)) {
193 double gOrigin = g(origin);
196 RealType step = useGuess ? std::max<RealType>(std::fabs(guess) * relativeStep, 1e-3) : 1;
197 bool searchUp = (useGuess || !loFinite || hiFinite) ? gOrigin < 0 :
true;
198 if (!useGuess && loFinite && !hiFinite)
205 if (hiFinite && b >= hi) {
210 if (!std::isfinite(b))
224 if (loFinite && a <= lo) {
229 if (!std::isfinite(a))
243 const RealType anchor = loFinite ? lo : (hiFinite ? hi : 0);
244 auto split = [anchor, loFinite, hiFinite](RealType left, RealType right) {
245 const RealType direction = (loFinite || (!hiFinite && left >= 0)) ? 1 : -1;
246 RealType tl = direction * (left - anchor), tr = direction * (right - anchor);
247 RealType tNear = std::min(tl, tr), tFar = std::max(tl, tr), t;
248 if (tNear > 0 && tFar > 4 * tNear)
249 t = std::sqrt(tNear) * std::sqrt(tFar);
250 else if (tNear == 0 && tFar > 1e-280 && (loFinite || hiFinite))
253 t = tNear + (tFar - tNear) / 2;
254 return anchor + direction * t;
259 for (
int iter = 0; iter < 2000; ++iter) {
260 RealType tl = std::fabs(a - anchor), tr = std::fabs(b - anchor);
261 bool spansMagnitudes =
262 std::min(tl, tr) == 0 ? std::max(tl, tr) > 1e-280 : std::max(tl, tr) > 4 * std::min(tl, tr);
263 if (std::isfinite(ga) && std::isfinite(gb) && !(spansMagnitudes && (loFinite || hiFinite)))
265 RealType middle = split(a, b);
266 if (!(middle > a && middle < b))
268 double gm = g(middle);
279 auto [left, right] = math::toms748<RealType>([&g](RealType x) {
return static_cast<RealType
>(g(x)); }, a, b,
280 static_cast<RealType
>(ga),
static_cast<RealType
>(gb));
281 return left + (right - left) / 2;
284template <
typename RealType>
287 RealType guess = this->Mean();
288 if (!std::isfinite(guess))
289 guess = this->Median();
291 math::findMin<RealType>([
this](
const RealType &x) {
return -this->logf(x); }, guess, root);
295template <
typename RealType>
297 RealType minPoint, RealType maxPoint)
const
301 const double lowerBoundary = std::max(minPoint, this->MinValue());
302 const double upperBoundary = std::min(maxPoint, this->MaxValue());
303 if (!(lowerBoundary < upperBoundary))
308 double center = std::clamp<double>(this->Median(), lowerBoundary, upperBoundary);
309 if (!std::isfinite(center))
310 center = std::isfinite(lowerBoundary) ? lowerBoundary : (std::isfinite(upperBoundary) ? upperBoundary : 0.0);
311 double scale = 1.0 / this->f(center);
312 if (!(scale > 0) || !std::isfinite(scale))
314 auto side = [
this, &funPtr, center, scale](
double end,
double direction) ->
long double {
315 const double ratio = direction * (end - center) / scale;
318 const double limit = std::isfinite(ratio) ? ratio / (1 + ratio) : 1.0;
320 [
this, &funPtr, center, scale, direction](
double u) {
323 const double denominator = 1.0 - u;
324 const double x = center + direction * scale * u / denominator;
325 const double y = funPtr(x);
326 return (y == 0.0) ? 0.0 : y * this->f(x) * scale / (denominator * denominator);
330 return side(lowerBoundary, -1.0) + side(upperBoundary, 1.0);
333template <
typename RealType>
336 if (x < this->MinValue())
338 if (x > this->MaxValue())
340 return this->f(x) / this->S(x);
343template <
typename RealType>
346 return std::exp(LogLikelihoodFunction(sample));
349template <
typename RealType>
352 long double res = 0.0;
353 for (
const RealType &var : sample)
354 res += this->logf(var);
358template <
typename RealType>
362 size_t n = orderStatistic.size();
364 throw std::invalid_argument(
"Order statistic should not be empty");
365 if (!(alpha > 0 && alpha < 1))
366 throw std::invalid_argument(
"Significance level should be positive and smaller than 1");
369 double interval = K / std::sqrt(n);
370 double nInv = 1.0 / n;
372 for (
size_t i = 1; i != n; ++i) {
373 RealType x = orderStatistic[i - 1];
374 if (x > orderStatistic[i])
375 throw std::invalid_argument(
"Order statistic should be sorted in ascending order");
376 double upperBound = Fn + interval;
378 double lowerBound = Fn - interval;
379 double FReal = this->F(x);
380 if (FReal < lowerBound || FReal > upperBound)
383 double SReal = this->S(orderStatistic[n - 1]);
384 return (SReal > interval || SReal < nInv - interval) ? false :
true;
The ContinuousDistribution class Abstract class for all continuous distributions.
Definition continuous.hpp:22
void LogProbabilityDensityFunction(std::span< const RealType > x, std::span< double > y) const
fill vector y with logf(x)
Definition continuous.hpp:131
RealType quantileImpl(double p) const override
Definition continuous.hpp:146
RealType quantileImpl(double p, RealType initValue) const override
Definition continuous.hpp:140
bool KolmogorovSmirnovTest(std::span< const RealType > orderStatistic, double alpha) const
Definition continuous.hpp:359
virtual ~ContinuousDistribution()
Definition continuous.hpp:29
RealType searchQuantile(double p, bool upperTail, RealType guess, double relativeStep=1e-3) const
Deterministic root search for the quantile: brackets the root, starting from the guess when it is fin...
Definition continuous.hpp:164
RealType quantileImpl1m(double p, RealType initValue) const override
Definition continuous.hpp:152
virtual double logf(const RealType &x) const =0
std::complex< double > integrateCharacteristicFunction(double t) const
Definition continuous.hpp:105
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
long double ExpectedValue(const std::function< double(RealType)> &funPtr, RealType minPoint, RealType maxPoint) const override
Definition continuous.hpp:296
void ProbabilityDensityFunction(std::span< const RealType > x, std::span< double > y) const
fill vector y with f(x)
Definition continuous.hpp:122
RealType quantileImpl1m(double p) const override
Definition continuous.hpp:158
double LikelihoodFunction(std::span< const RealType > sample) const override
Definition continuous.hpp:344
virtual double f(const RealType &x) const
Definition continuous.hpp:37
double LogLikelihoodFunction(std::span< const RealType > sample) const override
Definition continuous.hpp:350
ContinuousDistribution()
Definition continuous.hpp:26
double Hazard(const RealType &x) const override
Definition continuous.hpp:334
The KolmogorovSmirnovRand class Kolmogorov-Smirnov distribution.
Definition kolmogorov_smirnov.hpp:19
virtual void sample(detail::EngineRef g, std::span< T > outputData) const
Fills the output with variate(g); distributions with a faster bulk algorithm override it.
Definition distribution.hpp:66
The UnivariateDistribution class Abstract class for all univariate probability distributions.
Definition univariate.hpp:28
T Quantile1m(double p) const
Definition univariate.hpp:324
std::complex< Real > integrateOscillatory(const F &litude, std::type_identity_t< Real > frequency, std::type_identity_t< Real > lower=0, std::type_identity_t< Real > tolerance=1e-10, int maxCycles=512)
QAWF-style Fourier integral on a semi-infinite interval.
Definition quadrature.hpp:352
Real integrate(const F &f, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > tolerance=1e-11, int maxSubdivisions=512)
Global adaptive Gauss-Kronrod quadrature (QUADPACK QAG).
Definition quadrature.hpp:226
Definition bivariate_normal.hpp:10