36double factorial(
unsigned n)
39 for (
unsigned i = 2; i <= n; ++i) r *= static_cast<double>(i);
47 const DistributionFamily &family()
const override;
48 double mean()
const override {
return p1_; }
49 bool meanIsAffine()
const override {
return true; }
50 double variance()
const override {
return p1_ * p1_ * p1_ / p2_; }
51 double rawMoment(
unsigned n)
const override {
52 if (n == 0)
return 1.0;
53 if (n == 1)
return p1_;
54 const double mu = p1_, lambda = p2_;
56 const double r = mu / (2.0 * lambda);
57 double sum = 0.0, rpow = 1.0;
58 for (
unsigned s = 0; s < n; ++s) {
60 factorial(n - 1 + s) / (factorial(s) * factorial(n - 1 - s));
64 return std::pow(mu,
static_cast<double>(n)) * sum;
66 double pdf(
double c)
const override {
67 const double mu = p1_, lambda = p2_;
68 if (!(mu > 0.0) || !(lambda > 0.0))
return kNaN;
69 if (c <= 0.0)
return 0.0;
70 const double d = c - mu;
71 return std::sqrt(lambda / (2.0 * M_PI * c * c * c))
72 * std::exp(-lambda * d * d / (2.0 * mu * mu * c));
74 double cdf(
double c)
const override {
75 const double mu = p1_, lambda = p2_;
76 if (!(mu > 0.0) || !(lambda > 0.0))
return kNaN;
77 if (c <= 0.0)
return 0.0;
78 const double s = std::sqrt(lambda / c);
79 const double term1 =
Phi(s * (c / mu - 1.0));
83 double term2 = std::exp(2.0 * lambda / mu) *
Phi(-s * (c / mu + 1.0));
84 if (!std::isfinite(term2)) term2 = 0.0;
87 DistSupport support()
const override {
return {0.0,
kInf}; }
88 bool integrationRange(
double &lo,
double &hi)
const override {
89 if (!(p1_ > 0.0 && p2_ > 0.0))
return false;
92 hi = p1_ + 12.0 * std::sqrt(p1_ * p1_ * p1_ / p2_);
95 std::pair<double, double> plotRange(
double trunc_lo,
double trunc_hi)
const override {
96 double lo = trunc_lo, hi = trunc_hi;
97 if (!std::isfinite(lo)) lo = 0.0;
98 if (!std::isfinite(hi))
99 hi = p1_ + 4.0 * std::sqrt(p1_ * p1_ * p1_ / p2_);
102 double sample(std::mt19937_64 &rng)
const override {
105 const double mu = p1_, lambda = p2_;
106 std::normal_distribution<double> N01(0.0, 1.0);
107 std::uniform_real_distribution<double> U01(0.0, 1.0);
108 const double nu = N01(rng);
109 const double y = nu * nu;
110 const double x = mu + (mu * mu * y) / (2.0 * lambda)
111 - (mu / (2.0 * lambda))
112 * std::sqrt(4.0 * mu * lambda * y + mu * mu * y * y);
113 if (U01(rng) <= mu / (mu + x))
return x;
116 std::unique_ptr<Distribution> affine(
double a,
double b)
const override {
119 if (!(a > 0.0) || b != 0.0)
return nullptr;
120 return std::make_unique<InverseGaussianDistribution>(a * p1_, a * p2_);
122 std::string serialise()
const override {
129 "inverse_gaussian", 2,
"IG", {
"μ",
"λ"},
130 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
131 return std::make_unique<InverseGaussianDistribution>(p1, p2);
136 return inverse_gaussian_family;
145std::unique_ptr<Distribution>
146inverseGaussianSumRule(
const std::vector<ClosureTerm> &terms)
149 double total_mu = 0.0;
150 for (
const auto &t : terms) {
151 if (!t.dist)
return nullptr;
152 if (t.a != 1.0 || t.b != 0.0)
return nullptr;
153 const double mu = t.dist->p1(), lambda = t.dist->p2();
154 if (!(mu > 0.0) || !(lambda > 0.0))
return nullptr;
155 const double w_phi = lambda / (mu * mu);
156 if (std::isnan(
phi))
phi = w_phi;
157 else if (
phi != w_phi)
return nullptr;
160 if (!(total_mu > 0.0) || std::isnan(
phi))
return nullptr;
161 return std::make_unique<InverseGaussianDistribution>(
162 total_mu,
phi * total_mu * total_mu);
165[[maybe_unused]]
const ClosureRuleRegistrar inverse_gaussian_sum_rule(
166 "inverse_gaussian",
"inverse_gaussian", &inverseGaussianSumRule);
168[[maybe_unused]]
const DistributionFamilyRegistrar inverse_gaussian_family_registrar(
169 inverse_gaussian_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 phi(double z)
Standard normal pdf φ(z) = exp(-z²/2)/√(2π).
double Phi(double z)
Standard normal CDF Φ(z) = ½(1 + erf(z/√2)).
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.