305 const std::vector<std::vector<T>>& STb,
307 const std::vector<bool>& isinf_i,
308 const std::vector<double>& nsrv,
309 const std::vector<std::vector<double>>& cshare,
310 const std::vector<std::vector<bool>>& supp,
311 std::size_t states_max) {
313 const std::size_t Mc = STb.size();
314 const std::size_t B = Nb.size();
317 std::vector<std::vector<std::vector<int>>> sp(B);
318 std::vector<std::vector<std::vector<int>>> compb(B);
319 std::vector<std::vector<std::size_t>> idxb(B);
320 std::vector<std::size_t> nst(B);
321 std::size_t nstates = 1;
322 for (std::size_t b = 0; b < B; ++b) {
323 for (std::size_t i = 0; i < Mc; ++i)
324 if (supp.empty() || supp[i][b]) idxb[b].push_back(i);
325 if (idxb[b].empty()) {
327 throw UnsupportedError(
"mam_bgchain_ctmc: background class " + std::to_string(b + 1) +
328 " holds " + std::to_string(Nb[b]) +
329 " jobs but visits no station");
330 idxb[b].push_back(0);
332 compb[b] = bgchain_detail::closed_block(idxb[b].size(), Nb[b]);
333 sp[b].assign(compb[b].size(), std::vector<int>(Mc, 0));
334 for (std::size_t r = 0; r < compb[b].size(); ++r)
335 for (std::size_t t = 0; t < idxb[b].size(); ++t)
336 sp[b][r][idxb[b][t]] = compb[b][r][t];
337 nst[b] = compb[b].size();
340 if (nstates > states_max)
342 "mam_bgchain_ctmc: the background chain of this model has " + std::to_string(nstates) +
343 " states, above the limit of " + std::to_string(states_max) +
344 ". The chain enumerates the closed-class population vector over the " +
346 " stations the closed classes visit, so its size grows as nchoosek(N+Mc-1,Mc-1) per "
347 "class, and it carries " + std::to_string(B) +
348 " classes. Lower options.config.bgaggr to aggregate more of the closed chains into "
349 "fewer classes, raise options.config.bgstates_max to solve it anyway, or reduce the "
350 "closed populations.");
354 std::vector<std::vector<std::vector<long>>> tgt(B);
355 for (std::size_t b = 0; b < B; ++b) {
356 const std::size_t mb = idxb[b].size();
357 std::map<std::vector<int>,
long> index;
358 for (std::size_t s = 0; s < nst[b]; ++s) index[compb[b][s]] = static_cast<long>(s);
359 tgt[b].assign(nst[b], std::vector<long>(Mc * Mc, -1));
360 for (std::size_t s = 0; s < nst[b]; ++s) {
361 for (std::size_t ii = 0; ii < mb; ++ii) {
362 if (compb[b][s][ii] == 0)
continue;
363 for (std::size_t jj = 0; jj < mb; ++jj) {
364 if (jj == ii)
continue;
365 std::vector<int> cand = compb[b][s];
368 const auto it = index.find(cand);
369 if (it != index.end())
370 tgt[b][s][idxb[b][ii] * Mc + idxb[b][jj]] = it->second;
377 std::vector<std::size_t> strideb(B, 1);
378 for (std::size_t b = 0; b < B; ++b) {
380 for (std::size_t b2 = b + 1; b2 < B; ++b2) s *= nst[b2];
385 out.
space.assign(nstates, std::vector<std::vector<int>>(Mc, std::vector<int>(B, 0)));
386 out.
totocc.assign(nstates, std::vector<int>(Mc, 0));
387 std::vector<std::vector<std::size_t>> subidx(nstates, std::vector<std::size_t>(B, 0));
388 for (std::size_t s = 0; s < nstates; ++s) {
390 for (std::size_t bb = B; bb-- > 0;) {
391 subidx[s][bb] = rem % nst[bb];
394 for (std::size_t b = 0; b < B; ++b) {
395 const std::vector<int>& vec = sp[b][subidx[s][b]];
396 for (std::size_t i = 0; i < Mc; ++i) {
397 out.
space[s][i][b] = vec[i];
398 out.
totocc[s][i] += vec[i];
403 std::vector<std::vector<T>> mu(Mc, std::vector<T>(B, zero));
404 for (std::size_t b = 0; b < B; ++b)
405 for (std::size_t i = 0; i < Mc; ++i)
410 std::vector<std::vector<std::vector<T>>> rate_full(
411 nstates, std::vector<std::vector<T>>(Mc, std::vector<T>(B, zero)));
412 std::vector<std::vector<T>> cap_busy(nstates, std::vector<T>(Mc, zero));
413 for (std::size_t s = 0; s < nstates; ++s) {
414 for (std::size_t i = 0; i < Mc; ++i) {
415 const int eclosed = out.
totocc[s][i];
416 if (eclosed == 0)
continue;
419 held_d =
static_cast<double>(eclosed);
421 const std::size_t ecap =
422 std::min<std::size_t>(
static_cast<std::size_t
>(eclosed), cshare[i].size() - 1);
423 held_d = cshare[i][ecap];
425 if (!(held_d > 0.0))
continue;
427 cap_busy[s][i] = held;
428 for (std::size_t b = 0; b < B; ++b) {
429 if (out.
space[s][i][b] == 0 || mu[i][b] == zero)
continue;
431 static_cast<double>(eclosed));
432 const T r = T(held * frac * mu[i][b]);
433 rate_full[s][i][b] = r;
434 for (std::size_t j = 0; j < Mc; ++j) {
435 if (j == i)
continue;
437 const long tsub = tgt[b][subidx[s][b]][i * Mc + j];
438 if (tsub < 0)
continue;
439 const std::size_t sdest =
440 s + (
static_cast<std::size_t
>(tsub) - subidx[s][b]) * strideb[b];
441 Q(s, sdest) += T(r * Pb[b](i, j));
454 for (T& v : out.
pi) {
459 for (T& v : out.
pi) v /= tot;
461 out.
QLen.assign(Mc, std::vector<T>(B, zero));
462 out.
Tput.assign(Mc, std::vector<T>(B, zero));
463 out.
Ubusy.assign(Mc, std::vector<T>(B, zero));
464 for (std::size_t s = 0; s < nstates; ++s) {
465 const T p = out.
pi[s];
466 if (p == zero)
continue;
467 for (std::size_t i = 0; i < Mc; ++i)
468 for (std::size_t b = 0; b < B; ++b) {
470 out.
Tput[i][b] += T(p * rate_full[s][i][b]);
473 for (std::size_t i = 0; i < Mc; ++i) {
478 for (std::size_t s = 0; s < nstates; ++s) {
479 const T p = out.
pi[s];
480 const int occ = out.
totocc[s][i];
481 if (p == zero || occ == 0)
continue;
482 for (std::size_t b = 0; b < B; ++b) {
484 static_cast<double>(out.
space[s][i][b]) /
static_cast<double>(occ));
617 const std::vector<T>& alpha_s,
const Matrix<T>& Tsvc,
618 const Matrix<T>& Ain,
const std::vector<int>& esup_in,
619 double nservers,
const std::vector<double>& gref_in,
623 const std::size_t ma = Da0.
rows();
624 const std::size_t
me = esup_in.size();
625 const std::size_t ms = alpha_s.size();
626 if (Kmax < 1) Kmax = 1;
629 const std::vector<int>& esup = esup_in;
630 const std::vector<double>& gref = gref_in;
633 for (std::size_t i = 0; i < ms; ++i) {
635 for (std::size_t j = 0; j < ms; ++j) s += Tsvc(i, j);
639 for (std::size_t j = 0; j < ms; ++j) alphaRow(0, j) = alpha_s[j];
641 Matrix<T> Ime(
me,
me, zero), Ima(ma, ma, zero), Ims(ms, ms, zero);
642 for (std::size_t i = 0; i <
me; ++i) Ime(i, i) = one;
643 for (std::size_t i = 0; i < ma; ++i) Ima(i, i) = one;
644 for (std::size_t i = 0; i < ms; ++i) Ims(i, i) = one;
649 for (std::size_t e = 0; e <
me; ++e)
650 for (std::size_t ep = 0; ep <
me; ++ep) {
651 if (ep < e) Adown(e, ep) = Ain(e, ep);
652 else if (ep > e) Aup(e, ep) = Ain(e, ep);
655 auto env_at_level = [&](std::size_t k) {
657 for (std::size_t e = 0; e <
me; ++e) {
658 const double g = bgchain_detail::closed_share(
static_cast<double>(esup[e]),
659 static_cast<double>(k), nservers);
660 const double ratio = (gref[e] > 0.0) ? g / gref[e] : 1.0;
663 for (std::size_t ep = 0; ep <
me; ++ep) {
664 if (ep == e)
continue;
665 const T v = T(Aup(e, ep) + rt * Adown(e, ep));
673 auto diagm = [&](
const std::vector<T>& v) {
675 for (std::size_t i = 0; i < v.size(); ++i) D(i, i) = v[i];
681 std::vector<Matrix<T>> Q0(Kmax), Q1(Kmax + 1), Q2(Kmax + 1);
682 std::vector<std::vector<T>> phiae(Kmax);
684 Q1[0] = qbd_detail::madd(
kron(Da0, Ime),
kron(Ima, env_at_level(0)));
685 Q0[0] =
kron(
kron(Da1, Ime), alphaRow);
690 for (std::size_t k = 1; k <= Kmax; ++k) {
691 std::vector<T> rep(ma *
me, zero);
692 for (std::size_t a = 0; a < ma; ++a)
693 for (std::size_t e = 0; e <
me; ++e)
695 static_cast<double>(k),
static_cast<double>(esup[e]), nservers));
698 Q1[k] = qbd_detail::madd(
699 qbd_detail::madd(Da0kron,
kron(
kron(Ima, Ak), Ims)),
kron(diagm(rep), Tsvc));
700 if (k < Kmax) Q0[k] = Da1kron;
702 Q2[1] =
kron(diagm(rep), tvec);
704 Q2[k] =
kron(diagm(rep),
matmul(tvec, alphaRow));
708 Q1[Kmax] = qbd_detail::madd(Q1[Kmax], Da1kron);
711 const std::vector<T>& plev = res.
pi.pi;
716 for (std::size_t k = 0; k <= Kmax; ++k)
718 out.
ploss = plev[Kmax];
720 std::vector<T> penv(
me, zero), gacc(
me, zero);
721 T
util = zero, tput = zero;
722 for (std::size_t k = 0; k <= Kmax; ++k) {
723 const std::vector<T>& pk = res.
pi.pi_level[k];
724 std::vector<T> marg(
me, zero);
726 for (std::size_t a = 0; a < ma; ++a)
727 for (std::size_t e = 0; e <
me; ++e) marg[e] += pk[a *
me + e];
729 for (std::size_t a = 0; a < ma; ++a)
730 for (std::size_t e = 0; e <
me; ++e) {
731 T block = zero, dep = zero;
732 for (std::size_t s = 0; s < ms; ++s) {
733 const T v = pk[(a *
me + e) * ms + s];
735 dep += T(v * tvec(s, 0));
738 util += T(block * phiae[k - 1][a *
me + e]);
739 tput += T(dep * phiae[k - 1][a *
me + e]);
742 for (std::size_t e = 0; e <
me; ++e) {
745 static_cast<double>(esup[e]),
static_cast<double>(k),
750 for (
const T& v : penv) psum += v;
752 for (std::size_t e = 0; e <
me; ++e) {
758 for (std::size_t e = 0; e <
me; ++e) {
877 "solver_mam_bgchain: the level-dependent QBD recursion inverts a matrix per level and "
878 "falls back to a pseudo-inverse when a level is singular, neither of which is exact "
879 "arithmetic; rerun with --arith double or --arith real");
887 for (std::size_t i = 0; i < M; ++i)
888 for (std::size_t k = 0; k < K; ++k) {
890 if (std::isfinite(r) && r > 0.0) S(i, k) = T(one / L.
rates(i, k));
898 std::vector<bool> isopenchain(C,
false);
899 std::vector<std::size_t> openChains, closedChains;
900 for (std::size_t c = 0; c < C; ++c) {
902 for (std::size_t k : L.
inchain[c])
903 if (std::isinf(L.
classes[k - 1].population)) open =
true;
904 isopenchain[c] = open;
905 if (open) openChains.push_back(c);
906 else if (dem.
Nchain[c] > 0.0) closedChains.push_back(c);
908 const std::size_t R = closedChains.size();
911 "solver_mam_bgchain: the bgchain method requires at least one closed class: the "
912 "background chain IS the closed population vector, so a purely open model has nothing "
913 "to build it from. Use dec.source.");
916 std::vector<std::size_t> cst;
917 for (std::size_t i = 0; i < M; ++i) {
918 bool visited =
false;
919 for (std::size_t c : closedChains)
921 if (visited) cst.push_back(i);
923 const std::size_t Mc = cst.size();
925 throw UnsupportedError(
"solver_mam_bgchain: the closed classes of this model visit no "
929 std::vector<Matrix<T>> Pchain(C,
Matrix<T>(M, M, zero));
930 for (std::size_t c = 0; c < C; ++c) {
932 for (std::size_t i = 0; i < M; ++i)
933 for (std::size_t k1 : L.
inchain[c]) {
934 const T a = dem.
alpha(i, k1 - 1);
936 for (std::size_t j = 0; j < M; ++j) {
938 for (std::size_t k2 : L.
inchain[c])
939 acc += rtst(i * K + (k1 - 1), j * K + (k2 - 1));
940 if (acc != zero) P(i, j) += T(a * acc);
947 std::vector<double> lambdaChain(C, 0.0);
948 std::map<std::size_t, Map<T>> chainArrival;
949 for (std::size_t c : openChains) {
952 std::vector<Mmap<T>> parts;
953 for (std::size_t k : L.
inchain[c]) {
955 if (!std::isfinite(rk) || !(rk > 0.0))
continue;
961 mm.
Dc.assign(1, mk.
D1);
964 lambdaChain[c] = lam;
965 if (!parts.empty()) {
973 std::vector<bool> isopenclass(K,
false);
974 for (std::size_t c : openChains)
975 for (std::size_t k : L.
inchain[c]) {
976 isopenclass[k - 1] =
true;
977 for (std::size_t i = 0; i < M; ++i)
987 sol.
C.assign(K, zero);
988 sol.
X.assign(K, zero);
991 for (std::size_t c : closedChains) Ntot +=
static_cast<int>(std::llround(dem.
Nchain[c]));
995 std::vector<std::vector<double>> cshare(M, std::vector<double>(Ntot + 1, 0.0));
996 std::vector<double> nsrvAll(M, 1.0);
997 std::vector<bool> isinfAll(M,
false);
998 for (std::size_t i = 0; i < M; ++i) {
999 nsrvAll[i] = L.
stations[i].nservers;
1000 isinfAll[i] = (L.
stations[i].sched == SchedStrategy::INF);
1001 for (
int e = 0; e <= Ntot; ++e)
1002 cshare[i][e] = std::min(
static_cast<double>(e), nsrvAll[i]);
1004 std::vector<double> Xclosed(C, 0.0);
1005 for (std::size_t c : closedChains) {
1007 for (std::size_t i = 0; i < M; ++i) denom += num_traits<T>::to_double(dem.
Lchain(i, c));
1008 if (denom > 0.0) Xclosed[c] = dem.
Nchain[c] / denom;
1011 const std::size_t states_max = (
opt.bgstates_max > 0) ?
opt.bgstates_max : 20000;
1012 const std::size_t phases_max = (
opt.qbdphases_max > 0) ?
opt.qbdphases_max : 500;
1017 const std::size_t bgaggr_opt = (
opt.bgaggr > 0) ?
opt.bgaggr : 1;
1018 const std::size_t naggr =
1019 std::min(std::max<std::size_t>(bgaggr_opt, 1), std::max<std::size_t>(R - 1, 1));
1022 const bool noAggr = (R == 1) || (naggr >= R - 1);
1026 std::vector<std::vector<std::size_t>> othersOf(R), grpOf(R);
1027 for (std::size_t ridx = 0; ridx < R; ++ridx) {
1028 for (std::size_t oi = 0; oi < R; ++oi)
1029 if (oi != ridx) othersOf[ridx].push_back(closedChains[oi]);
1030 if (!noAggr && !othersOf[ridx].empty()) {
1031 std::vector<std::vector<double>> D(Mc, std::vector<double>(othersOf[ridx].size(), 0.0));
1032 for (std::size_t ii = 0; ii < Mc; ++ii)
1033 for (std::size_t oi = 0; oi < othersOf[ridx].size(); ++oi)
1035 grpOf[ridx] = bgchain_detail::mam_bgchain_groups(D, naggr);
1038 const std::size_t npass = noAggr ? 1 : R;
1042 const double relax = 0.5;
1046 for (std::size_t i = 0; i < a.
rows(); ++i)
1047 for (std::size_t j = 0; j < a.
cols(); ++j)
1053 while (maxdiff(sol.
Tp, TNprev) >
opt.tol && totiter <
opt.iter_max) {
1057 std::vector<double> QopenAcc(M, 0.0);
1058 std::vector<std::vector<double>> cshareAcc(M, std::vector<double>(Ntot + 1, 0.0));
1060 for (std::size_t pidx = 0; pidx < npass; ++pidx) {
1061 const std::size_t r = closedChains[pidx];
1066 std::vector<std::vector<std::size_t>> members;
1068 for (std::size_t c : closedChains) members.push_back({c});
1070 members.push_back({r});
1071 for (std::size_t g = 0; g < naggr; ++g) {
1072 std::vector<std::size_t> mem;
1073 for (std::size_t oi = 0; oi < othersOf[pidx].size(); ++oi)
1074 if (grpOf[pidx][oi] == g) mem.push_back(othersOf[pidx][oi]);
1075 members.push_back(mem);
1078 const std::size_t B = members.size();
1080 std::vector<int> Nb(B, 0);
1081 std::vector<std::vector<T>> STb(Mc, std::vector<T>(B, zero));
1082 std::vector<Matrix<T>> Pb;
1085 std::vector<std::vector<bool>> suppb(Mc, std::vector<bool>(B,
false));
1086 for (std::size_t b = 0; b < B; ++b) {
1087 const std::vector<std::size_t>& mem = members[b];
1088 for (std::size_t o : mem) {
1089 Nb[b] +=
static_cast<int>(std::llround(dem.
Nchain[o]));
1090 for (std::size_t ii = 0; ii < Mc; ++ii)
1092 suppb[ii][b] =
true;
1094 if (mem.size() == 1) {
1097 for (std::size_t ii = 0; ii < Mc; ++ii) {
1098 STb[ii][b] = dem.
STchain(cst[ii], mem[0]);
1099 for (std::size_t jj = 0; jj < Mc; ++jj)
1100 P0(ii, jj) = Pchain[mem[0]](cst[ii], cst[jj]);
1103 }
else if (mem.empty()) {
1106 std::vector<std::vector<double>> w(Mc, std::vector<double>(mem.size(), 0.0));
1107 for (std::size_t ii = 0; ii < Mc; ++ii) {
1108 double rowsum = 0.0;
1109 for (std::size_t oi = 0; oi < mem.size(); ++oi) {
1110 w[ii][oi] = Xclosed[mem[oi]] *
1112 rowsum += w[ii][oi];
1114 for (std::size_t oi = 0; oi < mem.size(); ++oi)
1115 w[ii][oi] = (rowsum > 0.0) ? w[ii][oi] / rowsum
1116 : 1.0 /
static_cast<double>(mem.size());
1119 for (std::size_t ii = 0; ii < Mc; ++ii) {
1121 for (std::size_t oi = 0; oi < mem.size(); ++oi) {
1123 st += T(wv * dem.
STchain(cst[ii], mem[oi]));
1124 for (std::size_t jj = 0; jj < Mc; ++jj)
1125 Pagg(ii, jj) += T(wv * Pchain[mem[oi]](cst[ii], cst[jj]));
1134 for (std::size_t b = 0; b < B; ++b) {
1135 for (std::size_t ii = 0; ii < Mc; ++ii) {
1137 for (std::size_t jj = 0; jj < Mc; ++jj) s += Pb[b](ii, jj);
1139 for (std::size_t jj = 0; jj < Mc; ++jj) Pb[b](ii, jj) /= s;
1141 for (std::size_t jj = 0; jj < Mc; ++jj) Pb[b](ii, jj) = zero;
1142 Pb[b](ii, ii) = one;
1147 std::vector<bool> isinfC(Mc,
false);
1148 std::vector<double> nsrvC(Mc, 1.0);
1149 std::vector<std::vector<double>> cshareC(Mc);
1150 for (std::size_t ii = 0; ii < Mc; ++ii) {
1151 isinfC[ii] = isinfAll[cst[ii]];
1152 nsrvC[ii] = nsrvAll[cst[ii]];
1153 cshareC[ii] = cshare[cst[ii]];
1161 const std::size_t bmax = noAggr ? B : 1;
1162 for (std::size_t b = 0; b < bmax; ++b) {
1163 if (members[b].empty())
continue;
1164 const std::size_t rb = members[b][0];
1165 for (std::size_t k : L.
inchain[rb])
1166 for (std::size_t i = 0; i < M; ++i) {
1167 sol.
Q(i, k - 1) = zero;
1168 sol.
U(i, k - 1) = zero;
1169 sol.
R(i, k - 1) = zero;
1170 sol.
Tp(i, k - 1) = zero;
1172 for (std::size_t ii = 0; ii < Mc; ++ii) {
1173 const std::size_t i = cst[ii];
1174 for (std::size_t k : L.
inchain[rb]) {
1175 const T a = dem.
alpha(i, k - 1);
1183 const T stc = dem.
STchain(i, rb);
1185 const T q = T(bg.
QLen[ii][b] * w);
1186 const T x = T(bg.
Tput[ii][b] * a);
1187 sol.
Q(i, k - 1) = q;
1188 sol.
Tp(i, k - 1) = x;
1189 sol.
U(i, k - 1) = isinfC[ii] ? q : T(bg.
Ubusy[ii][b] * w);
1193 const std::size_t iref = L.
classes[L.
inchain[rb][0] - 1].refstat;
1195 for (std::size_t k : L.
inchain[rb]) tputref += sol.
Tp(iref - 1, k - 1);
1201 std::vector<double> Uclosed(M, 0.0);
1202 for (std::size_t ii = 0; ii < Mc; ++ii) {
1204 for (std::size_t b = 0; b < B; ++b) u += num_traits<T>::to_double(bg.
Ubusy[ii][b]);
1205 Uclosed[cst[ii]] = u;
1209 for (std::size_t i = 0; i < M; ++i) {
1210 bool solved =
false;
1212 if (sc != SchedStrategy::EXT && sc != SchedStrategy::INF) {
1213 std::vector<std::size_t> kopen;
1214 for (std::size_t k = 0; k < K; ++k)
1216 if (!kopen.empty()) {
1218 bool haveDa =
false;
1220 for (std::size_t c : openChains) {
1221 if (!(lambdaChain[c] > 1e-14))
continue;
1222 const auto it = chainArrival.find(c);
1223 if (it == chainArrival.end())
continue;
1225 for (std::size_t k : L.
inchain[c]) vsum += V(i, k - 1);
1226 const double rate_ic =
1228 if (!(rate_ic > 1e-14))
continue;
1235 std::vector<Mmap<T>> two(2);
1236 two[0].D0 = Da.
D0; two[0].D1 = Da.
D1; two[0].Dc.assign(1, Da.
D1);
1237 two[1].D0 = scaled.
D0; two[1].D1 = scaled.
D1;
1238 two[1].Dc.assign(1, scaled.
D1);
1245 T lamtot = zero, svcwork = zero;
1246 for (std::size_t k : kopen) {
1247 lamtot += lambdaOpen(i, k);
1248 svcwork += T(lambdaOpen(i, k) * S(i, k));
1250 std::vector<std::vector<T>> pies;
1251 std::vector<Matrix<T>> subgens;
1252 std::size_t msTotal = 0;
1260 const bool isPSstation = (sc == SchedStrategy::PS);
1261 for (std::size_t k : kopen) {
1264 const T mu = T(one / S(i, k));
1270 std::vector<T> pik =
map_pie(phk);
1271 const T w = T(lambdaOpen(i, k) / lamtot);
1272 for (T& v : pik) v = T(v * w);
1273 pies.push_back(pik);
1274 subgens.push_back(phk.
D0);
1275 msTotal += phk.
D0.rows();
1277 std::vector<T> alphaS(msTotal, zero);
1279 std::size_t off = 0;
1280 for (std::size_t idx = 0; idx < pies.size(); ++idx) {
1281 const std::size_t n = subgens[idx].rows();
1282 for (std::size_t a = 0; a < n; ++a) {
1283 alphaS[off + a] = pies[idx][a];
1284 for (std::size_t b = 0; b < n; ++b)
1285 Tblk(off + a, off + b) = subgens[idx](a, b);
1291 std::vector<int> esup(1, 0);
1292 const auto pos = std::find(cst.begin(), cst.end(), i);
1293 if (pos != cst.end()) {
1295 bg,
static_cast<std::size_t
>(pos - cst.begin()));
1300 const std::size_t nphases = Da.
D0.rows() * esup.size() * msTotal;
1301 if (nphases > phases_max)
1303 "solver_mam_bgchain: the modulated QBD of station " +
1304 std::to_string(i + 1) +
" needs " + std::to_string(nphases) +
1305 " phases (" + std::to_string(Da.
D0.rows()) +
" arrival x " +
1306 std::to_string(esup.size()) +
" environment x " +
1307 std::to_string(msTotal) +
" service), above the limit of " +
1308 std::to_string(phases_max) +
1309 ". The environment axis is the closed population held by the "
1310 "station, so it grows with the closed population. Raise "
1311 "options.config.qbdphases_max, or reduce the closed population "
1312 "or the order of the arrival and service processes.");
1314 std::vector<double> gref(esup.size(), 0.0);
1315 for (std::size_t e = 0; e < esup.size(); ++e)
1316 gref[e] = cshare[i][std::min<std::size_t>(
1317 static_cast<std::size_t
>(esup[e]),
1318 cshare[i].size() - 1)];
1324 if (
opt.cutoff > 0) {
1325 Kmax = std::max<std::size_t>(2,
opt.cutoff);
1327 const double free = std::max(1e-8, 1.0 - Uclosed[i]);
1330 double rho = lam * Smix / (nsrvAll[i] * free);
1331 rho = std::min(std::max(rho, 1e-3), 1.0 - 1e-3);
1333 static_cast<long>(std::ceil(std::log(1e-8) / std::log(rho)));
1334 Kmax =
static_cast<std::size_t
>(std::min<long>(
1335 std::max<long>(kv, 20), 200));
1340 nsrvAll[i], gref, Kmax);
1346 for (
int e = 0; e <= Ntot; ++e) {
1348 const std::size_t n = st.
esup.size();
1351 }
else if (e <= st.
esup[0]) {
1355 }
else if (e >= st.
esup[n - 1]) {
1356 const double slope = (st.
cshare[n - 1] - st.
cshare[n - 2]) /
1358 g = st.
cshare[n - 1] + slope * (e - st.
esup[n - 1]);
1361 while (lo + 1 < n && st.
esup[lo + 1] < e) ++lo;
1362 const double w =
static_cast<double>(e - st.
esup[lo]) /
1363 static_cast<double>(st.
esup[lo + 1] - st.
esup[lo]);
1367 std::min(std::max(g, 0.0),
1368 std::min(
static_cast<double>(e), nsrvAll[i]));
1376 for (
int e = 0; e <= Ntot; ++e) cshareAcc[i][e] += cshare[i][e];
1381 std::vector<double> Qopen(M, 0.0);
1382 for (std::size_t i = 0; i < M; ++i) {
1383 Qopen[i] = QopenAcc[i] /
static_cast<double>(npass);
1384 for (
int e = 0; e <= Ntot; ++e)
1385 cshare[i][e] = (1.0 - relax) * cshare[i][e] +
1386 relax * (cshareAcc[i][e] /
static_cast<double>(npass));
1390 for (std::size_t i = 0; i < M; ++i) {
1391 std::vector<std::size_t> kopen;
1392 for (std::size_t k = 0; k < K; ++k)
1396 if (kopen.empty()) {
1397 for (std::size_t k = 0; k < K; ++k)
1398 if (isopenclass[k]) {
1399 sol.
Tp(i, k) = lambdaOpen(i, k);
1406 T lamtot = zero, work = zero;
1407 for (std::size_t k : kopen) {
1408 lamtot += lambdaOpen(i, k);
1409 work += T(lambdaOpen(i, k) * S(i, k));
1411 const T Smix = T(work / lamtot);
1412 for (std::size_t k : kopen) {
1413 sol.
Tp(i, k) = lambdaOpen(i, k);
1414 if (sc == SchedStrategy::EXT) {
1418 }
else if (sc == SchedStrategy::INF) {
1419 sol.
R(i, k) = S(i, k);
1420 sol.
Q(i, k) = T(lambdaOpen(i, k) * S(i, k));
1421 sol.
U(i, k) = sol.
Q(i, k);
1425 if (sc == SchedStrategy::PS) {
1427 rk = T(Rtot * S(i, k) / Smix);
1431 const T cand = T(Rtot - Smix + S(i, k));
1437 sol.
Q(i, k) = T(lambdaOpen(i, k) * rk);
1446 for (std::size_t c = 0; c < C; ++c)
1447 for (std::size_t k : L.
inchain[c])
1449 for (std::size_t k = 0; k < K; ++k) {
1451 for (std::size_t i = 0; i < M; ++i) acc += sol.
R(i, k);