LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
solver_mam_reneging.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_SOLVERS_MAM_SOLVER_MAM_RENEGING_H
6#define LINE_SOLVERS_MAM_SOLVER_MAM_RENEGING_H
7
8/**
9 * @file
10 * @ingroup line_solvers
11 * The reneging route of `solver_mam_retrial.m`: the MAP/M/s+G queue whose
12 * waiting jobs abandon after a generally distributed patience, after O. Gursoy,
13 * K. A. Mehr and N. Akar, "The MAP/M/s + G Call Center Model with Generally
14 * Distributed Patience Times". Gate: `mam_reneging_applicable.m`.
15 *
16 * THE FLUID IS THE VIRTUAL WAITING TIME. The background chain is (busy servers,
17 * MAP phase), s+1 blocks of MAP phases; the last block has drift +1 and stands
18 * for the work an admitted arrival adds, every other block drift -1. The
19 * patience CDF is quantized into `MamOptions::mapmsg_quantization` regimes over
20 * [0, T], T the first mean * 1.25^k at which the CDF reaches 1 - 1e-4. An arrival
21 * that finds the virtual wait in regime k abandons with the patience CDF at the
22 * regime's representative wait (the midpoint, and T for the tail [T, inf)),
23 * which is the abandonment of a FCFS queue because the virtual wait IS the wait
24 * that arrival would see.
25 *
26 * MATLAB solves the fluid queue with the MAPMsG library's `MRMFQSolver`; this
27 * port, like the JAR's, solves the same queue with `mfq_multiregime` (Kankaya
28 * and Akar, the method MRMFQSolver implements) and reads the per-regime state
29 * masses off its distribution function: the mass on regime d is
30 * P(X < B_d) - P(X <= B_{d-1}) and the atom at zero is P(X <= 0). On M/M/3+M,
31 * MAP/M/3+M and M/M/4+Erlang-2 this construction and the native-python MRMFQ
32 * port coincide to 1e-14.
33 *
34 * THE PATIENCE MUST BE MARKOVIAN, and that is refused by name rather than
35 * fitted. The regime grid, the horizon and E[min(v, P)] are all read off a
36 * (D0, D1) pair. A Det, Gamma, Lognormal, Pareto, Uniform or Weibull patience
37 * carries none in the C++ model layer, and the JAR's `refreshImpatience` stores
38 * none either. MATLAB stores `getProcess()` for these laws, which is the raw
39 * parameter list and not a generator, and the reneging route then fails inside
40 * `schur` on NaN, so there is no reference behaviour to reproduce.
41 *
42 * DOUBLE ONLY. `mfq_multiregime` is double only (an ordered real Schur form,
43 * LAPACK), so an exact or multiprecision instantiation refuses by name instead
44 * of carrying a double-accurate answer under a wider type.
45 */
46
47#include <cstddef>
48#include <string>
49#include <type_traits>
50#include <vector>
51
59#include "line/util/error.h"
60#include "line/util/expm.h"
61#include "line/util/linalg.h"
62#include "line/util/lu.h"
63#include "line/util/matrix.h"
64
65namespace line {
66namespace mam {
67
68/** What `mam_reneging_applicable.m` returns: the station it found, or why it found none. */
70 bool ok = false;
71 std::size_t source = 0; ///< 1-based station index of the Source
72 std::size_t station = 0; ///< 1-based station index of the reneging queue
73 std::size_t cls = 1; ///< 1-based class index; the reference is single-class
74 int nservers = 0; ///< s
75 std::string why; ///< the reference's `errorMsg`, empty when ok
76};
77
78namespace reneging_detail {
79
80/** Does station `ist` (1-based) declare RENEGING for class `r` (1-based)? */
81template <class T>
82bool declares(const qn::NetworkStruct<T>& L, std::size_t ist, std::size_t r) {
83 const qn::Station<T>& st = L.stations[ist - 1];
84 return r - 1 < st.impatience.size() && st.impatience[r - 1] == lang::ImpatienceType::RENEGING;
85}
86
87/** The patience law at (ist, r) when it is a usable (D0, D1) pair; null otherwise. */
88template <class T>
90 std::size_t r) {
91 if (!declares(L, ist, r)) return nullptr;
92 const qn::Station<T>& st = L.stations[ist - 1];
93 if (r - 1 >= st.patience.size()) return nullptr;
94 const lang::Distrib<T>& p = st.patience[r - 1];
95 if (p.disabled || !p.has_map()) return nullptr;
97 !basic_detail::is_markovian_type(p.type))
98 return nullptr;
99 return &p;
100}
101
102/** Matrix<T> to Matrix<double>. */
103template <class T>
105 Matrix<double> B(A.rows(), A.cols(), 0.0);
106 for (std::size_t i = 0; i < A.rows(); ++i)
107 for (std::size_t j = 0; j < A.cols(); ++j) B(i, j) = num_traits<T>::to_double(A(i, j));
108 return B;
109}
110
111inline void add_block(Matrix<double>& A, std::size_t r0, std::size_t c0, const Matrix<double>& B,
112 double scale) {
113 for (std::size_t i = 0; i < B.rows(); ++i)
114 for (std::size_t j = 0; j < B.cols(); ++j) A(r0 + i, c0 + j) += scale * B(i, j);
115}
116
117/** The station metrics of the MAP/M/s+G queue. */
119 double tput = 0.0, util = 0.0, qlen = 0.0, respt = 0.0;
120};
121
122/**
123 * `solveReneging` + `convertPatienceToRegimes` of `solver_mam_retrial.m`, as
124 * fixed in 2c0848d76f (stationary arrival rate, the regime grid, the QLen
125 * formula), in double.
126 *
127 * @param C, D the arrival MAP
128 * @param mu the exponential service rate
129 * @param s the server count
130 * @param P0, P1 the patience as a (D0, D1) pair
131 * @param Qz the regime count, at least 2
132 */
133inline RenegingMetrics solve(const Matrix<double>& C, const Matrix<double>& D, double mu, int s,
134 const Matrix<double>& P0, const Matrix<double>& P1, std::size_t Qz) {
135 Map<double> pat;
136 pat.D0 = P0;
137 pat.D1 = P1;
138
139 // ---- the regimes of the patience CDF ------------------------------------
140 double Th = map_mean(pat);
141 while (map_cdf(pat, std::vector<double>(1, Th))[0] < 1.0 - 1e-4) Th *= 1.25;
142 std::vector<double> BL(Qz);
143 for (std::size_t k = 0; k < Qz; ++k)
144 BL[k] = Th * static_cast<double>(k) / static_cast<double>(Qz - 1); // linspace(0, T, Qz)
145 BL[Qz - 1] = Th;
146 std::vector<double> vrep(Qz);
147 for (std::size_t k = 0; k + 1 < Qz; ++k) vrep[k] = (BL[k] + BL[k + 1]) / 2.0;
148 vrep[Qz - 1] = BL[Qz - 1];
149 const std::vector<double> ga = map_cdf(pat, vrep); // ga[k] is the reference's ga(k+2)
150
151 // ---- the background generators -----------------------------------------
152 const std::size_t m = C.rows();
153 const std::size_t S = static_cast<std::size_t>(s);
154 const std::size_t n = (S + 1) * m;
155 const Matrix<double> I = eye<double>(m);
156 Matrix<double> Qy0(n, n, 0.0);
157 for (std::size_t row = 1; row <= S + 1; ++row) {
158 const std::size_t rs = (row - 1) * m;
159 const double busy = static_cast<double>(row - 1) * mu;
160 if (row == 1) {
161 add_block(Qy0, rs, rs, C, 1.0);
162 add_block(Qy0, rs, rs + m, D, 1.0);
163 } else if (row == S + 1) {
164 add_block(Qy0, rs, rs, I, -busy);
165 add_block(Qy0, rs, rs - m, I, busy);
166 } else {
167 add_block(Qy0, rs, rs, C, 1.0);
168 add_block(Qy0, rs, rs, I, -busy);
169 add_block(Qy0, rs, rs - m, I, busy);
170 add_block(Qy0, rs, rs + m, D, 1.0);
171 }
172 }
173 // Above level zero every server is busy: an arrival is admitted to the
174 // all-busy block with probability 1 - ga[k] and abandons otherwise.
175 std::vector<Matrix<double>> Qy;
176 Qy.reserve(Qz);
177 for (std::size_t k = 0; k < Qz; ++k) {
178 Matrix<double> Qk(n, n, 0.0);
179 const std::size_t rs = (S - 1) * m;
180 add_block(Qk, rs, rs, D, ga[k]);
181 add_block(Qk, rs, rs, C, 1.0);
182 add_block(Qk, rs, rs + m, D, 1.0 - ga[k]);
183 const std::size_t rs2 = S * m;
184 add_block(Qk, rs2, rs2, I, -static_cast<double>(S) * mu);
185 add_block(Qk, rs2, rs2 - m, I, static_cast<double>(S) * mu);
186 Qy.push_back(Qk);
187 }
188 std::vector<double> Rd(n, -1.0);
189 for (std::size_t i = n - m; i < n; ++i) Rd[i] = 1.0;
190 std::vector<std::vector<double>> R(Qz, Rd), Rt(Qz + 1, Rd);
191 std::vector<Matrix<double>> Qt;
192 Qt.reserve(Qz + 1);
193 Qt.push_back(Qy0);
194 for (std::size_t k = 0; k < Qz; ++k) Qt.push_back(Qy[k]);
195 // thresholds: B(1) dropped and 1e7 appended, as the reference's solveReneging
196 std::vector<double> B(Qz);
197 for (std::size_t k = 0; k + 1 < Qz; ++k) B[k] = BL[k + 1];
198 B[Qz - 1] = 1e7;
199 std::vector<double> cdfpts(Qz + 1, 0.0);
200 for (std::size_t k = 0; k < Qz; ++k) cdfpts[k + 1] = B[k];
201 const MultiRegimeResult res =
202 mfq_multiregime(Qy, R, Qt, Rt, B, std::vector<double>(), cdfpts);
203 const std::vector<std::vector<double>>& F = res.cdf; // P(X < p)
204 const std::vector<std::vector<double>>& Fm = res.cdfm; // P(X <= p)
205
206 // ---- the per-regime masses, weighted by the per-phase arrival rate -----
207 std::vector<double> lmap(m, 0.0);
208 for (std::size_t i = 0; i < m; ++i)
209 for (std::size_t j = 0; j < m; ++j) lmap[i] += D(i, j);
210 // E[min(v, P)] = alpha (-S)^-1 (I - expm(S v)) e for the patience P = (alpha, S = D0)
211 const std::vector<double> alpha = map_pie(pat);
212 const std::size_t np = P0.rows();
213 Matrix<double> negS(np, np, 0.0);
214 for (std::size_t i = 0; i < np; ++i)
215 for (std::size_t j = 0; j < np; ++j) negS(i, j) = -P0(i, j);
216 std::vector<double> meanMin(Qz, 0.0);
217 for (std::size_t k = 0; k < Qz; ++k) {
218 const Matrix<double> E = expm(P0, vrep[k]);
219 std::vector<double> rhs(np, 0.0);
220 for (std::size_t i = 0; i < np; ++i) {
221 rhs[i] = 1.0;
222 for (std::size_t j = 0; j < np; ++j) rhs[i] -= E(i, j);
223 }
224 const std::vector<double> x = solve(negS, rhs);
225 for (std::size_t i = 0; i < np; ++i) meanMin[k] += alpha[i] * x[i];
226 }
227 const std::size_t norm = S * m;
228 double total = 0.0, abandon = 0.0, queued = 0.0;
229 for (std::size_t i = 0; i < n; ++i) total += Fm[0][i] * lmap[i % m];
230 for (std::size_t d = 0; d < Qz; ++d)
231 for (std::size_t i = 0; i < norm; ++i) {
232 const double mass = (F[d + 1][i] - Fm[d][i]) * lmap[i % m];
233 total += mass;
234 abandon += ga[d] * mass;
235 queued += meanMin[d] * mass;
236 }
237 const double abandonProb = abandon / total;
238 const double expectedQueued = queued / total;
239
240 // pi * D1 * e, the stationary arrival rate, not the per-phase rates added up
241 Map<double> arv;
242 arv.D0 = C;
243 arv.D1 = D;
244 const double lambda = map_lambda(arv);
245 // Abandoning customers occupy the waiting room too, so QLen = busy servers +
246 // lambda * E[min(V, P)] (Little on the waiting room) and RespT = QLen / Tput.
247 RenegingMetrics out;
248 out.tput = lambda * (1.0 - abandonProb);
249 out.util = out.tput / (mu * static_cast<double>(S));
250 out.qlen = out.tput / mu + lambda * expectedQueued;
251 out.respt = out.qlen / out.tput;
252 return out;
253}
254
255} // namespace reneging_detail
256
257/**
258 * True when some station-class pair declares RENEGING, with or without a
259 * patience law this analyzer can read. A RENEGING pair whose law is not
260 * Markovian must still be seen by the gates: read off `mam_has_reneging_patience`
261 * alone, such a model would fall through to dec.source and be solved with the
262 * patience ignored.
263 */
264template <class T>
266 for (std::size_t i = 1; i <= L.nstations; ++i)
267 for (std::size_t r = 1; r <= L.nclasses; ++r)
268 if (reneging_detail::declares(L, i, r)) return true;
269 return false;
270}
271
272/** `mam_has_reneging_patience.m`: RENEGING together with a usable patience law. */
273template <class T>
275 for (std::size_t i = 1; i <= L.nstations; ++i)
276 for (std::size_t r = 1; r <= L.nclasses; ++r)
277 if (reneging_detail::markovian_patience(L, i, r) != nullptr) return true;
278 return false;
279}
280
281/**
282 * Port of `mam_reneging_applicable.m`: is this the MAP/M/s+G shape? Returns
283 * rather than throws, since the dispatch uses it as a branch predicate; the
284 * messages are the reference's.
285 */
286template <class T>
288 MamRenegingInfo info;
289 for (std::size_t k = 0; k < L.nclasses; ++k)
290 if (std::isfinite(L.classes[k].population)) {
291 info.why = "MAPMsG requires open queueing model.";
292 return info;
293 }
294 if (L.nclasses > 1) {
295 info.why = "MAPMsG currently supports single class only.";
296 return info;
297 }
298 info.cls = 1;
299 for (std::size_t i = 1; i <= L.nstations; ++i) {
300 const qn::NodeType nt = L.stations[i - 1].nodetype;
301 if (nt == qn::NodeType::Source) {
302 info.source = i;
303 } else if (nt == qn::NodeType::Queue) {
304 if (info.station == 0) {
305 info.station = i;
306 } else {
307 info.station = 0;
308 info.why = "MAPMsG requires single queue station.";
309 return info;
310 }
311 }
312 }
313 if (info.source == 0) {
314 info.why = "No Source node found.";
315 return info;
316 }
317 if (info.station == 0) {
318 info.why = "No Queue node found.";
319 return info;
320 }
321 const std::size_t q = info.station, src = info.source, r = info.cls;
322 const qn::Station<T>& st = L.stations[q - 1];
323 if (st.impatience.empty()) {
324 info.why = "No patience/impatience configuration found.";
325 return info;
326 }
327 if (!reneging_detail::declares(L, q, r)) {
328 info.why = "Queue does not have reneging configured.";
329 return info;
330 }
331 if (reneging_detail::markovian_patience(L, q, r) == nullptr) {
332 // a declared law that is not Markovian is named (MATLAB mam_reneging_applicable, JAR renegingApplicable)
333 const bool named = r - 1 < st.patience.size() && !st.patience[r - 1].disabled &&
334 st.patience[r - 1].type != lang::ProcessType::DISABLED;
335 info.why = named ? std::string("The patience of this class is ") +
336 lang::process_to_text(st.patience[r - 1].type) +
337 ", not a Markovian law (the patience must be a Markovian law: "
338 "Exp, Erlang, HyperExp, Coxian, APH or PH)."
339 : std::string("No patience distribution for this class (the patience must be a "
340 "Markovian law: Exp, Erlang, HyperExp, Coxian, APH or PH).");
341 return info;
342 }
344 info.why = "MAPMsG requires FCFS scheduling.";
345 return info;
346 }
347 const lang::Distrib<T>& svc = L.service[q - 1][r - 1];
348 if (L.disabled[q - 1][r - 1] || svc.disabled) {
349 info.why = "Invalid service process.";
350 return info;
351 }
352 if (!svc.has_map() || svc.D0.rows() != 1) {
353 info.why = "MAPMsG requires exponential service (single-phase).";
354 return info;
355 }
356 const lang::Distrib<T>& arv = L.service[src - 1][r - 1];
357 if (L.disabled[src - 1][r - 1] || arv.disabled || !arv.has_map() ||
358 !basic_detail::is_markovian_type(arv.type)) {
359 info.why = "Invalid arrival process.";
360 return info;
361 }
362 const double ns = L.stations[q - 1].nservers;
363 if (!std::isfinite(ns) || ns < 1.0) {
364 info.why = "MAPMsG requires a finite, positive server count.";
365 return info;
366 }
367 info.nservers = static_cast<int>(ns);
368 info.ok = true;
369 return info;
370}
371
372/**
373 * The sentence `supportsModelMethod('default')` refuses a declared reneging
374 * with when the model is not the MAP/M/s+G shape, or combines it with
375 * setup/delay-off; empty otherwise. dec.source would serve the patience as if
376 * it were absent, so a 'default' run must not fall through to it.
377 */
378template <class T>
380 if (!mam_declares_reneging(L)) return std::string();
381 const MamRenegingInfo info = mam_reneging_detect(L);
382 if (!info.ok)
383 return "SolverMAM: this model declares a reneging patience outside the MAP/M/s+G shape "
384 "(one Source, one FCFS Queue with exponential service, one open class) that the "
385 "default method solves through the reneging analyzer; dec.source would ignore the "
386 "patience. " + info.why + " Use SolverCTMC, SolverSSA, SolverJMT or SolverLDES.";
387 if (!L.setupparam.empty())
388 return "SolverMAM: this model combines setup/delay-off times with a reneging topology; only "
389 "the dec.source decomposition honours setup times, and the default method routes "
390 "such a topology to an analyzer that does not read them. Use SolverJMT or SolverLDES.";
391 return std::string();
392}
393
394/**
395 * The reneging route of `solver_mam_retrial.m`.
396 *
397 * @param L the refreshed struct
398 * @param opt the MAM options; `mapmsg_quantization` is the regime count
399 * @param info a successful `mam_reneging_detect(L)`
400 */
401template <class T>
403 const MamRenegingInfo& info) {
404 if (!info.ok)
405 throw UnsupportedError(ErrorKind{"Reneging"},
406 "SolverMAM: not a MAP/M/s+G reneging queue: " + info.why);
407 if (opt.mapmsg_quantization < 2)
408 throw InputError("SolverMAM: options.config.mapmsg_quantization must be at least 2, got " +
409 std::to_string(opt.mapmsg_quantization) +
410 "; one regime leaves no grid between 0 and the patience horizon");
411 if constexpr (!std::is_same<T, double>::value) {
412 throw UnsupportedError(ErrorKind{"Arithmetic"},
413 "SolverMAM: the MAP/M/s+G reneging analyzer solves a multi-regime fluid queue "
414 "through mfq_multiregime, whose ordered real Schur basis is double only; use --arith "
415 "double");
416 } else {
417 const std::size_t q = info.station, src = info.source, r = info.cls;
418 const lang::Distrib<T>& arv = L.service[src - 1][r - 1];
419 const lang::Distrib<T>& svc = L.service[q - 1][r - 1];
421 const double mu = -svc.D0(0, 0);
423 reneging_detail::solve(arv.D0, arv.D1, mu, info.nservers, pat->D0, pat->D1,
424 opt.mapmsg_quantization);
425
427 const std::size_t M = L.nstations, K = L.nclasses;
428 out.Q = Matrix<T>(M, K, 0.0);
429 out.U = Matrix<T>(M, K, 0.0);
430 out.R = Matrix<T>(M, K, 0.0);
431 out.Tp = Matrix<T>(M, K, 0.0);
432 out.C.assign(K, 0.0);
433 out.X.assign(K, 0.0);
434 out.Q(q - 1, r - 1) = met.qlen;
435 out.U(q - 1, r - 1) = met.util;
436 out.R(q - 1, r - 1) = met.respt;
437 out.Tp(q - 1, r - 1) = met.tput;
438 out.X[r - 1] = met.tput;
439 out.C[r - 1] = met.respt;
440 // the reference's totiter for this route is the regime count
441 out.iter = static_cast<int>(opt.mapmsg_quantization);
442 return out;
443 }
444}
445
446} // namespace mam
447} // namespace line
448
449#endif // LINE_SOLVERS_MAM_SOLVER_MAM_RENEGING_H
InputError(const std::string &what)
Definition error.h:105
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
UnsupportedError(const std::string &what)
Definition error.h:119
A network plus its refreshed NetworkStruct.
std::vector< std::vector< Distrib< T > > > service
service[i][r], 0-based station and class; a disabled entry marks a pair never visited.
std::map< std::size_t, SetupDelayOffParam< T > > setupparam
Setup / delay-off, keyed by 1-based STATION index.
std::vector< std::vector< bool > > disabled
std::vector< JobClass > classes
std::vector< Station< T > > stations
stations[k-1] is the k-th station
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
LU factorization with partial pivoting, templated on the number type.
The option and result types SolverMAM shares with its analyzers.
Cumulative distribution of the inter-arrival time of a MAP.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Multi-regime FEEDBACK Markovian fluid queue: density, density derivative and distribution of the flui...
const char * process_to_text(ProcessType p)
The MATLAB ProcessType name, as sn.procid prints it.
Definition lang_types.h:649
NodeType
Node kinds, with the values of MATLAB NodeType.
Definition lang_types.h:339
RenegingMetrics solve(const Matrix< double > &C, const Matrix< double > &D, double mu, int s, const Matrix< double > &P0, const Matrix< double > &P1, std::size_t Qz)
solveReneging + convertPatienceToRegimes of solver_mam_retrial.m, as fixed in 2c0848d76f (stationary ...
const lang::Distrib< T > * markovian_patience(const qn::NetworkStruct< T > &L, std::size_t ist, std::size_t r)
The patience law at (ist, r) when it is a usable (D0, D1) pair; null otherwise.
void add_block(Matrix< double > &A, std::size_t r0, std::size_t c0, const Matrix< double > &B, double scale)
Matrix< double > to_double(const Matrix< T > &A)
Matrix<T> to Matrix<double>.
bool declares(const qn::NetworkStruct< T > &L, std::size_t ist, std::size_t r)
Does station ist (1-based) declare RENEGING for class r (1-based)?
MultiRegimeResult mfq_multiregime(const std::vector< Matrix< double > > &Q, const std::vector< std::vector< double > > &R, const std::vector< Matrix< double > > &Qt, const std::vector< std::vector< double > > &Rt, const std::vector< double > &Thr, const std::vector< double > &pdfpoints, const std::vector< double > &cdfpoints)
Multi-regime feedback fluid queue.
bool mam_declares_reneging(const qn::NetworkStruct< T > &L)
True when some station-class pair declares RENEGING, with or without a patience law this analyzer can...
MamRenegingInfo mam_reneging_detect(const qn::NetworkStruct< T > &L)
Port of mam_reneging_applicable.m: is this the MAP/M/s+G shape?
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
Definition map_moment.h:101
bool mam_has_reneging_patience(const qn::NetworkStruct< T > &L)
mam_has_reneging_patience.m: RENEGING together with a usable patience law.
std::vector< T > map_cdf(const Map< T > &m, const std::vector< T > &points)
Cumulative distribution of the inter-arrival time at the given points.
Definition map_cdf.h:63
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
Definition map_moment.h:89
std::string mam_reneging_default_refusal(const qn::NetworkStruct< T > &L)
The sentence supportsModelMethod('default') refuses a declared reneging with when the model is not th...
T map_lambda(const Map< T > &m)
Stationary arrival rate, lambda = pi D1 e.
Definition map_moment.h:79
mva::MvaSolution< T > solver_mam_reneging(const qn::NetworkStruct< T > &L, const MamOptions &opt, const MamRenegingInfo &info)
The reneging route of solver_mam_retrial.m.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
Matrix< T > eye(std::size_t n)
Identity of order n.
Definition linalg.h:28
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Definition expm.h:141
A queueing network and its refreshed NetworkStruct.
Port of solver_mam_basic.m, the dec.source analyzer and the default algorithm of SolverMAM.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Definition error.h:37
bool has_map() const
True when the type carries a (D0,D1) pair of its own.
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.
Definition lang_types.h:915
The options SolverMAM reads.
Definition mam_types.h:30
What mam_reneging_applicable.m returns: the station it found, or why it found none.
std::size_t cls
1-based class index; the reference is single-class
std::size_t source
1-based station index of the Source
std::string why
the reference's errorMsg, empty when ok
std::size_t station
1-based station index of the reneging queue
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
Matrix< T > D0
Definition map_moment.h:54
Return value of mfq_multiregime: one row of N per-state values per point.
std::vector< std::vector< double > > cdf
P(X < p).
std::vector< std::vector< double > > cdfm
P(X <= p).
The station metrics of the MAP/M/s+G queue.
Class-level results, the [Q,U,R,T,C,X] of the MATLAB analyzers.
Definition mva_types.h:97
std::vector< T > X
Definition mva_types.h:99
std::vector< T > C
Definition mva_types.h:99
One station of the network.
std::vector< Distrib< T > > patience
Queue.setPatience(class, dist): the abandonment timer of a WAITING job, with impatience[r] naming whi...
SchedStrategy sched
std::vector< lang::ImpatienceType > impatience