5#ifndef LINE_SOLVERS_MAM_SOLVER_MNA_H
6#define LINE_SOLVERS_MAM_SOLVER_MNA_H
123namespace mna_detail {
153 ": Fork nodes are not supported yet by the QNA-family solvers, as "
154 "the reference's line_error states");
157 who +
": the reference indexes the stateful-indexed sn.rt with station indices, which "
158 "is only correct when every stateful node is a station; this model has " +
159 std::to_string(L.
nof_stateful()) +
" stateful nodes and " +
160 std::to_string(L.
nstations) +
" stations");
168 std::vector<std::vector<PhService<T>>> svc(M, std::vector<PhService<T>>(K));
169 for (std::size_t i = 0; i < M; ++i) {
173 for (std::size_t r = 0; r < K; ++r) {
180 svc[i][r].sigma.assign(1, one);
197using basic_detail::station_visits;
208Matrix<T> init_flow_scv(
const qn::NetworkStruct<T>& L,
const std::vector<bool>& is_source,
209 const Matrix<T>& kRR) {
210 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
211 const std::size_t M = L.nstations, K = L.nclasses;
212 Matrix<T> f2(M * K, M * K, zero);
213 for (std::size_t i = 0; i < M; ++i)
214 for (std::size_t j = 0; j < M; ++j) {
215 if (is_source[j])
continue;
216 for (std::size_t r = 0; r < K; ++r)
217 for (std::size_t s = 0; s < K; ++s) {
218 const T p = L.rt(i * K + r, j * K + s);
219 if (p > zero) f2(i * K + r, j * K + s) = T(one + p * T(one - kRR(i, r)));
230void superpose(
const qn::NetworkStruct<T>& L,
const Matrix<T>& Tp,
const Matrix<T>& f2,
231 Matrix<T>& a1, Matrix<T>& a2) {
232 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
233 const std::size_t M = L.nstations, K = L.nclasses;
234 for (std::size_t i = 0; i < M; ++i) {
236 for (std::size_t k = 0; k < K; ++k) lambda_i += Tp(i, k);
237 for (std::size_t r = 0; r < K; ++r) {
241 for (std::size_t j = 0; j < M; ++j)
242 for (std::size_t r = 0; r < K; ++r)
243 for (std::size_t s = 0; s < K; ++s) {
244 const T p = L.rt(j * K + s, i * K + r);
245 if (!(p > zero))
continue;
246 a1(i, r) = T(a1(i, r) + Tp(j, s) * p);
252 a2(i, r) = T(a2(i, r) + T(one / lambda_i) * f2(j * K + s, i * K + r) *
266void split(
const qn::NetworkStruct<T>& L,
const std::vector<bool>& is_source,
267 const std::vector<T>& d2,
const Matrix<T>& kRR, Matrix<T>& f2) {
268 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
269 const std::size_t M = L.nstations, K = L.nclasses;
270 for (std::size_t i = 0; i < M; ++i)
271 for (std::size_t j = 0; j < M; ++j) {
272 if (is_source[j])
continue;
273 for (std::size_t r = 0; r < K; ++r)
274 for (std::size_t s = 0; s < K; ++s) {
275 const T p = L.rt(i * K + r, j * K + s);
276 if (p > zero) f2(i * K + r, j * K + s) = T(one + p * T(d2[i] - kRR(i, r)));
283T qna_departure_scv(
const qn::NetworkStruct<T>& L, std::size_t i0,
const Matrix<T>& a1,
284 const Matrix<T>& a2,
const Matrix<T>& scv,
const T& lambda_ist,
const T& rho,
287 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
288 const T mubar = (rho > zero) ? T(lambda_ist / rho) : zero;
290 for (std::size_t r = 0; r < L.nclasses; ++r) {
291 if (L.disabled[i0][r] || !(L.rates(i0, r) > zero) || !(lambda_ist > zero))
continue;
292 const T q = T(mubar / mi / L.rates(i0, r));
293 c2 += T(T(a1(i0, r) / lambda_ist) * q * q * T(scv(i0, r) + one));
296 for (std::size_t r = 0; r < L.nclasses; ++r) a2sum += a2(i0, r);
297 return T(one + T(rho * rho * T(c2 - one) / sqrt(mi)) + T(T(one - rho * rho) * T(a2sum - one)));
309T station_rho(
const qn::NetworkStruct<T>& L, std::size_t i0,
const Matrix<T>& a1,
const T& mi) {
310 const T zero = num_traits<T>::from_int(0);
311 const T ftol = num_traits<T>::from_double(GlobalConstants::FineTol);
313 for (std::size_t r = 0; r < L.nclasses; ++r) {
314 if (L.disabled[i0][r])
continue;
315 rho += T(a1(i0, r) / T(ftol + L.rates(i0, r)));
340Mmap<T> arrival_mmap(
const Matrix<T>& a1,
const Matrix<T>& a2, std::size_t i0, std::size_t K,
341 bool bounded, std::size_t space_max) {
342 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
344 for (std::size_t k = 0; k < K; ++k) {
346 if (a1(i0, k) == zero) {
349 cur.Dc.assign(1, Matrix<T>(1, 1, zero));
351 const Map<T> ph = aph_fit_mean_scv(T(one / a1(i0, k)), a2(i0, k));
354 cur.Dc.assign(1, ph.D1);
356 if (k == 0) node = cur;
357 else if (bounded) node =
mmap_super_safe(std::vector<Mmap<T>>{node, cur}, space_max);
365using basic_detail::zero_nans;
386 "solver_mna_open: the flow fixed point stops on a tolerance, the APH arrival fit takes "
387 "a ceiling of a real reciprocal, and the MMAP[K]/PH[K]/1 station solve runs the ADDA "
388 "doubling iteration; rerun this model with --arith double or --arith real");
390 using namespace mna_detail;
395 check_gates(L,
"solver_mna_open");
399 "solver_mna_open: MNA's open analyzer takes its arrival rates from the class "
400 "sources; a closed chain has none and belongs to solver_mna_closed");
401 if (cfg.dep_scv ==
"etaqa")
403 "solver_mna_open: config.dep_scv = 'etaqa' reads the departure SCV off "
404 "qbd_depproc_jointmom, and the MATLAB routine of that name raises a dimension error "
405 "on EVERY input this branch can hand it -- it slices the level-0 vector as pi(1,:) "
406 "from a QBD_pi that returns one long row, so v0 is numLevels times too long "
407 "(measured: arrival/service orders 1/1, 1/2 and 2/2 all throw). The reference's "
408 "try/catch therefore always falls back to the QNA formula, while the ported "
409 "qbd_depproc_jointmom takes the correct slice and SUCCEEDS; running it here would "
410 "report a departure SCV the reference never produces. Use the default 'qna'");
411 if (cfg.dep_scv !=
"qna")
412 throw UnsupportedError(
"solver_mna_open: unknown config.dep_scv '" + cfg.dep_scv +
413 "'; the reference offers 'qna' and 'etaqa'");
415 Matrix<T> S(M, K, zero), scv(M, K, zero);
416 for (std::size_t i = 0; i < M; ++i)
417 for (std::size_t r = 0; r < K; ++r) {
420 scv(i, r) = std::isnan(v) ? zero : L.
scv(i, r);
423 const std::vector<std::vector<PhService<T>>> svc = service_laws(L);
425 std::vector<bool> is_source(M,
false);
426 for (std::size_t i = 0; i < M; ++i)
427 is_source[i] = (L.
stations[i].nodetype == qn::NodeType::Source);
430 Matrix<T> f2 = init_flow_scv(L, is_source, kRR);
432 Matrix<T> Q(M, K, zero), U(M, K, zero), R(M, K, zero), Tp(M, K, zero);
433 Matrix<T> a1(M, K, zero), a2(M, K, zero);
434 std::vector<T> d2(M, zero), lambda(C, zero);
437 std::vector<T> d2c(C, zero);
438 std::size_t sourceIdx = 0;
439 for (std::size_t c = 0; c < C; ++c) {
442 std::vector<T> lam_in, scv_in;
443 for (std::size_t k : L.
inchain[c]) {
444 lam_in.push_back(L.
disabled[ref - 1][k - 1] ? zero : L.
rates(ref - 1, k - 1));
445 scv_in.push_back(scv(ref - 1, k - 1));
447 for (
const T& x : lam_in)
450 for (std::size_t a = 0; a < L.
inchain[c].size(); ++a)
451 Tp(ref - 1, L.
inchain[c][a] - 1) = lam_in[a];
459 "solver_mna_open: the reference seeds the source departure SCV with "
460 "d2c(sourceIdx,:), indexing the 1 x nchains vector d2c by the reference STATION " +
461 std::to_string(sourceIdx) +
462 "; MATLAB evaluates that only when the reference station is station 1");
464 T num = zero, den = zero;
465 for (std::size_t c = 0; c < C; ++c) {
466 num += T(d2c[c] * lambda[c]);
469 if (den > zero) d2[sourceIdx - 1] = T(num / den);
473 auto sweep = [&](
const std::vector<T>&,
474 std::size_t itnum) -> std::pair<std::vector<T>, std::vector<T>> {
475 std::vector<T> xref(2 * M * K, zero);
476 for (std::size_t i = 0; i < M; ++i)
477 for (std::size_t k = 0; k < K; ++k) {
478 xref[i * K + k] = a1(i, k);
479 xref[M * K + i * K + k] = a2(i, k);
483 for (std::size_t c = 0; c < C; ++c)
484 for (std::size_t m = 0; m < M; ++m)
485 for (std::size_t k : L.
inchain[c]) Tp(m, k - 1) = T(V(m, k - 1) * lambda[c]);
487 superpose(L, Tp, f2, a1, a2);
491 for (std::size_t i = 0; i < M; ++i) {
494 if (sched == SchedStrategy::INF) {
498 for (std::size_t c = 0; c < C; ++c)
499 for (std::size_t k : L.
inchain[c]) {
500 const std::size_t r = k - 1;
502 U(i, r) = T(S(i, r) * Tp(i, r));
503 Q(i, r) = T(Tp(i, r) * S(i, r) * V(i, r));
504 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
506 }
else if (sched == SchedStrategy::PS) {
511 }
else if (sched == SchedStrategy::FCFS) {
513 for (std::size_t r = 0; r < K; ++r) lambda_ist += a1(i, r);
514 const T rho = station_rho(L, i, a1, mi);
515 if (rho < T(one - tol)) {
516 d2[i] = qna_departure_scv(L, i, a1, a2, scv, lambda_ist, rho, mi);
518 for (std::size_t r = 0; r < K; ++r)
522 for (std::size_t r = 0; r < K; ++r) {
524 U(i, r) = T(Tp(i, r) * S(i, r) / mi);
526 }
else if (sched != SchedStrategy::EXT) {
528 std::string(
"solver_mna_open: no isolated-station solution for ") +
534 split(L, is_source, d2, kRR, f2);
536 std::vector<T> xnew(2 * M * K, zero);
537 for (std::size_t i = 0; i < M; ++i)
538 for (std::size_t k = 0; k < K; ++k) {
539 xnew[i * K + k] = a1(i, k);
540 xnew[M * K + i * K + k] = a2(i, k);
542 return std::make_pair(xnew, xref);
546 fo.
iter_max =
static_cast<std::size_t
>(
opt.iter_max) + 1;
552 for (std::size_t i = 0; i < M; ++i) {
553 if (L.
stations[i].sched != SchedStrategy::FCFS)
continue;
555 const T rho = station_rho(L, i, a1, mi);
556 if (!(rho < T(one - tol))) {
557 for (std::size_t r = 0; r < K; ++r) {
559 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
563 const Mmap<T> arv = arrival_mmap(a1, a2, i, K,
false,
opt.space_max);
564 std::vector<PhService<T>> sl;
565 for (std::size_t r = 0; r < K; ++r) sl.push_back(svc[i][r]);
567 if (std::isfinite(L.
cap[i])) {
568 const std::size_t capK =
static_cast<std::size_t
>(std::llround(L.
cap[i]));
569 T meanQ = zero, lossProb = zero;
573 for (std::size_t r = 0; r < K; ++r)
574 if (!L.
disabled[i][r]) lamTot += a1(i, r);
576 lamTot, det.
muRate,
static_cast<unsigned>(std::llround(L.
stations[i].nservers)),
577 static_cast<unsigned>(capK));
581 const basic_detail::TruncRenorm<T>
tr =
582 basic_detail::truncate_renorm(arv, sl, capK);
584 lossProb =
tr.lossProb;
588 std::vector<T> eff(K, zero);
590 for (std::size_t r = 0; r < K; ++r) {
591 const T inflow = L.
disabled[i][r] ? zero : a1(i, r);
592 eff[r] = T(inflow * T(one - lossProb));
598 for (std::size_t r = 0; r < K; ++r)
599 if (!L.
disabled[i][r]) sw += T(eff[r] * S(i, r));
600 const T w = T(T(meanQ / sumT) - T(sw / sumT));
601 Wq = (w > zero) ? w : zero;
603 for (std::size_t r = 0; r < K; ++r) {
605 U(i, r) = T(Tp(i, r) * S(i, r) / mi);
606 if (Tp(i, r) > zero) {
607 R(i, r) = T(Wq + S(i, r));
608 Q(i, r) = T(Tp(i, r) * R(i, r));
616 for (std::size_t r = 0; r < K; ++r) {
617 Q(i, r) = m[arv.
classes() == 1 ? 0 : r];
618 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
628 out.
C.assign(K, zero);
630 out.
X.assign(K, zero);
631 for (std::size_t k = 0; k < K; ++k)
632 for (std::size_t i = 0; i < M; ++i) out.
C[k] += R(i, k);
633 for (std::size_t i = 0; i < M; ++i)
634 for (std::size_t k = 0; k < K; ++k)
635 if (out.
Q(i, k) < zero) out.
Q(i, k) = T(-out.
Q(i, k));
639 for (std::size_t k = 0; k < K; ++k)
661 "solver_mna_closed: the throughput bisection and the inner flow fixed point stop on a "
662 "tolerance, the APH arrival fit takes a ceiling of a real reciprocal, and the "
663 "MMAP[K]/PH[K]/1 station solve runs the ADDA doubling iteration; rerun this model "
664 "with --arith double or --arith real");
666 using namespace mna_detail;
672 const std::size_t space_max = 16;
674 check_gates(L,
"solver_mna_closed");
677 "solver_mna_closed: the reference drives its bisection over classes but stores the "
678 "throughput in the chain-indexed lambda, and renormalizes chain c's queue lengths "
679 "with the class-indexed sn.njobs(c); both are only correct when each chain holds "
680 "exactly one class, and this model has " +
681 std::to_string(C) +
" chains over " + std::to_string(K) +
" classes");
682 std::vector<double> Npop(K, 0.0);
683 for (std::size_t r = 0; r < K; ++r) {
684 if (!std::isfinite(L.
classes[r].population))
686 "solver_mna_closed: MNA's closed analyzer brackets each class's throughput by its "
687 "population; an open class has none and belongs to solver_mna_open");
688 Npop[r] = L.
classes[r].population;
691 Matrix<T> S(M, K, zero), scv(M, K, zero);
692 for (std::size_t i = 0; i < M; ++i)
693 for (std::size_t r = 0; r < K; ++r) {
696 scv(i, r) = std::isnan(v) ? zero : L.
scv(i, r);
699 const std::vector<std::vector<PhService<T>>> svc = service_laws(L);
700 std::vector<bool> is_source(M,
false);
701 for (std::size_t i = 0; i < M; ++i)
702 is_source[i] = (L.
stations[i].nodetype == qn::NodeType::Source);
713 std::vector<T> lambda_lb(K, zero), lambda_ub(K, zero), lambda(K, zero);
714 for (std::size_t r = 0; r < K; ++r) {
717 for (std::size_t i = 0; i < M; ++i) {
718 if (!std::isfinite(L.
stations[i].nservers))
continue;
721 if (!any || v < best) {
728 "solver_mna_closed: class '" + L.
classes[r].name +
729 "' is served at no finite-server station, so the reference's throughput upper "
730 "bound min(sn.rates(sn.nservers<Inf,k)) is empty and the assignment fails");
734 Matrix<T> Q(M, K, zero), U(M, K, zero), R(M, K, zero), Tp(M, K, zero);
735 Matrix<T> a1(M, K, zero), a2(M, K, zero), f2(M * K, M * K, zero);
736 std::vector<T> d2(M, zero);
737 std::vector<T> QN(K, zero);
738 std::vector<T> QNc(K, zero);
739 for (std::size_t r = 0; r < K; ++r) QNc[r] = num_traits<T>::from_double(Npop[r]);
743 std::size_t maxLevel = 1;
744 for (std::size_t r = 0; r < K; ++r) maxLevel += static_cast<std::size_t>(std::llround(Npop[r]));
747 auto flow_sweep = [&](
const std::vector<T>&,
748 std::size_t itnum) -> std::pair<std::vector<T>, std::vector<T>> {
749 std::vector<T> xref(2 * M * K, zero);
750 for (std::size_t i = 0; i < M; ++i)
751 for (std::size_t k = 0; k < K; ++k) {
752 xref[i * K + k] = a1(i, k);
753 xref[M * K + i * K + k] = a2(i, k);
762 for (std::size_t c = 0; c < C; ++c) {
764 for (std::size_t i = 0; i < M; ++i) colsum += Q(i, c);
765 for (std::size_t i = 0; i < M; ++i)
771 for (std::size_t c = 0; c < C; ++c)
772 for (std::size_t m = 0; m < M; ++m)
773 for (std::size_t k : L.
inchain[c]) Tp(m, k - 1) = T(V(m, k - 1) * lambda[c]);
775 superpose(L, Tp, f2, a1, a2);
777 for (std::size_t i = 0; i < M; ++i) {
778 if (L.
stations[i].nodetype == qn::NodeType::Join)
continue;
781 if (sched == SchedStrategy::INF) {
783 for (std::size_t c = 0; c < C; ++c)
784 for (std::size_t k : L.
inchain[c]) {
785 const std::size_t r = k - 1;
787 U(i, r) = T(S(i, r) * Tp(i, r));
788 Q(i, r) = T(Tp(i, r) * S(i, r) * V(i, r));
789 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
791 }
else if (sched == SchedStrategy::PS) {
793 for (std::size_t c = 0; c < C; ++c) {
795 for (std::size_t k : L.
inchain[c]) Nc += Npop[k - 1];
796 for (std::size_t k : L.
inchain[c]) {
797 const std::size_t r = k - 1;
798 Tp(i, r) = T(lambda[c] * V(i, r));
799 U(i, r) = T(S(i, r) * Tp(i, r));
802 for (std::size_t r = 0; r < K; ++r) usum += U(i, r);
804 const T uden = (usum < T(one - ftol)) ? usum : T(one - ftol);
805 for (std::size_t k : L.
inchain[c]) {
806 const std::size_t r = k - 1;
811 Q(i, r) = T(T(U(i, r) - tail) / T(one - uden));
812 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
815 }
else if (sched == SchedStrategy::FCFS) {
817 for (std::size_t r = 0; r < K; ++r) lambda_ist += a1(i, r);
818 const T rho = station_rho(L, i, a1, mi);
819 if (rho < T(one - tol)) {
820 d2[i] = qna_departure_scv(L, i, a1, a2, scv, lambda_ist, rho, mi);
825 for (std::size_t r = 0; r < K; ++r) {
827 U(i, r) = T(Tp(i, r) * S(i, r) / mi);
828 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
830 }
else if (sched != SchedStrategy::EXT) {
832 std::string(
"solver_mna_closed: no isolated-station solution for ") +
838 split(L, is_source, d2, kRR_one, f2);
840 std::vector<T> xnew(2 * M * K, zero);
841 for (std::size_t i = 0; i < M; ++i)
842 for (std::size_t k = 0; k < K; ++k) {
843 xnew[i * K + k] = a1(i, k);
844 xnew[M * K + i * K + k] = a2(i, k);
846 return std::make_pair(xnew, xref);
850 auto outer_sweep = [&](
const std::vector<T>&,
851 std::size_t itout) -> std::pair<std::vector<T>, std::vector<T>> {
855 for (std::size_t r = 0; r < K; ++r) {
856 if (QN[r] < QNc[r]) lambda_lb[r] = lambda[r];
857 else lambda_ub[r] = lambda[r];
871 f2 = init_flow_scv(L, is_source, kRR_one);
874 io.iter_max =
static_cast<std::size_t
>(
opt.iter_max) + 1;
875 io.iter_tol =
opt.tol;
879 for (std::size_t i = 0; i < M; ++i) {
880 if (L.
stations[i].sched != SchedStrategy::FCFS)
continue;
882 const T rho = station_rho(L, i, a1, mi);
883 if (!(rho < T(one - tol))) {
886 const Mmap<T> arv = arrival_mmap(a1, a2, i, K,
true, space_max);
889 probe.
D1 = arv.
Dc[0];
891 for (std::size_t r = 0; r < K; ++r)
892 Q(i, r) = (L.
rates(i, 0) > zero)
897 std::vector<PhService<T>> sl;
898 for (std::size_t r = 0; r < K; ++r) sl.push_back(svc[i][r]);
904 const std::vector<T>& pdistr = pd[0];
906 for (std::size_t n = 0; n + 1 < maxLevel; ++n) head += pdistr[n];
907 for (std::size_t r = 0; r < K; ++r) {
908 const std::size_t Nk =
static_cast<std::size_t
>(std::llround(Npop[r]));
909 std::vector<T> p(Nk + 1, zero);
910 for (std::size_t n = 0; n <= Nk; ++n) p[n] =
num_abs(pdistr[n]);
911 p[Nk] =
num_abs(T(one - head));
913 for (std::size_t n = 0; n <= Nk; ++n) mass += p[n];
916 for (std::size_t n = 0; n <= Nk; ++n)
918 if (m < zero) m = zero;
925 for (std::size_t r = 0; r < K; ++r)
926 R(i, r) = (Tp(i, r) > zero) ? T(Q(i, r) / Tp(i, r)) : zero;
929 for (std::size_t r = 0; r < K; ++r) {
931 for (std::size_t i = 0; i < M; ++i) QN[r] += Q(i, r);
933 return std::make_pair(QN, QNc);
937 fo.
iter_max =
static_cast<std::size_t
>(
opt.iter_max);
943 for (std::size_t c = 0; c < C; ++c) {
945 for (std::size_t i = 0; i < M; ++i) colsum += Q(i, c);
946 for (std::size_t i = 0; i < M; ++i)
951 for (std::size_t i = 0; i < M; ++i)
952 if (L.
stations[i].sched == SchedStrategy::INF)
953 for (std::size_t r = 0; r < K; ++r) U(i, r) = Q(i, r);
960 out.
C.assign(K, zero);
962 out.
X.assign(K, zero);
963 for (std::size_t k = 0; k < K; ++k)
964 for (std::size_t i = 0; i < M; ++i) out.
C[k] += R(i, k);
965 for (std::size_t i = 0; i < M; ++i)
966 for (std::size_t k = 0; k < K; ++k)
967 if (out.
Q(i, k) < zero) out.
Q(i, k) = T(-out.
Q(i, k));
971 for (std::size_t k = 0; k < K; ++k)
Acyclic phase-type fitters from the first two moments.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::size_t nof_stateful() const
std::vector< std::vector< Distrib< T > > > service
service[i][r], 0-based station and class; a disabled entry marks a pair never visited.
bool has_service_law(std::size_t i, std::size_t r) const
Does (station i, class r) have a service law an analyzer may convert?
std::vector< std::vector< bool > > disabled
std::vector< double > cap
sn.cap and sn.classcap: the total and per-class buffers.
std::vector< JobClass > classes
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 ...
std::vector< std::vector< std::size_t > > inchain
1-based class indices per chain
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
Superposition of independent renewal flows (Whitt's QNA stationary-interval method).
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
The exception types the port throws.
The option and result types SolverMAM shares with its analyzers.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
The MMAP assembly primitives solver_mam_basic.m builds its per-station arrival stream from: mmap_expo...
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
The MMAP[K]/PH[K]/1 FCFS queue: per-class mean number in system and per-class queue-length distributi...
T da_traffic_superpos(const std::vector< T > &lambda, const std::vector< T > &a2)
Superposition of independent renewal flows (Whitt's QNA stationary-interval method).
FpiResult< T > da_fpi(const std::function< std::pair< std::vector< T >, std::vector< T > >(const std::vector< T > &, std::size_t)> &iterfun, const std::vector< T > &x0, const FpiOptions &options=FpiOptions())
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
mam::Map< T > dist_to_map(const Distrib< T > &d)
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
const char * sched_to_text(SchedStrategy s)
mva::MvaSolution< T > solver_mna_open(const qn::NetworkStruct< T > &L, const MamOptions &opt, const MnaConfig &cfg=MnaConfig())
Port of solver_mna_open.m.
std::vector< T > mmapph1fcfs_ncmean(const Mmap< T > &arrival, const std::vector< PhService< T > > &svc)
Per-class mean number of customers in the system, BUTools' 'ncMoms', 1.
Map< T > aph_fit_mean_scv(const T &mean, const T &scv)
Port of APH.fitMeanAndSCV, the entry point the analyzers fit arrivals with.
MmckDetection< T > mam_detect_mmck(const qn::NetworkStruct< T > &L, std::size_t ist, const Mmap< T > &arv)
Port of mam_detect_mmck.m: is the exact M/M/c/K closed form legitimate at this station?
Map< T > aph_from_2moments(const T &e1, const T &e2)
Port of BUTools' APHFrom2Moments.
std::vector< std::vector< T > > mmapph1fcfs_ncdistr(const Mmap< T > &arrival, const std::vector< PhService< T > > &svc, std::size_t levels)
Per-class queue-length distribution, BUTools' 'ncDistr', n: P(N_k = 0..n-1).
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
mva::MvaSolution< T > solver_mna_closed(const qn::NetworkStruct< T > &L, const MamOptions &opt)
Port of solver_mna_closed.m.
Mmap< T > mmap_super(const Mmap< T > &a, const Mmap< T > &b)
Superposition of two MMAPs: the phase process is the product chain, and the class list of the result ...
T map_lambda(const Map< T > &m)
Stationary arrival rate, lambda = pi D1 e.
Mmap< T > mmap_super_safe(const std::vector< Mmap< T > > &in, std::size_t maxorder)
Order-bounded superposition of several MMAPs (mmap_super_safe.m).
Matrix< T > npfqn_traffic_split_rr(const qn::NetworkStruct< T > &sn)
Port of npfqn_traffic_split_rr.m.
MmckResult< T > qsys_mmck(const T &lambda, const T &mu, unsigned c, unsigned K)
Exact analysis of the M/M/c/K queue (truncated Erlang form).
A queueing network and its refreshed NetworkStruct.
Deterministic (round-robin) split degrees of every station-class departure stream.
Exact analysis of the M/M/c/K queue (truncated Erlang form).
Port of solver_mam_basic.m, the dec.source analyzer and the default algorithm of SolverMAM.
The batch-arrival and batch-service queues of the MAM solver, and the two finite-capacity helpers sol...
Options mirroring the fields MATLAB reads off the options struct.
bool nanstop
stop when the increment norm is not finite
The MATLAB GlobalConstants, as reported by lineStart at its defaults.
The options SolverMAM reads.
A MAP as the pair of matrices (D0, D1).
An MMAP: the underlying MAP plus the per-class arrival matrices.
std::size_t classes() const
std::vector< Matrix< T > > Dc
per-class matrices, sum_c Dc = D1
What mam_detect_mmck returns; muRate is meaningful only when isMmck.
The options.config fields the two MNA analyzers read.
std::string dep_scv
config.dep_scv, read only by the OPEN analyzer.
Class-level results, the [Q,U,R,T,C,X] of the MATLAB analyzers.
double lG
log of the normalizing constant, the reference's lG.
One job class of the network.
double population
infinite for an open class
T meanQueueLength
L, mean number in system.