31double truncated_uniform_raw_moment(
double p1,
double p2,
double a,
double b,
34 const double lo = std::max(p1, a);
35 const double hi = std::min(p2, b);
36 if (hi <= lo)
return kNaN;
37 if (k == 0)
return 1.0;
38 return (std::pow(hi,
static_cast<double>(k + 1))
39 - std::pow(lo,
static_cast<double>(k + 1)))
40 / ((k + 1) * (hi - lo));
47 const DistributionFamily &family()
const override;
48 double mean()
const override {
return 0.5 * (p1_ + p2_); }
49 bool meanIsAffine()
const override {
return true; }
50 double variance()
const override {
51 const double w = p2_ - p1_;
52 return (w * w) / 12.0;
54 double rawMoment(
unsigned k)
const override {
55 if (k == 0)
return 1.0;
56 if (k == 1)
return mean();
57 const double a = p1_, b = p2_, kp1 =
static_cast<double>(k + 1);
58 return (std::pow(b, kp1) - std::pow(a, kp1)) / (kp1 * (b - a));
60 double pdf(
double c)
const override {
61 if (!(p2_ > p1_))
return kNaN;
62 return (c < p1_ || c > p2_) ? 0.0 : 1.0 / (p2_ - p1_);
64 double cdf(
double c)
const override {
65 if (c <= p1_)
return 0.0;
66 if (c >= p2_)
return 1.0;
67 return (c - p1_) / (p2_ - p1_);
69 DistSupport support()
const override {
return {p1_, p2_}; }
70 bool integrationRange(
double &lo,
double &hi)
const override {
75 std::pair<double, double> plotRange(
double trunc_lo,
double trunc_hi)
const override {
76 double lo = trunc_lo, hi = trunc_hi;
77 const double pad = 0.15 * (p2_ - p1_);
78 lo = std::isfinite(lo) ? std::max(lo, p1_ - pad) : p1_ - pad;
79 hi = std::isfinite(hi) ? std::min(hi, p2_ + pad) : p2_ + pad;
82 double sample(std::mt19937_64 &rng)
const override {
83 std::uniform_real_distribution<double> d(p1_, p2_);
86 std::optional<double> quantile(
double p)
const override {
87 if (!(p2_ > p1_))
return std::nullopt;
88 return p1_ + p * (p2_ - p1_);
90 std::optional<double> truncatedRawMoment(
double lo,
double hi,
91 unsigned k)
const override {
92 const double r = truncated_uniform_raw_moment(p1_, p2_, lo, hi, k);
93 if (std::isnan(r))
return std::nullopt;
96 std::optional<std::vector<double>> sampleTruncated(
97 std::mt19937_64 &rng,
double lo,
double hi,
unsigned n)
const override {
101 std::uniform_real_distribution<double> U(lo, hi);
102 std::vector<double> out;
104 for (
unsigned i = 0; i < n; ++i) out.push_back(U(rng));
107 std::optional<double> iidOrderStatMean(std::size_t n,
108 bool isMax)
const override {
109 const double a = p1_, b = p2_;
110 const double frac = isMax ?
static_cast<double>(n) / (n + 1)
112 return a + (b - a) * frac;
114 std::unique_ptr<Distribution> affine(
double a,
double b)
const override {
115 if (a == 0.0)
return nullptr;
117 double lo = (a > 0.0) ? a * p1_ : a * p2_;
118 double hi = (a > 0.0) ? a * p2_ : a * p1_;
119 if (b != 0.0) { lo += b; hi += b; }
120 return std::make_unique<UniformDistribution>(lo, hi);
122 std::string serialise()
const override {
128 "uniform", 2,
"U", {
"a",
"b"},
129 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
130 return std::make_unique<UniformDistribution>(p1, p2);
135 return uniform_family;
143std::unique_ptr<Distribution>
144uniformSumRule(
const std::vector<ClosureTerm> &terms)
146 const ClosureTerm *uniform =
nullptr;
147 for (
const auto &t : terms) {
148 if (!t.dist)
continue;
149 if (uniform)
return nullptr;
155 double b_total = 0.0;
156 for (
const auto &t : terms) b_total += t.b;
157 const double a = uniform->a;
158 const double p1 = uniform->dist->p1();
159 const double p2 = uniform->dist->p2();
160 const double new_lo = (a > 0.0) ? a * p1 + b_total : a * p2 + b_total;
161 const double new_hi = (a > 0.0) ? a * p2 + b_total : a * p1 + b_total;
162 return std::make_unique<UniformDistribution>(new_lo, new_hi);
165[[maybe_unused]]
const ClosureRuleRegistrar uniform_sum_rule(
166 "uniform",
"uniform", &uniformSumRule);
171double integralUniformCdf(
double a,
double b,
double c,
double d)
175 const double lo = std::max(c, a), hi = std::min(d, b);
177 total += ((hi - a) * (hi - a) - (lo - a) * (lo - a)) / (2.0 * (b - a));
179 const double lo2 = std::max(c, b);
187double uniformPairLess(
const Distribution &X,
const Distribution &Y)
189 const double a = X.p1(), b = X.p2(), c = Y.p1(), d = Y.p2();
190 if (!(b > a && d > c))
return kNaN;
191 return integralUniformCdf(a, b, c, d) / (d - c);
194[[maybe_unused]]
const ComparatorRuleRegistrar uniform_less_rule(
195 "uniform",
"uniform", &uniformPairLess);
204bool uniformUpperConjugateUpdate(
double &xm,
double &alpha,
205 const DistributionTemplate &lik,
double d)
207 if (lik.p1.literal != 0.0)
return false;
208 if (!(xm > 0.0) || !(alpha > 0.0) || !(d >= 0.0))
return false;
214double uniformUpperLogPredictive(
double xm,
double alpha,
215 const DistributionTemplate &lik,
double d)
217 if (lik.p1.literal != 0.0)
return kNaN;
218 if (!(xm > 0.0) || !(alpha > 0.0) || !(d >= 0.0))
return kNaN;
219 const double m = std::max(xm, d);
220 return std::log(alpha) + alpha * std::log(xm)
221 - std::log(alpha + 1.0) - (alpha + 1.0) * std::log(m);
224[[maybe_unused]]
const ConjugateRuleRegistrar uniform_upper_conjugate(
225 "uniform", 1,
"pareto",
226 {&uniformUpperConjugateUpdate, &uniformUpperLogPredictive});
228[[maybe_unused]]
const DistributionFamilyRegistrar uniform_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.