LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
solver_ba_snc.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_BA_SOLVER_BA_SNC_H
6#define LINE_SOLVERS_BA_SOLVER_BA_SNC_H
7
8/**
9 * @file
10 * @ingroup line_solvers
11 * Stochastic network calculus UPPER bound on the mean response times and queue
12 * lengths of a feed-forward open network, valid for EVERY work-conserving
13 * scheduling policy at every station.
14 *
15 * Port of matlab/src/solvers/BA/solver_ba_snc_analyzer.m, cross-checked against
16 * jline.solvers.ba.analyzers.Solver_ba_snc_analyzer and the native-Python
17 * solver_ba_snc.py. The api domain `line/api/snc` supplies the envelope
18 * algebra; this analyzer maps the LINE model onto it, propagates envelopes hop
19 * by hop, and reads the bound back per station and class.
20 *
21 * UNITS ARE JOBS, NOT WORK. The arrival envelope counts jobs and the service
22 * element is `snc_srv_exp`, the counting process of an Exp(mu) server. That is
23 * what lets a departure envelope from one station be the arrival envelope of the
24 * next: a service-time work unit differs from station to station, a job does
25 * not. On a single M/M/1 the resulting backlog bound decays as (lambda/mu)^n and
26 * the delay bound as exp(-(mu-lambda)*d), both exact rates.
27 *
28 * BOUND CONVENTION. R(i,r) is `snc_mean_delay` of the (arrival, service)
29 * envelope pair, i.e. the integral of the delay tail bound, so each entry is a
30 * valid upper bound on its own. Q follows by Little's law from the bounded R and
31 * the EXACT throughput T (an open network's per-class rates are fixed by the
32 * traffic equations, not by the policy), and so does C. U is exact for the same
33 * reason.
34 *
35 * ARITHMETIC. The api domain is double-only -- every bound is an exp/log
36 * expression minimized numerically over theta -- so this arm converts at the
37 * boundary with `num_traits<T>::to_double` and `from_double` rather than
38 * pretending to be Rational-clean. It is the one BA family that is not
39 * instantiable at exact arithmetic, and `registry.h` registers the domain as
40 * Double for that reason.
41 *
42 * Reference: M. Fidler, A. Rizk (2015). A Guide to the Stochastic Network
43 * Calculus. IEEE Communications Surveys and Tutorials 17(1), 92-105.
44 */
45
46#include <algorithm>
47#include <cmath>
48#include <cstddef>
49#include <limits>
50#include <map>
51#include <string>
52#include <vector>
53
65#include "line/util/error.h"
66#include "line/util/matrix.h"
67
68namespace line {
69namespace ba {
70
71/** The per-pair envelopes the analyzer built, keyed by (station, class). */
73 std::map<std::pair<std::size_t, std::size_t>, snc::Envelope> arv;
74 std::map<std::pair<std::size_t, std::size_t>, snc::Envelope> srv;
75 std::map<std::pair<std::size_t, std::size_t>, double> lam;
76 std::map<std::pair<std::size_t, std::size_t>, double> mu;
77 std::size_t M = 0, K = 0;
78};
79
80namespace detail {
81
82/** Superposition of independent flows: the exponential forms multiply. */
83inline snc::Envelope snc_sum(const std::vector<snc::Envelope>& parts) {
84 return [parts](double theta) {
85 snc::Env e{0.0, 0.0};
86 for (std::size_t k = 0; k < parts.size(); ++k) {
87 const snc::Env p = parts[k](theta);
88 e.sigma += p.sigma;
89 e.rho += p.rho;
90 }
91 return e;
92 };
93}
94
95/** Kahn's algorithm; empty result means the graph has a cycle. */
96inline std::vector<std::size_t> snc_topo_order(const std::vector<std::vector<bool>>& adj) {
97 const std::size_t n = adj.size();
98 std::vector<int> indeg(n, 0);
99 for (std::size_t i = 0; i < n; ++i)
100 for (std::size_t j = 0; j < n; ++j)
101 if (adj[i][j]) indeg[j]++;
102 std::vector<bool> done(n, false);
103 std::vector<std::size_t> order;
104 while (true) {
105 std::size_t cand = n;
106 for (std::size_t i = 0; i < n && cand == n; ++i)
107 if (!done[i] && indeg[i] == 0) cand = i;
108 if (cand == n) break;
109 order.push_back(cand);
110 done[cand] = true;
111 for (std::size_t j = 0; j < n; ++j)
112 if (adj[cand][j]) indeg[j]--;
113 indeg[cand] = 1; // keep it out of the candidate set
114 }
115 if (order.size() < n) return {};
116 return order;
117}
118
119} // namespace detail
120
121/**
122 * Builds the per-pair (arrival, service) envelopes of a feed-forward model.
123 *
124 * Every gate of the family is checked here rather than in the caller, so that
125 * the quantile accessors refuse an unsupported model with the same reason as
126 * the mean columns.
127 *
128 * @param L the model
129 */
130template <class T>
132 const std::size_t M = L.nstations, K = L.nclasses;
133 const double TOL = 1e-10;
135 env.M = M;
136 env.K = K;
137
138 // ---- model gates ----
139 for (std::size_t r = 0; r < L.classes.size(); ++r)
140 if (std::isfinite(L.classes[r].population))
141 throw UnsupportedError(
142 "solver_ba_snc: method 'snc.upper' supports fully open networks only "
143 "(no closed classes)");
144 std::vector<std::size_t> srcList, qstat;
145 for (std::size_t i = 0; i < M; ++i) {
146 if (L.stations[i].nodetype == qn::NodeType::Source)
147 srcList.push_back(i);
148 else
149 qstat.push_back(i);
150 }
151 if (srcList.empty())
152 throw UnsupportedError(
153 "solver_ba_snc: method 'snc.upper' requires an open network with a Source station");
154 for (std::size_t a = 0; a < qstat.size(); ++a) {
155 const std::size_t i = qstat[a];
156 if (L.stations[i].sched == lang::SchedStrategy::INF)
157 throw UnsupportedError(
158 "solver_ba_snc: method 'snc.upper' does not support delay (infinite-server) "
159 "stations: the service envelope is that of a single busy server");
160 const double ns = num_traits<T>::to_double(L.stations[i].nservers);
161 if (std::isfinite(ns) && ns > 1)
162 throw UnsupportedError(
163 "solver_ba_snc: method 'snc.upper' does not support multi-server stations");
164 }
165
166 // ---- station-space routing, with the Source absorbed into the injections ----
167 const Matrix<T> rtst = api::sn_rt_stations(L).rtst;
168
169 std::vector<std::size_t> pairStation, pairClass, pairFlat;
170 for (std::size_t a = 0; a < qstat.size(); ++a)
171 for (std::size_t r = 0; r < K; ++r) {
172 pairStation.push_back(qstat[a]);
173 pairClass.push_back(r);
174 pairFlat.push_back(qstat[a] * K + r);
175 }
176 const std::size_t np = pairFlat.size();
177
178 // Injections are kept per (source, class) so that the exogenous process of
179 // each stream is still identifiable once the pairs are known.
180 std::vector<std::size_t> srcOfCol, clsOfCol;
181 for (std::size_t si = 0; si < srcList.size(); ++si)
182 for (std::size_t r0 = 0; r0 < K; ++r0) {
183 srcOfCol.push_back(srcList[si]);
184 clsOfCol.push_back(r0);
185 }
186 const std::size_t ncols = srcOfCol.size();
187 std::vector<std::vector<double>> inject(np, std::vector<double>(ncols, 0.0));
188 std::vector<double> lambda0(np, 0.0);
189 for (std::size_t c = 0; c < ncols; ++c) {
190 const double arr = num_traits<T>::to_double(L.rates(srcOfCol[c], clsOfCol[c]));
191 if (!std::isfinite(arr) || arr <= 0) continue;
192 const std::size_t srow = srcOfCol[c] * K + clsOfCol[c];
193 for (std::size_t p = 0; p < np; ++p) {
194 inject[p][c] = arr * num_traits<T>::to_double(rtst(srow, pairFlat[p]));
195 lambda0[p] += inject[p][c];
196 }
197 }
198
199 Matrix<double> P(np, np, 0.0);
200 for (std::size_t p = 0; p < np; ++p)
201 for (std::size_t q = 0; q < np; ++q)
202 P(p, q) = num_traits<T>::to_double(rtst(pairFlat[p], pairFlat[q]));
203
204 // ---- restrict to the pairs that actually carry traffic ----
205 Matrix<double> ImPt(np, np, 0.0);
206 for (std::size_t i = 0; i < np; ++i)
207 for (std::size_t j = 0; j < np; ++j) ImPt(i, j) = (i == j ? 1.0 : 0.0) - P(j, i);
208 Matrix<double> rhs0(np, 1, 0.0);
209 for (std::size_t p = 0; p < np; ++p) rhs0(p, 0) = lambda0[p];
210 const Matrix<double> lamAll = matmul(inverse(ImPt), rhs0);
211 double lamMax = 0.0;
212 for (std::size_t p = 0; p < np; ++p) lamMax = std::max(lamMax, lamAll(p, 0));
213 const double lamTol = 1e-12 * std::max(1.0, lamMax);
214 std::vector<std::size_t> keep;
215 for (std::size_t p = 0; p < np; ++p)
216 if (lamAll(p, 0) > lamTol) keep.push_back(p);
217 if (keep.empty()) throw UnsupportedError("solver_ba_snc: the model carries no open traffic");
218
219 const std::size_t nk = keep.size();
220 std::vector<double> lam(nk, 0.0), mu(nk, 0.0);
221 std::vector<std::size_t> statk(nk), clsk(nk);
222 std::vector<std::vector<double>> injk(nk, std::vector<double>(ncols, 0.0));
223 Matrix<double> Pk(nk, nk, 0.0);
224 for (std::size_t a = 0; a < nk; ++a) {
225 const std::size_t p = keep[a];
226 lam[a] = lamAll(p, 0);
227 statk[a] = pairStation[p];
228 clsk[a] = pairClass[p];
229 injk[a] = inject[p];
230 for (std::size_t b = 0; b < nk; ++b) Pk(a, b) = P(p, keep[b]);
231 mu[a] = num_traits<T>::to_double(L.rates(statk[a], clsk[a]));
232 if (!std::isfinite(mu[a]) || mu[a] <= 0)
233 throw UnsupportedError("solver_ba_snc: station " + std::to_string(statk[a] + 1) +
234 " has no service rate for class " + std::to_string(clsk[a] + 1) +
235 " but carries its traffic");
236 if (L.procid(statk[a] + 1, clsk[a] + 1) != lang::ProcessType::EXP)
237 throw UnsupportedError(
238 "solver_ba_snc: method 'snc.upper' requires exponential service: station " +
239 std::to_string(statk[a] + 1) + " class " + std::to_string(clsk[a] + 1) +
240 " is not exponential");
241 }
242
243 // ---- routing restrictions: no split downstream of the Source ----
244 for (std::size_t a = 0; a < nk; ++a) {
245 std::size_t nsucc = 0, succ = 0;
246 for (std::size_t b = 0; b < nk; ++b)
247 if (Pk(a, b) > TOL) {
248 nsucc++;
249 succ = b;
250 }
251 if (nsucc > 1)
252 throw UnsupportedError(
253 "solver_ba_snc: method 'snc.upper' requires deterministic routing downstream of "
254 "the Source: station " +
255 std::to_string(statk[a] + 1) + " class " + std::to_string(clsk[a] + 1) +
256 " splits its flow over " + std::to_string(nsucc) + " destinations");
257 if (nsucc == 1 && std::fabs(Pk(a, succ) - 1.0) > 1e-8)
258 throw UnsupportedError(
259 "solver_ba_snc: method 'snc.upper' requires deterministic routing downstream of "
260 "the Source: station " +
261 std::to_string(statk[a] + 1) + " class " + std::to_string(clsk[a] + 1) +
262 " routes onward with probability " + std::to_string(Pk(a, succ)));
263 }
264 // A Source that splits is exact only when its process is Poisson, since a
265 // Bernoulli thinning of a Poisson stream is again Poisson.
266 for (std::size_t c = 0; c < ncols; ++c) {
267 std::size_t ndest = 0;
268 for (std::size_t a = 0; a < nk; ++a)
269 if (injk[a][c] > TOL) ndest++;
270 if (ndest <= 1) continue;
271 if (L.procid(srcOfCol[c] + 1, clsOfCol[c] + 1) != lang::ProcessType::EXP)
272 throw UnsupportedError(
273 "solver_ba_snc: method 'snc.upper' can split only a Poisson Source: source " +
274 std::to_string(srcOfCol[c] + 1) + " class " + std::to_string(clsOfCol[c] + 1) +
275 " is not exponential and feeds " + std::to_string(ndest) + " stations");
276 }
277
278 // ---- one service rate per station, and a feed-forward station graph ----
279 std::vector<std::size_t> stationsUsed;
280 for (std::size_t a = 0; a < nk; ++a)
281 if (std::find(stationsUsed.begin(), stationsUsed.end(), statk[a]) == stationsUsed.end())
282 stationsUsed.push_back(statk[a]);
283 for (std::size_t u = 0; u < stationsUsed.size(); ++u) {
284 double lo = std::numeric_limits<double>::infinity(), hi = 0.0;
285 for (std::size_t a = 0; a < nk; ++a)
286 if (statk[a] == stationsUsed[u]) {
287 lo = std::min(lo, mu[a]);
288 hi = std::max(hi, mu[a]);
289 }
290 if (hi - lo > 1e-8 * std::max(1.0, hi))
291 throw UnsupportedError(
292 "solver_ba_snc: method 'snc.upper' requires the classes sharing a station to have "
293 "equal service rates: station " +
294 std::to_string(stationsUsed[u] + 1) + " carries rates in [" + std::to_string(lo) +
295 ", " + std::to_string(hi) + "]");
296 }
297
298 const std::size_t ns = stationsUsed.size();
299 std::vector<std::vector<bool>> adj(ns, std::vector<bool>(ns, false));
300 const auto stIdx = [&](std::size_t station) {
301 return static_cast<std::size_t>(
302 std::find(stationsUsed.begin(), stationsUsed.end(), station) - stationsUsed.begin());
303 };
304 for (std::size_t a = 0; a < nk; ++a)
305 for (std::size_t b = 0; b < nk; ++b)
306 if (Pk(a, b) > TOL) adj[stIdx(statk[a])][stIdx(statk[b])] = true;
307 const std::vector<std::size_t> order = detail::snc_topo_order(adj);
308 if (order.empty())
309 throw UnsupportedError(
310 "solver_ba_snc: method 'snc.upper' requires a feed-forward network: the station graph "
311 "has a cycle, so a station's cross traffic is not determined upstream of it");
312
313 // ---- envelope propagation, station by station in feed-forward order ----
314 // The departure envelopes live in a shared vector read through a pointer, so
315 // that a predecessor filled later in the same station pass is still seen.
316 auto outH = std::make_shared<std::vector<snc::Envelope>>(nk);
317 std::vector<snc::Envelope> arvH(nk), srvH(nk);
318 for (std::size_t oi = 0; oi < ns; ++oi) {
319 const std::size_t i = stationsUsed[order[oi]];
320 std::vector<std::size_t> here;
321 for (std::size_t a = 0; a < nk; ++a)
322 if (statk[a] == i) here.push_back(a);
323
324 for (std::size_t h = 0; h < here.size(); ++h) {
325 const std::size_t a = here[h];
326 std::vector<snc::Envelope> parts;
327 for (std::size_t c = 0; c < ncols; ++c) {
328 if (injk[a][c] <= TOL) continue;
329 if (L.procid(srcOfCol[c] + 1, clsOfCol[c] + 1) == lang::ProcessType::EXP) {
330 parts.push_back(snc::snc_env_poisson_fn(injk[a][c]));
331 } else {
332 const mam::Map<T> m =
333 lang::dist_to_map(L.service[srcOfCol[c]][clsOfCol[c]]);
334 Matrix<double> D0(m.D0.rows(), m.D0.cols(), 0.0);
335 Matrix<double> D1(m.D1.rows(), m.D1.cols(), 0.0);
336 for (std::size_t x = 0; x < m.D0.rows(); ++x)
337 for (std::size_t y = 0; y < m.D0.cols(); ++y) {
338 D0(x, y) = num_traits<T>::to_double(m.D0(x, y));
339 D1(x, y) = num_traits<T>::to_double(m.D1(x, y));
340 }
341 parts.push_back(snc::snc_env_map_fn(D0, D1));
342 }
343 }
344 for (std::size_t b = 0; b < nk; ++b)
345 if (Pk(b, a) > TOL)
346 parts.push_back([outH, b](double theta) { return (*outH)[b](theta); });
347 if (parts.empty())
348 throw UnsupportedError("solver_ba_snc: station " + std::to_string(i + 1) +
349 " class " + std::to_string(clsk[a] + 1) +
350 " carries traffic with no identifiable source");
351 arvH[a] = detail::snc_sum(parts);
352 }
353 for (std::size_t h = 0; h < here.size(); ++h) {
354 const std::size_t a = here[h];
355 std::vector<snc::Envelope> cross;
356 for (std::size_t g = 0; g < here.size(); ++g)
357 if (here[g] != a) cross.push_back(arvH[here[g]]);
358 const double mua = mu[a];
359 const snc::Envelope crossSum = detail::snc_sum(cross);
360 const bool alone = cross.empty();
361 srvH[a] = [mua, crossSum, alone](double theta) {
362 const snc::Env s = snc::snc_srv_exp(mua, theta);
363 if (alone) return s;
364 return snc::snc_leftover(s, crossSum(theta));
365 };
366 const snc::Envelope arva = arvH[a], srva = srvH[a];
367 (*outH)[a] = [arva, srva](double theta) {
368 return snc::snc_output(arva(theta), srva(theta), theta);
369 };
370 }
371 }
372
373 for (std::size_t a = 0; a < nk; ++a) {
374 const std::pair<std::size_t, std::size_t> key(statk[a], clsk[a]);
375 env.arv[key] = arvH[a];
376 env.srv[key] = srvH[a];
377 env.lam[key] = lam[a];
378 env.mu[key] = mu[a];
379 }
380 return env;
381}
382
383/**
384 * @param L the model
385 * @param out the (Q,U,R,Tp,C,X) block to fill; shapes are set here
386 */
387template <class T, class Solution>
388void solver_ba_snc(const qn::NetworkStruct<T>& L, Solution& out) {
389 const T zero = num_traits<T>::from_int(0);
390 const std::size_t M = L.nstations, K = L.nclasses;
392
393 out.Q = Matrix<T>(M, K, zero);
394 out.U = Matrix<T>(M, K, zero);
395 out.R = Matrix<T>(M, K, zero);
396 out.Tp = Matrix<T>(M, K, zero);
397 out.C.assign(K, zero);
398 out.X.assign(K, zero);
399 out.lG = std::numeric_limits<double>::quiet_NaN();
400 out.iter = 1;
401
402 for (std::map<std::pair<std::size_t, std::size_t>, snc::Envelope>::const_iterator it =
403 env.arv.begin();
404 it != env.arv.end(); ++it) {
405 const std::size_t i = it->first.first, r = it->first.second;
406 const double ed = snc::snc_mean_delay(it->second, env.srv.at(it->first)).value;
407 out.R(i, r) = num_traits<T>::from_double(ed);
408 out.Tp(i, r) = num_traits<T>::from_double(env.lam.at(it->first));
409 out.U(i, r) = num_traits<T>::from_double(env.lam.at(it->first) / env.mu.at(it->first));
410 }
411
412 // ---- exact open-network quantities ----
413 for (std::size_t i = 0; i < M; ++i) {
414 if (L.stations[i].nodetype != qn::NodeType::Source) continue;
415 for (std::size_t r = 0; r < K; ++r) {
416 const T arr = L.rates(i, r);
417 const double ad = num_traits<T>::to_double(arr);
418 if (std::isfinite(ad) && ad > 0) {
419 out.Tp(i, r) = T(out.Tp(i, r) + arr);
420 out.X[r] = T(out.X[r] + arr);
421 }
422 }
423 }
424 for (std::size_t i = 0; i < M; ++i)
425 for (std::size_t r = 0; r < K; ++r) out.Q(i, r) = T(out.Tp(i, r) * out.R(i, r));
426 for (std::size_t r = 0; r < K; ++r) {
427 if (out.X[r] > zero) {
428 T sum = zero;
429 for (std::size_t i = 0; i < M; ++i) sum = T(sum + out.Q(i, r));
430 out.C[r] = T(sum / out.X[r]);
431 }
432 }
433}
434
435/** The response-time and queue-length QUANTILES of the 'snc' family. */
437 /** Response-time quantile per (station, class); NaN where no traffic. */
439 /** Queue-length quantile, in jobs, per (station, class); NaN where no traffic. */
441};
442
443/**
444 * Both quantile matrices from one envelope propagation.
445 *
446 * This is the native output of the family and has no counterpart in any other
447 * BA family, which bound means only. `SolverBA.getDelayPerc` /
448 * `getBacklogPerc` / `getPercTable` in MATLAB, the JAR and Python are the same
449 * call.
450 *
451 * @param L the model
452 * @param eps violation probability, 0 < eps < 1
453 */
454template <class T>
457 const double nan = std::numeric_limits<double>::quiet_NaN();
458 SncPercentiles out;
459 out.D = Matrix<double>(L.nstations, L.nclasses, nan);
460 out.B = Matrix<double>(L.nstations, L.nclasses, nan);
461 for (std::map<std::pair<std::size_t, std::size_t>, snc::Envelope>::const_iterator it =
462 env.arv.begin();
463 it != env.arv.end(); ++it) {
464 const std::size_t i = it->first.first, r = it->first.second;
465 out.D(i, r) = snc::snc_perc_delay(it->second, env.srv.at(it->first), eps).value;
466 out.B(i, r) = snc::snc_perc_backlog(it->second, env.srv.at(it->first), eps).value;
467 }
468 return out;
469}
470
471} // namespace ba
472} // namespace line
473
474#endif // LINE_SOLVERS_BA_SOLVER_BA_SNC_H
UnsupportedError(const std::string &what)
Definition error.h:51
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::vector< JobClass > classes
ProcessType procid(std::size_t ist, std::size_t r) const
sn.procid(i,r): the process type of a (station, class) pair.
std::vector< Station< T > > stations
stations[k-1] is the k-th station
Matrix< T > rates
(nstations x nclasses) service rates and SCVs, with a PARALLEL disabled flag instead of MATLAB's NaN ...
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
The exception types the port throws.
Dense matrix and non-owning view.
SnRtStations< T > sn_rt_stations(const qn::NetworkStruct< T > &sn)
void solver_ba_snc(const qn::NetworkStruct< T > &L, Solution &out)
SncPercentiles solver_ba_snc_perc(const qn::NetworkStruct< T > &L, double eps)
Both quantile matrices from one envelope propagation.
SncEnvelopes solver_ba_snc_envelopes(const qn::NetworkStruct< T > &L)
Builds the per-pair (arrival, service) envelopes of a feed-forward model.
mam::Map< T > dist_to_map(const Distrib< T > &d)
Env snc_leftover(const Env &srv, const Env &cross)
Leftover service envelope under blind (arbitrary) multiplexing.
Env snc_output(const Env &arv, const Env &srv, double theta)
Output (departure) arrival envelope of a flow leaving a server.
Definition snc_output.h:40
Envelope snc_env_map_fn(const Matrix< double > &D0, const Matrix< double > &D1)
The same envelope as a function of theta.
Env snc_srv_exp(double mu, double theta)
MGF service envelope of an exponential server, in JOB units.
Definition snc_srv_exp.h:46
Envelope snc_env_poisson_fn(double lambda)
The same envelope as a function of theta.
std::function< Env(double)> Envelope
An envelope as a function of the Chernoff parameter.
Definition snc_types.h:48
SncResult snc_mean_delay(const Envelope &arv, const Envelope &srv, double thetamax=1e3)
Upper bound on the mean delay, from integrating the delay tail bound.
SncResult snc_perc_delay(const Envelope &arv, const Envelope &srv, double eps, double thetamax=1e3)
Delay quantile at a prescribed violation probability.
SncResult snc_perc_backlog(const Envelope &arv, const Envelope &srv, double eps, double thetamax=1e3)
Backlog quantile at a prescribed violation probability.
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Definition linalg.h:72
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
Definition linalg.h:36
A queueing network and its refreshed NetworkStruct.
Port of matlab/src/api/sn/sn_rt_stations.m.
MGF arrival envelope of a MAP/MMPP flow with unit-size jobs.
MGF arrival envelope of a Poisson flow with unit-size jobs.
Leftover service envelope under blind (arbitrary) multiplexing.
Upper bound on the mean delay, from integrating the delay tail bound.
Output (departure) arrival envelope of a flow leaving a server.
Backlog quantile at a prescribed violation probability.
Delay quantile at a prescribed violation probability.
MGF service envelope of an exponential server, in JOB units.
The per-pair envelopes the analyzer built, keyed by (station, class).
std::map< std::pair< std::size_t, std::size_t >, snc::Envelope > arv
std::map< std::pair< std::size_t, std::size_t >, snc::Envelope > srv
std::map< std::pair< std::size_t, std::size_t >, double > lam
std::map< std::pair< std::size_t, std::size_t >, double > mu
The response-time and queue-length QUANTILES of the 'snc' family.
Matrix< double > D
Response-time quantile per (station, class); NaN where no traffic.
Matrix< double > B
Queue-length quantile, in jobs, per (station, class); NaN where no traffic.
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
The pair (sigma, rho) of an envelope evaluated at one theta.
Definition snc_types.h:42
double value
The bound: a violation probability, a quantile or a mean bound.
Definition snc_types.h:53