5#ifndef LINE_LANG_QN_STATE_H
6#define LINE_LANG_QN_STATE_H
55 std::vector<std::vector<T>>
kir;
58namespace state_detail {
63 case SchedStrategy::SIRO:
64 case SchedStrategy::POLLING:
65 case SchedStrategy::SEPT:
66 case SchedStrategy::LEPT:
67 case SchedStrategy::SRPT:
68 case SchedStrategy::SRPTPRIO:
81 case SchedStrategy::FCFS:
82 case SchedStrategy::HOL:
83 case SchedStrategy::LCFS:
84 case SchedStrategy::LCFSPRIO:
102 case SchedStrategy::FCFSPI:
103 case SchedStrategy::FCFSPIPRIO:
104 case SchedStrategy::FCFSPR:
105 case SchedStrategy::FCFSPRPRIO:
106 case SchedStrategy::LCFSPI:
107 case SchedStrategy::LCFSPIPRIO:
108 case SchedStrategy::LCFSPR:
109 case SchedStrategy::LCFSPRPRIO:
131 const std::vector<T>& state_i,
const std::vector<std::size_t>& phasesz,
132 const std::vector<std::size_t>& phaseshift, std::size_t nvar = 0) {
133 const std::size_t R =
sn.nclasses;
134 if (ist == 0 || ist >
sn.stations.size())
135 throw InputError(
"to_marginal: station index " + std::to_string(ist) +
" is out of range");
139 m.
nir.assign(R, zero);
140 m.
sir.assign(R, zero);
141 std::size_t maxph = 1;
142 for (std::size_t r = 0; r < R; ++r) maxph = std::max(maxph, phasesz[r]);
143 m.
kir.assign(R, std::vector<T>(maxph, zero));
148 const std::size_t jnd =
sn.node_of_station(ist);
149 if (
sn.isfjaugmented && jnd != 0 &&
sn.nodes[jnd - 1].nodetype == NodeType::Join &&
150 state_i.size() >= R) {
151 for (std::size_t r = 0; r < R; ++r) m.
nir[r] = state_i[state_i.size() - R + r];
165 const bool ordered_list = (sched == SchedStrategy::PAS || sched == SchedStrategy::OI);
169 std::size_t srvw = 0;
170 for (std::size_t r = 0; r < R; ++r) srvw += phasesz[r];
171 if (!ordered_list && state_i.size() < nvar + srvw)
172 throw InputError(
"to_marginal: state row is narrower than the server block it declares");
173 const std::size_t srv0 = ordered_list ? 0 : state_i.size() - nvar - srvw;
174 const std::size_t bufw = srv0;
177 for (std::size_t r = 0; r < R; ++r) {
178 for (std::size_t k = 0; k < phasesz[r]; ++k) {
179 const T v = state_i[srv0 + phaseshift[r] + k];
186 if (sched == SchedStrategy::EXT) {
205 std::numeric_limits<double>::infinity());
206 for (std::size_t r = 0; r < R; ++r) m.
nir[r] = ext;
207 }
else if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI) {
220 for (std::size_t r = 0; r < R; ++r) {
223 for (std::size_t k = 0; k < maxph; ++k) m.
kir[r][k] = zero;
225 const std::size_t w = state_i.size() > nvar ? state_i.size() - nvar : 0;
226 std::vector<std::size_t> clist;
227 for (std::size_t b = 0; b < w; ++b) {
229 if (tag >= 1 &&
static_cast<std::size_t
>(tag) <= R) {
231 clist.push_back(
static_cast<std::size_t
>(tag));
234 const typename std::map<std::size_t,
236 sn.pasparam.find(ist);
237 if (pit !=
sn.pasparam.end() && pit->second.svc_rate_fun) {
239 for (std::size_t p = 0; p < clist.size(); ++p) {
240 const std::vector<std::size_t> prefix(clist.begin(), clist.begin() + p + 1);
241 const T mucur = pit->second.svc_rate_fun(prefix);
253 for (std::size_t r = 0; r < R; ++r) m.
kir[r][0] = m.
nir[r];
255 }
else if (state_detail::buffer_is_class_tag(sched)) {
256 for (std::size_t r = 0; r < R; ++r) {
258 for (std::size_t b = 0; b < bufw; ++b)
260 m.
nir[r] = T(m.
sir[r] + waiting);
262 }
else if (state_detail::buffer_is_tag_phase_pairs(sched)) {
264 for (std::size_t r = 0; r < R; ++r) {
266 for (std::size_t b = 0; b < bufw; b += 2)
268 m.
nir[r] = T(m.
sir[r] + waiting);
273 }
else if (state_detail::buffer_is_per_class_count(sched)) {
274 for (std::size_t r = 0; r < R; ++r)
275 m.
nir[r] = bufw >= R ? T(m.
sir[r] + state_i[r]) : m.
sir[r];
286 if (
sn.stations[ist - 1].nodetype == NodeType::Place) {
288 case SchedStrategy::INF:
289 case SchedStrategy::PS:
290 case SchedStrategy::PSPRIO:
291 case SchedStrategy::DPS:
292 case SchedStrategy::DPSPRIO:
293 case SchedStrategy::GPS:
294 case SchedStrategy::GPSPRIO:
295 case SchedStrategy::LPS:
297 for (std::size_t r = 0; r < R; ++r) m.
nir[r] = T(m.
sir[r] + state_i[r]);
302 for (std::size_t r = 0; r < R; ++r)
303 if (
sn.disabled[ist - 1][r]) {
304 for (std::size_t k = 0; k < phasesz[r]; ++k) m.
kir[r][k] = zero;
308 for (std::size_t r = 0; r < R; ++r)
309 if (
sn.disabled[ist - 1][r]) {
311 for (std::size_t k = 0; k < phasesz[r]; ++k) m.
kir[r][k] = zero;
317 for (std::size_t r = 0; r < R; ++r) m.
ni += m.
nir[r];
331 const std::vector<std::vector<T>>& local) {
332 const std::size_t M =
sn.stations.size(), K =
sn.nclasses;
333 std::vector<double> n(M, 0.0);
334 for (std::size_t ist = 1; ist <= M; ++ist) {
335 const std::size_t isf =
sn.stateful_of_station(ist);
336 if (isf == 0 || isf > local.size())
continue;
337 if (
sn.stations[ist - 1].nodetype == NodeType::Source)
continue;
338 std::vector<std::size_t> ph(K, 1), shift(K, 0);
340 for (std::size_t k = 0; k < K; ++k) {
341 ph[k] =
sn.phasessz_of(ist, k + 1);
346 to_marginal(
sn, ist, local[isf - 1], ph, shift,
sn.nvars_of(
sn.node_of_station(ist)));
377 const std::size_t K =
sn.nclasses, I =
sn.nodes.size();
379 if (full.
rows() != I * K)
380 throw InputError(
"rt_state: the node-level routing has not been refreshed");
381 if (
sn.sdr.empty())
return sn.stoch_comp_stateful(full, K);
389 std::vector<double> p(I, 0.0);
390 for (std::size_t b = 1; b <
sn.sdr_nodes.branch.size(); ++b)
391 p[
sn.sdr_nodes.entryOf[b]] += Pb[b];
392 p[
sn.sdr_nodes.departure] += Ped;
394 for (std::size_t ind = 1; ind <= I; ++ind) {
396 for (std::size_t r = 1; r <= K && r <= nd.
routing.size(); ++r) {
397 if (nd.
routing[r - 1] != RoutingStrategy::SDR)
continue;
398 for (std::size_t jnd = 1; jnd <= I; ++jnd)
399 for (std::size_t s = 1; s <= K; ++s)
400 full((ind - 1) * K + (r - 1), (jnd - 1) * K + (s - 1)) =
404 return sn.stoch_comp_stateful(full, K);
415std::vector<std::vector<T>>
cartesian(
const std::vector<std::vector<T>>& a,
416 const std::vector<std::vector<T>>& b) {
417 if (a.empty())
return b;
418 if (b.empty())
return a;
419 std::vector<std::vector<T>> out;
420 out.reserve(a.size() * b.size());
421 for (std::size_t i = 0; i < a.size(); ++i)
422 for (std::size_t j = 0; j < b.size(); ++j) {
423 std::vector<T> row = a[i];
424 row.insert(row.end(), b[j].begin(), b[j].end());
438 std::vector<std::vector<T>> out;
439 if (m == 0)
return out;
440 const std::vector<std::vector<int>> rows =
442 out.reserve(rows.size());
443 for (std::size_t i = 0; i < rows.size(); ++i) {
445 r.reserve(rows[i].size());
446 for (std::size_t j = 0; j < rows[i].size(); ++j)
467 std::size_t off, std::vector<T>& row,
468 std::vector<std::vector<T>>& out) {
470 if (n == 0) out.push_back(row);
474 bool unbounded =
false;
475 for (std::size_t k = off; k < off + m && k < caps.size(); ++k) {
476 if (caps[k] < 0) { unbounded =
true;
break; }
479 if (!unbounded && n > room)
return;
480 const long here = off < caps.size() ? caps[off] : -1;
481 const long hi = here < 0 ? n : std::min<long>(n, here);
482 for (
long i = 0; i <= hi; ++i) {
492 const std::vector<long>& caps) {
493 std::vector<std::vector<T>> out;
494 if (m == 0)
return out;
520 const std::vector<std::size_t>& vec) {
521 std::vector<std::vector<std::size_t> > pu;
522 if (vec.empty())
return pu;
523 std::vector<std::size_t> uvec = vec;
524 std::sort(uvec.begin(), uvec.end());
525 uvec.erase(std::unique(uvec.begin(), uvec.end()), uvec.end());
526 if (uvec.size() == 1) {
530 if (uvec.size() == vec.size()) {
531 std::vector<std::size_t> p(vec.rbegin(), vec.rend());
534 }
while (std::prev_permutation(p.begin(), p.end()));
537 for (std::size_t i = 0; i < uvec.size(); ++i) {
538 std::vector<std::size_t> v = vec;
539 for (std::size_t j = 0; j < v.size(); ++j)
540 if (v[j] == uvec[i]) {
541 v.erase(v.begin() +
static_cast<std::ptrdiff_t
>(j));
545 for (std::size_t t = 0; t < tmp.size(); ++t) {
546 std::vector<std::size_t> row(1, uvec[i]);
547 row.insert(row.end(), tmp[t].begin(), tmp[t].end());
575 const std::vector<std::size_t>& n,
576 const std::vector<std::size_t>& phases) {
577 const std::size_t R =
sn.nclasses;
578 if (ist == 0 || ist >
sn.stations.size())
579 throw InputError(
"from_marginal: station index " + std::to_string(ist) +
" is out of range");
580 if (n.size() != R || phases.size() != R)
581 throw InputError(
"from_marginal: n and phases must have one entry per class");
591 for (std::size_t r = 0; r < R; ++r) {
593 if ((pt == ProcessType::MAP || pt == ProcessType::MMPP2) &&
594 sched != SchedStrategy::FCFS && st.
nodetype != NodeType::Source)
596 "from_marginal: a MAP/MMPP2 process at a non-FCFS station is not supported; "
597 "only the FCFS encoding carries the modulating phase");
608 bool is_retrial =
false;
610 const typename std::map<std::size_t, RetrialParam<T> >::const_iterator rit =
611 sn.retrialparam.find(ist);
612 if (rit !=
sn.retrialparam.end())
613 for (std::size_t r = 0; r < rit->second.retrial_proc.size(); ++r)
614 if (!rit->second.retrial_proc[r].disabled) { is_retrial =
true;
break; }
618 for (std::size_t r = 0; r < R; ++r)
619 if (n[r] > 0) { rr = r;
break; }
622 for (std::size_t r = 0; r < R; ++r) w += phases[r];
626 const std::size_t maxsrv =
627 std::isfinite(S) ? std::min(n[rr],
static_cast<std::size_t
>(S)) : n[rr];
628 const std::size_t maxorbit = n[rr];
629 std::vector<std::vector<T>> res3;
630 for (std::size_t csrv = 0; csrv <= maxsrv; ++csrv) {
631 const std::size_t orbit = n[rr] - csrv;
634 std::vector<std::vector<T>> srv3;
636 for (std::size_t cls = 0; cls < R; ++cls) {
637 const std::size_t want = cls == rr ? csrv : 0;
639 if (sc.empty() && want > 0) { ok3 =
false;
break; }
643 for (std::size_t i3 = 0; i3 < srv3.size(); ++i3) {
644 std::vector<T> row = buf;
645 row.insert(row.end(), srv3[i3].begin(), srv3[i3].end());
655 std::vector<std::vector<T>> out;
656 if (sched != SchedStrategy::EXT)
657 for (std::size_t r = 0; r < R; ++r)
661 if (
sn.classcap.size() >= ist && r <
sn.classcap[ist - 1].size() &&
662 static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
665 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI) {
684 const double W = ist <=
sn.cap.size() ?
sn.cap[ist - 1]
685 : std::numeric_limits<double>::infinity();
686 if (!std::isfinite(W))
688 "from_marginal: PAS stations require finite capacity for state-space generation");
689 const std::size_t w =
static_cast<std::size_t
>(W);
691 for (std::size_t r = 0; r < R; ++r) tot += n[r];
693 return std::vector<std::vector<T> >(
695 if (tot > w)
return out;
696 std::vector<std::size_t> vi;
697 for (std::size_t r = 0; r < R; ++r)
698 for (std::size_t j = 0; j < n[r]; ++j) vi.push_back(r + 1);
700 out.reserve(mi.size());
701 for (std::size_t i = 0; i < mi.size(); ++i) {
704 for (std::size_t j = 0; j < mi[i].size(); ++j)
726 for (std::size_t r = 0; r < R; ++r)
727 if (
sn.phases_of(ist, r + 1) == 0 && n[r] > 0)
730 if (state_detail::buffer_is_class_tag(sched) || state_detail::buffer_is_tag_phase_pairs(sched)) {
741 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
742 std::vector<std::size_t> vi;
743 for (std::size_t r = 0; r < R; ++r)
744 for (std::size_t j = 0; j < n[r]; ++j) vi.push_back(r + 1);
746 const std::size_t nsrv =
747 std::isfinite(S) ?
static_cast<std::size_t
>(S) : vi.size();
752 const std::size_t bw = state_detail::buffer_is_tag_phase_pairs(sched) ? 2u : 1u;
754 std::size_t srvw2 = 0;
755 for (std::size_t r = 0; r < R; ++r) srvw2 += phases[r];
757 return std::vector<std::vector<T>>{row};
765 std::sort(vi.begin(), vi.end(), [](std::size_t a, std::size_t b) { return a > b; });
766 std::vector<std::vector<T>> res2;
769 const std::size_t insrv = std::min(nsrv, vi.size());
770 std::vector<std::size_t> si(R, 0);
771 for (std::size_t j = vi.size() - insrv; j < vi.size(); ++j) si[vi[j] - 1] += 1;
772 std::vector<std::vector<T>> kst;
774 for (std::size_t r = 0; r < R; ++r) {
776 if (sr.empty() && si[r] > 0) { ok2 =
false;
break; }
780 std::vector<std::size_t> wait;
781 for (std::size_t j = 0; j + insrv < vi.size(); ++j) wait.push_back(vi[j]);
782 std::vector<std::vector<T>> bufs;
785 for (std::size_t j = 0; j < wait.size(); ++j)
789 }
else if (wait.empty()) {
794 bufs.push_back(std::vector<T>());
795 for (std::size_t j = 0; j < wait.size(); ++j) {
796 std::vector<std::vector<T>> next;
797 for (std::size_t b = 0; b < bufs.size(); ++b)
798 for (std::size_t p = 0; p < phases[wait[j] - 1]; ++p) {
799 std::vector<T> row = bufs[b];
807 for (std::size_t bi = 0; bi < bufs.size(); ++bi)
808 for (std::size_t i2 = 0; i2 < kst.size(); ++i2) {
809 std::vector<T> row = bufs[bi];
810 row.insert(row.end(), kst[i2].begin(), kst[i2].end());
813 }
while (std::prev_permutation(vi.begin(), vi.end()));
817 if (!state_detail::buffer_is_per_class_count(sched)) {
820 std::vector<std::vector<T>> srv;
821 for (std::size_t r = 0; r < R; ++r)
865 if (sched == SchedStrategy::POLLING && S != 1.0)
867 "from_marginal: a polling station must have exactly one server; the controller "
868 "encoding pins the visit to a single class at a time, so a multi-server polling "
869 "station cannot be represented (the reference refuses it the same way)");
870 const std::size_t nsrv =
871 std::isfinite(S) ?
static_cast<std::size_t
>(S) :
static_cast<std::size_t
>(-1);
872 std::size_t ntot = 0;
873 for (std::size_t r = 0; r < R; ++r) ntot += n[r];
874 const std::size_t maxsrv = std::min(nsrv, ntot);
875 const std::size_t minsrv = sched == SchedStrategy::POLLING ? 0 : maxsrv;
877 std::vector<std::vector<T>> res;
878 std::vector<std::size_t> sv(R, 0);
880 std::size_t stot = 0;
881 for (std::size_t r = 0; r < R; ++r) stot += sv[r];
882 if (stot >= minsrv && stot <= maxsrv) {
883 std::vector<std::vector<T>> srv_s;
885 for (std::size_t r = 0; r < R && ok; ++r) {
887 if (sr.empty() && sv[r] > 0) ok =
false;
892 for (std::size_t r = 0; r < R; ++r)
894 for (std::size_t i = 0; i < srv_s.size(); ++i) {
895 std::vector<T> row = buf;
896 row.insert(row.end(), srv_s[i].begin(), srv_s[i].end());
904 if (sv[r] < n[r]) { ++sv[r];
break; }
934 const std::vector<std::size_t>& nbuf) {
935 const std::size_t R = pi.
polled.size();
936 std::vector<std::vector<long>> trips;
939 if (!pi.
polled[srvclass - 1])
return std::vector<std::vector<T>>();
940 std::vector<long> ctrset;
949 for (
long c = 1; c <= static_cast<long>(nbuf[srvclass - 1]) + 1; ++c)
953 for (
long c = 1; c <= static_cast<long>(pi.
pk); ++c) ctrset.push_back(c);
957 for (
long c = 0; c <= static_cast<long>(nbuf[srvclass - 1]); ++c)
961 for (std::size_t i = 0; i < ctrset.size(); ++i)
962 trips.push_back(std::vector<long>{static_cast<long>(srvclass), 0, ctrset[i]});
965 for (std::size_t q = 1; q <= R; ++q) {
966 if (!pi.
has_sw[q - 1])
continue;
971 for (std::size_t k = 1; k <= pi.
ksw[q - 1]; ++k)
972 trips.push_back(std::vector<long>{static_cast<long>(q), static_cast<long>(k), 0});
974 std::size_t total = 0;
975 for (std::size_t r = 0; r < nbuf.size(); ++r) total += nbuf[r];
976 if (!anysw && total == 0) {
977 std::size_t first = 0;
978 for (std::size_t r = 1; r <= R; ++r)
979 if (pi.
polled[r - 1]) { first = r;
break; }
980 trips.push_back(std::vector<long>{
static_cast<long>(first), 0, 0});
984 const std::size_t npos =
static_cast<std::size_t
>(-1);
985 std::vector<std::vector<T>> out;
986 for (std::size_t i = 0; i < trips.size(); ++i) {
1023 std::vector<std::vector<T>> rows,
1024 const std::vector<std::size_t>& n,
1025 const std::vector<std::size_t>& phases) {
1026 if (rows.empty())
return rows;
1027 const std::size_t ind =
sn.node_of_station(ist);
1030 if (ind == 0)
return rows;
1031 const std::size_t width =
sn.nvars_of(ind);
1032 if (width == 0)
return rows;
1034 const std::size_t R =
sn.nclasses;
1036 const std::size_t pw = pi.
valid ? pi.
width : 0;
1044 const bool bas = ind <=
sn.isbasblocking.size() &&
sn.isbasblocking[ind - 1];
1050 const bool brk =
sn.has_breakdown_node(ind);
1051 std::size_t ntot = 0;
1052 for (std::size_t r = 0; r < n.size(); ++r) ntot += n[r];
1057 std::size_t rrw = 0;
1058 if (ind <=
sn.nvars.size())
1059 for (std::size_t r = 0; r < R && R + r <
sn.nvars[ind - 1].size(); ++r)
1060 rrw +=
sn.nvars[ind - 1][R + r];
1061 std::vector<std::vector<T>> ptrsets(1, std::vector<T>());
1062 for (std::size_t r = 1; r <= R; ++r) {
1063 if (
sn.rr_var_slot(ind, r) == 0)
continue;
1064 std::vector<T> vals;
1065 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1066 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
1067 for (std::size_t d = 0; d < ol.size(); ++d)
1070 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
1071 for (std::size_t d = 0; d < cy.size(); ++d)
1074 if (vals.empty()) vals.push_back(zero);
1075 std::vector<std::vector<T>> grown;
1076 for (std::size_t g = 0; g < ptrsets.size(); ++g)
1077 for (std::size_t v = 0; v < vals.size(); ++v) {
1078 std::vector<T> row = ptrsets[g];
1079 row.push_back(vals[v]);
1080 grown.push_back(row);
1082 ptrsets.swap(grown);
1085 std::vector<std::vector<T>> out;
1086 for (std::size_t i = 0; i < rows.size(); ++i) {
1089 std::vector<std::size_t> nbuf(R, 0);
1090 std::size_t srvclass = 0;
1092 std::size_t srvw = 0;
1093 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1094 const std::size_t srv0 = rows[i].size() - srvw;
1095 std::size_t off = 0;
1096 for (std::size_t r = 0; r < R; ++r) {
1098 for (std::size_t k = 0; k < phases[r]; ++k)
1099 c +=
static_cast<std::size_t
>(
1102 if (c > 0 && srvclass == 0) srvclass = r + 1;
1105 if (srv0 >= R) nbuf[r] =
static_cast<std::size_t
>(
1109 const std::vector<std::vector<T>> blocks =
1111 : std::vector<std::vector<T>>(1, std::vector<T>());
1119 const std::size_t head = pi.
valid ? pi.
off : width - pw;
1120 for (std::size_t b = 0; b < blocks.size(); ++b) {
1121 for (std::size_t g = 0; g < ptrsets.size(); ++g) {
1122 std::vector<T> row = rows[i];
1123 row.insert(row.end(), head - rrw, zero);
1124 row.insert(row.end(), ptrsets[g].begin(), ptrsets[g].end());
1125 row.insert(row.end(), blocks[b].begin(), blocks[b].end());
1126 row.insert(row.end(), width - head - pw, zero);
1128 for (
long v = 1; v >= 0; --v) {
1129 std::vector<T> r2 = row;
1143 for (std::size_t v = 0; v <= (ntot > 0 ? 1u : 0u); ++v) {
1144 std::vector<T> r2 = row;
1155 std::size_t srvw = 0;
1156 for (std::size_t r = 0; r < R && r < phases.size(); ++r) srvw += phases[r];
1157 for (std::size_t r = 1; r <= R; ++r) {
1159 if (
mc ==
nullptr ||
sn.nvars[ind - 1][r - 1] == 0)
continue;
1160 const std::size_t slot =
sn.map_var_slot(ind, r);
1161 std::size_t off = 0;
1162 for (std::size_t j = 0; j + 1 < r; ++j) off += phases[j];
1163 std::vector<std::vector<T>> grown;
1164 grown.reserve(out.size() *
mc->p);
1165 for (std::size_t i = 0; i < out.size(); ++i) {
1166 const std::size_t srv0 = out[i].size() - width - srvw;
1167 std::size_t busy = 0;
1168 for (std::size_t k = 0;
mc->single && k < phases[r - 1] && busy == 0; ++k)
1170 for (std::size_t h = 1; h <=
mc->p; ++h) {
1171 if (busy != 0 && h != busy)
continue;
1172 std::vector<T> row = out[i];
1174 grown.push_back(row);
1182namespace state_detail {
1190void pool_allocations(
const CtmcPool<T>& pool,
const std::vector<std::size_t>& n, std::size_t r,
1191 std::size_t k, std::vector<std::vector<std::size_t>>& x,
1192 std::vector<double>& load,
1193 std::vector<std::vector<std::vector<std::size_t>>>& out) {
1194 const std::size_t R = n.size();
1196 for (std::size_t s = 0; s < R; ++s) {
1197 if (pool.pools[s].empty())
continue;
1198 std::size_t ins = 0;
1199 for (std::size_t j = 0; j < x[s].size(); ++j) ins += x[s][j];
1200 if (n[s] <= ins)
continue;
1201 for (std::size_t j = 0; j < pool.pools[s].size(); ++j) {
1202 const std::size_t t = pool.pools[s][j];
1203 if (load[t - 1] < pool.count[t - 1])
return;
1209 if (pool.pools[r].empty() || k == pool.pools[r].size()) {
1210 pool_allocations(pool, n, r + 1, 0, x, load, out);
1213 const std::size_t t = pool.pools[r][k];
1214 std::size_t used = 0;
1215 for (std::size_t j = 0; j < k; ++j) used += x[r][j];
1216 const double room = pool.count[t - 1] - load[t - 1];
1217 const std::size_t cmax = std::min<std::size_t>(
1218 n[r] - used, room > 0 ?
static_cast<std::size_t
>(room + 0.5) : 0);
1219 for (std::size_t c = 0; c <= cmax; ++c) {
1221 load[t - 1] +=
static_cast<double>(c);
1222 pool_allocations(pool, n, r, k + 1, x, load, out);
1223 load[t - 1] -=
static_cast<double>(c);
1241 const std::vector<std::size_t>& n) {
1242 const std::size_t R =
sn.nclasses;
1243 const std::size_t ind =
sn.node_of_station(ist);
1246 std::vector<std::vector<T>> space;
1247 if (
sn.nvars_of(ind) != (pool.
rotate ? 1u : 0u))
1249 "' carries local variables that a heterogeneous server pool "
1251 std::size_t ntot = 0;
1252 for (std::size_t r = 0; r < R; ++r) {
1254 if (
sn.classcap.size() >= ist && r <
sn.classcap[ist - 1].size() &&
1255 static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
1257 if (pool.
pools[r].empty() && n[r] > 0)
return space;
1259 const double cap =
sn.cap[ist - 1];
1260 if (
static_cast<double>(ntot) > cap)
return space;
1261 const bool siro =
sn.stations[ist - 1].sched == SchedStrategy::SIRO;
1262 const std::size_t W =
1264 : std::max<std::size_t>(1, std::isfinite(cap) ? std::min<std::size_t>(
1265 ntot,
static_cast<std::size_t
>(cap))
1267 std::vector<std::vector<std::size_t>> x(R);
1268 for (std::size_t r = 0; r < R; ++r) x[r].assign(pool.
pools[r].size(), 0);
1269 std::vector<double> load(pool.
ntypes, 0.0);
1270 std::vector<std::vector<std::vector<std::size_t>>> alloc;
1271 state_detail::pool_allocations(pool, n, 0, 0, x, load, alloc);
1272 for (std::size_t a = 0; a < alloc.size(); ++a) {
1273 std::vector<std::size_t> w = n;
1274 for (std::size_t r = 0; r < R; ++r)
1275 for (std::size_t k = 0; k < alloc[a][r].size(); ++k) w[r] -= alloc[a][r][k];
1277 std::vector<std::vector<T>> srvset;
1279 for (std::size_t r = 0; r < R && ok; ++r) {
1280 const std::size_t Kr =
sn.phasessz_of(ist, r + 1);
1281 std::vector<std::vector<T>> blk;
1282 if (pool.
pools[r].empty()) {
1283 blk.push_back(std::vector<T>(Kr, zero));
1285 for (std::size_t k = 0; k < pool.
pools[r].size(); ++k) {
1286 const std::vector<std::vector<T>> sc =
1288 if (sc.empty()) { ok =
false;
break; }
1291 for (std::size_t b = 0; b < blk.
size(); ++b)
1292 if (blk[b].size() < Kr) blk[b].resize(Kr, zero);
1298 std::vector<std::vector<T>> bufset;
1300 std::vector<T> b(R, zero);
1301 for (std::size_t r = 0; r < R; ++r) b[r] = num_traits<T>::from_int(
static_cast<long>(w[r]));
1302 bufset.push_back(b);
1304 std::vector<std::size_t> vi;
1305 for (std::size_t r = 0; r < R; ++r) vi.insert(vi.end(), w[r], r + 1);
1306 if (vi.size() > W)
continue;
1308 std::vector<T> b(W - vi.size(), zero);
1309 for (std::size_t j = 0; j < vi.size(); ++j)
1311 bufset.push_back(b);
1312 }
while (std::next_permutation(vi.begin(), vi.end()));
1314 const std::vector<std::vector<T>> part =
cartesian(bufset, srvset);
1315 space.insert(space.end(), part.begin(), part.end());
1318 std::vector<std::vector<T>> ords;
1319 for (std::size_t p = 1; p <= pool.
perms.size(); ++p)
1323 const auto less = [](
const std::vector<T>& a,
const std::vector<T>& b) {
1324 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1326 if (av != bv)
return av > bv;
1328 return a.size() < b.size();
1330 const auto same = [](
const std::vector<T>& a,
const std::vector<T>& b) {
1331 if (a.size() != b.size())
return false;
1332 for (std::size_t i = 0; i < a.size(); ++i)
1336 std::sort(space.begin(), space.end(), less);
1337 space.erase(std::unique(space.begin(), space.end(), same), space.end());
1343 const std::vector<std::size_t>& n,
1344 const std::vector<std::size_t>& phases) {
1345 const std::size_t jnd0 =
sn.node_of_station(ist);
1347 if (jnd0 != 0 && !
sn.ctmcpool.empty() &&
sn.ctmcpool.count(jnd0))
1352 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1354 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1356 return std::vector<std::vector<T>>(1, row);
1369 if (jnd0 != 0 &&
sn.replyblock.size() >= jnd0) {
1370 std::vector<std::size_t> rclasses;
1371 for (std::size_t r = 0; r <
sn.replyblock[jnd0 - 1].size(); ++r)
1372 if (
sn.replyblock[jnd0 - 1][r]) rclasses.push_back(r + 1);
1373 if (!rclasses.empty()) {
1374 const double Sd =
sn.stations[ist - 1].nservers;
1375 const std::size_t S =
1376 std::isfinite(Sd) ?
static_cast<std::size_t
>(Sd) :
static_cast<std::size_t
>(0);
1381 if (snb.
nvars.size() >= jnd0)
1382 for (std::size_t r = 1; r <=
sn.nclasses && 2 *
sn.nclasses + r < snb.
nvars[jnd0 - 1].size();
1384 snb.
nvars[jnd0 - 1][2 *
sn.nclasses + r] = 0;
1385 std::vector<std::vector<std::size_t>> bspace(1, std::vector<std::size_t>());
1386 for (std::size_t i = 0; i < rclasses.size(); ++i) {
1387 std::vector<std::vector<std::size_t>> next;
1388 for (std::size_t j = 0; j < bspace.size(); ++j)
1389 for (std::size_t v = 0; v <= S; ++v) {
1390 std::vector<std::size_t> row = bspace[j];
1392 next.push_back(row);
1396 std::vector<std::vector<std::vector<T>>> subs(bspace.size());
1397 std::size_t maxw = 0;
1398 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1399 std::size_t tot = 0;
1400 for (std::size_t i = 0; i < bspace[bi].size(); ++i) tot += bspace[bi][i];
1401 if (tot > S)
continue;
1402 snb.
stations[ist - 1].nservers =
static_cast<double>(S - tot);
1404 for (std::size_t i = 0; i < subs[bi].size(); ++i)
1405 maxw = std::max(maxw, subs[bi][i].size());
1410 std::vector<std::vector<T>> out;
1411 for (std::size_t bi = 0; bi < bspace.size(); ++bi) {
1412 for (std::size_t i = 0; i < subs[bi].size(); ++i) {
1414 row.reserve(maxw + bspace[bi].size());
1415 if (subs[bi][i].size() < maxw)
1417 row.insert(row.end(), subs[bi][i].begin(), subs[bi][i].end());
1418 for (std::size_t j = 0; j < bspace[bi].size(); ++j)
1423 std::sort(out.begin(), out.end(), [](
const std::vector<T>& a,
const std::vector<T>& b) {
1424 for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
1425 const double av = num_traits<T>::to_double(a[i]);
1426 const double bv = num_traits<T>::to_double(b[i]);
1427 if (av != bv) return av < bv;
1429 return a.size() < b.size();
1431 out.erase(std::unique(out.begin(), out.end(),
1432 [](
const std::vector<T>& a,
const std::vector<T>& b) {
1433 if (a.size() != b.size()) return false;
1434 for (std::size_t i = 0; i < a.size(); ++i)
1435 if (num_traits<T>::to_double(a[i]) !=
1436 num_traits<T>::to_double(b[i]))
1488 const std::vector<std::size_t>& n,
1489 const std::vector<std::size_t>& s,
1490 const std::vector<std::size_t>& phases) {
1491 const std::size_t R =
sn.nclasses;
1492 if (ist == 0 || ist >
sn.stations.size())
1493 throw InputError(
"from_marginal_and_started: station index " + std::to_string(ist) +
1494 " is out of range");
1495 if (n.size() != R || s.size() != R || phases.size() != R)
1496 throw InputError(
"from_marginal_and_started: n, s and phases must have one entry per class");
1500 std::vector<std::vector<T>> out;
1502 std::size_t ntot = 0, stot = 0;
1503 for (std::size_t r = 0; r < R; ++r) {
1504 if (s[r] > n[r])
return out;
1511 if (ist <=
sn.classcap.size())
1512 for (std::size_t r = 0; r < R && r <
sn.classcap[ist - 1].size(); ++r)
1513 if (
static_cast<double>(n[r]) >
sn.classcap[ist - 1][r])
return out;
1515 if (S > 0.0 && std::isfinite(S) &&
static_cast<double>(stot) > S)
return out;
1518 if (sched == SchedStrategy::PAS || sched == SchedStrategy::OI)
1524 if (sched == SchedStrategy::EXT || st.
nodetype == NodeType::Source) {
1531 std::vector<std::vector<T>> srv;
1532 for (std::size_t r = 0; r < R; ++r) {
1533 if (phases[r] == 0)
continue;
1538 if (r <
sn.classes.size() && std::isinf(
sn.classes[r].population) &&
1539 !
sn.disabled[ist - 1][r] &&
sn.markidx_of(ist, r + 1) <= 1)
1541 srv =
cartesian(srv, std::vector<std::vector<T>>(1, init));
1543 if (srv.empty()) srv.push_back(std::vector<T>());
1544 for (std::size_t i = 0; i < srv.size(); ++i) {
1546 std::numeric_limits<double>::infinity()));
1547 row.insert(row.end(), srv[i].begin(), srv[i].end());
1554 const auto phase_one_block = [&](
const std::vector<std::size_t>& cnt,
1555 bool* ok) -> std::vector<T> {
1558 for (std::size_t r = 0; r < R; ++r) {
1563 if (
sn.phases_of(ist, r + 1) == 0 && cnt[r] > 0) *ok =
false;
1564 if (phases[r] == 0)
continue;
1570 std::size_t srvw = 0;
1571 for (std::size_t r = 0; r < R; ++r) srvw += phases[r];
1573 if (state_detail::buffer_is_per_class_count(sched)) {
1577 const bool all_in_service = std::isfinite(S) &&
static_cast<double>(ntot) <= S;
1578 std::vector<std::size_t> insrv(R, 0), wait(R, 0);
1579 for (std::size_t r = 0; r < R; ++r) {
1580 insrv[r] = all_in_service ? n[r] : s[r];
1581 wait[r] = n[r] - insrv[r];
1584 const std::vector<T> blk = phase_one_block(insrv, &ok);
1585 if (!ok)
return out;
1587 for (std::size_t r = 0; r < R; ++r)
1589 row.insert(row.end(), blk.begin(), blk.end());
1594 const bool paired = state_detail::buffer_is_tag_phase_pairs(sched);
1595 if (state_detail::buffer_is_class_tag(sched) || paired) {
1601 const std::size_t bw = paired ? 2u : 1u;
1607 std::vector<std::size_t> inbuf;
1608 for (std::size_t r = 0; r < R; ++r)
1609 for (std::size_t j = 0; j < n[r] - s[r]; ++j) inbuf.push_back(r + 1);
1612 std::sort(inbuf.begin(), inbuf.end(),
1613 [](std::size_t a, std::size_t b) { return a > b; });
1616 const std::vector<T> blk = phase_one_block(s, &ok);
1617 if (!ok)
return out;
1620 if (inbuf.empty()) {
1623 for (std::size_t j = 0; j < inbuf.size(); ++j) {
1629 static_cast<long>(phases[inbuf[j] - 1])));
1632 row.insert(row.end(), blk.begin(), blk.end());
1640 const std::vector<T> blk = phase_one_block(n, &ok);
1641 if (!ok)
return out;
1654 const std::vector<std::size_t>& n,
1655 const std::vector<std::size_t>& s,
1656 const std::vector<std::size_t>& phases) {
1657 const std::size_t jnd0 =
sn.node_of_station(ist);
1658 if (
sn.isfjaugmented && jnd0 != 0 &&
sn.nodes[jnd0 - 1].nodetype == NodeType::Join) {
1660 for (std::size_t r = 0; r <
sn.nclasses && r < n.size(); ++r)
1662 return std::vector<std::vector<T>>(1, row);
1681 const std::vector<std::size_t>& n,
1682 const std::vector<std::size_t>& phases) {
1683 if (ind == 0 || ind >
sn.nodes.size())
1684 throw InputError(
"from_marginal_node: node index " + std::to_string(ind) +
1685 " is out of range");
1688 if (!nd.
stateful)
return std::vector<std::vector<T>>();
1690 const std::size_t R =
sn.nclasses;
1692 throw InputError(
"from_marginal_node: n must have one entry per class");
1694 if (nd.
nodetype == NodeType::Transition) {
1700 const typename std::map<std::size_t, TransitionParam<T> >::const_iterator it =
1701 sn.transparam.find(ind);
1702 if (it ==
sn.transparam.end())
1704 "from_marginal_node: transition node has no TransitionParam; build it with "
1708 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm) {
1713 std::size_t fph = 0;
1714 for (std::size_t mm = 0; mm < tp.
nmodes; ++mm)
1718 return std::vector<std::vector<T> >{row};
1731 if (nd.
nodetype == NodeType::Cache) {
1732 const typename std::map<std::size_t, CacheParam<T> >::const_iterator cc =
1733 sn.nodeparam.find(ind);
1734 if (cc !=
sn.nodeparam.end()) {
1735 const std::size_t pend =
1736 cc->second.retrieval_capacity > 0 && cc->second.max_pending_retrieval > 0
1737 ?
static_cast<std::size_t
>(cc->second.max_pending_retrieval)
1739 std::size_t tot = 0;
1740 for (std::size_t r = 0; r < R; ++r) {
1741 bool is_hit =
false;
1742 for (std::size_t u = 0; u < cc->second.hitclass.size(); ++u)
1743 if (cc->second.hitclass[u] == r + 1) is_hit =
true;
1744 if (n[r] > (is_hit ? 1 + pend : 1))
return std::vector<std::vector<T> >();
1747 if (tot > 1 + pend)
return std::vector<std::vector<T> >();
1754 std::vector<std::vector<T> > acc;
1755 for (std::size_t r = 0; r < R; ++r) {
1757 if (sr.empty() && n[r] > 0)
return std::vector<std::vector<T> >();
1770 std::vector<std::vector<T> > ptrsets(1, std::vector<T>());
1772 for (std::size_t r = 1; r <= R; ++r) {
1773 if (
sn.rr_var_slot(ind, r) == 0)
continue;
1775 std::vector<T> vals;
1776 if (
sn.nodes[ind - 1].routing[r - 1] == RoutingStrategy::RROBIN) {
1777 const std::vector<std::size_t> ol =
sn.rr_outlinks(ind, r);
1778 for (std::size_t u = 0; u < ol.size(); ++u)
1781 const std::vector<std::size_t> cy =
sn.rr_weighted_outlinks(ind, r);
1782 for (std::size_t u = 0; u < cy.size(); ++u)
1786 std::vector<std::vector<T> > grown;
1787 for (std::size_t g = 0; g < ptrsets.size(); ++g)
1788 for (std::size_t v = 0; v < vals.size(); ++v) {
1789 std::vector<T> row = ptrsets[g];
1790 row.push_back(vals[v]);
1791 grown.push_back(row);
1793 ptrsets.swap(grown);
1818 if (nd.
nodetype == NodeType::Cache) {
1819 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
1820 sn.nodeparam.find(ind);
1821 if (ci ==
sn.nodeparam.end())
return acc;
1823 std::size_t tcc = 0;
1824 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
1825 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
1827 const std::size_t first_item = tcc <= cp.
nitems ? 1 : 0;
1828 std::vector<std::vector<T> > contents(1, std::vector<T>());
1829 for (std::size_t slot = 0; slot < tcc; ++slot) {
1830 std::vector<std::vector<T> > grown;
1831 for (std::size_t c = 0; c < contents.size(); ++c)
1832 for (std::size_t item = first_item; item <= cp.
nitems; ++item) {
1835 for (std::size_t j = 0; j < contents[c].size(); ++j)
1837 static_cast<double>(item)) { dup =
true;
break; }
1839 std::vector<T> row = contents[c];
1841 grown.push_back(row);
1843 contents.swap(grown);
1848 for (std::size_t i = 0; i < cp.
nitems; ++i) {
1849 std::vector<std::vector<T> > grown;
1850 for (std::size_t c = 0; c < contents.size(); ++c)
1851 for (
int b = 0; b <= 1; ++b) {
1852 std::vector<T> row = contents[c];
1854 grown.push_back(row);
1856 contents.swap(grown);
1864 std::vector<std::size_t> rcl, rci, rco;
1867 const long maxpend =
1869 std::vector<std::vector<T> > grown;
1870 for (std::size_t c = 0; c < contents.size(); ++c) {
1873 std::vector<std::size_t> active;
1874 for (std::size_t j = 0; j < rcl.size(); ++j)
1876 active.push_back(j);
1877 std::vector<std::vector<long> > pend(1, std::vector<long>(rcl.size(), 0));
1878 for (std::size_t a = 0; a < active.size(); ++a) {
1879 std::vector<std::vector<long> > next;
1880 for (std::size_t q = 0; q < pend.size(); ++q) {
1882 for (std::size_t j = 0; j < rcl.size(); ++j) used += pend[q][j];
1883 for (
long v = 0; v + used <= maxpend; ++v) {
1884 std::vector<long> row = pend[q];
1886 next.push_back(row);
1891 for (std::size_t q = 0; q < pend.size(); ++q) {
1892 std::vector<T> row = contents[c];
1893 for (std::size_t j = 0; j < rcl.size(); ++j)
1895 grown.push_back(row);
1898 contents.swap(grown);
1901 std::vector<std::vector<T> > joint =
cartesian(acc, contents);
1913 std::vector<bool> is_hit(R,
false), is_miss(R,
false);
1914 for (std::size_t u = 0; u < cp.
hitclass.size(); ++u)
1916 for (std::size_t u = 0; u < cp.
missclass.size(); ++u)
1919 std::vector<std::vector<T> > kept;
1920 for (std::size_t row = 0; row < joint.size(); ++row) {
1921 const std::vector<T>& st = joint[row];
1922 double tot = 0, other = 0, miss = 0;
1923 for (std::size_t r = 0; r < R; ++r) {
1926 if (is_miss[r]) miss += v;
1927 else if (!is_hit[r]) other += v;
1932 if (!(tot <= 1 || (other == 0 && miss <= 1 && tot <= 1 + maxpend)))
continue;
1935 for (std::size_t i = 0; i < cp.
nitems && ok; ++i) {
1939 for (std::size_t c = 0; c < tcc; ++c)
1963 const std::vector<std::size_t>& s,
const std::vector<std::size_t>& phases) {
1964 if (ind == 0 || ind >
sn.nodes.size())
1965 throw InputError(
"from_marginal_node_and_started: node index " + std::to_string(ind) +
1966 " is out of range");
1970 "from_marginal_node_and_started cannot be used on Petri net elements");
1972 if (!nd.
stateful)
return std::vector<std::vector<T>>();
2007 const std::vector<std::size_t>& phases) {
2008 if (ind == 0 || ind >
sn.nodes.size())
2009 throw InputError(
"from_marg_node: node index " + std::to_string(ind) +
" is out of range");
2011 const std::size_t R =
sn.nclasses;
2014 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
2016 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
2017 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
2020 std::vector<std::vector<int>> nset;
2022 nset.push_back(std::vector<int>(R, 0));
2024 const std::vector<std::vector<int>> all =
2026 for (std::size_t j = 0; j < all.size(); ++j) {
2028 for (std::size_t r = 0; r < R && ok; ++r)
2029 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
2030 if (ok) nset.push_back(all[j]);
2034 std::vector<std::vector<T>> space;
2035 std::size_t maxw = 0;
2036 std::vector<std::vector<std::vector<T>>> subspaces;
2037 for (std::size_t j = 0; j < nset.size(); ++j) {
2038 std::vector<std::size_t> nj(R, 0);
2039 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
2041 if (sj.empty())
continue;
2042 for (std::size_t a = 0; a < sj.size(); ++a) maxw = std::max(maxw, sj[a].size());
2043 subspaces.push_back(sj);
2045 for (std::size_t j = 0; j < subspaces.size(); ++j)
2046 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
2047 std::vector<T> row = subspaces[j][a];
2048 if (row.size() < maxw)
2050 space.push_back(row);
2052 if (space.empty())
return space;
2054 std::sort(space.begin(), space.end());
2055 space.erase(std::unique(space.begin(), space.end()), space.end());
2056 std::reverse(space.begin(), space.end());
2060namespace state_detail {
2071inline std::vector<std::vector<std::size_t> > multichoosecon(
const std::vector<std::size_t>& n,
2073 const std::size_t R = n.size();
2074 std::vector<std::vector<std::size_t> > out;
2075 if (R == 0)
return out;
2077 out.push_back(std::vector<std::size_t>(R, 0));
2081 for (std::size_t i = 0; i < R; ++i)
2083 std::vector<std::size_t> row(R, 0);
2089 for (std::size_t i = 0; i < R; ++i) {
2090 if (n[i] == 0)
continue;
2091 std::vector<std::size_t> n1 = n;
2093 const std::vector<std::vector<std::size_t> > tail = multichoosecon(n1, S - 1);
2094 for (std::size_t k = 0; k < tail.size(); ++k) {
2095 std::vector<std::size_t> row = tail[k];
2127 std::size_t ntot, std::size_t stot,
2128 const std::vector<std::size_t>& phases) {
2129 if (ind == 0 || ind >
sn.nodes.size())
2130 throw InputError(
"from_marg_node_started: node index " + std::to_string(ind) +
2131 " is out of range");
2132 std::vector<std::vector<T>> space;
2133 if (stot > ntot)
return space;
2136 const std::size_t R =
sn.nclasses;
2138 std::vector<double> ccap(R, std::numeric_limits<double>::infinity());
2140 const std::vector<double>& row =
sn.classcap[nd.
station - 1];
2141 for (std::size_t r = 0; r < R && r < row.size(); ++r) ccap[r] = row[r];
2144 std::vector<std::vector<int>> nset;
2146 nset.push_back(std::vector<int>(R, 0));
2148 const std::vector<std::vector<int>> all =
2150 for (std::size_t j = 0; j < all.size(); ++j) {
2152 for (std::size_t r = 0; r < R && ok; ++r)
2153 if (
static_cast<double>(all[j][r]) > ccap[r]) ok =
false;
2154 if (ok) nset.push_back(all[j]);
2158 std::size_t maxw = 0;
2159 std::vector<std::vector<std::vector<T>>> subspaces;
2160 for (std::size_t j = 0; j < nset.size(); ++j) {
2161 std::vector<std::size_t> nj(R, 0);
2162 for (std::size_t r = 0; r < R; ++r) nj[r] = static_cast<std::size_t>(nset[j][r]);
2163 const std::vector<std::vector<std::size_t> > sset =
2164 state_detail::multichoosecon(nj, stot);
2165 for (std::size_t k = 0; k < sset.size(); ++k) {
2166 const std::vector<std::vector<T>> sjk =
2168 if (sjk.empty())
continue;
2169 for (std::size_t a = 0; a < sjk.size(); ++a) maxw = std::max(maxw, sjk[a].size());
2170 subspaces.push_back(sjk);
2173 for (std::size_t j = 0; j < subspaces.size(); ++j)
2174 for (std::size_t a = 0; a < subspaces[j].size(); ++a) {
2175 std::vector<T> row = subspaces[j][a];
2176 if (row.size() < maxw)
2178 space.push_back(row);
2180 if (space.empty())
return space;
2182 std::sort(space.begin(), space.end());
2183 space.erase(std::unique(space.begin(), space.end()), space.end());
2184 std::reverse(space.begin(), space.end());
2213 const std::vector<std::size_t>& n,
2214 const std::vector<std::size_t>& phases, std::vector<T>& out) {
2215 if (ind == 0 || ind >
sn.nodes.size())
2216 throw InputError(
"from_marginal_node_first: node index " + std::to_string(ind) +
2217 " is out of range");
2221 if (rows.empty())
return false;
2226 const std::size_t R =
sn.nclasses;
2228 throw InputError(
"from_marginal_node_first: n must have one entry per class");
2230 for (std::size_t r = 0; r < R; ++r) {
2234 if (n[r] > 0)
return false;
2237 out.insert(out.end(), sr[0].begin(), sr[0].end());
2240 const typename std::map<std::size_t, CacheParam<T> >::const_iterator ci =
2241 sn.nodeparam.find(ind);
2242 if (ci ==
sn.nodeparam.end())
return true;
2244 std::size_t tcc = 0;
2245 for (std::size_t u = 0; u < cp.
itemcap.size(); ++u)
2246 if (cp.
itemcap[u] > 0) tcc +=
static_cast<std::size_t
>(cp.
itemcap[u]);
2247 for (std::size_t slot = 0; slot < tcc; ++slot)
2249 tcc <= cp.
nitems ?
static_cast<long>(slot + 1) : 0L));
2252 std::vector<std::size_t> rcl, rci, rco;
2266 std::size_t M,
const std::vector<std::size_t>& N,
2267 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2268 std::vector<std::vector<T>> ss;
2269 for (std::size_t r = 0; r < N.size(); ++r) {
2270 const std::vector<std::vector<T>> sr =
2273 if (sr.empty())
return std::vector<std::vector<T>>();
2293 std::size_t M,
const std::vector<std::size_t>& N,
2294 const std::vector<std::vector<bool>>& chains,
2295 const std::vector<std::vector<long>>& caps = std::vector<std::vector<long>>()) {
2296 const std::size_t C = chains.size();
2297 const std::size_t R = N.size();
2299 std::vector<std::vector<std::vector<int>>> chainInitPos(C);
2300 std::vector<std::size_t> inchain_sz(C, 0);
2301 for (std::size_t c = 0; c < C; ++c) {
2302 std::size_t tot = 0, k = 0;
2303 for (std::size_t r = 0; r < R; ++r)
2304 if (chains[c][r]) { tot += N[r]; ++k; }
2306 chainInitPos[c] = k == 0 ? std::vector<std::vector<int>>{std::vector<int>()}
2309 std::vector<std::vector<T>> ss;
2310 std::vector<std::size_t> v(C, 0);
2312 std::vector<std::size_t> subN;
2314 for (std::size_t c = 0; c < C; ++c) {
2315 const std::vector<int>& row = chainInitPos[c][v[c]];
2316 for (std::size_t j = 0; j < row.size(); ++j)
2317 subN.push_back(
static_cast<std::size_t
>(row[j]));
2323 std::vector<std::size_t> subNg(R, 0);
2326 for (std::size_t c = 0; c < C; ++c)
2327 for (std::size_t r = 0; r < R; ++r)
2328 if (chains[c][r]) subNg[r] = subN[k++];
2330 const std::vector<std::vector<T>> blk =
2333 ss.insert(ss.end(), blk.begin(), blk.end());
2336 for (; c < C; ++c) {
2337 if (++v[c] < chainInitPos[c].size())
break;
2362 if (ind == 0 || ind >
sn.nodes.size())
return 0;
2363 if (
sn.nodes[ind - 1].nodetype != NodeType::Place)
return 0;
2364 const typename std::map<std::size_t, std::vector<T>>::const_iterator it =
2365 sn.initmarking.find(ind);
2366 if (it ==
sn.initmarking.end() || r >= it->second.size())
return 0;
2368 return v > 0 ?
static_cast<std::size_t
>(v) : 0;
2399 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2400 std::vector<std::vector<std::size_t>>()) {
2401 const std::size_t R =
sn.nclasses, N =
sn.nodes.size();
2402 std::vector<std::vector<std::size_t>> cap(N, std::vector<std::size_t>(R, 0));
2403 const std::vector<double> njobs =
sn.njobs();
2407 std::size_t maxpend = 0;
2408 for (std::size_t r = 0; r < R; ++r)
2409 if (!std::isfinite(njobs[r])) maxpend = std::max(maxpend, cutoff[r]);
2410 if (maxpend > 0) --maxpend;
2412 for (std::size_t ind = 1; ind <= N; ++ind) {
2415 const std::size_t ist = nd.
station;
2416 const std::size_t isf =
sn.stateful_index(ind);
2417 if (ist != 0 && nd.
nodetype != NodeType::Source) {
2418 for (std::size_t r = 0; r < R; ++r) {
2420 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2421 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2422 const bool novisit = c <
sn.visits.size() &&
sn.visits[c].rows() != 0 &&
2423 isf != 0 && isf - 1 <
sn.visits[c].rows() &&
2429 if (nd.
nodetype != NodeType::Place && ist - 1 <
sn.disabled.size() &&
2430 r <
sn.disabled[ist - 1].size() &&
sn.disabled[ist - 1][r]) {
2431 cap[ind - 1][r] = 0;
2435 if (!std::isfinite(njobs[r])) {
2440 b =
static_cast<double>(
2441 (!cutoff_mat.empty() && ist - 1 < cutoff_mat.size() &&
2442 r < cutoff_mat[ist - 1].size())
2443 ? cutoff_mat[ist - 1][r]
2447 for (std::size_t k = 0; k < R; ++k)
2448 if (c <
sn.chains.size() && k <
sn.chains[c].size() &&
sn.chains[c][k] &&
2449 std::isfinite(njobs[k]))
2452 if (ist - 1 <
sn.classcap.size() && r <
sn.classcap[ist - 1].size())
2453 b = std::min(b,
sn.classcap[ist - 1][r]);
2455 for (std::size_t f = 0; f <
sn.regions.size(); ++f) {
2457 if (ist - 1 >= rg.
cap.size())
continue;
2458 if (r < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][r] >= 0)
2459 b = std::min(b, rg.
cap[ist - 1][r]);
2460 if (R < rg.
cap[ist - 1].size() && rg.
cap[ist - 1][R] >= 0)
2461 b = std::min(b, rg.
cap[ist - 1][R]);
2463 if (!(b > 0)) b = 0;
2464 cap[ind - 1][r] = std::isfinite(b) ?
static_cast<std::size_t
>(b)
2465 :
static_cast<std::size_t
>(-1);
2470 case NodeType::Cache: {
2471 for (std::size_t r = 0; r < R; ++r) cap[ind - 1][r] = 1;
2472 const typename std::map<std::size_t, CacheParam<T>>::const_iterator ci =
2473 sn.nodeparam.find(ind);
2474 if (ci !=
sn.nodeparam.end() && ci->second.retrieval_capacity > 0)
2475 for (std::size_t r = 0; r < R; ++r)
2476 for (std::size_t k = 0; k < ci->second.hitclass.size(); ++k)
2477 if (ci->second.hitclass[k] == r + 1) cap[ind - 1][r] = 1 + maxpend;
2480 case NodeType::Router:
2481 for (std::size_t r = 0; r < R; ++r) {
2483 for (std::size_t cc = 0; cc <
sn.chains.size(); ++cc)
2484 if (r <
sn.chains[cc].size() &&
sn.chains[cc][r]) { c = cc;
break; }
2486 (c <
sn.nodevisits.size() &&
sn.nodevisits[c].rows() != 0 &&
2487 ind - 1 <
sn.nodevisits[c].rows() &&
2496 for (std::size_t r = 0; r < R; ++r)
2497 cap[ind - 1][r] =
static_cast<std::size_t
>(-1);
2522 std::size_t maxst = 3000000,
2523 const std::vector<std::vector<std::size_t>>& cutoff_mat =
2524 std::vector<std::vector<std::size_t>>()) {
2525 const std::size_t R =
sn.nclasses;
2526 if (cutoff.size() != R)
2527 throw InputError(
"space_generator: cutoff must have one entry per class");
2537 const std::vector<double> njobs =
sn.njobs();
2538 std::vector<std::size_t> Np(R, 0);
2539 for (std::size_t r = 0; r < R; ++r) {
2540 const double nj = njobs[r];
2541 if (std::isfinite(nj)) {
2542 Np[r] =
static_cast<std::size_t
>(nj);
2546 "space_generator: class " + std::to_string(r) +
2547 " is open, so its population is unbounded; supply a cutoff for it");
2555 const std::vector<std::vector<std::size_t>> capc =
space_capacity_c(
sn, cutoff, cutoff_mat);
2556 const std::size_t unbounded =
static_cast<std::size_t
>(-1);
2557 for (std::size_t r = 0; r < R; ++r) {
2558 if (std::isfinite(njobs[r]))
continue;
2560 bool any_unbounded =
false;
2561 for (std::size_t ind = 1; ind <=
sn.nodes.size(); ++ind) {
2562 if (!
sn.nodes[ind - 1].stateful ||
sn.nodes[ind - 1].nodetype == NodeType::Source)
2564 if (capc[ind - 1][r] == unbounded) any_unbounded =
true;
2565 else hi = std::max(hi, capc[ind - 1][r]);
2567 if (!any_unbounded) Np[r] = std::min(Np[r], hi);
2570 std::vector<std::vector<bool>> chains =
sn.chains;
2571 if (chains.empty()) {
2572 chains.assign(R, std::vector<bool>(R,
false));
2573 for (std::size_t r = 0; r < R; ++r) chains[r][r] =
true;
2579 const std::vector<std::size_t>& sfn =
sn.stateful_nodes;
2580 const std::size_t NF = sfn.size();
2581 std::vector<std::size_t> lat_col(NF,
static_cast<std::size_t
>(-1));
2583 for (std::size_t k = 0; k < NF; ++k)
2584 if (
sn.nodes[sfn[k] - 1].nodetype != NodeType::Source) lat_col[k] = Mp++;
2592 std::vector<bool> is_open(R,
false);
2593 for (std::size_t r = 0; r < R; ++r)
2594 is_open[r] = !std::isfinite(njobs[r]);
2604 std::vector<std::vector<long>> lat_caps(R, std::vector<long>(Mp, -1));
2607 for (std::size_t k = 0; k < NF && ok; ++k) {
2608 if (lat_col[k] ==
static_cast<std::size_t
>(-1))
continue;
2609 const std::size_t ind = sfn[k];
2610 for (std::size_t r = 0; r < R; ++r) {
2611 const std::size_t cap = capc[ind - 1][r];
2612 lat_caps[r][lat_col[k]] =
2613 cap == unbounded ? -1 :
static_cast<long>(cap);
2616 if (!ok) lat_caps.clear();
2618 std::vector<std::vector<T>> pos;
2619 std::vector<std::size_t> nlev(R, 0);
2621 bool admissible =
true;
2622 for (std::size_t r = 0; r < R; ++r)
2623 if (!is_open[r] && nlev[r] != Np[r]) { admissible =
false;
break; }
2625 const std::vector<std::vector<T>> part =
2627 pos.insert(pos.end(), part.begin(), part.end());
2628 if (pos.size() > maxst)
2630 "space_generator: the population lattice exceeds the cap of " +
2631 std::to_string(maxst) +
" states; raise it or use another solver");
2635 for (; r < R; ++r) {
2636 if (nlev[r] < Np[r]) { ++nlev[r];
break; }
2643 std::sort(pos.begin(), pos.end());
2644 pos.erase(std::unique(pos.begin(), pos.end()), pos.end());
2652 std::vector<std::vector<std::vector<std::vector<T>>>> allper(pos.size());
2653 std::vector<bool> row_ok(pos.size(),
true);
2654 std::vector<std::size_t> maxw(NF, 0);
2655 std::vector<NetState<T>> out;
2656 for (std::size_t j = 0; j < pos.size(); ++j) {
2657 std::vector<std::vector<std::vector<T>>> per(NF);
2659 for (std::size_t k = 0; k < NF && ok; ++k) {
2660 const std::size_t ind = sfn[k];
2661 const std::size_t ist =
sn.nodes[ind - 1].station;
2662 std::vector<std::size_t> ph(R, 1), nmarg(R, 0);
2665 for (std::size_t r = 0; r < R; ++r) ph[r] =
sn.phasessz_of(ist, r + 1);
2666 if (lat_col[k] ==
static_cast<std::size_t
>(-1)) {
2676 for (std::size_t r = 0; r < R; ++r)
2677 if (!
sn.disabled[ist - 1][r]) nmarg[r] = 1;
2679 for (std::size_t r = 0; r < R; ++r)
2680 nmarg[r] =
static_cast<std::size_t
>(
2685 for (std::size_t r = 0; r < R && ok; ++r)
2686 if (capc[ind - 1][r] !=
static_cast<std::size_t
>(-1) &&
2687 nmarg[r] > capc[ind - 1][r])
2692 if (per[k].empty()) ok =
false;
2693 for (std::size_t b = 0; b < per[k].size(); ++b)
2694 maxw[k] = std::max(maxw[k], per[k][b].size());
2697 allper[j].swap(per);
2700 for (std::size_t j = 0; j < pos.size(); ++j) {
2701 if (!row_ok[j])
continue;
2702 std::vector<std::vector<std::vector<T>>>& per = allper[j];
2704 for (std::size_t k = 0; k < NF; ++k)
2705 for (std::size_t b = 0; b < per[k].size(); ++b)
2706 if (per[k][b].size() < maxw[k])
2707 per[k][b].insert(per[k][b].begin(), maxw[k] - per[k][b].size(),
2710 std::vector<NetState<T>> acc(1);
2711 for (std::size_t i = 0; i < NF; ++i) {
2712 std::vector<NetState<T>> next;
2713 for (std::size_t a = 0; a < acc.size(); ++a)
2714 for (std::size_t b = 0; b < per[i].size(); ++b) {
2716 ns.
local.push_back(per[i][b]);
2720 if (out.size() + acc.size() > maxst)
2722 "space_generator: the state space exceeds the cap of " +
2723 std::to_string(maxst) +
" states; raise it or use another solver");
2725 out.insert(out.end(), acc.begin(), acc.end());
2729 std::vector<std::vector<std::vector<T>>> seen;
2730 std::vector<NetState<T>> uniq;
2731 for (std::size_t i = 0; i < out.size(); ++i) {
2733 for (std::size_t p = 0; p < seen.size() && !dup; ++p)
2734 if (seen[p] == out[i].local) dup =
true;
2736 seen.push_back(out[i].local);
2737 uniq.push_back(out[i]);
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::vector< std::vector< bool > > replyblock
sn.replyblock (nnodes x nclasses) and sn.syncreply (nclasses).
std::vector< std::vector< std::size_t > > nvars
sn.nvars, (nnodes x 3R+1): the LOCAL VARIABLE columns each node appends to its state,...
std::vector< Station< T > > stations
stations[k-1] is the k-th station
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
@ KLIMITED
serve at most K per visit (K in pollingPar)
@ EXHAUSTIVE
serve until the queue empties
@ GATED
serve exactly the jobs present at the polling instant
@ DECREMENTING
serve until the queue is one shorter than at arrival
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
std::vector< double > pfqn_sdrprob(const SdrCoeff &c, const std::vector< double > &n)
SDR routing probabilities of eq.
std::vector< std::vector< int > > multichoose_rows(int n, int k)
All n-vectors of nonnegative integers summing to k, in MATLAB multichoose(n,k) order.
SdrCoeff pfqn_sdrcoeff(const SdrStruct &sdr)
Validates an SDR structure and returns its derived coefficients.
double pfqn_sdrped(const std::vector< double > &P)
Probability of being denied entry and routed straight to the departure centre.
std::vector< std::vector< T > > from_marginal(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n, const std::vector< std::size_t > &phases)
std::vector< std::vector< T > > polling_blocks(const PollingInfo< T > &pi, std::size_t srvclass, const std::vector< std::size_t > &nbuf)
Port of State.pollingBlocks + State.pollingProject: every controller configuration compatible with on...
void cache_retrieval_class_map(const CacheParam< T > &cp, std::vector< std::size_t > &rc_list, std::vector< std::size_t > &rc_items, std::vector< std::size_t > &rc_orig)
Port of State.cacheRetrievalClassMap: the canonical order of a cache's retrieval classes,...
Marginal< T > to_marginal(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< T > &state_i, const std::vector< std::size_t > &phasesz, const std::vector< std::size_t > &phaseshift, std::size_t nvar=0)
Port of State.toMarginal for a STATION, one state row at a time.
std::vector< double > station_populations(const NetworkStruct< T > &sn, const std::vector< std::vector< T > > &local)
Total jobs held by every STATION at one network state, indexed by station.
std::vector< NetState< T > > space_generator(const NetworkStruct< T > &sn, const std::vector< std::size_t > &cutoff, std::size_t maxst=3000000, const std::vector< std::vector< std::size_t > > &cutoff_mat=std::vector< std::vector< std::size_t > >())
Port of State.spaceGenerator: every network state, reachable or not.
std::vector< std::vector< T > > from_marginal_core(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n, const std::vector< std::size_t > &phases)
Port of State.fromMarginal for the station families CTMC enumerates: every local state in which stati...
std::vector< std::vector< T > > from_marginal_node(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< std::size_t > &n, const std::vector< std::size_t > &phases)
Port of State.fromMarginal at its OWN signature: the reference indexes by NODE, not by station,...
bool from_marginal_node_first(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< std::size_t > &n, const std::vector< std::size_t > &phases, std::vector< T > &out)
The FIRST row from_marginal_node emits, BUILT rather than enumerated.
std::size_t state_initial_occupancy(const NetworkStruct< T > &sn, std::size_t ind, std::size_t r)
Port of State.initialOccupancy: the class-r jobs node ind holds in the DECLARED initial state,...
std::vector< std::vector< T > > from_marg_node(const NetworkStruct< T > &sn, std::size_t ind, std::size_t ntot, const std::vector< std::size_t > &phases)
Port of State.fromMarg: the state space with a given TOTAL queue length.
void space_closed_single_capped_rec(std::size_t m, long n, const std::vector< long > &caps, std::size_t off, std::vector< T > &row, std::vector< std::vector< T > > &out)
space_closed_single with a PER-SLOT bound, the reference's spaceClosedSingle(M, N,...
std::vector< std::vector< T > > space_closed_single(std::size_t m, std::size_t n)
Port of State.spaceClosedSingle: the ways to place n jobs over m phases.
std::vector< std::vector< T > > from_marg_node_started(const NetworkStruct< T > &sn, std::size_t ind, std::size_t ntot, std::size_t stot, const std::vector< std::size_t > &phases)
Port of State.fromMargAndStarted: the states with a given TOTAL queue length AND a given TOTAL number...
std::vector< std::vector< T > > from_marginal_and_started_core(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n, const std::vector< std::size_t > &s, const std::vector< std::size_t > &phases)
Port of State.fromMarginalAndStarted: ONE state realizing both a per-class occupancy n and a per-clas...
std::vector< std::vector< T > > cartesian(const std::vector< std::vector< T > > &a, const std::vector< std::vector< T > > &b)
Port of State.cartesian: pair every row of a with every row of b.
std::vector< std::vector< T > > from_marginal_node_and_started(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< std::size_t > &n, const std::vector< std::size_t > &s, const std::vector< std::size_t > &phases)
Port of State.fromMarginalAndStarted at its OWN signature, which indexes by NODE rather than by stati...
std::vector< std::vector< std::size_t > > space_capacity_c(const NetworkStruct< T > &sn, const std::vector< std::size_t > &cutoff, const std::vector< std::vector< std::size_t > > &cutoff_mat=std::vector< std::vector< std::size_t > >())
Port of the capacityc table of State.spaceGeneratorNodes: the largest class-r marginal node ind may h...
PollingInfo< T > polling_info(const NetworkStruct< T > &sn, std::size_t ind)
Matrix< T > rt_state(const NetworkStruct< T > &sn, const std::vector< std::vector< T > > &local)
Port of sn.rtfun: the routing over the stateful nodes AT ONE STATE.
std::vector< std::vector< std::size_t > > pas_multiset_perms(const std::vector< std::size_t > &vec)
Port of matlab/util/multiset_perms.m on an ASCENDING multiset, ROW ORDER INCLUDED.
std::vector< std::vector< T > > from_marginal_and_started(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n, const std::vector< std::size_t > &s, const std::vector< std::size_t > &phases)
State.fromMarginalAndStarted with the trailing local-variable block appended, i.e.
std::vector< std::vector< T > > space_closed_multi_cs(std::size_t M, const std::vector< std::size_t > &N, const std::vector< std::vector< bool > > &chains, const std::vector< std::vector< long > > &caps=std::vector< std::vector< long > >())
Port of State.spaceClosedMultiCS: the same, but a CHAIN's population is shared among its classes,...
std::vector< std::vector< T > > append_local_vars(const NetworkStruct< T > &sn, std::size_t ist, std::vector< std::vector< T > > rows, const std::vector< std::size_t > &n, const std::vector< std::size_t > &phases)
Append the trailing local-variable block to every row the core builders produce, which is what makes ...
std::vector< std::vector< T > > space_closed_single_capped(std::size_t m, std::size_t n, const std::vector< long > &caps)
std::vector< std::vector< T > > space_closed_multi(std::size_t M, const std::vector< std::size_t > &N, const std::vector< std::vector< long > > &caps=std::vector< std::vector< long > >())
Port of State.spaceClosedMulti: how N[r] class-r jobs distribute over M stateful nodes,...
std::vector< std::vector< T > > from_marginal_pool(const NetworkStruct< T > &sn, std::size_t ist, const std::vector< std::size_t > &n)
Port of State.fromMarginalPool: the local states with marginal n at a station rewritten by ctmc::ctmc...
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Integer-composition enumeration shared by the CoMoM and MVAC ports.
State.pollingInfo and the controller description it returns.
Derived coefficients of an SDR structure, eqs.
long max_pending_retrieval
Truncation level of block B: how many secondary requests may be merged onto the in-flight fetches of ...
std::vector< int > itemcap
std::vector< std::size_t > missclass
std::vector< std::size_t > hitclass
CTMC pair form of a MAP service at an FCFS station, written by ctmc::ctmc_mapc on the solver's privat...
CTMC bookkeeping of a heterogeneous-server station, written by ctmc::ctmc_pools on the solver's priva...
std::vector< std::vector< std::size_t > > len
offset and length of block k of class r
std::vector< std::vector< std::size_t > > pools
pools[r-1]: compatible pools of r, ascending
bool rotate
ALIS/FAIRNESS order is part of the state.
std::vector< std::vector< std::size_t > > perms
every pool order, identity first
static constexpr double MaxInt
Stand-in for an unbounded COUNT, MATLAB GlobalConstants.MaxInt.
What State.toMarginal returns for one station and one state row.
std::vector< std::vector< T > > kir
jobs in service per class and phase
T ni
total jobs in the station
std::vector< T > nir
jobs per class
std::vector< T > sir
jobs in service per class
One network state: the per-stateful-node local rows it is composed of.
std::vector< std::vector< T > > local
local[isf] is that node's state row
The G-network signal declaration, per CLASS.
FINITE CAPACITY REGIONS, MATLAB's refreshRegions output.
std::vector< std::vector< double > > cap
(nstations x nclasses+1), -1 = unbounded
std::vector< RoutingStrategy > routing
sn.routing, per class.
Port of State.pollingInfo: the derived description of a polling controller.
std::vector< bool > has_sw
std::vector< std::size_t > ksw
std::vector< bool > polled
One station of the network.
double nservers
may be infinite (a Delay, or an inf-scheduled task)
The parameters of a Cache node, MATLAB's sn.nodeparam{ind} for a Cache.
std::vector< double > nmodeservers
servers per mode, may be infinite
std::vector< std::size_t > firingphases
phase count per mode, 0 when non-Markovian