37 const DistributionFamily &family()
const override;
38 double mean()
const override {
39 if (!(p2_ > 1.0))
return kInf;
40 return p2_ * p1_ / (p2_ - 1.0);
42 double variance()
const override {
43 if (!(p2_ > 2.0))
return kInf;
44 const double am1 = p2_ - 1.0;
45 return p1_ * p1_ * p2_ / (am1 * am1 * (p2_ - 2.0));
47 double rawMoment(
unsigned k)
const override {
48 if (k == 0)
return 1.0;
49 const double j =
static_cast<double>(k);
50 if (!(p2_ > j))
return kInf;
51 return p2_ * std::pow(p1_, j) / (p2_ - j);
53 double pdf(
double c)
const override {
54 const double xm = p1_, alpha = p2_;
55 if (!(xm > 0.0) || !(alpha > 0.0))
return kNaN;
56 if (c < xm)
return 0.0;
57 return (alpha / xm) * std::pow(xm / c, alpha + 1.0);
59 double cdf(
double c)
const override {
60 const double xm = p1_, alpha = p2_;
61 if (!(xm > 0.0) || !(alpha > 0.0))
return kNaN;
62 if (c <= xm)
return 0.0;
63 return 1.0 - std::pow(xm / c, alpha);
65 DistSupport support()
const override {
return {p1_,
kInf}; }
66 bool integrationRange(
double &lo,
double &hi)
const override {
67 if (!(p1_ > 0.0 && p2_ > 0.0))
return false;
73 hi = p1_ * std::pow(1e9, 1.0 / p2_);
76 std::pair<double, double> plotRange(
double trunc_lo,
double trunc_hi)
const override {
77 double lo = trunc_lo, hi = trunc_hi;
78 if (!std::isfinite(lo)) lo = p1_;
79 if (!std::isfinite(hi))
80 hi = p1_ * std::pow(1e3, 1.0 / p2_);
83 double sample(std::mt19937_64 &rng)
const override {
85 std::uniform_real_distribution<double> U01(0.0, 1.0);
86 return p1_ * std::pow(1.0 - U01(rng), -1.0 / p2_);
88 std::optional<double> quantile(
double p)
const override {
89 if (!(p1_ > 0.0) || !(p2_ > 0.0))
return std::nullopt;
90 return p1_ * std::pow(1.0 - p, -1.0 / p2_);
92 std::optional<double> truncatedRawMoment(
double lo,
double hi,
93 unsigned j)
const override {
94 const double xm = p1_, alpha = p2_;
95 if (!(xm > 0.0) || !(alpha > 0.0))
return std::nullopt;
96 const double a = std::max(std::isfinite(lo) ? lo : xm, xm);
97 if (std::isfinite(hi) && hi <= a)
return std::nullopt;
98 const double mass = std::pow(xm / a, alpha)
99 - (std::isfinite(hi) ? std::pow(xm / hi, alpha) : 0.0);
100 if (mass < 1e-12)
return std::nullopt;
101 if (j == 0)
return 1.0;
102 const double jd =
static_cast<double>(j);
103 if (jd == alpha)
return std::nullopt;
104 if (!std::isfinite(hi) && !(alpha > jd))
109 std::isfinite(hi) ? std::pow(hi, jd - alpha) : 0.0;
110 return alpha * std::pow(xm, alpha)
111 * (upper - std::pow(a, jd - alpha)) / (jd - alpha) / mass;
113 std::optional<std::vector<double>> sampleTruncated(
114 std::mt19937_64 &rng,
double lo,
double hi,
unsigned n)
const override {
115 const double xm = p1_, alpha = p2_;
116 if (!(xm > 0.0) || !(alpha > 0.0))
return std::nullopt;
117 const double a = std::max(std::isfinite(lo) ? lo : xm, xm);
118 std::vector<double> out;
120 std::uniform_real_distribution<double> U01(0.0, 1.0);
121 if (std::isinf(hi)) {
123 for (
unsigned i = 0; i < n; ++i)
124 out.push_back(a * std::pow(1.0 - U01(rng), -1.0 / alpha));
127 if (hi <= a)
return std::nullopt;
129 const double F_a = 1.0 - std::pow(xm / a, alpha);
130 const double F_b = 1.0 - std::pow(xm / hi, alpha);
131 if (!(F_a < F_b))
return std::nullopt;
132 for (
unsigned i = 0; i < n; ++i) {
133 const double u = F_a + U01(rng) * (F_b - F_a);
134 out.push_back(xm * std::pow(1.0 - u, -1.0 / alpha));
138 std::optional<double> iidOrderStatMean(std::size_t n,
139 bool isMax)
const override {
140 if (!(p1_ > 0.0) || !(p2_ > 0.0))
return std::nullopt;
141 if (isMax)
return std::nullopt;
144 const double na =
static_cast<double>(n) * p2_;
145 if (!(na > 1.0))
return kInf;
146 return na * p1_ / (na - 1.0);
148 std::unique_ptr<Distribution> affine(
double a,
double b)
const override {
151 if (!(a > 0.0) || b != 0.0)
return nullptr;
152 return std::make_unique<ParetoDistribution>(a * p1_, p2_);
154 std::string serialise()
const override {
160 "pareto", 2,
"Par", {
"xₘ",
"α"},
161 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
162 return std::make_unique<ParetoDistribution>(p1, p2);
167 return pareto_family;
177double paretoPairLess(
const Distribution &X,
const Distribution &Y)
179 const double xmx = X.p1(), ax = X.p2();
180 const double xmy = Y.p1(), ay = Y.p2();
181 if (!(xmx > 0.0) || !(ax > 0.0) || !(xmy > 0.0) || !(ay > 0.0))
184 return 1.0 - (ay / (ax + ay)) * std::pow(xmx / xmy, ax);
185 return (ax / (ax + ay)) * std::pow(xmy / xmx, ay);
188[[maybe_unused]]
const ComparatorRuleRegistrar pareto_less_rule(
189 "pareto",
"pareto", &paretoPairLess);
196bool paretoShapeConjugateUpdate(
double &k,
double &lambda,
197 const DistributionTemplate &lik,
double d)
199 const double xm0 = lik.p1.literal;
200 if (!(k > 0.0) || !(lambda > 0.0) || !(xm0 > 0.0) || !(d >= xm0))
203 lambda += std::log(d / xm0);
207double paretoShapeLogPredictive(
double k,
double lambda,
208 const DistributionTemplate &lik,
double d)
210 const double xm0 = lik.p1.literal;
211 if (!(k > 0.0) || !(lambda > 0.0) || !(xm0 > 0.0) || !(d >= xm0))
213 const double t = std::log(d / xm0);
214 return std::log(k) - std::log(d) + k * std::log(lambda)
215 - (k + 1.0) * std::log(lambda + t);
218[[maybe_unused]]
const ConjugateRuleRegistrar pareto_shape_conjugate(
219 "pareto", 1,
"gamma",
220 {&paretoShapeConjugateUpdate, &paretoShapeLogPredictive});
222[[maybe_unused]]
const DistributionFamilyRegistrar pareto_family_registrar(
Internal helpers shared by the per-family Distribution implementations under src/distributions/.
Base holding the two parameters; subclasses add closed forms.
BaseDistribution(double p1, double p2)
std::string double_to_text(double v)
Format a double back into the canonical text form used by gate_value extras and gate_rv distribution ...
A registered family's descriptor: its complete identity.