37 const DistributionFamily &family()
const override;
38 double mean()
const override {
return p1_ / p2_; }
39 double variance()
const override {
return p1_ / (p2_ * p2_); }
40 double rawMoment(
unsigned k)
const override {
41 if (k == 0)
return 1.0;
42 if (k == 1)
return mean();
46 for (
unsigned i = 0; i < k; ++i) rising *= (s + static_cast<double>(i));
47 return rising / std::pow(p2_,
static_cast<double>(k));
49 double pdf(
double c)
const override {
50 const double s = p1_, lambda = p2_;
51 if (!(s > 0.0) || !(lambda > 0.0))
return kNaN;
52 if (c < 0.0)
return 0.0;
59 if (s < 1.0)
return kNaN;
60 return (s == 1.0) ? lambda : 0.0;
62 return std::exp(s * std::log(lambda) + (s - 1.0) * std::log(c)
63 - lambda * c - std::lgamma(s));
65 double cdf(
double c)
const override {
66 const double s = p1_, lambda = p2_;
67 if (!(s > 0.0) || !(lambda > 0.0))
return kNaN;
68 if (c <= 0.0)
return 0.0;
69 return gammaP(s, lambda * c);
71 DistSupport support()
const override {
return {0.0,
kInf}; }
72 bool integrationRange(
double &lo,
double &hi)
const override {
73 if (!(p1_ > 0.0 && p2_ > 0.0))
return false;
77 hi = (p1_ + 12.0 * std::sqrt(p1_)) / p2_;
80 std::pair<double, double> plotRange(
double trunc_lo,
double trunc_hi)
const override {
81 double lo = trunc_lo, hi = trunc_hi;
82 if (!std::isfinite(lo)) lo = 0.0;
83 if (!std::isfinite(hi)) hi = std::max(2.0 * p1_ / p2_, 6.0 / p2_);
89 if (p1_ < 1.0 && lo <= 0.0) lo = 0.005 * hi;
92 double sample(std::mt19937_64 &rng)
const override {
94 std::gamma_distribution<double> d(p1_, 1.0 / p2_);
97 std::unique_ptr<Distribution> affine(
double a,
double b)
const override {
99 if (!(a > 0.0) || b != 0.0)
return nullptr;
100 if (!(p1_ > 0.0))
return nullptr;
101 return std::make_unique<GammaDistribution>(p1_, p2_ / a);
103 std::string serialise()
const override {
109 "gamma", 2,
"Γ", {
"k",
"λ"},
110 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
111 return std::make_unique<GammaDistribution>(p1, p2);
126std::unique_ptr<Distribution>
127gammaSumRule(
const std::vector<ClosureTerm> &terms)
129 double lambda =
kNaN;
130 double total_shape = 0.0;
131 for (
const auto &t : terms) {
132 if (!t.dist)
return nullptr;
133 if (t.a != 1.0 || t.b != 0.0)
return nullptr;
134 if (!(t.dist->p1() > 0.0))
return nullptr;
135 const double w_lambda = t.dist->p2();
136 if (std::isnan(lambda)) lambda = w_lambda;
137 else if (lambda != w_lambda)
return nullptr;
138 total_shape += t.dist->p1();
140 return std::make_unique<GammaDistribution>(total_shape, lambda);
143[[maybe_unused]]
const ClosureRuleRegistrar gamma_sum_rule(
144 "gamma",
"gamma", &gammaSumRule);
151bool gammaRateConjugateUpdate(
double &k,
double &lambda,
152 const DistributionTemplate &lik,
double d)
154 const double k0 = lik.p1.literal;
155 if (!(k > 0.0) || !(lambda > 0.0) || !(k0 > 0.0) || !(d > 0.0))
162double gammaRateLogPredictive(
double k,
double lambda,
163 const DistributionTemplate &lik,
double d)
165 const double k0 = lik.p1.literal;
166 if (!(k > 0.0) || !(lambda > 0.0) || !(k0 > 0.0) || !(d > 0.0))
168 return std::lgamma(k + k0) - std::lgamma(k) - std::lgamma(k0)
169 + k * std::log(lambda) + (k0 - 1.0) * std::log(d)
170 - (k + k0) * std::log(lambda + d);
173[[maybe_unused]]
const ConjugateRuleRegistrar gamma_rate_conjugate(
175 {&gammaRateConjugateUpdate, &gammaRateLogPredictive});
177[[maybe_unused]]
const DistributionFamilyRegistrar gamma_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 gammaP(double a, double x)
Regularised lower incomplete gamma for a > 0, x >= 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.