5#ifndef LINE_API_QSYS_QSYS_MGCK_SYNC_H
6#define LINE_API_QSYS_QSYS_MGCK_SYNC_H
110 for (std::size_t i = 0; i < M.
rows(); ++i)
112 for (std::size_t j = 0; j < M.
cols(); ++j) R(i, j) = zero;
121 for (std::size_t j = 0; j < M.
cols(); ++j)
123 for (std::size_t i = 0; i < M.
rows(); ++i) R(i, j) = zero;
130 for (std::size_t i = 0; i < A.
rows(); ++i)
131 for (std::size_t j = 0; j < A.
cols(); ++j) C(i, j) += B(i, j);
142 const std::size_t dim = QG.
rows();
145 for (std::size_t i = 0; i < dim; ++i)
146 for (std::size_t j = 0; j < dim; ++j) P(i, j) += QG(i, j) / theta;
147 const std::size_t n = cn.size();
149 std::vector<T> dn(n, zero);
152 for (std::size_t k = n; k-- > 0;) {
153 dn[k] = tail / theta;
160 for (std::size_t k = 0; k < n; ++k) {
161 for (std::size_t i = 0; i < dim; ++i)
162 for (std::size_t j = 0; j < dim; ++j) {
163 const T v = Pn(i, j);
164 if (v == zero)
continue;
165 Om(i, j) += cn[k] * v;
166 Ps(i, j) += dn[k] * v;
168 if (k + 1 < n) Pn =
matmul(Pn, P);
176 const std::size_t dim = Q.
rows();
179 std::vector<T> dinv(dim, zero);
180 for (std::size_t i = 0; i < dim; ++i)
181 if (QE(i, i) != zero) dinv[i] = one / QE(i, i);
183 for (std::size_t i = 0; i < dim; ++i) {
184 if (inE[i]) P(i, i) += one;
185 for (std::size_t j = 0; j < dim; ++j) P(i, j) -= dinv[i] * QE(i, j);
188 for (std::size_t i = 0; i < dim; ++i) C(i, i) -= dinv[i];
190 for (std::size_t i = 0; i < dim; ++i) {
192 for (std::size_t j = 0; j < dim; ++j) s += P(i, j);
193 const T d =
num_abs(T(s - one));
194 if (d > rowdev) rowdev = d;
198 "qsys_mgck_sync: embedded chain rows deviate from 1 by " +
202 for (std::size_t i = 0; i < dim; ++i)
203 for (std::size_t j = 0; j < dim; ++j) A(i, j) = P(j, i) - (i == j ? one : zero);
204 for (std::size_t j = 0; j < dim; ++j) {
206 for (std::size_t k = 0; k < dim; ++k) s += C(j, k);
209 std::vector<T> b(dim, zero);
211 const std::vector<T> u =
solve(A, b);
212 std::vector<T> pi =
vecmul(u, C);
214 for (
const T& v : pi) tot += v;
215 for (T& v : pi) v /= tot;
221 std::size_t nmaxCap) {
229 bool faster,
const T& tol, std::size_t nmaxCap, std::vector<std::size_t>& level) {
230 const std::size_t dim = K + 1;
232 Matrix<T> Q(dim, dim, zero), Qbar(dim, dim, zero), Delta(dim, dim, zero);
235 for (std::size_t i = 1; i <= K; ++i) {
238 if (!faster && i < c) Qbar(i, i + 1) = lambda;
239 else Q(i, i + 1) = lambda;
241 Delta(i, i > c ? i - c : 0) = one;
243 std::vector<bool> inE(dim,
false), inG(dim,
true);
246 const std::vector<T> cn =
coefficients(svc, lambda, tol, nmaxCap);
252 for (std::size_t i = 0; i < dim; ++i) level[i] = i;
253 return emc(Q, inE,
matmul(Om, Delta), Ps, Qbar);
261 void add(std::size_t i, std::size_t j,
const T& v) {
268 for (std::size_t k = 0; k <
val.size(); ++k) M(
from[k],
to[k]) +=
val[k];
277inline std::vector<int>
tick(
int a,
int q,
const std::vector<int>& B,
int nph) {
281 if (b + 1 >= nph) ++done;
282 else Bn.push_back(b + 1);
284 const int start = std::min(done, q);
285 for (
int k = 0; k < start; ++k) Bn.push_back(0);
286 std::sort(Bn.begin(), Bn.end());
289 s.push_back(q - start);
290 s.insert(s.end(), Bn.begin(), Bn.end());
294inline std::vector<int>
make_state(
int a,
int q,
const std::vector<int>& B) {
298 s.insert(s.end(), B.begin(), B.end());
304std::vector<T>
expanded(
const T& lambda, std::size_t c, std::size_t K,
const T& d, std::size_t nphU,
305 bool faster,
const T& tol, std::size_t nmaxCap,
306 std::vector<std::size_t>& level) {
308 const int lo = faster ? 0 : -1;
309 const int nph =
static_cast<int>(nphU);
310 const int ci =
static_cast<int>(c), Ki =
static_cast<int>(K);
311 std::map<std::vector<int>, std::size_t> keys;
312 std::vector<std::vector<int>> states;
313 auto add = [&](
const std::vector<int>& s) -> std::size_t {
314 const auto it = keys.find(s);
315 if (it != keys.end())
return it->second;
317 const std::size_t
id = states.size() - 1;
324 std::vector<bool> inA, inB;
326 for (std::size_t head = 0; head < states.size(); ++head) {
327 const std::vector<int> s = states[head];
328 const int a = s[0], q = s[1];
329 const std::vector<int> B(s.begin() + 2, s.end());
330 const int tot = a + q +
static_cast<int>(B.size());
331 inA.resize(states.size(),
false);
332 inB.resize(states.size(),
false);
334 TQ.
add(head, head, -lambda);
335 TQ.
add(head, add(
make_state(1, 0, std::vector<int>())), lambda / cT);
338 lambda * (cT - one) / cT);
346 if (1 +
static_cast<int>(B.size()) < ci) {
347 std::vector<int> Bn = B;
349 std::sort(Bn.begin(), Bn.end());
354 TQ.
add(head, head, -lambda);
355 TQ.
add(head, add(t), lambda);
357 TDBA.
add(head, add(
tick(1, q, B, nph)), one);
366 if (b + 1 < nph) Bn.push_back(b + 1);
370 TQ.
add(head, head, -lambda);
373 TDB.
add(head, add(
tick(0, q, B, nph)), one);
376 const std::size_t dim = states.size();
377 inA.resize(dim,
false);
378 inB.resize(dim,
false);
379 std::vector<bool> inE(dim,
false);
380 for (std::size_t i = 0; i < dim; ++i) inE[i] = !inA[i] && !inB[i];
385 const std::vector<T> cn =
393 for (std::size_t j = 1; j < nphU; ++j) {
403 for (std::size_t i = 0; i < dim; ++i)
404 level[i] =
static_cast<std::size_t
>(states[i][0] + states[i][1]) + (states[i].size() - 2);
427 std::size_t nphases,
const T& tol, std::size_t nmaxCap) {
429 "qsys_mgck_sync requires transcendental arithmetic");
431 if (!(lambda > zero))
throw InputError(
"qsys_mgck_sync: lambda must be a positive real scalar");
432 if (c < 1)
throw InputError(
"qsys_mgck_sync: c must be a positive integer");
433 if (K < c)
throw InputError(
"qsys_mgck_sync: K must be an integer >= c");
434 std::string v = variant;
435 std::transform(v.begin(), v.end(), v.begin(),
436 [](
unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
437 if (v !=
"faster" && v !=
"slower")
438 throw InputError(
"qsys_mgck_sync: Unknown variant '" + variant +
439 "'; use 'faster' or 'slower'.");
440 const bool faster = (v ==
"faster");
442 std::vector<std::size_t> level;
449 "qsys_mgck_sync: The synchronous phase expansion (nphases >= 1) requires a "
450 "deterministic service time.");
457 for (std::size_t s = 0; s < pi.size(); ++s) r.
queueLengthDist[level[s]] += pi[s];
458 T L = zero, Lq = zero, busy = zero;
459 for (std::size_t n = 0; n <= K; ++n) {
478 r.
analyzer =
"sync." + v +
":M/G/" + std::to_string(c) +
"/" + std::to_string(K);
480 r.
analyzer =
"sync." + v +
".n" + std::to_string(nphases) +
":M/D/" + std::to_string(c) +
481 "/" + std::to_string(K);
489 std::size_t nphases = 0) {
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
The exception types the port throws.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Running progress log of a LINE solver run (the "solver console").
LU factorization with partial pivoting, templated on the number type.
Dense matrix and non-owning view.
std::vector< int > make_state(int a, int q, const std::vector< int > &B)
void unif(const Matrix< T > &QG, const std::vector< T > &cn, const T &theta, Matrix< T > &Om, Matrix< T > &Ps)
i_unif: Om = E[exp(QG S)], Ps = E[int_0^S exp(QG t) dt] from c_n at rate theta, with d_n = (1 - sum_{...
std::vector< T > emc(const Matrix< T > &Q, const std::vector< bool > &inE, const Matrix< T > &OmDelta, const Matrix< T > &Psi, const Matrix< T > &Qbar)
i_emc: stationary law of the embedded chain at regenerations, converted to time.
std::vector< int > tick(int a, int q, const std::vector< int > &B, int nph)
i_tick: advance every non-owner phase by one tick; a completed job frees its server for a waiting one...
Matrix< T > colmask(const Matrix< T > &M, const std::vector< bool > &keep)
Column-masked copy: M diag(keep).
std::vector< T > expanded(const T &lambda, std::size_t c, std::size_t K, const T &d, std::size_t nphU, bool faster, const T &tol, std::size_t nmaxCap, std::vector< std::size_t > &level)
i_expanded: synchronous phase expansion; states are [a, q, sorted B phases].
Matrix< T > matadd(const Matrix< T > &A, const Matrix< T > &B)
std::vector< T > coefficients(const ServiceLaw< T > &svc, const T &lambda, const T &tol, std::size_t nmaxCap)
std::vector< T > plain(const T &lambda, std::size_t c, std::size_t K, const ServiceLaw< T > &svc, bool faster, const T &tol, std::size_t nmaxCap, std::vector< std::size_t > &level)
i_plain: synchronous approximation without state expansion; state i <-> i jobs.
Matrix< T > rowmask(const Matrix< T > &M, const std::vector< bool > &keep)
Row-masked copy: rows with keep[i] false are zeroed, i.e.
SvclawCoeffsResult< T > qsys_svclaw_coeffs(const ServiceLaw< T > &svc, const T &theta, const T &tol, std::size_t nmaxCap)
qsys_svclaw_coeffs: uniformization coefficients of a service-time descriptor; see qsys_svclaw_coeffs....
MgckSyncResult< T > qsys_mgck_sync(const T &lambda, std::size_t c, std::size_t K, const ServiceLaw< T > &svc, const std::string &variant, std::size_t nphases, const T &tol, std::size_t nmaxCap)
Synchronous approximation of the M/G/c/K queue with dual bounds.
Conservation laws of a layered queueing network, enumerated from its structure.
std::vector< T > vecmul(const std::vector< T > &v, const Matrix< T > &A)
Row vector times matrix, v A.
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Matrix< T > eye(std::size_t n)
Identity of order n.
Number-type abstraction for the templated API port.
The MAP/G/1/K queue with tail drop: Markovian arrivals, an arbitrary service law F,...
Uniformization coefficients of a service-time descriptor, shared by the qsys functions that take the ...
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Return value of qsys_mgck_sync, mirroring the MATLAB result struct.
T meanSojournTime
meanQueueLength / throughput
T meanQueueLengthQ
mean number waiting
T utilization
mean busy servers / c in the synchronized model
T meanQueueLength
mean number in system
T meanWaitingTime
meanQueueLengthQ / throughput
T throughput
lambda (1 - pK)
std::string variant
"faster" or "slower"
std::vector< T > queueLengthDist
P(n jobs in system), n = 0..K.
std::size_t stateSpaceSize
T lossProbability
pK (PASTA)
Service-time descriptor, the C++ form of the MATLAB svc struct.
static ServiceLaw deterministic(const T &d)
Constant service time d.
T det
deterministic service time
A sparse transition list, summed into a dense matrix as MATLAB's sparse() does.
std::vector< std::size_t > from
std::vector< std::size_t > to
void add(std::size_t i, std::size_t j, const T &v)
Matrix< T > dense(std::size_t dim) const