LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
nnpp.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_NNPP_H
6#define LINE_LANG_NNPP_H
7
8/**
9 * @file
10 * @ingroup line_lang
11 * NNPP: a nonstationary non-Poisson arrival process, generated by thinning a
12 * majorizing stream (Lewis and Shedler 1979) whose epochs come from a Weibull
13 * equilibrium renewal process inverted through the majorizing mean-value
14 * function (SCIATA, Liu, Kuhl, Liu and Wilson, WSC 2015).
15 *
16 * The rate function lambda(t) lives on [0, S] and is either an EPTMP
17 * (exponential of a polynomial plus sines) or a piecewise-linear interpolation
18 * of knots. With dispersion C = 1 the renewal gaps are Exp(1) and the method
19 * IS Lewis-Shedler thinning of an NHPP; with C != 1 the Weibull shape is chosen
20 * so the renewal gaps have mean 1 and SCV C, which is what gives the arrival
21 * counts their dispersion ratio.
22 *
23 * EVERY DETERMINISTIC QUANTITY HERE IS PINNED ACROSS THE FOUR CODEBASES at 1e-12
24 * relative: the majorizer (golden section with a safety max, or the exact knot
25 * maximum), the target mean value mu(t) (exact trapezoid, or composite Simpson
26 * with a fixed panel rule), and the Weibull shape/scale (exactly 200 bisection
27 * steps in log-shape). The operation order follows the shared specification,
28 * so do not "simplify" an expression here without changing the other three.
29 *
30 * The sampler is stochastic and only statistically comparable across
31 * languages. One `Stream` per arrival path carries the last renewal epoch in
32 * majorizer space, the first-gap flag and the last accepted arrival.
33 */
34
35#include <algorithm>
36#include <cmath>
37#include <cstddef>
38#include <cstdint>
39#include <iostream>
40#include <limits>
41#include <random>
42#include <string>
43#include <vector>
44
46#include "line/util/error.h"
48
49namespace line {
50namespace lang {
51
52class Nnpp {
53public:
54 /** The rate-function family, with the codes `sn.proc` carries. */
55 enum Kind { EPTMP = 1, PWLINEAR = 2 };
56
57 /** One arrival path: renewal epoch in majorizer space, first-gap flag, last arrival. */
58 struct Stream {
59 double u = 0.0;
60 bool first = true;
61 double t_last = 0.0;
62 };
63
64 Nnpp() {}
65
66 /**
67 * EPTMP: lambda(t) = exp(sum_i alpha_i t^i + sum_k gamma_k sin(omega_k t + phi_k))
68 * on [0, horizon].
69 */
70 static Nnpp eptmp(const std::vector<double>& alpha, const std::vector<double>& gamma,
71 const std::vector<double>& omega, const std::vector<double>& phi,
72 double horizon, double dispersion = 1.0, bool cyclic = true,
73 int Q = 200) {
74 if (alpha.empty()) throw InputError("NNPP.eptmp: alpha must hold at least one coefficient");
75 if (gamma.size() != omega.size() || gamma.size() != phi.size())
76 throw InputError("NNPP.eptmp: gamma, omega and phi must have the same length");
77 if (!(horizon > 0.0) || !std::isfinite(horizon))
78 throw InputError("NNPP.eptmp: the horizon must be finite and positive");
79 for (double v : alpha)
80 if (!std::isfinite(v)) throw InputError("NNPP.eptmp: alpha must be finite");
81 for (std::size_t k = 0; k < gamma.size(); ++k)
82 if (!std::isfinite(gamma[k]) || !std::isfinite(omega[k]) || !std::isfinite(phi[k]))
83 throw InputError("NNPP.eptmp: gamma, omega and phi must be finite");
84 Nnpp n;
85 n.kind_ = EPTMP;
86 n.alpha_ = alpha;
87 n.gamma_ = gamma;
88 n.omega_ = omega;
89 n.phi_ = phi;
90 n.horizon_ = horizon;
91 n.init(dispersion, cyclic, Q);
92 return n;
93 }
94
95 /** PWLINEAR: lambda linearly interpolated between (times[j], rates[j]); horizon = times.back(). */
96 static Nnpp piecewise_linear(const std::vector<double>& times, const std::vector<double>& rates,
97 double dispersion = 1.0, bool cyclic = true, int Q = 200) {
98 if (times.size() < 2 || rates.size() != times.size())
99 throw InputError("NNPP.piecewiseLinear: times and rates must have the same length, at "
100 "least 2");
101 if (times[0] != 0.0) throw InputError("NNPP.piecewiseLinear: times[0] must be 0");
102 for (std::size_t j = 0; j + 1 < times.size(); ++j)
103 if (!(times[j + 1] > times[j]))
104 throw InputError("NNPP.piecewiseLinear: times must be strictly increasing");
105 if (!std::isfinite(times.back()))
106 throw InputError("NNPP.piecewiseLinear: times must be finite");
107 for (double r : rates)
108 if (!(r >= 0.0) || !std::isfinite(r))
109 throw InputError("NNPP.piecewiseLinear: rates must be finite and non-negative");
110 Nnpp n;
111 n.kind_ = PWLINEAR;
112 n.times_ = times;
113 n.rates_ = rates;
114 n.horizon_ = times.back();
115 n.init(dispersion, cyclic, Q);
116 return n;
117 }
118
119 /**
120 * Rebuild from the `params` row of `sn.proc` ([m+1, p, alpha, gamma, omega, phi]
121 * for EPTMP, [n, times, rates] for PWLINEAR).
122 */
123 static Nnpp from_params(int kind, const std::vector<double>& params, double horizon,
124 double dispersion, bool cyclic, int Q) {
125 if (kind == EPTMP) {
126 if (params.size() < 2) throw InputError("NNPP: malformed EPTMP params row");
127 const std::size_t m1 = static_cast<std::size_t>(params[0]);
128 const std::size_t p = static_cast<std::size_t>(params[1]);
129 if (params.size() != 2 + m1 + 3 * p) throw InputError("NNPP: malformed EPTMP params row");
130 std::vector<double> a(params.begin() + 2, params.begin() + 2 + m1);
131 std::vector<double> g(params.begin() + 2 + m1, params.begin() + 2 + m1 + p);
132 std::vector<double> w(params.begin() + 2 + m1 + p, params.begin() + 2 + m1 + 2 * p);
133 std::vector<double> f(params.begin() + 2 + m1 + 2 * p, params.end());
134 return eptmp(a, g, w, f, horizon, dispersion, cyclic, Q);
135 }
136 if (kind == PWLINEAR) {
137 if (params.empty()) throw InputError("NNPP: malformed PWLINEAR params row");
138 const std::size_t n = static_cast<std::size_t>(params[0]);
139 if (params.size() != 1 + 2 * n) throw InputError("NNPP: malformed PWLINEAR params row");
140 std::vector<double> t(params.begin() + 1, params.begin() + 1 + n);
141 std::vector<double> r(params.begin() + 1 + n, params.end());
142 return piecewise_linear(t, r, dispersion, cyclic, Q);
143 }
144 throw InputError("NNPP: unknown rate-function kind " + std::to_string(kind));
145 }
146
147 // ---------------------------------------------------------------------
148 // Rate function and mean value
149 // ---------------------------------------------------------------------
150
151 /** lambda(t), cyclic aware; zero past the horizon when not cyclic. */
152 double rate_at(double t) const {
153 if (t < 0.0) return 0.0;
154 if (cyclic_) return lam(reduce(t));
155 if (t > horizon_) return 0.0;
156 return lam(t);
157 }
158
159 /** mu(t) = int_0^t lambda, cyclic aware; constant past the horizon when not cyclic. */
160 double mean_value(double t) const {
161 if (!(t > 0.0)) return 0.0;
162 if (cyclic_) {
163 const double k = std::floor(t / horizon_);
164 const double r = t - k * horizon_;
165 return k * mu_s_ + mu_within(r);
166 }
167 if (t >= horizon_) return mu_s_;
168 return mu_within(t);
169 }
170
171 double time_average_rate() const { return mu_s_ / horizon_; }
172 double mean() const {
173 return mu_s_ > 0.0 ? horizon_ / mu_s_ : std::numeric_limits<double>::infinity();
174 }
175 double rate() const { return mu_s_ / horizon_; }
176 double scv() const { return std::numeric_limits<double>::quiet_NaN(); }
177 double skewness() const { return std::numeric_limits<double>::quiet_NaN(); }
178
179 /** The Q+1 majorizer breakpoints z_i = i*S/Q. */
180 const std::vector<double>& majorizer_breakpoints() const { return z_; }
181 /** The Q piecewise-constant majorizer rates. */
182 const std::vector<double>& majorizer_rates() const { return lt_; }
183 /** muTilde(S), the majorizer mass over one cycle. */
184 double mean_value_majorizer() const { return M_.back(); }
185 /** muTilde(t), cyclic aware. */
186 double mean_value_majorizer(double t) const {
187 if (!(t > 0.0)) return 0.0;
188 double k = 0.0;
189 if (cyclic_) {
190 k = std::floor(t / horizon_);
191 t = t - k * horizon_;
192 } else if (t >= horizon_) {
193 return M_.back();
194 }
195 std::size_t i = static_cast<std::size_t>(std::floor(t / h_));
196 if (i >= lt_.size()) i = lt_.size() - 1;
197 return k * M_.back() + M_[i] + lt_[i] * (t - z_[i]);
198 }
199 double acceptance_rate() const { return M_.back() > 0.0 ? mu_s_ / M_.back() : 0.0; }
200 double dispersion() const { return disp_; }
201 bool is_cyclic() const { return cyclic_; }
202 double horizon() const { return horizon_; }
203 double weibull_shape() const { return wshape_; }
204 double weibull_scale() const { return wscale_; }
205 int q() const { return static_cast<int>(lt_.size()); }
206 int kind() const { return kind_; }
207 std::string kind_name() const { return kind_ == EPTMP ? "eptmp" : "pwlinear"; }
208 std::string method() const { return disp_ == 1.0 ? "thinning" : "sciata"; }
209 std::string name() const { return "NNPP"; }
210
211 const std::vector<double>& alpha() const { return alpha_; }
212 const std::vector<double>& gamma() const { return gamma_; }
213 const std::vector<double>& omega() const { return omega_; }
214 const std::vector<double>& phi() const { return phi_; }
215 const std::vector<double>& times() const { return times_; }
216 const std::vector<double>& rates() const { return rates_; }
217
218 /** The `params` row of `sn.proc`, see `from_params`. */
219 std::vector<double> params() const {
220 std::vector<double> p;
221 if (kind_ == EPTMP) {
222 p.push_back(static_cast<double>(alpha_.size()));
223 p.push_back(static_cast<double>(gamma_.size()));
224 p.insert(p.end(), alpha_.begin(), alpha_.end());
225 p.insert(p.end(), gamma_.begin(), gamma_.end());
226 p.insert(p.end(), omega_.begin(), omega_.end());
227 p.insert(p.end(), phi_.begin(), phi_.end());
228 } else {
229 p.push_back(static_cast<double>(times_.size()));
230 p.insert(p.end(), times_.begin(), times_.end());
231 p.insert(p.end(), rates_.begin(), rates_.end());
232 }
233 return p;
234 }
235
236 /**
237 * Weibull (shape, scale) whose mean is 1 and SCV is C: 200 bisection steps on
238 * x = log(shape) in [log 0.02, log 200]. C == 1 is exactly (1, 1).
239 */
240 static void weibull_for_dispersion(double C, double& shape, double& scale) {
241 if (!(C > 0.0) || !std::isfinite(C))
242 throw InputError("NNPP: the dispersion ratio must be finite and positive");
243 if (C == 1.0) {
244 shape = 1.0;
245 scale = 1.0;
246 return;
247 }
248 auto g = [C](double x) {
249 const double a = std::exp(x);
250 return std::exp(std::lgamma(1.0 + 2.0 / a) - 2.0 * std::lgamma(1.0 + 1.0 / a)) - 1.0 - C;
251 };
252 double lo = std::log(0.02), hi = std::log(200.0);
253 const double glo = g(lo), ghi = g(hi);
254 if (!(glo > 0.0 && ghi < 0.0))
255 throw InputError("NNPP: no Weibull shape in [0.02, 200] gives dispersion " +
256 std::to_string(C));
257 for (int it = 0; it < 200; ++it) {
258 const double mid = 0.5 * (lo + hi);
259 if (g(mid) > 0.0)
260 lo = mid;
261 else
262 hi = mid;
263 }
264 shape = std::exp(0.5 * (lo + hi));
265 scale = std::exp(-std::lgamma(1.0 + 1.0 / shape));
266 }
267
268 // ---------------------------------------------------------------------
269 // Majorizer inverse and sampling
270 // ---------------------------------------------------------------------
271
272 /** Majorizer rate in force at an in-cycle time tc. */
273 double majorizer_at(double tc) const {
274 std::size_t i = static_cast<std::size_t>(std::floor(tc / h_));
275 if (i >= lt_.size()) i = lt_.size() - 1;
276 return lt_[i];
277 }
278
279 /** muTilde^{-1}(u), absolute time, cyclic aware; +Inf when the majorizer has no mass. */
280 double majorizer_inverse(double u) const {
281 const double MQ = M_.back();
282 if (!(MQ > 0.0)) return std::numeric_limits<double>::infinity();
283 double k = 0.0;
284 if (cyclic_) {
285 k = std::floor(u / MQ);
286 u = u - k * MQ;
287 } else if (u > MQ) {
288 return std::numeric_limits<double>::infinity();
289 }
290 const std::size_t Q = lt_.size();
291 // smallest i in 1..Q with M[i] >= u
292 std::size_t i = static_cast<std::size_t>(std::lower_bound(M_.begin() + 1, M_.end(), u) -
293 M_.begin());
294 if (i > Q) i = Q;
295 while (i < Q && !(lt_[i - 1] > 0.0)) ++i;
296 while (i > 1 && !(lt_[i - 1] > 0.0)) --i; // u == MQ landed past the last positive rate
297 const double t = z_[i - 1] + (u - M_[i - 1]) / lt_[i - 1];
298 return k * horizon_ + t;
299 }
300
301 /** The equilibrium (first) renewal gap: scale * Y^(1/shape), Y ~ Gamma(1/shape, 1). */
302 template <class Unif>
303 double equilibrium_gap(Unif& unif) const {
304 const double u = unif();
305 if (wshape_ == 1.0) return -std::log1p(-u);
306 const double y = ldes::ssj::gamma_inverse(1.0 / wshape_, 1.0, u);
307 return wscale_ * std::pow(y, 1.0 / wshape_);
308 }
309
310 /** A noninitial renewal gap: scale * (-log(1-U))^(1/shape). */
311 template <class Unif>
312 double renewal_gap(Unif& unif) const {
313 const double u = unif();
314 const double e = -std::log1p(-u);
315 if (wshape_ == 1.0) return e;
316 return wscale_ * std::pow(e, 1.0 / wshape_);
317 }
318
319 /**
320 * The next accepted arrival epoch (absolute time) of the path `s`, or +Inf when
321 * a non-cyclic process has no more arrivals. `unif()` returns U(0,1).
322 */
323 template <class Unif>
324 double next_arrival(Stream& s, Unif& unif) const {
325 if (!(M_.back() > 0.0)) return std::numeric_limits<double>::infinity();
326 for (;;) {
327 const double X = s.first ? equilibrium_gap(unif) : renewal_gap(unif);
328 s.first = false;
329 s.u = s.u + X;
330 if (!cyclic_ && s.u > M_.back()) return std::numeric_limits<double>::infinity();
331 const double t = majorizer_inverse(s.u);
332 const double tc = cyclic_ ? reduce(t) : std::min(t, horizon_);
333 const double maj = majorizer_at(tc);
334 double p = (maj > 0.0) ? lam(tc) / maj : 0.0;
335 if (p < 0.0) p = 0.0;
336 if (p > 1.0) p = 1.0;
337 if (unif() <= p) {
338 s.t_last = t;
339 return t;
340 }
341 }
342 }
343
344 /**
345 * n successive interarrival times along one path from time 0. A non-cyclic
346 * process that runs out of arrivals returns fewer than n.
347 */
348 template <class Unif>
349 std::vector<double> sample(std::size_t n, Unif&& unif) const {
350 std::vector<double> out;
351 out.reserve(n);
352 Stream s;
353 double prev = 0.0;
354 for (std::size_t j = 0; j < n; ++j) {
355 const double t = next_arrival(s, unif);
356 if (!std::isfinite(t)) break;
357 out.push_back(t - prev);
358 prev = t;
359 }
360 return out;
361 }
362
363 /** sample(n) off a std::mt19937_64, U drawn in (0,1). */
364 std::vector<double> sample(std::size_t n, std::mt19937_64& rng) const {
365 std::uniform_real_distribution<double> U(0.0, 1.0);
366 auto unif = [&]() {
367 double u = U(rng);
368 while (!(u > 0.0)) u = U(rng);
369 return u;
370 };
371 return sample(n, unif);
372 }
373
374private:
375 void init(double dispersion, bool cyclic, int Q) {
376 if (Q < 1) throw InputError("NNPP: the majorizer needs Q >= 1 subintervals");
377 weibull_for_dispersion(dispersion, wshape_, wscale_);
379 std::cerr << "[LINE] Warning: NNPP: dispersion " << dispersion
380 << " exceeds 2; SCIATA is designed for C in (0, 2]." << std::endl;
381 disp_ = dispersion;
382 cyclic_ = cyclic;
383 const double S = horizon_;
384 h_ = S / Q;
385 z_.assign(static_cast<std::size_t>(Q) + 1, 0.0);
386 for (int i = 0; i <= Q; ++i) z_[static_cast<std::size_t>(i)] = i * S / Q;
387 lt_.assign(static_cast<std::size_t>(Q), 0.0);
388 for (int i = 1; i <= Q; ++i) {
389 const double a = z_[static_cast<std::size_t>(i - 1)], b = z_[static_cast<std::size_t>(i)];
390 lt_[static_cast<std::size_t>(i - 1)] = (kind_ == EPTMP) ? golden_max(a, b) : pwl_max(a, b);
391 }
392 M_.assign(static_cast<std::size_t>(Q) + 1, 0.0);
393 for (int i = 1; i <= Q; ++i) {
394 const std::size_t ii = static_cast<std::size_t>(i);
395 M_[ii] = M_[ii - 1] + lt_[ii - 1] * (z_[ii] - z_[ii - 1]);
396 }
397 mu_s_ = (kind_ == EPTMP) ? simpson(S, 64 * static_cast<long>(Q)) : trapezoid(S);
398 }
399
400 /** Reduce an absolute time into [0, S). */
401 double reduce(double t) const {
402 const double k = std::floor(t / horizon_);
403 double r = t - k * horizon_;
404 if (r < 0.0) r = 0.0;
405 if (r >= horizon_) r = 0.0;
406 return r;
407 }
408
409 /** lambda at an in-cycle time t in [0, S]. */
410 double lam(double t) const {
411 if (kind_ == EPTMP) {
412 const std::size_t m = alpha_.size() - 1;
413 double s = alpha_[m];
414 for (std::size_t i = m; i-- > 0;) s = s * t + alpha_[i];
415 for (std::size_t k = 0; k < gamma_.size(); ++k)
416 s += gamma_[k] * std::sin(omega_[k] * t + phi_[k]);
417 return std::exp(s);
418 }
419 const std::size_t n = times_.size();
420 // largest j <= n-2 with times[j] <= t
421 std::size_t j = static_cast<std::size_t>(
422 std::upper_bound(times_.begin(), times_.begin() + static_cast<long>(n - 1), t) -
423 times_.begin());
424 j = (j == 0) ? 0 : j - 1;
425 return rates_[j] + (rates_[j + 1] - rates_[j]) * (t - times_[j]) / (times_[j + 1] - times_[j]);
426 }
427
428 double golden_max(double a, double b) const {
429 const double phi = (1.0 + std::sqrt(5.0)) / 2.0;
430 const double delta = 1e-4;
431 double best = std::max(lam(a), lam(b));
432 double x1 = a + (2.0 - phi) * (b - a);
433 double x2 = a + (phi - 1.0) * (b - a);
434 double f1 = lam(x1), f2 = lam(x2);
435 best = std::max(best, std::max(f1, f2));
436 while ((b - a) >= delta) {
437 if (f1 < f2) {
438 a = x1;
439 x1 = x2;
440 f1 = f2;
441 x2 = a + (phi - 1.0) * (b - a);
442 f2 = lam(x2);
443 best = std::max(best, f2);
444 } else {
445 b = x2;
446 x2 = x1;
447 f2 = f1;
448 x1 = a + (2.0 - phi) * (b - a);
449 f1 = lam(x1);
450 best = std::max(best, f1);
451 }
452 }
453 return best;
454 }
455
456 double pwl_max(double a, double b) const {
457 double best = std::max(lam(a), lam(b));
458 for (std::size_t j = 0; j < times_.size(); ++j)
459 if (a < times_[j] && times_[j] < b) best = std::max(best, rates_[j]);
460 return best;
461 }
462
463 /** Composite Simpson of lambda on [0, t] with N (even) panels. */
464 double simpson(double t, long N) const {
465 const double h = t / static_cast<double>(N);
466 double s = lam(0.0) + lam(t);
467 for (long i = 1; i < N; ++i) s += ((i % 2 == 1) ? 4.0 : 2.0) * lam(static_cast<double>(i) * h);
468 return s * h / 3.0;
469 }
470
471 /** Exact trapezoid of the piecewise-linear lambda on [0, t], t in [0, S]. */
472 double trapezoid(double t) const {
473 double s = 0.0;
474 for (std::size_t j = 0; j + 1 < times_.size(); ++j) {
475 const double a = times_[j];
476 if (!(t > a)) break;
477 const double b = std::min(t, times_[j + 1]);
478 const double fb = (b == times_[j + 1]) ? rates_[j + 1] : lam(b);
479 s += 0.5 * (rates_[j] + fb) * (b - a);
480 }
481 return s;
482 }
483
484 /** mu(t) for t in [0, S]. */
485 double mu_within(double t) const {
486 if (!(t > 0.0)) return 0.0;
487 if (kind_ == PWLINEAR) return trapezoid(t);
488 if (t == horizon_) return mu_s_;
489 const long Q = static_cast<long>(lt_.size());
490 long N = 2 * static_cast<long>(std::ceil(32.0 * Q * t / horizon_));
491 if (N < 2) N = 2;
492 return simpson(t, N);
493 }
494
495 int kind_ = EPTMP;
496 std::vector<double> alpha_, gamma_, omega_, phi_;
497 std::vector<double> times_, rates_;
498 double horizon_ = 1.0;
499 double disp_ = 1.0;
500 bool cyclic_ = true;
501 double wshape_ = 1.0, wscale_ = 1.0;
502 double h_ = 1.0;
503 std::vector<double> z_, lt_, M_;
504 double mu_s_ = 0.0;
505};
506
507} // namespace lang
508} // namespace line
509
510#endif // LINE_LANG_NNPP_H
InputError(const std::string &what)
Definition error.h:105
double renewal_gap(Unif &unif) const
A noninitial renewal gap: scale * (-log(1-U))^(1/shape).
Definition nnpp.h:312
const std::vector< double > & alpha() const
Definition nnpp.h:211
const std::vector< double > & rates() const
Definition nnpp.h:216
Kind
The rate-function family, with the codes sn.proc carries.
Definition nnpp.h:55
int kind() const
Definition nnpp.h:206
double majorizer_inverse(double u) const
muTilde^{-1}(u), absolute time, cyclic aware; +Inf when the majorizer has no mass.
Definition nnpp.h:280
double majorizer_at(double tc) const
Majorizer rate in force at an in-cycle time tc.
Definition nnpp.h:273
const std::vector< double > & majorizer_breakpoints() const
The Q+1 majorizer breakpoints z_i = i*S/Q.
Definition nnpp.h:180
double skewness() const
Definition nnpp.h:177
int q() const
Definition nnpp.h:205
std::vector< double > sample(std::size_t n, std::mt19937_64 &rng) const
sample(n) off a std::mt19937_64, U drawn in (0,1).
Definition nnpp.h:364
double horizon() const
Definition nnpp.h:202
double time_average_rate() const
Definition nnpp.h:171
double scv() const
Definition nnpp.h:176
std::string kind_name() const
Definition nnpp.h:207
const std::vector< double > & majorizer_rates() const
The Q piecewise-constant majorizer rates.
Definition nnpp.h:182
std::string name() const
Definition nnpp.h:209
const std::vector< double > & omega() const
Definition nnpp.h:213
double mean() const
Definition nnpp.h:172
std::string method() const
Definition nnpp.h:208
static void weibull_for_dispersion(double C, double &shape, double &scale)
Weibull (shape, scale) whose mean is 1 and SCV is C: 200 bisection steps on x = log(shape) in [log 0....
Definition nnpp.h:240
double weibull_shape() const
Definition nnpp.h:203
static Nnpp eptmp(const std::vector< double > &alpha, const std::vector< double > &gamma, const std::vector< double > &omega, const std::vector< double > &phi, double horizon, double dispersion=1.0, bool cyclic=true, int Q=200)
EPTMP: lambda(t) = exp(sum_i alpha_i t^i + sum_k gamma_k sin(omega_k t + phi_k)) on [0,...
Definition nnpp.h:70
const std::vector< double > & gamma() const
Definition nnpp.h:212
std::vector< double > params() const
The params row of sn.proc, see from_params.
Definition nnpp.h:219
static Nnpp from_params(int kind, const std::vector< double > &params, double horizon, double dispersion, bool cyclic, int Q)
Rebuild from the params row of sn.proc ([m+1, p, alpha, gamma, omega, phi] for EPTMP,...
Definition nnpp.h:123
bool is_cyclic() const
Definition nnpp.h:201
double mean_value_majorizer() const
muTilde(S), the majorizer mass over one cycle.
Definition nnpp.h:184
static Nnpp piecewise_linear(const std::vector< double > &times, const std::vector< double > &rates, double dispersion=1.0, bool cyclic=true, int Q=200)
PWLINEAR: lambda linearly interpolated between (times[j], rates[j]); horizon = times....
Definition nnpp.h:96
double mean_value(double t) const
mu(t) = int_0^t lambda, cyclic aware; constant past the horizon when not cyclic.
Definition nnpp.h:160
double acceptance_rate() const
Definition nnpp.h:199
const std::vector< double > & phi() const
Definition nnpp.h:214
double rate() const
Definition nnpp.h:175
const std::vector< double > & times() const
Definition nnpp.h:215
double weibull_scale() const
Definition nnpp.h:204
double rate_at(double t) const
lambda(t), cyclic aware; zero past the horizon when not cyclic.
Definition nnpp.h:152
double next_arrival(Stream &s, Unif &unif) const
The next accepted arrival epoch (absolute time) of the path s, or +Inf when a non-cyclic process has ...
Definition nnpp.h:324
double equilibrium_gap(Unif &unif) const
The equilibrium (first) renewal gap: scale * Y^(1/shape), Y ~ Gamma(1/shape, 1).
Definition nnpp.h:303
double mean_value_majorizer(double t) const
muTilde(t), cyclic aware.
Definition nnpp.h:186
std::vector< double > sample(std::size_t n, Unif &&unif) const
n successive interarrival times along one path from time 0.
Definition nnpp.h:349
double dispersion() const
Definition nnpp.h:200
static VerboseLevel get_verbose()
The session verbosity.
The exception types the port throws.
The variate layer of the Java LDES engine, reproduced: SSJ's randvar generators as inverse-CDF functi...
Running progress log of a LINE solver run (the "solver console").
double gamma_inverse(double alpha, double lambda, double u)
GammaDist.inverseF(alpha, lambda, u): the quantile of a Gamma of shape alpha and RATE lambda,...
double delta(double t)
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
One arrival path: renewal epoch in majorizer space, first-gap flag, last arrival.
Definition nnpp.h:58