29 const DistributionFamily &family()
const override;
31 bool valid()
const {
return p1_ > 0.0 && p1_ <= 1.0; }
33 double mean()
const override {
return 1.0 / p1_; }
34 bool isDiscrete()
const override {
return true; }
35 double variance()
const override {
return (1.0 - p1_) / (p1_ * p1_); }
36 double rawMoment(
unsigned k)
const override {
37 if (k == 0)
return 1.0;
40 if (!valid())
return kNaN;
41 const double q = 1.0 - p1_;
42 double total = 0.0, term = p1_;
43 for (
long j = 1; j <= 100000000L; ++j) {
44 total += std::pow(
static_cast<double>(j),
static_cast<double>(k)) * term;
46 if (term < 1e-18)
break;
50 double pdf(
double c)
const override {
51 if (!valid())
return kNaN;
52 const double r = std::nearbyint(c);
53 if (std::fabs(c - r) > 1e-9 || r < 1.0)
return 0.0;
54 return std::pow(1.0 - p1_, r - 1.0) * p1_;
56 double cdf(
double c)
const override {
57 if (!valid())
return kNaN;
58 if (c < 1.0)
return 0.0;
59 const double kf = std::floor(c);
60 return 1.0 - std::pow(1.0 - p1_, kf);
62 DistSupport support()
const override {
return {1.0,
kInf}; }
63 bool integrationRange(
double &lo,
double &hi)
const override {
64 if (!valid())
return false;
67 hi = (p1_ >= 1.0) ? 1.0
68 : 1.0 + std::ceil(std::log(1e-13) / std::log(1.0 - p1_));
71 std::pair<double, double> plotRange(
double trunc_lo,
72 double trunc_hi)
const override {
73 double lo = trunc_lo, hi = trunc_hi;
74 if (!std::isfinite(lo)) lo = 1.0;
75 if (!std::isfinite(hi)) {
78 double a = lo, b = lo;
79 integrationRange(a, b);
84 double sample(std::mt19937_64 &rng)
const override {
87 std::geometric_distribution<long> d(p1_);
88 return static_cast<double>(d(rng) + 1);
90 std::optional<double> quantile(
double p)
const override {
91 if (!valid())
return std::nullopt;
92 if (p <= 0.0)
return 1.0;
93 if (p1_ >= 1.0)
return 1.0;
95 const double k = std::ceil(std::log(1.0 - p) / std::log(1.0 - p1_));
96 return k < 1.0 ? 1.0 : k;
98 std::unique_ptr<Distribution> affine(
double,
double)
const override {
101 std::string serialise()
const override {
107 "geometric", 1,
"Geo", {
"p",
nullptr},
108 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
109 return std::make_unique<GeometricDistribution>(p1, p2);
114 return geometric_family;
121bool geometricPConjugateUpdate(
double &alpha,
double &beta,
122 const DistributionTemplate &,
double d)
124 if (!(alpha > 0.0) || !(beta > 0.0))
return false;
125 const double r = std::nearbyint(d);
126 if (std::fabs(d - r) > 1e-9 || r < 1.0)
return false;
132double geometricPLogPredictive(
double alpha,
double beta,
133 const DistributionTemplate &,
double d)
135 if (!(alpha > 0.0) || !(beta > 0.0))
return kNaN;
136 const double r = std::nearbyint(d);
137 if (std::fabs(d - r) > 1e-9 || r < 1.0)
return kNaN;
138 return lbeta(alpha + 1.0, beta + r - 1.0) -
lbeta(alpha, beta);
141[[maybe_unused]]
const ConjugateRuleRegistrar geometric_p_conjugate(
142 "geometric", 0,
"beta",
143 {&geometricPConjugateUpdate, &geometricPLogPredictive});
145[[maybe_unused]]
const DistributionFamilyRegistrar geometric_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)
double lbeta(double a, double b)
ln B(a, b) = lnΓ(a) + lnΓ(b) − lnΓ(a+b), for a, b > 0.
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.