38 const DistributionFamily &family()
const override;
39 double mean()
const override {
40 return p2_ * std::tgamma(1.0 + 1.0 / p1_);
42 double variance()
const override {
43 const double g1 = std::tgamma(1.0 + 1.0 / p1_);
44 return p2_ * p2_ * (std::tgamma(1.0 + 2.0 / p1_) - g1 * g1);
46 double rawMoment(
unsigned k)
const override {
47 if (k == 0)
return 1.0;
49 const double j =
static_cast<double>(k);
50 return std::pow(p2_, j) * std::tgamma(1.0 + j / p1_);
52 double pdf(
double c)
const override {
53 const double k = p1_, lambda = p2_;
54 if (!(k > 0.0) || !(lambda > 0.0))
return kNaN;
55 if (c < 0.0)
return 0.0;
60 if (k < 1.0)
return kNaN;
61 return (k == 1.0) ? 1.0 / lambda : 0.0;
63 const double u = std::pow(c / lambda, k);
64 return (k / lambda) * std::pow(c / lambda, k - 1.0) * std::exp(-u);
66 double cdf(
double c)
const override {
67 const double k = p1_, lambda = p2_;
68 if (!(k > 0.0) || !(lambda > 0.0))
return kNaN;
69 if (c <= 0.0)
return 0.0;
70 return -std::expm1(-std::pow(c / lambda, k));
72 DistSupport support()
const override {
return {0.0,
kInf}; }
73 bool integrationRange(
double &lo,
double &hi)
const override {
74 if (!(p1_ > 0.0 && p2_ > 0.0))
return false;
77 hi = p2_ * std::pow(36.0, 1.0 / p1_);
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))
84 hi = p2_ * std::pow(6.907755278982137, 1.0 / p1_);
87 double sample(std::mt19937_64 &rng)
const override {
88 std::weibull_distribution<double> d(p1_, p2_);
91 std::optional<double> quantile(
double p)
const override {
92 if (!(p1_ > 0.0) || !(p2_ > 0.0))
return std::nullopt;
95 return p2_ * std::pow(-std::log1p(-p), 1.0 / p1_);
97 std::optional<double> truncatedRawMoment(
double lo,
double hi,
98 unsigned j)
const override {
99 const double k = p1_, lambda = p2_;
100 if (!(k > 0.0) || !(lambda > 0.0))
return std::nullopt;
104 const double u_a = (std::isfinite(lo) && lo > 0.0)
105 ? std::pow(lo / lambda, k) : 0.0;
106 const double u_b = std::isfinite(hi)
107 ? (hi > 0.0 ? std::pow(hi / lambda, k) : 0.0) :
kInf;
108 const double mass = std::exp(-u_a) - std::exp(-u_b);
109 if (mass < 1e-12)
return std::nullopt;
110 if (j == 0)
return 1.0;
111 const double a = 1.0 +
static_cast<double>(j) / k;
112 const double P_a = u_a > 0.0 ?
gammaP(a, u_a) : 0.0;
113 const double P_b = std::isfinite(u_b) ?
gammaP(a, u_b) : 1.0;
114 if (std::isnan(P_a) || std::isnan(P_b))
return std::nullopt;
115 return std::pow(lambda,
static_cast<double>(j)) * std::tgamma(a)
116 * (P_b - P_a) / mass;
118 std::optional<std::vector<double>> sampleTruncated(
119 std::mt19937_64 &rng,
double lo,
double hi,
unsigned n)
const override {
120 const double k = p1_, lambda = p2_;
121 if (!(k > 0.0) || !(lambda > 0.0))
return std::nullopt;
122 std::vector<double> out;
124 const double u_lo = (std::isfinite(lo) && lo > 0.0)
125 ? std::pow(lo / lambda, k) : 0.0;
126 if (std::isinf(hi)) {
130 std::exponential_distribution<double> E(1.0);
131 for (
unsigned i = 0; i < n; ++i)
132 out.push_back(lambda * std::pow(u_lo + E(rng), 1.0 / k));
136 const double F_lo = -std::expm1(-u_lo);
137 const double F_hi = hi > 0.0
138 ? -std::expm1(-std::pow(hi / lambda, k)) : 0.0;
139 if (!(F_lo < F_hi))
return std::nullopt;
140 std::uniform_real_distribution<double> U01(0.0, 1.0);
141 for (
unsigned i = 0; i < n; ++i) {
142 const double u = F_lo + U01(rng) * (F_hi - F_lo);
143 out.push_back(lambda * std::pow(-std::log1p(-u), 1.0 / k));
147 std::optional<double> iidOrderStatMean(std::size_t n,
148 bool isMax)
const override {
149 if (!(p1_ > 0.0) || !(p2_ > 0.0))
return std::nullopt;
150 if (isMax)
return std::nullopt;
154 p2_ * std::pow(
static_cast<double>(n), -1.0 / p1_);
155 return scale * std::tgamma(1.0 + 1.0 / p1_);
157 std::unique_ptr<Distribution> affine(
double a,
double b)
const override {
160 if (!(a > 0.0) || b != 0.0)
return nullptr;
161 return std::make_unique<WeibullDistribution>(p1_, a * p2_);
163 std::string serialise()
const override {
169 "weibull", 2,
"Wbl", {
"k",
"λ"},
170 +[](
double p1,
double p2) -> std::unique_ptr<Distribution> {
171 return std::make_unique<WeibullDistribution>(p1, p2);
176 return weibull_family;
182double weibullPairLess(
const Distribution &X,
const Distribution &Y)
184 if (X.p1() != Y.p1())
return kNaN;
185 const double ax = std::pow(X.p2(), X.p1());
186 const double ay = std::pow(Y.p2(), Y.p1());
187 if (!(ax > 0.0) || !(ay > 0.0))
return kNaN;
188 return ay / (ax + ay);
191[[maybe_unused]]
const ComparatorRuleRegistrar weibull_less_rule(
192 "weibull",
"weibull", &weibullPairLess);
194[[maybe_unused]]
const DistributionFamilyRegistrar weibull_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.