36 const DistributionFamily &family()
const override;
37 double mean()
const override {
return p1_; }
38 bool meanIsAffine()
const override {
return true; }
39 bool isDiscrete()
const override {
return true; }
40 double variance()
const override {
return p1_; }
41 double rawMoment(
unsigned k)
const override {
43 if (k == 0)
return 1.0;
44 std::vector<double> m(k + 1, 0.0);
46 for (
unsigned j = 1; j <= k; ++j) {
48 for (
unsigned i = 0; i < j; ++i) s +=
binomial_coeff(j - 1, i) * m[i];
53 double pdf(
double c)
const override {
54 if (!(p1_ > 0.0))
return kNaN;
55 const double r = std::nearbyint(c);
56 if (std::fabs(c - r) > 1e-9 || r < 0.0)
return 0.0;
57 return std::exp(-p1_ + r * std::log(p1_) - std::lgamma(r + 1.0));
59 double cdf(
double c)
const override {
60 if (!(p1_ > 0.0))
return kNaN;
61 if (c < 0.0)
return 0.0;
62 const long kmax =
static_cast<long>(std::floor(c));
64 for (
long k = 0; k <= kmax; ++k)
65 s += std::exp(-p1_ + k * std::log(p1_) - std::lgamma(k + 1.0));
66 return s > 1.0 ? 1.0 : s;
68 DistSupport support()
const override {
return {0.0,
kInf}; }
69 bool integrationRange(
double &lo,
double &hi)
const override {
71 if (!(p1_ > 0.0))
return false;
73 hi = p1_ + 12.0 * std::sqrt(p1_) + 30.0;
76 std::pair<double, double> plotRange(
double trunc_lo,
77 double trunc_hi)
const override {
78 double lo = trunc_lo, hi = trunc_hi;
79 if (!std::isfinite(lo)) lo = 0.0;
80 if (!std::isfinite(hi)) hi = p1_ + 4.0 * std::sqrt(p1_) + 5.0;
83 double sample(std::mt19937_64 &rng)
const override {
84 std::poisson_distribution<long> d(p1_);
85 return static_cast<double>(d(rng));
87 std::optional<double> quantile(
double p)
const override {
88 if (!(p1_ > 0.0))
return std::nullopt;
89 if (p <= 0.0)
return 0.0;
91 for (
long k = 0; k < 1000000; ++k) {
92 s += std::exp(-p1_ + k * std::log(p1_) - std::lgamma(k + 1.0));
93 if (s >= p)
return static_cast<double>(k);
97 std::unique_ptr<Distribution> affine(
double,
double)
const override {
100 std::string serialise()
const override {
106 "poisson", 1,
"Pois", {
"λ",
nullptr},
107 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
108 return std::make_unique<PoissonDistribution>(p1, p2);
113 return poisson_family;
123bool poissonRateConjugateUpdate(
double &k,
double &lambda,
124 const DistributionTemplate &,
double d)
126 if (!(k > 0.0) || !(lambda > 0.0))
return false;
127 const double r = std::nearbyint(d);
128 if (std::fabs(d - r) > 1e-9 || r < 0.0)
return false;
134double poissonRateLogPredictive(
double k,
double lambda,
135 const DistributionTemplate &,
double d)
137 if (!(k > 0.0) || !(lambda > 0.0))
return kNaN;
138 const double r = std::nearbyint(d);
139 if (std::fabs(d - r) > 1e-9 || r < 0.0)
return kNaN;
140 return std::lgamma(k + r) - std::lgamma(k) - std::lgamma(r + 1.0)
141 + k * std::log(lambda) - (k + r) * std::log(lambda + 1.0);
144[[maybe_unused]]
const ConjugateRuleRegistrar poisson_rate_conjugate(
145 "poisson", 0,
"gamma",
146 {&poissonRateConjugateUpdate, &poissonRateLogPredictive});
148[[maybe_unused]]
const DistributionFamilyRegistrar poisson_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 binomial_coeff(unsigned n, unsigned k)
C(n, k) as a double (exact for the small moment orders used here).
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.