LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
distributions.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_LANG_DISTRIBUTIONS_H
6#define LINE_LANG_DISTRIBUTIONS_H
7
8/**
9 * @file
10 * @ingroup line_lang
11 * @ingroup line_public
12 * The distributions a user names, spelled as their Python twins.
13 *
14 * queue1.set_service(closed, Exp(1.0));
15 * delay.set_service(open, Erlang(3.0, 2));
16 * delay.set_service(open, HyperExp(0.5, 3.0, 10.0));
17 *
18 * against Python's `Exp(1.0)`, `Erlang(3.0, 2)`, `HyperExp(0.5, 3.0, 10.0)`.
19 *
20 * EACH IS A THIN NAME OVER THE FACTORY THAT ALREADY EXISTS. Every constructor
21 * assigns the `Distrib<double>` that `lang_types.h` builds, so the numeric
22 * behaviour is the factory's and nothing new is computed here; deriving from
23 * `Distrib<double>` is what lets one slice cleanly into `set_service`, which
24 * takes the base by const reference.
25 *
26 * The fitters keep Python's static-method spelling
27 * (`HyperExp::fit_mean_and_scv`), forwarding to `line/lang/dist_fitters.h`.
28 *
29 * `double`-only, as Python is. Reach for `lang::Distrib<T>`'s own factories
30 * directly for the multiprecision paths.
31 */
32
33#include <cstddef>
34#include <fstream>
35#include <string>
36#include <vector>
37
40#include "line/util/error.h"
41
42namespace line {
43
45
46/** Every named law below is a `Distrib<double>` under another name. */
47#define LINE_DIST_CTOR(Cls) \
48 struct Cls : lang::Distrib<double>
49
50/** `Exp(rate)`: the exponential law of the given RATE, as Python's `Exp`. */
52 explicit Exp(double rate) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::exp_rate(rate); }
53 /** `Exp.fitMean(mean)`. */
54 static Exp fit_mean(double m) { return Exp(1.0 / m); }
55 /** `Exp.fitRate(rate)`. */
56 static Exp fit_rate(double r) { return Exp(r); }
57};
58
59/** `Erlang(phase_rate, nphases)`. */
61 Erlang(double phase_rate, std::size_t nphases) {
62 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::erlang(phase_rate, nphases);
63 }
64 /** `Erlang.fitMeanAndSCV(mean, scv)`. */
65 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
67 }
68 /** `Erlang.fitMeanAndOrder(mean, k)`. */
69 static lang::Distrib<double> fit_mean_and_order(double m, std::size_t k) {
71 }
72};
73
74/** `HyperExp(p, lambda1, lambda2)`. */
75LINE_DIST_CTOR(HyperExp) {
76 HyperExp(double p, double lambda1, double lambda2) {
77 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::hyperexp(p, lambda1, lambda2);
78 }
79 HyperExp(const std::vector<double>& p, const std::vector<double>& lambda) {
80 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::hyperexp_n(p, lambda);
81 }
82 /** `HyperExp.fitMeanAndSCV(mean, scv)`. */
83 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
85 }
86 /** `HyperExp.fitMeanAndSCVBalanced(mean, scv)`. */
87 static lang::Distrib<double> fit_mean_and_scv_balanced(double m, double scv) {
89 }
90};
91
92/** `Coxian(mu, phi)`. */
94 Coxian(const std::vector<double>& mu, const std::vector<double>& phi) {
95 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::coxian(mu, phi);
96 }
97 /** `Coxian.fitMeanAndSCV(mean, scv)`. */
98 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
100 }
101 /** `Coxian.fitCentral(mean, var, skew)`: the SECOND argument is the variance, not the SCV. */
102 static lang::Distrib<double> fit_central(double m, double var, double skew) {
103 return lang::coxian_fit_central<double>(m, var, skew);
104 }
105};
106
107/** `Cox2(mu1, mu2, phi1)`. */
109 Cox2(double mu1, double mu2, double phi1) {
110 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::cox2(mu1, mu2, phi1);
111 }
112 /** `Cox2.fitMeanAndSCV(mean, scv)`: the Coxian two-moment fit, two phases for SCV >= 1/2. */
113 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
115 }
116 /** `Cox2.fitCentral(mean, var, skew)`: the SECOND argument is the variance, not the SCV. */
117 static lang::Distrib<double> fit_central(double m, double var, double skew) {
118 return lang::cox2_fit_central<double>(m, var, skew);
119 }
120};
121
122/** `PH(alpha, A)`: a general phase-type law. */
124 PH(const std::vector<double>& alpha, const Matrix<double>& A) {
125 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::phase_type(alpha, A, false);
126 }
127};
128
129/** `APH(alpha, A)`: the acyclic phase-type law. */
131 APH(const std::vector<double>& alpha, const Matrix<double>& A) {
132 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::phase_type(alpha, A, true);
133 }
134 /** `APH.fitMeanAndSCV(mean, scv)`. */
135 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
136 return lang::aph_fit_mean_scv<double>(m, scv);
137 }
138 /** `APH.fitCentral(mean, var, skew)`: the SECOND argument is the variance, not the SCV. */
139 static lang::Distrib<double> fit_central(double m, double var, double skew) {
140 return lang::aph_fit_central<double>(m, var, skew);
141 }
142};
143
144/** `MAP(D0, D1)`. */
146 MAP(const Matrix<double>& D0, const Matrix<double>& D1) {
148 }
149};
150
151/** `Det(t)`: the deterministic law. */
153 explicit Det(double t) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::det(t); }
154};
155
156/** `Immediate()`: a zero-time transition. */
157LINE_DIST_CTOR(Immediate) {
158 Immediate() { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::immediate(); }
159};
160
161/** `Disabled()`: the class is not served here. */
162LINE_DIST_CTOR(Disabled) {
163 Disabled() { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::disabled_dist(); }
164};
165
166/** `Uniform(a, b)`. */
168 Uniform(double a, double b) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::uniform(a, b); }
169};
170
171/** `Pareto(shape, scale)`. */
173 Pareto(double shape, double scale) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::pareto(shape, scale); }
174 /** `Pareto.fitMeanAndSCV(mean, scv)`. */
175 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
177 }
178};
179
180/** `Gamma(shape, scale)`. */
182 Gamma(double shape, double scale) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::gamma_dist(shape, scale); }
183 /** `Gamma.fitMeanAndSCV(mean, scv)`. */
184 static lang::Distrib<double> fit_mean_and_scv(double m, double scv) {
186 }
187};
188
189/** `Weibull(scale, shape)`. */
191 Weibull(double scale, double shape) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::weibull(scale, shape); }
192};
193
194/** `Lognormal(logmean, logsigma)`. */
195LINE_DIST_CTOR(Lognormal) {
196 Lognormal(double logmean, double logsigma) {
197 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::lognormal(logmean, logsigma);
198 }
199};
200
201/** `Normal(mu, sigma)`. */
203 Normal(double mu, double sigma) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::normal(mu, sigma); }
204};
205
206/** `Geometric(p)`. */
207LINE_DIST_CTOR(Geometric) {
208 explicit Geometric(double p) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::geometric(p); }
209};
210
211/** `Bernoulli(p)`. */
212LINE_DIST_CTOR(Bernoulli) {
213 explicit Bernoulli(double p) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::bernoulli(p); }
214};
215
216/** `Binomial(n, p)`. */
217LINE_DIST_CTOR(Binomial) {
218 Binomial(double n, double p) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::binomial(n, p); }
219};
220
221/** `Poisson(lambda)`. */
223 explicit Poisson(double lambda) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::poisson(lambda); }
224};
225
226/** `DiscreteUniform(a, b)`. */
227LINE_DIST_CTOR(DiscreteUniform) {
228 DiscreteUniform(double a, double b) {
230 }
231};
232
233/** `Zipf(s, n)`. */
235 Zipf(double s, std::size_t n) { static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::zipf(s, n); }
236};
237
238/** `DiscreteSampler(p, x)`. */
239LINE_DIST_CTOR(DiscreteSampler) {
240 explicit DiscreteSampler(const std::vector<double>& p) {
241 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::discrete_sampler(p, std::vector<double>());
242 }
243 DiscreteSampler(const std::vector<double>& p, const std::vector<double>& x) {
245 }
246};
247
248/** `Replayer(samples)` / `Replayer(path)`: the trace-driven law. */
249LINE_DIST_CTOR(Replayer) {
250 explicit Replayer(const std::vector<double>& samples) {
251 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::replayer(samples);
252 }
253 explicit Replayer(const std::string& path) {
254 std::ifstream in(path.c_str());
255 if (!in) throw InputError("Replayer: cannot open the trace file '" + path + "'");
256 std::vector<double> samples;
257 double value = 0.0;
258 while (in >> value) samples.push_back(value);
259 if (!in.eof())
260 throw InputError("Replayer: the trace file '" + path + "' contains a non-number");
261 if (samples.empty())
262 throw InputError("Replayer: the trace file '" + path + "' has no samples");
263 static_cast<lang::Distrib<double>&>(*this) =
265 }
266 Replayer(const std::vector<double>& samples, const std::string& path) {
267 static_cast<lang::Distrib<double>&>(*this) = lang::Distrib<double>::replayer_from(samples, path);
268 }
269};
270
271#undef LINE_DIST_CTOR
272
273} // namespace line
274
275#endif // LINE_LANG_DISTRIBUTIONS_H
InputError(const std::string &what)
Definition error.h:105
The moment fitters the reference distributions carry as STATIC FACTORIES: Erlang.fitMeanAndOrder,...
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Distrib< T > hyperexp_fit_mean_scv_balanced(const T &mean, const T &scv)
HyperExp.fitMeanAndSCVBalanced(MEAN, SCV): the balanced-means branch, p / mu1 = (1 - p) / mu2.
Distrib< T > aph_fit_central(const T &mean, const T &var, const T &skew)
APH.fitCentral(MEAN, VAR, SKEW): the three central moments converted to raw ones and matched by a can...
Distrib< T > erlang_fit_mean_order(const T &mean, std::size_t k)
Erlang.fitMeanAndOrder(MEAN, k): k phases, each of rate k / MEAN.
Distrib< T > coxian_fit_central(const T &mean, const T &var, const T &skew)
Coxian.fitCentral, which the reference forwards to Cox2.fitCentral.
Distrib< T > aph_fit_mean_scv(const T &mean, const T &scv)
APH.fitMeanAndSCV(MEAN, SCV), through mam::aph_fit_mean_scv.
Distrib< T > gamma_fit_mean_scv(const T &mean, const T &scv)
Gamma.fitMeanAndSCV(MEAN, SCV): shape 1/SCV, scale MEAN * SCV.
Distrib< T > pareto_fit_mean_scv(const T &mean, const T &scv)
Pareto.fitMeanAndSCV(MEAN, SCV): alpha = 1 + sqrt(1 + 1/SCV) and k = MEAN (alpha - 1) / alpha.
Distrib< T > coxian_fit_mean_scv(const T &mean, const T &scv)
Coxian.fitMeanAndSCV(MEAN, SCV), branch for branch.
Distrib< T > hyperexp_fit_mean_scv(const T &mean, const T &scv)
HyperExp.fitMeanAndSCV(MEAN, SCV), which is map_hyperexp at p = 0.99 read back as (p,...
Distrib< T > cox2_fit_central(const T &mean, const T &var, const T &skew)
Cox2.fitCentral(MEAN, VAR, SKEW): the two-phase Coxian matching three central moments exactly when th...
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
lang::Distrib< double > Distribution
LINE_DIST_CTOR(Exp)
Exp(rate): the exponential law of the given RATE, as Python's Exp.
static Distrib replayer(const std::vector< T > &samples)
Replayer / Trace: the samples, with their empirical first two moments.
static Distrib normal(const T &mu, const T &sigma)
Normal(mu, sigma): the Gaussian, for use as a continuous Prior's parameter density.
static Distrib exp_rate(const T &r)
Definition lang_types.h:955
static Distrib phase_type(const std::vector< T > &alpha, const Matrix< T > &A, bool acyclic)
PH / APH given by (alpha, A): D0 = A and D1 = (-A e) alpha.
static Distrib weibull(const T &scale, const T &shape)
static Distrib replayer_from(const std::vector< T > &samples, const std::string &path)
Replayer / Trace read FROM A FILE, which keeps the path beside the samples.
static Distrib disabled_dist()
Definition lang_types.h:997
static Distrib erlang_fit(const T &m, const T &c2)
Erlang fitted to a mean and an SCV, as MATLAB's Erlang.fitMeanAndSCV.
static Distrib pareto(const T &shape, const T &scale)
Pareto(shape, scale), with the MATLAB parameter order (alpha, k).
static Distrib gamma_dist(const T &shape, const T &scale)
Gamma(shape, scale), Weibull(scale, shape) and Lognormal(mu, sigma).
static Distrib cox2(const T &mu1, const T &mu2, const T &phi1)
Cox2(mu1, mu2, phi1), MATLAB's two-phase Coxian constructor.
static Distrib map_dist(const Matrix< T > &D0, const Matrix< T > &D1, ProcessType tag)
A MAP given by its two matrices; the moments are those of its stationary phase.
static Distrib poisson(const T &lambda)
Poisson(lambda), whose SCV is 1/lambda – the count's variance is lambda and its mean is lambda,...
static Distrib bernoulli(const T &p)
Bernoulli(p): one trial, mean p and variance p(1-p).
static Distrib hyperexp_n(const std::vector< T > &p, const std::vector< T > &lambda)
The same for any number of branches, which is what MATLAB HyperExp accepts and what the writers emit ...
static Distrib discrete_uniform(const T &a, const T &b)
DiscreteUniform(a, b) over the integers a..b inclusive.
static Distrib geometric(const T &p)
Geometric(p) on the MATLAB convention: the NUMBER OF TRIALS to the first success, support {1,...
static Distrib det(const T &m)
Definition lang_types.h:998
static Distrib uniform(const T &a, const T &b)
Uniform(a, b).
static Distrib lognormal(const T &logmean, const T &logsigma)
static Distrib hyperexp(const T &p, const T &lambda1, const T &lambda2)
HyperExp(p, lambda1, lambda2): phase i chosen with probability p_i.
static Distrib immediate()
The point mass at zero.
Definition lang_types.h:986
static Distrib erlang(const T &phase_rate, std::size_t r)
Erlang(alpha, r): r phases of rate alpha, as MATLAB's Erlang(phaseRate, nphases).
static Distrib coxian(const std::vector< T > &mu, const std::vector< T > &phi)
Coxian(mu, phi): phase i completes with probability phi(i) and otherwise moves to phase i+1.
static Distrib discrete_sampler(const std::vector< T > &p, const std::vector< T > &x)
DiscreteSampler(p, x): the pmf p over the points x.
static Distrib binomial(const T &n, const T &p)
Binomial(n, p).
static Distrib zipf(const T &s, std::size_t n)
Zipf(s, n) over the ranks 1..n, with the generalized harmonic moments H(s-1,n)/H(s,...