30 const DistributionFamily &family()
const override;
32 bool valid()
const {
return p1_ > 0.0 && p2_ > 0.0 && p2_ <= 1.0; }
35 double logpmf(
long k)
const {
37 return std::lgamma(k + r) - std::lgamma(r) - std::lgamma(k + 1.0)
38 + r * std::log(p2_) + k * std::log(1.0 - p2_);
41 double mean()
const override {
return p1_ * (1.0 - p2_) / p2_; }
42 bool isDiscrete()
const override {
return true; }
43 double variance()
const override {
44 return p1_ * (1.0 - p2_) / (p2_ * p2_);
46 double rawMoment(
unsigned k)
const override {
47 if (k == 0)
return 1.0;
48 if (!valid())
return kNaN;
51 double total = 0.0, cum = 0.0;
52 const double mu = mean();
53 for (
long j = 0; j <= 100000000L; ++j) {
54 const double pj = std::exp(logpmf(j));
55 total += std::pow(
static_cast<double>(j),
static_cast<double>(k)) * pj;
57 if (j >
static_cast<long>(mu) && cum > 1.0 - 1e-15)
break;
61 double pdf(
double c)
const override {
62 if (!valid())
return kNaN;
63 const double r = std::nearbyint(c);
64 if (std::fabs(c - r) > 1e-9 || r < 0.0)
return 0.0;
65 return std::exp(logpmf(
static_cast<long>(r)));
67 double cdf(
double c)
const override {
68 if (!valid())
return kNaN;
69 if (c < 0.0)
return 0.0;
70 const long kmax =
static_cast<long>(std::floor(c));
72 for (
long k = 0; k <= kmax; ++k) s += std::exp(logpmf(k));
73 return s > 1.0 ? 1.0 : s;
75 DistSupport support()
const override {
return {0.0,
kInf}; }
76 bool integrationRange(
double &lo,
double &hi)
const override {
77 if (!valid())
return false;
79 hi = mean() + 12.0 * std::sqrt(variance()) + 30.0;
82 std::pair<double, double> plotRange(
double trunc_lo,
83 double trunc_hi)
const override {
84 double lo = trunc_lo, hi = trunc_hi;
85 if (!std::isfinite(lo)) lo = 0.0;
86 if (!std::isfinite(hi)) hi = mean() + 4.0 * std::sqrt(variance()) + 5.0;
89 double sample(std::mt19937_64 &rng)
const override {
92 std::gamma_distribution<double> g(p1_, (1.0 - p2_) / p2_);
93 const double lambda = g(rng);
94 std::poisson_distribution<long> po(lambda > 0.0 ? lambda : 1e-12);
95 return static_cast<double>(po(rng));
97 std::optional<double> quantile(
double p)
const override {
98 if (!valid())
return std::nullopt;
99 if (p <= 0.0)
return 0.0;
101 for (
long k = 0; k <= 100000000L; ++k) {
102 s += std::exp(logpmf(k));
103 if (s >= p)
return static_cast<double>(k);
107 std::unique_ptr<Distribution> affine(
double,
double)
const override {
110 std::string serialise()
const override {
116 "negative_binomial", 2,
"NB", {
"r",
"p"},
117 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
118 return std::make_unique<NegativeBinomialDistribution>(p1, p2);
123 return negative_binomial_family;
131bool negativeBinomialPConjugateUpdate(
double &alpha,
double &beta,
132 const DistributionTemplate &lik,
135 const double r = lik.p1.literal;
136 if (!(alpha > 0.0) || !(beta > 0.0) || !(r > 0.0))
return false;
137 const double f = std::nearbyint(d);
138 if (std::fabs(d - f) > 1e-9 || f < 0.0)
return false;
144double negativeBinomialPLogPredictive(
double alpha,
double beta,
145 const DistributionTemplate &lik,
148 const double r = lik.p1.literal;
149 if (!(alpha > 0.0) || !(beta > 0.0) || !(r > 0.0))
return kNaN;
150 const double f = std::nearbyint(d);
151 if (std::fabs(d - f) > 1e-9 || f < 0.0)
return kNaN;
152 return std::lgamma(f + r) - std::lgamma(r) - std::lgamma(f + 1.0)
153 +
lbeta(alpha + r, beta + f) -
lbeta(alpha, beta);
156[[maybe_unused]]
const ConjugateRuleRegistrar negative_binomial_p_conjugate(
157 "negative_binomial", 1,
"beta",
158 {&negativeBinomialPConjugateUpdate, &negativeBinomialPLogPredictive});
160[[maybe_unused]]
const DistributionFamilyRegistrar
161 negative_binomial_family_registrar(negative_binomial_family);
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.